自己设计并制作了一个自动温度控制系统

来源:互联网 发布:ubuntu还是deepin 编辑:程序博客网 时间:2024/04/28 06:44

自己设计并制作了一个自动温度控制系统

一、课题任务

设计并制作一个水温自动控制系统,控制对象为1升净水,容器为搪瓷器皿。水温可以在一定范围内由人工设定,并能在环境温度降低时实现自动控制,以保持设定的温度基本不变。

1.基本要求 

(1)温度设定范围为40~90℃,最小设定分度为1℃。

(2)具有温度显示功能,分辨率为0.1℃,显示的绝对误差小于1℃。

(3)当温度达到某一设定值并稳定后,水温的波动控制在±2℃以内。要求温度调控达到稳定状态时,必须给出声或光提示信号。

(4)环境温度降低时(例如用电风扇降温)水温的波动控制在±2℃以内。

2.发挥部分

(1)当温度达到某一设定值并稳定后,水温的波动控制在±1℃以内。要求温度调控达到稳定状态时,必须给出声或光提示信号。

(2)采用适当的控制方法,当设定温度突变(由35℃提高到45℃)时,在超调量不超过2℃的前提下,尽量减小系统的调节时间,并要求温度控制的静态误差≤0.5℃。 

(3)在设定温度发生突变(由35℃提高到45℃)时,自动打印水温随时间变化的曲线。

(4)其他。

 

二、       方案比较与选择

根据要求,系统至少有以下功能模块构成:

1.      温度测量模块:

温度测量是本系统的核心问题之一。基于单片机的温度测量,温度传感器毫无疑问是最佳的选择,常见的有数字式温度传感器和模拟温度传感器。


前者以DS18B20为代表。其采用单总线的接口方式与微处理器连接。仅需要一条总线即可实现微处理器的双向通讯。单总线具有经济性好,抗干扰能力强,适合于恶劣环境的现场温度测量,使用方便等优点,使用户可轻松地组建传感器网络。测量温度范围宽,测量精度高 DS18B20 的测量范围为 -55 ℃ ~+ 125 ℃ ; 在 -10~+ 85°C 范围内,精度为 ± 0.5°C 。持多点组网功能 多个 DS18B20 可以并联在惟一的单线上,实现多点测温。供电方式灵活 ,DS18B20 可以通过内部寄生电路从数据线上获取电源。因此,当数据线上的时序满足一定的要求时,可以不接外部电源,从而使系统结构更趋简单,可靠性更高。测量参数可配置 DS18B20 的测量分辨率可通过程序设定 9~12 位。模拟温度传感器,以Pt100为代表。

    DS18B20 具有体积更小、适用电压更宽、更经济、可选更小的封装方式,更宽的电压适用范围,适合于构建自己的经济的测温系统,因此也就被设计者们所青睐。

2.      温度显示模块:

由于温度精度以及实时性的要求,需要多位动态显示。常见的显示方式有两种,一种是数码管,另一种是液晶屏幕。动态显示是一种最常见的数码管多位显示方法,应用非常广泛。所有数码管段选都连接在一起的时候,动态显示是多个数码管,交替显示,利用人的视觉暂停作用使人看到多个数码管同时显示的效果。就像我们看的电影是有一帧一帧的画面显示的,当速度够快的时候我们看到它就是动态的。当我们显示数码管的速度够快的时候,也就可以看到它们是同时显示了。


1602液晶也叫1602字符型液晶,它是一种专门用来显示字母、数字、符号的点阵型液晶模块。它是由若干个5x7或者5x11的点阵字符位组成,每个点阵字符位都可以用显示一个字符,每位之间有一个点距的间隔,每行之间也有间隔,起到了字符间距和行间距的作用。

 

3.      温度设定模块:

轻触开关是一种电子开关,使用时,轻轻按开关按钮就可使开关接通,当松开手时,开关断开。使用3个开关,分别实现,功能转换,设定+,设定-,即可完成所有设定操作。

4.      温度控制模块:

