基于C51单片机+DS18B20温度传感器+LCD1602显示器的智能水温控制系统(PID)

一、DS18B20传感器相关介绍

DS18B20特性

  1. 独特的单总线接口,就需一条线则可实现双向通信(测温)
  2. 测温范围:-55℃~+125℃,可通过编程设定9—12位分辨率,对应分辨温度分别为0.5、0.25、0.125、0.0625℃。
  3. 支持多点组网(可连接多个DS18B20温度传感器),多个DS18B20可以并联(3或2线)实现多个组网测温,但注意超过8个要解决好供电问题,否则电压过低会导致传输不稳定,从而数据不准确。
  4. 工作电压:3.0~5.5V (寄生电源方式下可由数据线供电)
  5. 在使用过程中不需要外围电路,全部传感元件及转换电路都在芯片内了。(上拉电阻)
  6. 测温结果直接是数字量输出,单总线串行传送方式,同时可传送CRC校验码(校验数据采集是否正确),具有极强的抗干扰和纠错能力。
  7. 在9位分辨率时最多在93.75ms内把温度转换为数字,12位分辨率时最多在750ms内把温度值转换为数字。
  8. 负压特性:电源极性接反时,芯片不会因发热而烧毁, 但不能正常工作。

封装形式与引脚说明

引脚

供电方式(外部电源供电、寄生电源供电、寄生电源强上拉)

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

DS18B20指令(ROM指令操作)

序号 指令 代码 说明
1 读取ROM 33H 读DS18B20的64位序列号(只能适用于总线上只有一个DS18B20)
2 写暂存器 4EH 在该写暂存器指令后向DS18B20的暂存器TH.TL以及配置寄存器中写入数据。
3 读暂存器 BEH 发送该指令后DS18B20将从一个字节开始,依次送出9个字节的内容。如果不想读完所有字节。控制器可以在任何时间发出复位指令中止读取或直接不读取。
4 复制暂存器 48H 将TH.TL和配置寄存器的内容拷贝到EEPROM中,如果使用寄生电源,总线控制器必须在这条指令发出后10us内启动强上拉并保持至少10ms时间。
5 启动温度转换指令 44H 温度转换完成后存放在第1个和第2个字节中,如果是寄生电源,总线必须在发出这条指令后的10us内启动强上拉。
6 复制EEPROM指令 B8H 把TH.TL和配置寄存器的值拷贝回暂存器。这种拷贝操作在DS18B20上电时自动执行,上电后,暂存器里就存了有效数据。
7 读供电方式指令 B4H 发给DS18B20后,再发出读时间间隙,后返回电源模式:0为寄生电源、1为外部电源。

DS18B20程序代码

/********************************************
******************DS18B20********************
*********************************************/ 
void delay_18B20(unsigned int i)//延时1微秒
{
   while(i--);
}

void ds1820rst(void)  //DS18B20复位
{ 
	unsigned char x=0;
	DS = 1;           //DQ复位
	delay_18B20(4);   //延时
	DS = 0;           //DQ拉低
    TR0=0;
	delay_18B20(100); //精确延时大于
    TR0=1;
	DS = 1;           //拉高
	delay_18B20(40); 
} 

uchar ds1820rd(void)//读数据
{ 
	unsigned char i=0;
	unsigned char dat = 0;
    TR0=0;
	for (i=8;i>0;i--)
	{   
		DS = 0; //给脉冲信号
		dat>>=1;
		DS = 1; //给脉冲信号
		if(DS)
		dat|=0x80;
		delay_18B20(10);
	}
   return(dat);
}

void ds1820wr(uchar wdata)//写数据
{
	unsigned char i=0;
    TR0=0;
    for (i=8; i>0; i--)
    { 
		DS = 0;
		DS = wdata&0x01;
		delay_18B20(10);
		DS = 1;
		wdata>>=1;
   }
}



uint get_temper()//获取温度
{  
     
	uchar a,b;

	ds1820rst();    
	ds1820wr(0xcc);//跳过读序列号
	ds1820wr(0x44);//启动温度转换
	ds1820rst();    
	ds1820wr(0xcc);//跳过读序列号 
	ds1820wr(0xbe);//读取温度 
	a=ds1820rd();
	b=ds1820rd();
   
	tvalue=b;
	tvalue<<=8;
	tvalue=tvalue|a;
    TR0=1;
    if(tvalue<0x0fff)   tflag=0;
    else {tvalue=~tvalue+1;tflag=1;}
	  tvalue=tvalue*(0.625);//温度值扩大10倍,精确到1位小数
	  temp=tvalue;
	return temp;
}


