基于51单片机的NTC热敏电阻和ADC电压测量

        本次设计利用AT89C51作为主控,利用74HC573作为数码管驱动芯片,数码管为六位共阴数码管,利用独立按键进行用户交互,实现温度/电压二者之间的转换,利用8位LED进行状态显示,利用IIC驱动PCF8591进行ADC获取数值和DAC模拟输出,通过NTC热敏电阻的特性,转换成温度值,利用ADC转换进行电压输入和模拟输出实现测量电压越高,输出电压越高。

一、硬件设计

1、PCF8591

        PCF8591是一个单片集成、单独供电、低功耗、8-bit CMOS数据获取器件。PCF8591具有4个模拟输入、1个模拟输出和1个串行I²C总线接口。PCF8591的3个地址引脚A0, A1和A2可用于硬件地址编程,允许在同个I2C总线上接入8个PCF8591器件,而无需额外的硬件。在PCF8591器件上输入输出的地址、控制和数据信号都是通过双线双向I2C总线以串行的方式进行传输。相比较与ADC0808,ADC0804,PCF8591具有节省IO口,转换稳定等特性,且PCF8591有四个ADC输入,一个DAC输出口,针对本次设计的要求是完美符合的。如下

2、74HC573驱动数码管

        74HC573是拥有八路输出的透明锁存器,输出为三态门,是一种高性能硅栅CMOS器件,是一种锁存芯片,74HC573一般用于扩展单片机的IO口,一般情况下驱动一个6位数码管需要大于8+6=14个IO口,但是在利用74HC573的情况下只需要8+2=10个IO口,足足节省了4个IO口。

二、软件设计

1、IIC驱动PCF8591

(1)IIC协议驱动代码

        IIC驱动代码具有一般的通用性,通过IIC的读写时序可以得出以下代码,这里不过多演示IIC协议原理。

#include "delay.h"
#include "iic.h"

void delay_5us()
{
	unsigned char i;

	i = 12;
	while (--i);	
}

//金丝草;使用iic通讯方案1
//方案1:每个函数结束后未释放SDA线,且SCL=1; STOP信号均为高。起始前面处理一下
//方案2:每个函数结束后释放SDA线,且SCL=0;STOP信号均为高。后面信号处理一下。
//本次采用方案1
//1、IIC开始信号
void START_IIC(void)
{
	SCL = 0;
	SDA = 1;
	delay_5us();
	SCL = 1;
	delay_5us();
	SDA = 0;
	delay_5us();
}
 
//2、IIC结束信号
void STOP_IIC(void)
{
	SCL = 0;
	SDA = 0;
	delay_5us();
	SCL = 1;
	delay_5us();
	SDA = 1;
	delay_5us();
}
 
//器件的地址共计7位,第8位为0表示要写数据给设备
//为1表示要读取设备的数据
//3、IIC写数据
void write_1_byte_IIC(unsigned char datax)
{
	unsigned char i;
	for (i = 0x80;i != 0;i >>= 1)
	{
		SCL = 0;
		delay_5us();
		if ((datax & i) == i)  //马来逼,这个地方原始数据为datax&i==1  &的结果为16进制应该与i比较,并且&没有==优先级高
			SDA = 1;
		else
			SDA = 0;
		delay_5us();
		SCL = 1;
		delay_5us();
	}
}
 
//4、IIC读数据 
unsigned char read_1_byte_IIC(void) //读取1字节数据
{
	unsigned char i;
	unsigned char datax = 0;
	for (i = 0x80;i != 0;i >>= 1)
	{
		SCL = 0;
		SDA = 1;  //释放SDA线
		delay_5us();
		SCL = 1;
		delay_5us();
		if (SDA)
			datax |= i;//读取SDA线上的数据
		delay_5us();
	}
	return(datax);
}
 
//5、读取接收ACK应答信号
bit read_ACK_IIC(void)
{
	bit ACK = 0;
	SCL = 0;
	SDA = 1;
	delay_5us();
	SCL = 1;
	delay_5us();
	ACK = SDA;	
	return(ACK);//如果ACK=1,则未收到应答   //如果ACK=0,则收到应答
}
 
//6、发送应答ACK信号
void write_ACK_IIC(bit ACK)
{
	SCL = 0;
	SDA = ACK; //ACK=1,表示不发送应答,=0表示发送应答
	delay_5us();
	SCL = 1;
	delay_5us();
}

(2)PCF8591驱动代码

        PCF8591驱动主要是利用IIC协议进行PCF8591寄存器的读写操作,一般情况下,遵循PCF8591的一般读写就可以完成功能,这里不过多解释。如下:

//PCF8591 iic通讯时序还没有AT24C02快呢,iic器件遵守iic通讯协议,故,在这里就使用AT24C02器件的iic通讯协议了
//PCF8591芯片地址为1001 xxxy最后4位看原理图,在本单片机里芯片地址位1001 000y  即0x9?其中y位表示是读取器件还是向器件写入
//读器件使用0x91,向器件写入数据使用0x90
//PCF8591使用逐次逼近型A/D转换,转换时间us级。
 
// SCL = P2_1;//时钟连接P2.1口
// SDA = P2_0;//时钟连接P2.0口
 
/*高位							地位
	0	x	x	x	0	x	x	x
	bit7位默认为0
	bit6位是否允许模拟电压输出,在DA转换时设置1,AD转换设置0或1均可。
	bit5和bit4位是选择模拟电压输出方式,一般位00单端输入方式。
	bit3位默认为0
	bit2位第是自动增量使能位,如果自动增量(auto-increment)标志置1,每次A/D 转换后通道号将自动增加。
	bit1和bit0位是在AD转换时选择哪一个通道输入的电压转换位数字量 00表示打开通道AIN0	01表示打开通道AIN1	10表示打开通道AIN2	11表示打开通带AIN3
*/
//AIN0通道连接光敏电阻,AIN1通道连接热敏电阻,AIN2通道连接模拟信号输入(滑动电阻器),AIN3未连接其他器件
#include "iic.h"
 
