为好朋友东东设计了个单片机热水锅炉自动温度控制系统。因为他家的热水锅炉因温度太低,没及时加热,爆过几 次。也有因加热过头,烧干水,化了管子。东东很快做好了实物,程序得到验证,两人皆大欢喜。
1.下限5°C时加热器加热,上限40°C时停止。温度下降,直到下限时重新加热。
2.温度70°C时冷却水泵工作,温度降到45°C时停止。下次仍为70°C时水泵工作。
3.加热/水泵 按钮可切换切换加热器和冷却泵的设定及显示(HTR为加热器,CTP为冷却水泵)。
程序中对两组上下限设定做成可调的,方便实际使用中对上下限的细调。
E:\DPJ_C\18B20LCD\DD2\18B20DD2.C
- //2012 05 04
- #include<reg51.h>
- #include<intrins.h>
- #define uchar unsigned char
- #define uint unsigned int
- sbit RS=P2^0;
- sbit RW=P2^1;
- sbit E=P2^2;
- sbit BF=P0^7;
- sbit DQ=P3^3;
- sbit KEY0=P1^0;
- sbit KEY1=P1^1;
- sbit KEY2=P1^2;
- sbit KEY3=P1^3;
- sbit HTR=P1^4; //加热器
- sbit CTP=P1^5; //冷却泵
- uchar h_TH=40,h_TL=5,p_TH=70,p_TL=45;
- uchar code digit[12]={"0123456789- "};
- uchar code digit1[15]={"011233445677889"};
- uchar code digit2[16]={"0112234456677889"};
- uchar code Now[]={"Now:"};
- uchar code TH[]={"TH"};
- uchar code TL[]={"TL"};
- uchar code Cent[]={0xdf,0x43}; //温度单位℃
- bit flag1,flag2,flag3; //flag1温度为负的标志 flag2电热标志 flag3 水泵标志
- /*****************************************************
- us 延时子函数
- ***************************************************/
- void ds18b20_delay(uchar us)
- {
- while(us--);
- }
- /*****************************************************
- ms 延时子函数
- ***************************************************/
- void delay(uint ms)
- {
- uchar i;
- while(ms--)
- for(i=0;i<123;i++);
- }
- /*****************************************************
- 判断液晶模块的忙碌状态
- ***************************************************/
- bit BusyTest()
- {
- bit result;
- RS=0;
- RW=1;
- E=1;
- _nop_();
- _nop_();
- _nop_();
- _nop_(); //空操作四个机器周期,给硬件反应时间
- result=BF;
- E=0; //将E恢复低电平
- return result;
- }
- /*****************************************************
- 将模式设置指令或显示地址写入液晶模块
- ***************************************************/
- void WriteCmd (uchar dictate)
- {
- while(BusyTest()==1); //如果忙就等待
- RS=0;
- RW=0;
- E=0;
- _nop_();
- _nop_(); //空操作两个机器周期,给硬件反应时间
- P0=dictate;
- _nop_();
- _nop_();
- _nop_();
- _nop_(); //空操作四个机器周期,给硬件反应时间
- E=1;
- _nop_();
- _nop_();
- _nop_();
- _nop_();
- E=0;
- }
- /*****************************************************
- 函数功能:指定字符显示的实际地址
- 入口参数:x
- ***************************************************/
- void WriteAdd(uchar x)
- {
- WriteCmd(x|0x80); //显示位置的确定方法规定为"80H+地址码x"
- }
- /*****************************************************
- 将数据(字符的标准ASCII码)写入液晶模块
- ***************************************************/
- void WriteData(uchar y)
- {
- while(BusyTest()==1);
- RS=1; //RS为高电平,RW为低电平时,可以写入数据
- RW=0;
- E=0; //E置低电平(根据表8-6,写指令时,E为高脉冲,
- // 就是让E从0到1发生正跳变,所以应先置"0"
- P0=y; //将数据送入P0口,即将数据写入液晶模块
- _nop_();
- _nop_();
- _nop_();
- _nop_(); //空操作四个机器周期,给硬件反应时间
- E=1; //E置高电平
- _nop_();
- _nop_();
- _nop_();
- _nop_(); //空操作四个机器周期,给硬件反应时间
- E=0; //当E由高电平跳变成低电平时,液晶模块开始执行命令
- }
- /*****************************************************
- LCD1602 初始化
- ***************************************************/
- void LcdInitiate(void)
- {
- delay(15); //延时15ms,首次写指令时应给LCD一段较长的反应时间
- WriteCmd(0x38); //显示模式设置:16×2显示,5×7点阵,8位数据接口
- delay(5); //延时5ms ,给硬件一点反应时间
- WriteCmd(0x38);
- delay(5); //延时5ms ,给硬件一点反应时间
- WriteCmd(0x38); //连续三次,确保初始化成功
- delay(5); //延时5ms ,给硬件一点反应时间
- WriteCmd(0x0c); //显示模式设置:显示开,无光标,光标不闪烁
- delay(5); //延时5ms ,给硬件一点反应时间
- // WriteCmd(0x06); //显示模式设置:光标右移,字符不移
- delay(5); //延时5ms ,给硬件一点反应时间
- WriteCmd(0x01); //清屏幕指令,将以前的显示内容清除
- delay(5); //延时5ms ,给硬件一点反应时间
- }
- /************************************************************************
- 以下是DS18B20的操作程序
- ************************************************************************/
- /*****************************************************
- DS18B20初始化
- ***************************************************/
- void Init_DS18B20()
- {
- uchar x=0;
- DQ=1;
- ds18b20_delay(8);
- DQ=0;
- ds18b20_delay(80);
- DQ=1;
- ds18b20_delay(14);
- x=DQ;
- ds18b20_delay(20);
- }
- /*****************************************************
- 函数功能:写一个字节
- 入口参数:
- ***************************************************/
- void WriteOneChar(uchar dat)
- {
- uchar i;
- for(i=8;i>0;i--)
- {
- DQ=0;
- if(dat&0x01==0x01)
- DQ=1;
- else
- DQ=0;
- ds18b20_delay(5);
- DQ=1;
- ds18b20_delay(1);
- dat>>=1;
- }
- }
- /*****************************************************
- 读一个字节
- ***************************************************/
- uchar ReadOneChar()
- {
- uchar dat=0,i;
- for(i=8;i>0;i--)
- {
- dat>>=1;
- DQ=0;
- ds18b20_delay(1);
- DQ=1;
- if(DQ==1)
- dat|=0x80;
- else
- dat&=0x7f;
- ds18b20_delay(4);
- }
- return(dat);
- }
- /*****************************************************
- 显示Now:
- ***************************************************/
- void display_Now()
- {
- uchar i;
- WriteAdd(0x00); //写显示地址,将在第1行第1列开始显示
- for(i=0;i<4;i++)
- WriteData(Now[i]);
- delay(50); //延时1ms给硬件一点反应时间
- }
- /*****************************************************
- 显示温度的小数点
- ***************************************************/
- void display_dot(void)
- {
- WriteAdd(0x07); //写显示地址,将在第1行第10列开始显示
- WriteData('.'); //将小数点的字符常量写入LCD
- delay(50); //延时1ms给硬件一点反应时间
- }
- /*****************************************************
- 显示温度的单位(°C)
- ***************************************************/
- void display_cent(void)
- {
- uchar i;
- WriteAdd(0x09); //写显示地址,将在第1行第13列开始显示
- for(i=0;i<2;i++)
- WriteData(Cent[i]); //将字符常量写入LCD
- WriteAdd(0x45);
- for(i=0;i<2;i++)
- WriteData(Cent[i]);
- WriteAdd(0x4e);
- for(i=0;i<2;i++)
- WriteData(Cent[i]);
- }
- /*****************************************************
- 显示温度的整数部分
- ***************************************************/
- void display_temp1(uchar x)
- {
- uchar j,k,l; //j,k,l分别储存温度的百位、十位和个位
- j=x/100; //取百位
- k=(x%100)/10; //取十位
- l=x%10; //取个位
- WriteAdd(0x04); //写显示地址,将在第1行第5列开始显示
- if(flag1==1)
- {
- WriteData(digit[10]); //将"-" 号写入LCD
- }
- else
- if(j==0)
- {j=11;}
- WriteData(digit[j]); //将百位数字的字符常量写入LCD
- if(j==0&&k==0)
- {k=11;}
- WriteData(digit[k]); //将十位数字写入LCD
- WriteData(digit[l]); //将个位数字写入LCD
- delay(50);
- }
- /*****************************************************
- 显示温度的小数部分
- ***************************************************/
- void display_temp2(uchar x)
- {
- WriteAdd(0x08); //写显示地址,将在第2行第11列开始显示
- if(flag1==1)
- {
- WriteData(digit1[x]); //温度为负,将小数部分的第一位数字写入LCD
- }
- else
- WriteData(digit2[x]); //温度为正,将小数部分的第一位数字写入LCD
- }
- /*****************************************************
- 显示温度设定部分
- ***************************************************/
- void display_THTL ()
- {
- uchar i,hhh,hhl,phh,phl,hlh,hll,plh,pll;
- hhh=h_TH/10;
- hhl=h_TH%10;
- phh=p_TH/10;
- phl=p_TH%10;
- hlh=h_TL/10;
- hll=h_TL%10;
- plh=p_TL/10;
- pll=p_TL%10;
- WriteAdd(0x40); //第2行第1个字节开始
- for(i=0;i<2;i++)
- WriteData(TH[i]);
- WriteAdd(0x43);
- if(flag2)
- {
- WriteData(digit[phh]);
- WriteData(digit[phl]);
- }
- else
- {
- WriteData(digit[hhh]);
- WriteData(digit[hhl]);
- }
- WriteAdd(0x49); //第2行第10个字节开始
- for(i=0;i<2;i++)
- WriteData(TL[i]);
- WriteAdd(0x4c);
- if(flag2)
- {
- WriteData(digit[plh]);
- WriteData(digit[pll]);
- WriteAdd(0x0d);
- WriteData('C');
- WriteAdd(0x0e);
- WriteData('T');
- WriteAdd(0x0f);
- WriteData('P');
- }
- else
- {
- WriteData(digit[hlh]);
- WriteData(digit[hll]);
- WriteAdd(0x0d);//也可以这样的写法
- WriteData('H');
- WriteAdd(0x0e);
- WriteData('T');
- WriteAdd(0x0f);
- WriteData('R');
- }
- }
- /*****************************************************
- 准备读温度
- ***************************************************/
- void ReadyReadTemp()
- {
- Init_DS18B20(); //将DS18B20初始化
- WriteOneChar(0xCC); // 跳过读序号列号的操作
- WriteOneChar(0x44); // 启动温度转换
- //for(time=0;time<100;time++); //温度转换需要一点时间
- Init_DS18B20(); //将DS18B20初始化
- WriteOneChar(0xCC); //跳过读序号列号的操作
- WriteOneChar(0xBE); //读取温度寄存器,前两个分别是温度的低位和高位
- }
- /*****************************************************
- 函数功能:按键扫描子函数
- ***************************************************/
- void keyscan()
- {
- while(!KEY0) //加热/水泵切换
- {
- delay(10);
- if(KEY0)
- flag2=!flag2;
- }
- while(!KEY1) //上限/下限切换
- {
- delay(10);
- if(KEY1)
- flag3=!flag3;
- }
- while(!KEY2) //设置温度加
- {
- delay(10);
- if(KEY2)
- {
- if(flag2)
- {
- if(flag3)
- p_TL++;
- else
- p_TH++;
- }
- else
- {
- if(flag3)
- h_TL++;
- else
- h_TH++;
- }
- }
- }
- while(!KEY3) //设置温度减
- {
- delay(10);
- if(KEY3)
- {
- if(flag2)
- {
- if(flag3)
- p_TL--;
- else
- p_TH--;
- }
- else
- {
- if(flag3)
- h_TL--;
- else
- h_TH--;
- }
- }
- }
- }
- /*****************************************************
- 主函数
- ***************************************************/
- void main()
- {
- uint temp;
- uchar TL; //储存暂存器的温度低位
- uchar TH; //储存暂存器的温度高位
- uchar TN; //储存温度的整数部分
- uchar TD; //储存温度的小数部分
- LcdInitiate(); //将液晶初始化
- delay(5); //延时5ms给硬件一点反应时间
- display_Now();
- display_dot(); //显示温度的小数点
- display_cent(); //显示 ℃
- HTR=1;
- CTP=1;
- while(1)
- {
- keyscan();
- ReadyReadTemp(); //读温度准备
- TL=ReadOneChar(); //先读温度值低位
- TH=ReadOneChar(); //后读温度值高位
- ds18b20_delay(150);
- if(TN<h_TL)
- HTR=0;
- if(TN>h_TH)
- HTR=1;
- if(TN>p_TH)
- CTP=0;
- if(TN<p_TL)
- CTP=1;
- // if(TH&0xf8==0xf8) //TH高5 位为1,温度值为负 。负数一直调试未成,原来是忽视了优先等级。改成if((TH&0XF8)==0XF8),负温度就正常了。
- // {
- // flag1=1;
- // TL=~(TL)+0x01;
- // TH=~TH;
- // }
- // else
- temp=TH;
- temp=temp<<8|TL;
- TN=temp*0.0625;
- // flag1=0;
- TD=TL&0x0f;
- display_THTL();
- display_temp1(TN); //显示温度的整数部分
- display_temp2(TD); //显示温度的小数部分
- delay(10);
- }
- }
复制代码
|