void dis_temp(int t)//显示温度
{
	uchar d0,d1,d2,d3;
	if(tflag==0)
	{
		d0=t/1000+0x30;//百位
		d1=t%1000/100+0x30;//十位
		d2=t%100/10+0x30;//个位
		d3=t%10+0x30;//小数位
		if(d0==0x30)
		{
			wr_com(0x80+10);
			wr_data(d1);
			wr_com(0x80+11);
			wr_data(d2);
			wr_com(0x80+12);
			wr_data(0x2e);
			wr_com(0x80+13);
			wr_data(d3);
		}
		else
		{
			wr_com(0x80+10);
			wr_data(d0);
			wr_com(0x80+11);
			wr_data(d1);
			wr_com(0x80+12);
			wr_data(d2);
			wr_com(0x80+13);
			wr_data(' ');
		}
		
	}
	else
	{
		wr_com(0x80+10);
		wr_data('-');
		wr_com(0x80+11);
		wr_data(d1);
		wr_com(0x80+12);
		wr_data(d2);
		wr_com(0x80+13);
		wr_data(' ');
	}
	wr_com(0x80+14); //摄氏度符号
	wr_data(0xdf);
	temper=t/10;
}

二、LCD1602显示温度

接口信号说明

在这里插入图片描述

基本操作步骤与时序

在这里插入图片描述
在这里插入图片描述

LCD1602接线图

在这里插入图片描述

初始化过程

延时15ms
写指令38H(不检测忙信号)
延时5ms
写指令38H(不检测忙信号)
延时5ms
写指令38H(不检测忙信号)
(以后每次写指令,读/写数据操作之前均需检测忙信号) 写指令38H:显示模式设置
写指令08H:显示关闭
写指令01H:显示清屏
写指令06H:显示光标移动设置
写指令0CH:显示开及光标设置

LCD1602程序代码

/********************************************
******************LCD1602********************
*********************************************/ 
void delay(i)//延时函数
{
	uint j;
	for(i;i>0;i--)
	for(j=110;j>0;j--);
}

void wr_com(uchar ml)//LCD液晶写命令
{
	lcdrs=0;  //寄存器低电平选择指令寄存器
	P0=ml;
	delay(5);
	lcden=1;
	delay(5);
	lcden=0;

}

void wr_data(uchar shuju)//LCD液晶写数据
{
	lcdrs=1;
	P0=shuju;
	delay(5);
	lcden=1;
	delay(5);
	lcden=0;

}

void init()      //按照时序操作的初始化
{	
	lcdrw=0;     //低电平为写操作
	wr_com(0x38);//显示模式设置,设置为16*2显示,5*7点阵,八位数据口
	wr_com(0x0c);//开显示,但不开光标,光标不闪
	wr_com(0x06);//显示光标移动设置
	wr_com(0x01);// 清屏
	wr_com(0x80);// 数据指针初始化
	for(num=0;num<16;num++)
		{
			wr_data(str1[num]);//实际温度
		}
	wr_com(0x80+0x40);         //地址初始化
	for(num=0;num<16;num++)
		{
			wr_data(str2[num]);//设置温度
		}	 
}

三、其他模块

其他模块包括独立按键模块单片机核心模块继电器模块。通过独立按键设置目标温度,然后通过温度传感器将数字温度信号传递给单片机,单片机通过高低电平转换,控制继电器的通断,进而实现加热设备对水温进行控制。

独立按键模块

独立按键式直接用I/O口线构成的单个按键电路,其特点式每个按键单独占用一根I/O口线,每个按键的工作不会影响其他I/O口线的状态。独立式按键电路配置灵活,软件结构简单,但每个按键必须占用一个I/O口线,因此,在按键较多时,I/O口线浪费较大,不宜采用。

在这里插入图片描述