//本代码加入了读取ACK问题,使用了goto语句
 
//AD转换,读取com通道的8位数据,0x00/0x40表示打开通道AIN0	0x01/0x41表示打开通道AIN1	0x02/0x42表示打开通道AIN2	0x03/0x43表示打开通带AIN3
unsigned char read_AD_data(unsigned char com)
{
	unsigned char dat = 0;
	unsigned char i = 0;
	read_ad_data:
	START_IIC();
	write_1_byte_IIC(0x90);//准备向pcf8591器件写入数据,此器件的地址为1001 A0 A1 A2 R/W
	if (!read_ACK_IIC())//若接收到ACK则与器件握手成功
	{
		write_1_byte_IIC(com);//向器件写入使用哪个AD通到开始采集数据,0x00/0x40表示通道AIN0	0x01/0x41表示通道AIN1	0x02/0x42表示通道AIN2	0x03/0x43表示通带AIN3
		if (!read_ACK_IIC())
		{
			START_IIC();//和at24c02 读取数据有点类似   马来币之前没有写 手册英文没有看到这个地方如何读取的,参考别人写的代码
			write_1_byte_IIC(0x91);//准备读取pcf8591发来的数据
			if (!read_ACK_IIC())
			{
				dat = read_1_byte_IIC();
				write_ACK_IIC(1);//主机接收到数据向从设备不发送应答信号
				STOP_IIC();	//结束本次通讯
				return dat;
			}
			else
			{
				STOP_IIC();
				goto read_ad_data;
			}
		}
		else
		{
			STOP_IIC();
			goto read_ad_data;
		}
	}
	else
	{
		i++;
		if (i == 255)
		{
			return i;//如果握手失败255次则直接结束本函数,并向函数返回运行结果255;
		}
		STOP_IIC();
		goto read_ad_data;
	}
		
}
 
//DA转换,输出模拟量通过芯片的AOUT端口输出
unsigned char write_DA_data(unsigned char dat)//0~255对应0V~5V
{
	unsigned char i = 0;
	write_da_data:
	START_IIC();
	write_1_byte_IIC(0x90);
	if (read_ACK_IIC() == 0)
	{
		write_1_byte_IIC(0x40);//允许器件模拟输出,并且不自动增加输出端口
		if (!read_ACK_IIC())
		{
			write_1_byte_IIC(dat);
			if (!read_ACK_IIC())
			{
				STOP_IIC();
				return i;//如果握手失败255次则直接结束本函数,并向函数返回运行结果255;
			}
			else
			{
				STOP_IIC();
				goto write_da_data;
				
			}
				
		}
	 else
	 {
			STOP_IIC();
			goto write_da_data;
	 }
	}
	else
	{
		i++;
		if (i == 255)
		{
			return i;//如果握手失败255次则直接结束本函数,并向函数返回运行结果255;
		}
		STOP_IIC();
		goto write_da_data;
	}
}
//数字量转换成模拟电压公式如下
unsigned char convert_data(unsigned char DA)
{
	unsigned char i = 0;
	i = (unsigned char)(DA * 5 / 256.0 + 0.0005);//pcf8591内部数字量转化为模拟量的计算公式
	return i;
}

2、74HC573驱动数码管

        74HC595驱动一般写入时序是,将数据送入并行总线,LE引脚拉低,操作简单,本次设计利用6位共阴数码管,本次设计进行函数的深层次封装,得出如下代码:

sbit wei = P2^7;
sbit duan = P2^6;

unsigned duan_[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f};

void nixie(u8 pos, u8 num, u8 dot)
{
		wei=1;
		P0 = ~(0x01 << pos-1);
		wei=0;			
		
		duan=1;
		if(dot)P0 = duan_[num]| 0x80;
		else P0 = duan_[num];
		duan=0;	
		
		delay(1);
		P0=0xFF;	
}

三、功能演示

1、初始状态

        程序初始运行,显示温度值,由于本次设计的温度下限是30,温度上限是40,所以此时灯光是绿灯。

2、温度过高或者过低

        温度过高或者过低的时候,都会报警,当温度低于下限的时候,黄灯会进行闪烁,当温度高于上限的时候,红灯会闪烁,本次设计的上限是40,下限是30.演示如下图:

3、电压测量模式

        显示屏上一般会显示两个电压值,分别是左电阻,一个是右电阻,通过拉动滑动变阻器,电压值会进行改变,此时电压处在正常区间,绿灯时亮起的。

4、电压过高或过低

        电压过高或者过低都会触发报警,上限时4v,下限是2v,任意一个电阻高于4V时,红灯会进行闪烁,当没有带你呀高于4v时,且有任意一个电压低于2V,此时黄灯进行闪烁,如下图:

5、DAC输出

        本次设计有DAC输出功能,系统测量第一个电阻的电压,通过第一个电阻的电压值,调整DAC输出,电压越高,led灯越亮,如下图:

四、项目总结

        本次设计利用AT89C51借助PCF8591进行三路ADC的测量,第一路ADC为热敏电阻,通过热敏电阻特性得到温度值,其他两路使用ADC模数转换进行测量电压,同时集成温度报警、电压报警,按键模式切换等。

详情请参考我的bilibili

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值