控制核心选择STC89C52。STC89C52是STC公司生产的一种低功耗、高性能CMOS8位微控制器,具有 8K 在系统可编程Flash存储器。STC89C52使用经典的MCS-51内核,指令代码完全兼容传统8051,还做了很多的改进使得芯片具有传统51单片机不具备的功能。在单芯片上,拥有灵巧的8 位CPU 和在系统可编程Flash,使得STC89C52为众多嵌入式控制应用系统提供高灵活、超有效的解决方案。 具有以下标准功能: 8k字节Flash,512字节RAM, 32 位I/O 口线,看门狗定时器,内置4KB EEPROM,MAX810复位电路,3个16 位定时器/计数器,4个外部中断,一个7向量4级中断结构(兼容传统51的5向量2级中断结构),全双工串行口。另外 STC89X52 可降至0Hz 静态逻辑操作,支持2种软件可选择节电模式。空闲模式下,CPU 停止工作,允许RAM、定时器/计数器、串口、中断继续工作。掉电保护方式下,RAM内容被保存,振荡器被冻结,单片机一切工作停止,直到下一个中断或硬件复位为止。最高运作频率35MHz,6T/12T可选。能够满足本系统的需求。


外电路的控制,通过继电器来完成。选用HK4100F型号,额定电压5V的电磁式继电器。其有如下特点。

降温模块,由于本系统打算将加热电路与继电器的常开触点,即一般情况下加热装置继电器以及继电器均断开,因此理论上当温度过高时,继电器断开,完全可以采用自然降温使得温度达到正常。为了使效果更好,可增加风扇或者空调装置进行降温。

5.      声/光报警模块:

选用绿色和红色LED分别作为外温度在设置范围内和之外的信号标志,对于后者可以添加蜂鸣器或者电铃作为报警装置,由于可能会扰民,因此添加开关,可手动控制其是否警报。

三、        电路设计


本系统先在PROTUES上进行电路初步设计以及仿真实验。根据以上分析,设计电路如下。

主要有以下几个部分

1.      单片机最小系统

2.      温度显示

3.      加热和继电器电路

4.      温度获取和设置

DS16B20                   功能按键

5.      报警和降温

四、       程序设计




五、       测试方案

通过KEIL编译通过,然后在PROTUES进行仿真,测试系统运行效果。为了提高系统稳定性和可靠性,选择在开发板上进行实际测试以及PC上的程序调试。最后硬件平台搭建,通过选择合适规格的零件,焊接从而完成整个系统的预定功能。

六、       
系统调试

通过优化单片机与LCD1602的接口选择,解决了之前,由于没有加上拉电阻导致无法显示的问题。调整了函数结构,使得温度实时更新,提高了系统的灵敏度和实时性。仿真效果,如上图所示。

七、       数据测试与处理

为了进一步与实际接近,在普中EM3_V3.0型号开发板上进行了实验。成功实现以下功能:

(1)温度设定范围为0~125℃,最小设定分度为1℃。比要求的40~90℃更宽。

(2)具有温度显示功能,分辨率为0.01℃,显示的绝对误差小于1℃。比要求的0.1℃提升一个数量级,绝对误差小于要求的1℃。

(3)当温度达到某一设定值并稳定后,水温的波动控制在±X℃(X为0-9之间的整数,可调)以内。比要求的±2℃更灵活且更具有实用性。

(4)要求温度调控达到稳定状态时,给出光提示信号。

(5)环境温度不在设定范围内时,,反应及时且快速。温度过高,触发器断开,停止加热,自然降温,并且可以调用风扇进行降温。温度过低,触发器闭合加热,直到其达到指定温度。

没有实现以下功能:

(6)当设定温度突变(由35℃提高到45℃)时,在超调量不超过2℃的前提下,尽量减小系统的调节时间,并要求温度控制的静态误差≤0.5℃。 

(7)在设定温度发生突变(由35℃提高到45℃)时,自动打印水温随时间变化的曲线。

 

八、       总结

本水温自动控制系统,较好地实现了人工设定温度,实时显示温度,自动控制温度的功能,并且结合实际应用,对一些地方进行了改进,例如提高了温度显示的精确度,另外实现了对“最高温度”、“最低温度”,“误差范围”的调节,使测定的范围和波动范围更加灵活,更具有实际运用价值。

   但由于时间和能力有限,还有发挥部分一部分功能没有实现。软件仿真上,在PROTUES进行的仿真,效果稳定。硬件上,实现了基于普中EM3_V3开发板的运行和调试,效果稳定,此外还单独搭建了实验装置平台,很不幸在多次努力尝试之后,依然存在一些显示问题,没能比开发板上更好的运行。

