2011河南城建学院电子设计大赛暑期实做训练
第一次实做练习
题目: 单片机数字控温器
队员: 黄霄杰、杨新、高思召、李品
2011.7.31
目录
第一章. 任务及总体设计方案-------------------------------- 第二章. 单元模块设计---------------------------------------------------- 第三章. 电路总接线图及温度采集仿真------------------------------- 第四章. 第五章 第六章 第七章
PID及PWM控制直流电机---------------------------------- 设计总结---------------------------------- 参考文献----------------------------------------------------------- 总程序---------------------------------------------------------------
1
一、任务及总体设计方案
(一)任务
设计并制作一个单片机数字温度控制器,控制对象为1升净水,容器为陶瓷器皿。水温可以在一定范围内由人工设定,并能在环境温度变化时实现自动控制,以保持设定的温度基本不变。 二、要求 1、基本要求
(1)温度控制范围为30度~100度之间; (2)可键盘设置控制温度值,并显示; (3)数字显示水的实际温度;
(4)设置温度控制值和检测值之间的误差在±1度; 2、发挥部分
(1)设计温度报警电路;
(2)升温或降温在5—10分钟之内完成;
(二)总体设计方案
1、部分单元模块方案的选择和比较
1.1 温度采集模块
方案一:采用热敏电阻采集温度模拟量,通过A/D转换器件接入单片机处理。该方案成本低,但需要相对复杂的外部模拟电路,且热敏电阻自身带有较大非线性误差。经过讨论放弃该方案。
方案二:使用带有A/D(模数转换)单片集成的DS18B20传感器。DS18B20输出数字量,可直接与单片机通信。最终选择该方案。 1.2 温度显示模块
方案一:采用八位八段数码管显示设定和测量的温度。方案成本低,数码管具有低能耗,低损耗,寿命长,耐老化,对外界环境要求低,适合训练使用。选择该方案。
方案二:采用LCD液晶显示。液晶显示功耗低,且显示效果好,但相对成本高。本设计没采用该方案,不过LCD的使用是必须掌握的。 1.3加热和降温模块
方案一:采用固体继电器控制加热或降温。固体继电器具有高频通断能力,可以结合PWM脉宽调制从而控制加热或降温功率。方案成本高,且相关知识了解不深。结合实际情况,不采用该方案。
2
方案二:采用电磁继电器控制。虽然电磁继电器不具有高频通断能力,但通过PWM来控制一个周期内加热或降温时间,从而逐次逼近,效果也不错。所以使用电磁继电器。
2、设计最终方案
方案:以STC89C52单片机作微控制器,数字传感器DS18B20来采集温度,通过矩阵键盘来设定温度,并用八段数码管显示,在程序中来设置温度的上下限,当温度超出上下限时,由单片机发出控制信号,外界控制电路接收信号并作相应的响应来调节温度。设计以直流电机来模拟加热和降温过程。
2.1系统的总体结构图如下图1.1
图1.1
二、单元模块设计
1、电源模块
电源模块给系统各个模块提供所需的电力,220V交流电通过变压器降压、整流、滤波、稳压后得到5V 的稳定直流电压输出。电源模块的电路设计如下图2-1 所示。
3
图2.1 电源模块原理图
2、温度采集模块
温度采集模块的电路原理图如下图2.2所示。
图2.2 温度采集模块电路原理图
3、数码管显示模块
数码管的位选段由P3.0~P3.2进行控制选通,段选端则有P2八位口进行控制,利用其动态扫
描,来显示八位不同的数字温度。其电路原理图如下图2.3所示。数码管不能直接由单片机端口驱动所以用了74LM245作为驱动,实际制作时驱动后面加了限流电阻,但是数码管太暗,所以我们把电阻全部短路掉,即使如此还不太亮,实际上八个数码管需要很大的电流,这八个电阻实际上是没必要加的,当然在数码管少的时候要加上限流电阻。
4
可以。
图2.3 数码管显示原理图
4、温度控制部分和报警蜂鸣器的连接电路
其电路原理图如下图3.4所示。温度控制用了两个继电器,一个加热一个制冷,这种小型继电器
是6脚的,比较常见的5脚继电器通常是把这里的1、6脚合在了一起。这里5和2脚是继电器的
线圈,当通电时线圈把常开触点吸和,外电路220v电路闭合开始工作。三极管用9012或4550都
5
图2.4 温度控制和报警蜂鸣器电路原理图
5、温度调节按钮电路
其中S11、S12、S13为设置键,S11设置温度十位,S12设置温度个位,S13设置温度十分位;按下设置键后,再按下S1~S10,显示十进制0~9,修改设定温度值.按钮电路原理图如图2.5所示。
图2.5 温度调节按钮电路
6
6.总原理图
7
7.PCB图
总图
4*4键盘
8
数码管
三维图
9
三、 电路总结线图及温度采集仿真
设计电路图及其仿真如图3.1所示。
图3.1总体电路图及其温度采集仿真 四、PID及PWM控制直流电机
10
1、PID控制
设计以16s为一个采样周期,设计先前设定一个温度范围,当超出此范围采用周期内全程加热或降温,在此范围时,采用PID算法,有效优化系统响应速度和因为大惯性加热和降温器件带来的系统不稳定因素。
2、PWM控制直流电机
本设计以直流电机模拟加热和降温过程,系统以16s作为PWM输出周期,以PID控制器输出决定的PWM高电平输出时间为加热或降温时间,有效控制大惯性器件对实验结果的影响。
五、培训收获
这是本次暑期培训的第一次试做,由于缺乏经验所以历时较长,经过半个月由于作品终于调试
好,期间遇到了许多没有料到的困难,原来理论上成功与实物的制作相差甚远,理论的成功与实物的成功有巨大的差别,调试电路期间经历了许多挫折,从制作PCB板子到编程再到总体调试,这一个说不上难的题目使我们倍感压力,不过我们小组积极应对,方案确定之后,PCB板做的还算顺利,由于没有加热设备和制冷设备我们用两个小电机模拟加热和制冷,这里用到了两个220v3A的继电器,实际上是可以达到加热和制冷的功率要求的,这次设计我们除了制做了总体电路板之外还做了显示模块和键盘模块,由于条件的限制我们都采用了单层板布线的制板方式,总体实物焊接完成之后并没有像我们想的那样顺利,加热和制冷的电机出现错误开启和关断的现象,最后我们从软件和硬件上发现许多不足,圆满完成了设计要求,当然我们看到了自己的许多缺点和不足,从中学到了不少知识和经验。
六、参考文献
【1】谭浩强.C程序设计(第三版)[M].北京:清华大学出版社,2005 【2】兰吉昌.51单片机应用设计百例.北京:化学工业出版社,2008.12
【3】蓝和慧,宁武,闫晓金.全国大学生电子设计竞赛单片机应用技能精解.北京:电子工业出版社,2009.4
七、总程序
#include 11 #include #define uchar unsigned char #define uint unsigned int unsigned char TempL=0; unsigned char TempH=0; sbit jdq1=P1^0; sbit jdq2=P1^1; sbit ysq=P1^2; sbit seg1=P2^0; sbit seg2=P2^1; sbit seg3=P2^2; uchar code EL[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f};//共阴极数码管段码 uchar flag_get1=0,flag_get2=0,count0=0,count1=0,count2=0,num0=0,num1=0,date=0,a=3,b=0,c=0,aa=0,bb=0,cc=0,h=0,j=0,k=0,x=0; uint temp=0; uchar str[8]; float d=0,dd=0,t=0,tt=0,pwm1=0,pwm2=0,w=0,r=0; /*------------------------------------------------ 12 //临时变量低位 //临时变量高位 键盘扫描程序 ------------------------------------------------*/ uchar keyscan(void) //键盘扫描函数,使用行列反转扫描法 { uchar cord_h,cord_l;//行列值中间变量 P3=0x0f; //行线输出全为0 cord_h=P3&0x0f; //读入列线值 if(cord_h!=0x0f) //先检测有无按键按下 { delay(100); //去抖 if(cord_h!=0x0f) { cord_h=P3&0x0f; //读入列线值 P3=cord_h|0xf0; //输出当前列线值 cord_l=P3&0xf0; //读入行线值 return(cord_h+cord_l);//键盘最后组合码值 } }return(0xff); //返回该值 } void shedingjian() {uchar key; key=keyscan(); switch(key) { case 0xbb:h=1;break; case 0x7b:j=1;break; case 0xe7:k=1;break; 13 }} void shuzhi() {uchar key; key=keyscan(); switch(key) { case 0xee:date=0,x=1;break;//0按下相应的键显示相对应的码值 case 0xde:date=1,x=1;break;//1 按下相应的键显示相对应的码值 case 0xbe:date=2,x=1;break;//2 case 0x7e:date=3,x=1;break;//3 case 0xed:date=4,x=1;break;//4 case 0xdd:date=5,x=1;break;//5 case 0xbd:date=6,x=1;break;//6 case 0x7d:date=7,x=1;break;//7 case 0xeb:date=8,x=1;break;//8 case 0xdb:date=9,x=1;break;//9 }} void shewen() { shedingjian(); if(h==1) { shuzhi(); 14 if(x==1) {a=date; h=0;x=0;} } if(j==1) { shuzhi(); if(x==1) {b=date; j=0;x=0;} } if(k==1) { shuzhi(); if(x==1) {c=date;t=date; k=0;x=0;} } d=a*10+b+t/10; } void PID() {float e1=0,e2=0,e3=0,uk=0,duk=0; uchar KP=24,KI=2,KD=0.5; e1=d-dd; duk=KP*(e1-e2)+KI*e1+KD*(e1-2*e2+e3); uk=uk+duk; if(uk>100)uk=100; else if(uk<-100)uk=-100; 15 if(uk<0) {pwm1=-uk;w=pwm1;} else {pwm2=uk;r=pwm2;} e3=e2;e2=e1; } void main() { TMOD=0x11;//定时器设置 IP=0x01;//定时0优先 TH0=0xd8; TL0=0xf0; TH1=0xf5; TL1=0xf0; ET0=ET1=1;//使能定时器中断 TR0=TR1=1;//启动定时器 EA=1; jdq1=0; jdq2=0; 16 while(1) { shewen(); if(flag_get1==1) //采样周期到 { if(dd>d) //降温控制 { if(dd>(d+4)) {jdq1=0;jdq2=1;} if(dd<=(d+4)) {PID();} if(dd>(d+10)) {ysq=0; delay(2000); ysq=1;} } else if(d>dd) //加热控制 { if(d>(dd+4)) {jdq1=1;jdq2=0;} if(d<=(dd+4)) {PID();} if(d>(dd+10)) {ysq=0; delay(2000); 17 ysq=1;} } else {jdq1=0;jdq2=0;} flag_get1=0; } if(flag_get2==1) {flag_get2=0; EA=0; temp=ReadTemperature(); TempH=temp>>4; TempL=temp&0x0f; TempL=TempL*6/10; aa=(TempH%100)/10; bb=(TempH%100)%10; cc=TempL; tt=TempL; dd=aa*10+bb+tt/10; EA=1; } 18 }} /******************************************************************/ /* 定时器0中断 */ /******************************************************************/ void tim(void) interrupt 1 using 1//定时0中断,用于用于控制加热和降温时间{TH0=0xd8;//定时器重装值 TL0=0xf0; ET0=1; EA=0; num1++; if(num1==16) {num1=0;flag_get1=1; if(pwm1!=0) {pwm1=0; if(count1++ {jdq1=1;jdq2=0;} else {jdq1=0;jdq2=0;} if(count2==100) {r=0;count2=0;} } } EA=1; } /******************************************************************/ /* 定时器1中断 */ /******************************************************************/ void tim1(void) interrupt 3 using 1//定时1中断,用于数码管扫描和温度检测间隔 { TH1=0xf5;//定时器重装值 TL1=0xf0; ET1=1; EA=0; num0++; if(num0==100) {num0=0;flag_get2=1;} count0++; str[3]=0x39; //显示c符号 str[7]=0x39; str[0]=EL[a]; //设置的温度十位值 str[1]=EL[b]|0x80; //设置的温度个位值,带小数点 str[2]=EL[c]; //设置的温度十分位值 str[4]=EL[aa]; //测量的温度十位值; str[5]=EL[bb]|0x80; //测量的温度个位值,带小数点 20 str[6]=EL[cc];//测量的温度十分位值; if(count0==1) {seg3=0,seg2=0,seg1=0; P0=str[0];}//数码管扫描 if(count0==2) {seg3=0,seg2=0,seg1=1; P0=str[1];} if(count0==3) { seg3=0,seg2=1,seg1=0; P0=str[2];} if(count0==4) { seg3=0,seg2=1,seg1=1; P0=str[3];} if(count0==5) { seg3=1,seg2=0,seg1=0; P0=str[4];} if(count0==6) { seg3=1,seg2=0,seg1=1; P0=str[5];} if(count0==7) { seg3=1,seg2=1,seg1=0; P0=str[6];} if(count0==8) { seg3=1,seg2=1,seg1=1; P0=str[7]; count0=0;} EA=1; } 21 18B20程序#ifndef __DS18B20_H__ #define __DS18B20_H__ sbit DQ=P1^3; float temperature; //温度值 void delay(unsigned int i)//延时函数 { while(i--); } /******************************************************************/ /* 初始化 */ /******************************************************************/ void Init_DS18B20(void) { unsigned char x=0; DQ = 1; //DQ复位 delay(8); //稍做延时 DQ = 0; //单片机将DQ拉低 delay(80); //精确延时 大于 480us DQ = 1; //拉高总线 delay(10); x=DQ; //稍做延时后 如果x=0则初始化成功 x=1则初始化失败 22 delay(5); } /******************************************************************/ /* 读一个字节 */ /******************************************************************/ unsigned char ReadOneChar(void) { unsigned char i=0; unsigned char dat = 0; for (i=8;i>0;i--) { DQ = 0; // 给脉冲信号 dat>>=1; DQ = 1; // 给脉冲信号 if(DQ) dat|=0x80; delay(5); } return(dat); } /******************************************************************/ /* 写一个字节 */ /******************************************************************/ void WriteOneChar(unsigned char dat) { unsigned char i=0; for (i=8; i>0; i--) { 23 DQ = 0; DQ = dat&0x01; delay(5); DQ = 1; dat>>=1; } delay(5); } /******************************************************************/ /* 读取温度 */ /******************************************************************/ unsigned int ReadTemperature(void) { unsigned char a=0; unsigned int b=0; unsigned int t=0; Init_DS18B20(); WriteOneChar(0xCC); // 跳过读序号列号的操作 WriteOneChar(0x44); // 启动温度转换 delay(200); Init_DS18B20(); WriteOneChar(0xCC); //跳过读序号列号的操作 WriteOneChar(0xBE); //读取温度寄存器等(共可读9个寄存器) 前两个就是温度a=ReadOneChar(); //低位 b=ReadOneChar(); //高位 b<<=8; t=a+b; 24 return(t); delay(30); } #endif 25 因篇幅问题不能全部显示,请点此查看更多更全内容