独立按键的软件常采用查询式结构。先逐位查询没跟I/O口线的输入状态,如某一根I/O口线输入为低电平,则可确认该I/O口线所对应的按键已按下,然后,再转向该键的功能处理程序。

独立键盘理想的波形是按下去时保持低电平,实际上在上升沿和下降沿的过程中(即按键和离键时的一段微小时间)会出现抖动。消抖的方法有两种,一种是通过硬件:在电路上连个电容;另一种是软件消抖,根据经验增加10ms的延时。这样即能起到消抖的作用。

sbit key = P1 ^ 1;
 
while(!key); //有按键抬起
delay_ms(10);
while(!key); //确实有按键抬起

单片机核心模块

在这里插入图片描述

继电器模块

在这里插入图片描述

当输入高电平时,晶体管T1饱和导通,继电器线圈通电,触点吸合。
当输入低电平时,晶体管T1截止,继电器线圈断电,触点断开。

四、温控系统PID

采用位置式PID控制水温

void PIDInit (struct PID *p) 
{ 
	memset ( p,0,sizeof(struct PID)); //用参数0初始化p
} 

/**********************************************
根据位置式离散PID公式
PID = Kp*e(k)+Ki*∑e(k)+Kd[e(k)-e(k-1)]
e(k)代表本次偏差 
e(k-1)代表上一次的偏差  
∑e(k)代表e(k)以及之前的偏差的累积和;其中k为1,2,,k;
PID代表输出
***********************************************/
unsigned int PIDCalc( struct PID *p, unsigned int NextPoint ) 
{ 
	unsigned int dError,Error; 
	Error = p->SetPoint - NextPoint; // 偏差 
	p->SumError += Error; // 积分 
	dError = p->LastError - p->PrevError; // 当前微分 
	p->PrevError = p->LastError; 
	p->LastError = Error; 
	return (p->Proportion * Error//比例
	+ p->Integral * p->SumError  //积分项
	+ p->Derivative * dError); //   微分项 
} 

五、主函数 main( )

/********************************************
********************主函数*******************
*********************************************/ 
void main(void)
{
	unsigned char i;
	init();//LCD初始化
	TMOD=0x01;//定时器初始化
	TH0=0x2f; 
	TL0=0x40;
	EA=1;
	ET0=1;
	TR0=1;
	high_time=50; 
	low_time=50; 
	PIDInit ( &spid ); //初始化结构
	spid.Proportion= 7; //设定PID系数
	spid.Integral = 3; 
	spid.Derivative =20; 
	spid.SetPoint =100; //PID设置定位点
	set[0]=set_temper/10;
	set[1]=set_temper%10;
	wr_com(0x80+0x40+10);	//显示设置温度
	wr_data(table[set[0]]);
    delay(1);
	wr_com(0x80+0x40+11);
	wr_data(table[set[1]]);
	delay(1);
	wr_com(0x80+0x40+14);	//显示温度符号
	wr_data(0xdf);
	delay(1);
	while(1)
	{
		keyscan(); 	//按键扫描
		for(i=0;i<10;i++)	//循环10次
		{
			dis_temp(get_temper());	//显示温度值
			if((key0==0)||(key1==0)) break;	//如果有按键退出显示循环
		}
		if((key0!=0)&&(key1!=0))		compare_temper(); 	//比较温度
	}
}

六、项目展示

在这里插入图片描述
基于单片机AT89C52的温控系统代码
以上就是系统的代码 (总共491行),也可以留言找我发邮箱哦。

版权声明:本文为CSDN博主「Zeal.Zhang」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/a2145565/article/details/114175661

生成海报
点赞 0

Zeal.Zhang

我还没有学会写个人说明!

暂无评论

发表评论

相关推荐

ESP8266 无限重启踩坑

最近做了一个电子墨水屏万年历,在移植屏幕代码时遇到了esp8266无限软复位的问题,如果你的串口打印是以下图片所示,那么恭喜你问题解决了。 造成软复位的原因是因为,程序里有死循环&#xf

Keil MDK5 STM32F103C8T6开发环境配置

Windows下使用Keil MDK5进行stm32f103c8t6的开发和编译, 配合ST-LINK工具进行烧录, 使用原生(非HAL)的方式. 所需硬件 stm32f103系列开发板 stm32f103c8t6核心板 参数 ARM 32-b