恒温控制器系统概述
该恒温控制器系统包含以下几个功能:
- 可按键设定温度
- 可显示当前温度和用户设定温度
- 有升温、降温模块
- 可最终达到恒温
仿真软件
- Keil 5
- Proteus 8.6
系统设计
电路设计
恒温控制系统一共有6个模块,分别是主控芯片模块、按键输入模块、设定温度显示模块、当前温度显示模块、温度采集模块和升温、降温模块。
- 按键输入模块:该模块由4*3的矩阵键盘和1个确认按钮构成。系统刚开始启动后,用户通过矩阵键盘输入想要设定的温度(0°~99°),输入完毕后按下确认键,然后将该温度数据传送给主控芯片AT89C51;
- 设定温度显示模块:该模块由一个2位8段LED数码管构成,主控芯片AT89C51使用P3口控制该数码管的段选,使用P2.4和P2.5两个端口来控制该数码管的位选。主控芯片AT89C51将从矩阵键盘得到的设定温度信息,通过2位8段LED数码管显示出来;
- 温度采集模块;该模块由一个DS18B20温度传感器构成。使用DS18B20温度传感器采集当前的温度,并将该温度信息传送给主控芯片AT89C51;
- 当前温度显示模块:该模块由两个74HC573锁存器和一个4位8段LED数码管构成,主控芯片AT89C51使用P2.6和P2.7控制两个74HC573锁存器的片选,两个锁存器的输入口均与主控芯片的P0口相连,并使用一个100欧的排阻作为P0口的上拉电阻,两个锁存器的输出口分别与4位8段LED数码管的段选口与位选口相连;
- 升温、降温模块:该模块由一个绿色LED和一个红色LED构成,绿色LED负责降温,每闪烁一次温度下降0.5°,红色LED负责升温,每闪烁一次温度上升0.5°。主控芯片AT89C51根据当前温度和用户设定温度之间的差值,来控制升温还是降温,以达到恒温的目的。
软件代码编写
程序的具体流程如下:
- 硬件初始化,关闭所有的数码管;
- 进行两次按键扫描循环,分别获取用户设定温度的十位和个位,获取完毕后,判断确认键是否被按下,如果用户按下确认键则进入到主程序循环中;
while(ok) //用户设定温度 { while(key1 == 15) { key1 = keyscan(); delay(50); } while(key2 == 15) { key2 = keyscan(); delay(50); } delay(100);//等待确认键 } //键盘扫描 uchar keyscan() { uchar temp,key; key = 15; // 默认值,如果没有按键按下key就为该默认值 P1 = 0xfe; //扫描第一行 temp = P1; temp = temp & 0xf0; if(temp!=0xf0) { delay(10); // 延时消抖 temp = P1; temp = temp & 0xf0; if(temp!=0xf0) { temp = P1; switch(temp) //扫描列 { case 0xee: key = 1; break; case 0xde: key = 2; break; case 0xbe: key = 3; break; } while(temp!=0xf0) //等待按键释放 { temp = P1; temp = temp & 0xf0; } } } P1 = 0xfd; //扫描第二行 temp = P1; temp = temp & 0xf0; if(temp!=0xf0) { delay(10); // 延时消抖 temp = P1; temp = temp & 0xf0; if(temp!=0xf0) { temp = P1; switch(temp) //扫描列 { case 0xed: key = 4; break; case 0xdd: key = 5; break; case 0xbd: key = 6; break; } while(temp!=0xf0) //等待按键释放 { temp = P1; temp = temp & 0xf0; } } } P1 = 0xfb; //扫描第三行 temp = P1; temp = temp & 0xf0; if(temp!=0xf0) { delay(10); // 延时消抖 temp = P1; temp = temp & 0xf0; if(temp!=0xf0) { temp = P1; switch(temp) //扫描列 { case 0xeb: key = 7; break; case 0xdb: key = 8; break; case 0xbb: key = 9; break; } while(temp!=0xf0) //等待按键释放 { temp = P1; temp = temp & 0xf0; } } } P1 = 0xf7; //扫描第四行 temp = P1; temp = temp & 0xf0; if(temp!=0xf0) { delay(10); // 延时消抖 temp = P1; temp = temp & 0xf0; if(temp!=0xf0) { temp = P1; switch(temp) //扫描列 { case 0xe7: key = 0; break; case 0xd7: key = 0; break; case 0xb7: key = 0; break; } while(temp!=0xf0) //等待按键释放 { temp = P1; temp = temp & 0xf0; } } } return key; }
- 在主程序循环中,首先调用dis_set()函数显示用户设定温度;
for(i=20;i>0;i--) dis_set(key1, key2); //显示用户设定的温度 //显示设定温度函数 void dis_set(uchar k1, uchar k2) { display2(1, k1); display2(2, k2); display2(0, k1); } //设定温度数据显示函数 void display2(uchar num, uchar tem_data) { if(num==0) { S1 = 1; S2 = 1; delay(5); } if(num==1) { S1 = 0; S2 = 1; P3 = table[tem_data]; //table为 0-9的16进制编码表 delay(5); } else if(num==2) { S1 = 1; S2 = 0; P3 = table[tem_data]; delay(5); } }
然后再从温度传感器获取当前温度,获取当前温度的流程如下图所示,先调用DSreset()函数进行温度传感器的初始化,再调用temwrite()函数,对传感器写入温度转换的指令,进行温度获取和转换,然后调用get_tem()函数对传感器写入读取寄存器指令,从寄存器中读取存储的温度数据,并对该数据进行精度转换处理,最后获得一个保留了1位小数的当前温度数据;
temchange(); //获取当前温度 //温度获取和转换函数 void temchange(void) { DSreset(); delay(1); temwrite(0xcc); //写跳过ROM指令 temwrite(0x44); //写温度转换指令 } //读取寄存器中存储的温度数据 uint get_tem(void) { uchar l8,h8; DSreset(); delay(1); temwrite(0xcc); //写跳过ROM指令 temwrite(0xbe); //写读寄存器指令 l8 = temread(); //读低8位数据 h8 = temread(); //读高8位数据 tem = h8; tem = tem<<8; tem = tem|l8; //合成一个16位数据 f_tem = tem*0.0625; tem = f_tem*10+0.5; //*10用于保留1位小数点,+0.5用于四舍五入 return (tem); }
DS18B20温度传感器的基本操作代码如下,各项操作要严格遵守DS18B20温度传感器的时序图,延时时间要足够,可以根据使用的主控芯片适当地修改循环的次数来调整延时。
初始化
//温度传感器初始化 uint DSreset(void) { uint i; DS = 0; i = 73; while(i>0) i--; DS = 1; i = 0; while(DS) {//等待DS18B20拉低总线 delay(1); i++; if(i>10) { return 0;//初始化失败 } } DS = 1; return 1;//初始化成功 }
读1位数据
//读1位数据 bit temreadbit(void) { uint i; bit tem_bitdata; DS = 0; i++; //延时 DS = 1; i++; i++; tem_bitdata = DS; i = 10; while(i>0) i--; return(tem_bitdata); }
读1字节数据
//读1字节数据 uchar temread(void) { uint i; uchar j,tem_data; for(i=1;i<=8;i++) { j = temreadbit(); tem_data = (j<<7)|(tem_data>>1); //移位,让最低位在最后面 } return (tem_data); }
写1字节数据
//写1字节数据 void temwrite(uchar tem_data) { uint i; uchar j; bit send_bitdata; for(j=1;j<=8;j++) { send_bitdata = tem_data&0x01; //取要发送数据的最低位 tem_data = tem_data>>1; //右移一位 if(send_bitdata) //写1 { DS = 0; i++; i++; DS = 1; i = 10; while(i>0) i--; } else //写0 { DS = 0; i = 10; while(i>0) i--; DS = 1; i++; i++; } } }
- 获取完当前温度,调用dis_tem()函数显示当前温度;
for(i=20;i>0;i--) //显示当前温度 dis_tem(get_tem()); //显示当前温度函数 void dis_tem(uint t) { uchar i; i = t/100; //取温度的十位 display1(1,i); i = t%100/10; //取温度的个位 display1(2,i+10); i = t%10; //取温度的小数点后一位 display1(3,i); } //当前温度数据显示函数 void display1(uchar num, uchar tem_data) { WE = 1; //选位,低电平有效 P0 = ~((0x01)<<(num)); WE = 0; DU = 1; //选段,高电平有效 P0 = table[tem_data]; DU = 0; delay(10); }
- 将当前温度和用户设定温度传入deal()函数,进行恒温控制,在恒温控制函数deal()中,根据判断当前温度和用户设定温度之间的差值进行不同的处理,如果当前温度小于用户设定温度,就进行升温处理,即红灯闪烁一次,每闪烁一次温度上升0.5°,如果当前温度大于用户设定温度,就进行降温处理,即绿灯闪烁一次,每闪烁一次温度下降0.5°,如果当前温度与用户设定温度想等,则不做处理,只显示温度;
void deal(uint t, uint t_set) { uchar i; if(tt_set) { work(15, 0x40); //降温 } else { i = 15; while(i--) { dis_tem(tem_set); dis_set(key1, key2); } } } //升温、降温模块 void work(uint s, uchar led) { uchar i; if(led==0x20) { i = s; led0 = ~(led0); //灯亮 tem = tem+5; while(i--) { dis_tem(tem); dis_set(key1, key2); } led0 = ~(led0); //灯灭 i = s; while(i--) { dis_tem(tem); dis_set(key1, key2); } } else { i = s; led1 = ~(led1); //灯亮 tem = tem-5; while(i--) { dis_tem(tem); dis_set(key1, key2); } led1 = ~(led1); //灯灭 i = s; while(i--) { dis_tem(tem); dis_set(key1, key2); } } }
- 进行一次恒温控制后,系统又回到主程序循环的起始点,不断重复上述3-5步骤,使温度保持在用户设定的温度,达到恒温的效果。