九、       参考文献

[1]HK4100F继电器资料

[2]普中EM3_V3开发板资料

[3]51单片机C语言应用开发技术大全(第二版).人民邮电出版社.


十、       附录:

A、设计电路图(原理图、PCB图)

B、程序(要求有文字、注释)

由于相关程序较长,受版面限制,故上传至

C、相关作品图片


#include<reg51.h>#include<intrins.h>#define uint unsigned int #define uchar unsigned char/*LCD1602显示模块*//*用于PROTUES仿真#define LCD1602_DATAPINS P2sbit LCD1602_RS=P3^0;sbit LCD1602_RW=P3^1;   sbit LCD1602_E=P3^2;      */#define LCD1602_DATAPINS P0sbit LCD1602_RS=P2^6;sbit LCD1602_RW=P2^5;   sbit LCD1602_E=P2^7;/*按键调节模块*/sbit k1=P1^1;//功能键sbit k2=P1^2;//加sbit k3=P1^3;//减 void keyscan();void key1_switch();void key2_add();void key3_minus();uchar k_num;void LCD1602_SetTemp(uchar add,uchar dat);uchar high=90,low=10,set_t=30,set_d=2;//这里的数据类型可能有问题!!/*其他模块接口*/sbit DSPORT=P3^7; //温度传感器单总线端sbit SPEAKER=P1^5;//蜂鸣器sbit RELAY=P1^4;//继电器sbit COOLER=P1^7;//降温装置/*LCD1602相关函数*/void Delay1us(uint a);void LCD1602_WriteCom(uchar com);//LCD1602写入8位命令子函数void LCD1602_WriteData(uchar dat);void LCD1602_Init();//LCD1602初始化子程序  void LCD1602_ShowTemp(int temp);/*DS18B20温度传感器相关函数*/void  Delay15us(uchar aa);uchar Ds18b20Init();void  Ds18b20WriteByte(uchar dat);uchar Ds18b20ReadByte();void  Ds18b20SwitchTemp();int   Ds18b20ReadTemp();float temp_max=125.00,temp_min=-55.00;uchar ii=0,jj=0,kk=0;uchar words_h[2]={"H="};uchar words_l[2]={"L="};uchar words_s[4]={"Set="};void Sound();void Temp_control(int temp);uchar count=0;//用来解决主程序执行太快,按键光标来不及显示的问题void Temp_control(int temp){unsigned int kk=400;uchar set_h,set_l;set_h=set_t+set_d;set_l=set_t-set_d;if (temp<=set_h&&temp>=set_l) //设定温度范围之内{  RELAY = 0; //继电器断开 COOLER=0;//风扇关闭}else {TR0=0;while (kk--){Sound();}RELAY = 1; //继电器打开,外电路(常开触电)闭合加热if (temp>=set_h)//温度过高{RELAY = 0; //继电器断开 COOLER=1;//打开}TR0=1;}}/*其他模块相关函数*/void Sound()//蜂鸣器{   SPEAKER=1;Delay15us(40);SPEAKER=0;Delay15us(40);}void Delay1us(uint a){uint b,c;for(c=a;c>0;c--)for(b=110;b>0;b--);}void LCD1602_WriteCom(uchar com)  //写入命令{LCD1602_E=0;LCD1602_RS=0;//0就写指令LCD1602_RW=0; //0就是写LCD1602_DATAPINS=com;Delay1us(10);LCD1602_E=1;Delay1us(10);LCD1602_E=0;}   void LCD1602_WriteData(uchar dat)//写入数据{LCD1602_E=0;LCD1602_RS=1;LCD1602_RW=0;LCD1602_DATAPINS=dat;Delay1us(10);LCD1602_E=1;Delay1us(10);LCD1602_E=0;}void LCD1602_Init() //LCD初始化子程序{//uint num; LCD1602_WriteCom(0x38);  //开显示LCD1602_WriteCom(0x0f);  //开显示不显示光标LCD1602_WriteCom(0x06);  //写一个指针加1LCD1602_WriteCom(0x01);  //清屏LCD1602_WriteCom(0x80);  //设置数据指针起点LCD1602_WriteCom(0x80+0x0B);for (ii=0;ii<2;ii++){LCD1602_WriteData(words_h[ii]);}LCD1602_SetTemp(13,high);LCD1602_WriteCom(0x80+0x40);for (kk=0;kk<4;kk++){LCD1602_WriteData(words_s[kk]);}LCD1602_SetTemp(4+0x40,set_t);LCD1602_WriteCom(0x80+0x47);LCD1602_WriteData(0x23);  //显示正负号LCD1602_WriteCom(0x80+0x48);LCD1602_WriteData(0x30+set_d);LCD1602_WriteCom(0x80+0x4B);for (jj=0;jj<2;jj++){LCD1602_WriteData(words_l[jj]);}LCD1602_SetTemp(13+0x40,low);TMOD=0X01;TH0=(65536-50000)/256;TL0=(65536-50000)%256;EA=1;//总中断ET0=1;TR0=1; }void  Delay15us(uchar aa){do{_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();aa--;}while(aa);}/*DS18B20温度传感器相关函数*/uchar Ds18b20Init(){uchar flag;DSPORT=0;  //总线拉低Delay15us(40);//延时480~960usDSPORT=1;Delay15us(2);flag=DSPORT;Delay15us(6);//Ds18b20发出应答信号,延时60~240usDelay15us(25);return flag;} uchar Ds18b20ReadByte(){uchar byte,bi; uint i;for (i=0;i<8;i++){DSPORT=0;_nop_();_nop_();_nop_();_nop_(); //保持低电平至少1us,但不能低于15usDSPORT=1;bi=DSPORT;//读取一位数据,循环8次为一个字节byte = (byte >> 1) | (bi << 7);//将byte左移一位,然后与上右移7位后的bi,8次合成一个字节Delay15us(4);}return byte;} void  Ds18b20WriteByte(uchar dat){ uint i; for (i=0;i<8;i++) { DSPORT=0;_nop_();DSPORT=dat&0x01;//一位一位得读,从最低位开始Delay15us(5);DSPORT=1;_nop_();dat>>=1; }} void  Ds18b20SwitchTemp(){Ds18b20Init();Delay15us(7);Ds18b20WriteByte(0xcc);//跳过ROM指令Ds18b20WriteByte(0x44);//启动温度转换指令} int   Ds18b20ReadTemp(){int temp=0;uchar temp_h,temp_l;Ds18b20SwitchTemp();Ds18b20Init();Delay1us(1);Ds18b20WriteByte(0xcc); //跳过ROM操作命令Ds18b20WriteByte(0xbe); //发送读取温度命令temp_l = Ds18b20ReadByte();//读取温度值共16位,先读低字节temp_h = Ds18b20ReadByte();temp= temp_h;temp<<=8;temp|= temp_l;return temp;} void LCD1602_ShowTemp(int temp){float tt;uchar show[5]={0,0,0,0,0};if (temp<0)//温度为负{LCD1602_WriteCom(0x80);//写地址 80表示初始地址    LCD1602_WriteData('-');  //显示负temp=temp-1;temp=~temp;tt=temp;temp=tt*0.0625*100;}else//温度为正{LCD1602_WriteCom(0x80);//写地址 80表示初始地址    LCD1602_WriteData('+');  //显示正tt=temp;temp=tt*0.0625*100;}show[0]=temp/10000;show[1]=temp%10000/1000;show[2]=temp%1000/100;show[3]=temp%100/10;show[4]=temp%10;LCD1602_WriteCom(0x82);LCD1602_WriteData('0'+show[0]); //百位 LCD1602_WriteCom(0x83);LCD1602_WriteData('0'+show[1]); //十位 LCD1602_WriteCom(0x84);LCD1602_WriteData('0'+show[2]); //个位 LCD1602_WriteCom(0x85);LCD1602_WriteData('.');LCD1602_WriteCom(0x86);LCD1602_WriteData('0'+show[3]); //十分位LCD1602_WriteCom(0x87);LCD1602_WriteData('0'+show[4]); //百分位LCD1602_WriteCom(0x88);LCD1602_WriteData(0xdf);LCD1602_WriteCom(0x89);LCD1602_WriteData('C');LCD1602_WriteCom(0x0C);temp=temp/100;Temp_control(temp);}void key1_switch()//功能切换{uchar set_h,set_l;set_h=set_t+set_d;set_l=set_t-set_d;//k1键指令if(k1==0){Delay1us(10);//延时消抖if(k1==0){k_num++;while(!k1);//按键没有松开if(k_num==1){TR0=0; //关掉计时器,使得光标得以显示LCD1602_WriteCom(0x80+0x46);LCD1602_WriteCom(0x0f);Delay15us(6);}if(k_num==2){LCD1602_WriteCom(0x80+0x48);LCD1602_WriteCom(0x0f);Delay15us(6);}if(k_num==3){LCD1602_WriteCom(0x80+0x0F);LCD1602_WriteCom(0x0f);Delay15us(6);}if(k_num==4){LCD1602_WriteCom(0x80+0x4F);LCD1602_WriteCom(0x0f);Delay15us(6);}if(k_num==5){k_num=0;LCD1602_WriteCom(0x0C);//光标不显示if (high<low)  //用来default{ high=90; low=40;//恢复默认值} if(set_h>high||set_l<low) {  high=90; low=10;//恢复默认值   set_t=30;  set_d=2;//恢复默认值 } TR0=1;//计时器重新打开,使得屏幕得以刷新}}}}void key2_add()//功能加{if(k_num!=0){if(k2==0){Delay1us(5);if(k2==0){while(!k2);if(k_num==1){set_t++;if (set_t>=high)  set_t=high;  LCD1602_SetTemp(4+0x40,set_t);  LCD1602_WriteCom(0x80+0x46);}if(k_num==2){set_d++;if (set_d>9)  set_d=0;LCD1602_WriteCom(0x80+0x48);LCD1602_WriteData(0x30+set_d);LCD1602_WriteCom(0x80+0x48);}if(k_num==3){high++;if (high>=temp_max)  high=0;  LCD1602_SetTemp(13,high);  LCD1602_WriteCom(0x80+0x0F);//  LCD1602_WriteCom(0x80+0x40+8);}if(k_num==4){low++;if (low>=temp_max) low=0;  LCD1602_SetTemp(13+0x40,low);  LCD1602_WriteCom(0x80+0x4F);//  LCD1602_WriteCom(0x80+0x40+13);}}}}}void key3_minus()//功能减{if(k_num!=0){if(k3==0){Delay1us(5);if(k3==0){while(!k3);if(k_num==1){if (set_t<=0)set_t=high+1;set_t--;  LCD1602_SetTemp(4+0x40,set_t);  LCD1602_WriteCom(0x80+0x46);}if(k_num==2){if (set_d<=0) set_d=10;set_d--;LCD1602_WriteCom(0x80+0x48);LCD1602_WriteData(0x30+set_d);LCD1602_WriteCom(0x80+0x48);}if(k_num==3){if (high<0) high=temp_max;high--;  LCD1602_SetTemp(13,high);  LCD1602_WriteCom(0x80+0x0F);//  LCD1602_WriteCom(0x80+0x40+8);}if(k_num==4){if (low<=0)low=high;low--;  LCD1602_SetTemp(13+0x40,low);  LCD1602_WriteCom(0x80+0x4F);//  LCD1602_WriteCom(0x80+0x40+16);}}}}}void keyscan()//按键检测{  key1_switch();  key2_add();  key3_minus();}void LCD1602_SetTemp(uchar add,uchar dat)//数码管制定位置显示{  uchar head,body,end;  head=dat/100;  body=dat%100/10;  end=dat%10;  LCD1602_WriteCom(0x80+add);  LCD1602_WriteData(0x30+head);  LCD1602_WriteData(0x30+body);  LCD1602_WriteData(0x30+end);}void main(){LCD1602_Init();while(1){   keyscan();   }}void timer0() interrupt 1{  TH0=(65536-50000)/256;TL0=(65536-50000)%256;count++;if (count==10)//让温度每0.5s刷新一次{count=0;   LCD1602_ShowTemp(Ds18b20ReadTemp());}}



1 0
原创粉丝点击