自制可调温度控制器
- 格式:doc
- 大小:269.50 KB
- 文档页数:17
自制可调温度控制器作者:温正伟原载:无线电杂志按一下S2电路开始显示和监测,如再按一下S2进入温度设定状态,设定值每秒闪烁一次,这时可以按S1或S3进行调节,再按下S2时退回显示当前温度状态并保存温度值到DS18B20。
使用2051的第9脚做控制输出端,低电平有效,笔者用它通过9012去驱动一个5V的继电器。
笔者把这个电路安装到电脑前面板上,继电器触头端接机箱的散热风扇,设定一个温度值如28度,当机箱内的温度超出28度时,控制端为低电平,继电器闭合,风扇启动进行散热。
图三就是装在电脑面板上的实物照片。
图2:电原理图4.软件实现这个温度控制器制作的最大难点应该算是2051程序的编写和调试。
因在电路中有数字显示,按键设定,数据采集和继电器控制。
首先要考虑的是在电路中3个数码管的阴极是接在P1上的,也就是说要使用动态显示的编程方法,笔者在程序中使用了一个定时中断去处理显示,定时器的定时值为20毫秒,每间隔20毫秒程序但会执行定时中断显示所要显示的数字,同时在这个定时中断中还会去扫描按键,看是否有键被按下并对其结果进行处理。
在这20ms的时间里程序还会完成温度数据的采集和转换和对当前温度和设置温度的对比等等。
在编写采集DS18B20数据的函数时运用了DS18B20的单总线协议,在读写DS18B20时IO口的电平时序上应尽可能做到与资料上提供的数据相一致。
程序大部分使用模块化设计,读者朋友修改或使用它的函数编写自己温控程序,程序的最新版本可以访问笔者的个人网站。
图三实物图用实验板搭建的实物图源程序如下:/*-------------------------------温度控制器V1.51显示为三个共阳极LED温度传感器用单总线DS18B20CPU为2051,三个按键,分别为UP,DOWN,SET 温度调节上限为125度,下限为-55度只能用于单只18B20本软件仅供学习与参考,引用时请注明版权-------------------------------*/#include <AT89X051.H>#include <intrins.h>#define Key_UP P3_0 //上调温度#define Key_DOWN P3_1 //下调温度#define Key_SET P1_7 //设定键(温度设定,长按开电源)#define RelayOutPort P3_5 //继电器输出#define LEDPort P1 //LED控制口#define LEDOneC P3_2 //LED DS1控制(百位)#define LEDTwoC P3_3 //LED DS2控制(十位)#define LEDThreeC P3_4 //LED DS3控制(个位)#define TMPort P3_7 //DS1820 DataPortunsigned char codeLEDDis[]={0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,0x80,0x90,0xFF,0xBF}; //0-9的LED笔划,0xFF为空,0xF7为负号static unsigned char bdata StateREG; //可位寻址的状态寄存器sbit DS1820ON = StateREG^0; //DS1820是否存在sbit SetTF = StateREG^1; //是否是在温度设置状态sbit KeySETDown = StateREG^2; //是否已按过SET键标识sbit PowTF = StateREG^3; //电源电源标识sbit KeyTF = StateREG^4; //键盘是否允许//sbit KeySETDowning = StateREG^5; //SET是否正在按下static unsigned char bdata TLV _at_ 0x0029; //温度变量高低位static unsigned char bdata THV _at_ 0x0028;static signed char TMV; //转换后的温度值static unsigned char KeyV,TempKeyV; //键值static signed char TMRomV _at_ 0x0027; //高温限制static signed char TMSetV _at_ 0x0026; //温度设定值static unsigned char KSDNum; //SET键连按时的采集次数static unsigned char IntNum,IntNum2,IntNum3; //中断发生次数,IntNum用于SET长按检测,IntNum2用于设定状态时LED闪烁static signed char LED_One,LED_Two,LED_Three; //LED的显示位LED_One为十位,LED_Two为个位static unsigned char Sign; //负号标识void main(void){void InitDS1820(void); //定义函数void ROMDS1820(void);void TMVDS1820(void);void TMRDS1820(void);void TMWDS1820(void);void TMREDS1820(void);void TMERDS1820(void);void ReadDS1820(void);void WriteDS1820(void);void Delay_510(void);void Delay_110(void);void Delay_10ms(void);void Delay_4s(void);void V2ToV(void);StateREG = 0; //初始化变量SetTF = 1;PowTF = 1; //关电源THV = 0;TLV = 0;TMV = 0;KeyV = 0;TempKeyV = 0;KSDNum = 0;IntNum = 0;IntNum2 = 0;IntNum3 = 0;LED_One = 0;LED_Two = 0;InitDS1820(); //初始化ROMDS1820(); //跳过ROMTMERDS1820(); //E2PRAM中温度上限值调入RAMInitDS1820(); //初始化ROMDS1820(); //跳过ROMTMRDS1820(); //读出温度指令ReadDS1820(); //读出温度值和上限值TMSetV = TMRomV; //拷贝保存在DS18B20ROM里的上限值到TMSetVEA = 1; //允许CPU中断ET0 = 1; //定时器0中断打开TMOD = 0x1; //设定时器0为模式1,16位模式TH0=0xB1;TL0=0xDF; //设定时值为20000us(20ms)TR0 = 1; //开始定时while(1);}//定时器0中断外理中键扫描和显示void KeyAndDis_Time0(void) interrupt 1 using 2{TH0=0xB1;TL0=0xDF; //设定时值为20000us(20ms)LEDPort = 0xFF;if (!Key_UP)KeyV = 1;if (!Key_DOWN)KeyV = 2;if (!Key_SET)KeyV = 3;//KeySETDowning = 0; //清除if (KeyV != 0) //有键按下{Delay_10ms(); //延时防抖按下10ms再测if (!Key_UP)TempKeyV = 1;if (!Key_DOWN)TempKeyV = 2;if (!Key_SET)TempKeyV = 3;if (KeyV == TempKeyV) //两次值相等为确定接下了键{if (KeyV == 3) //按下SET键,如在SET状态就退出,否则进入{//KeySETDowning = 1; //表明SET正在按下PowTF = 0; //电源标识开if (!KeyTF)if (SetTF){SetTF = 0; //标识位标识退出设定InitDS1820(); //初始化ROMDS1820(); //跳过ROMTMWDS1820(); //写温度上限指令WriteDS1820(); //写温度上限到DS18B20ROMWriteDS1820(); //写温度上限到DS18B20ROMWriteDS1820(); //写温度上限到DS18B20ROMInitDS1820(); //初始化ROMDS1820(); //跳过ROMTMREDS1820(); //温度上限值COPY回E2PRAM}elseSetTF = 1;if (!KeySETDown) //没有第一次按下SET时,KeySETDown标识置1KeySETDown = 1;elseKSDNum = KSDNum + 1; //前一秒内有按过SET则开始计数}if (SetTF) //在SET状态下{if ((KeyV == 1) && (!KeyTF))TMSetV = TMSetV + 1; //上调温度if ((KeyV == 2) && (!KeyTF))TMSetV = TMSetV - 1; //下调温度if (TMSetV <= -55) //限制温度上下限TMSetV = -55;if (TMSetV >= 125)TMSetV = 125;}if ((!KeyTF) && (IntNum3 == 0)) KeyTF = 1; //当键盘处于可用时,锁定}if (KeySETDown) //在2秒内按下了SET则计中断发生次数用于长按SET时计时用IntNum = IntNum + 1;if (IntNum > 55) //中断发生了55次时(大约1.2秒)75为1.5秒左右{IntNum = 0;KeySETDown = 0;if (KSDNum == 55) //如一直长按了SET1.2秒左右{RelayOutPort = 1; //关闭继电器输出PowTF = 1; //电源标识关LEDOneC = 0;LEDTwoC = 0;LEDThreeC = 0;LEDPort = 0xBF; //显示"--"Delay_4s(); //延时LEDOneC = 1;LEDTwoC = 1; //关显示LEDThreeC = 1;Delay_4s();IntNum = 0;IntNum2 = 0;IntNum3 = 0;}KSDNum = 0;}}KeyV = 0;TempKeyV = 0; //清空变量准备下次键扫描if (!PowTF){InitDS1820(); //初始化ROMDS1820(); //跳过ROMTMVDS1820(); //温度转换指令Delay_510();Delay_510(); //延时等待转换完成InitDS1820(); //初始化ROMDS1820(); //跳过ROMTMRDS1820(); //读出温度指令ReadDS1820(); //读出温度值V2ToV(); //转换显示值if (TMV > TMSetV) //根据采集到的温度值控制继电器{RelayOutPort = 0;}else{RelayOutPort = 1;}if (SetTF) IntNum2 = IntNum2 + 1; //用于闪烁计数if (IntNum2 > 50 ) IntNum2 = 0;if (KeyTF) IntNum3 = IntNum3 + 1; //用于防止按键连按if (IntNum3 > 25){IntNum3 = 0;KeyTF = 0;}if ((SetTF) && (IntNum2 < 25)) goto InitEnd; //计数在后半段时显示LEDPort = LED_One;LEDOneC = 0;Delay_510();LEDOneC = 1; //显示百位数LEDPort = LED_Two;LEDTwoC = 0;Delay_510();LEDTwoC = 1; //显示十位数LEDPort = LED_Three;LEDThreeC = 0;Delay_510();LEDThreeC = 1; //显示个位数}InitEnd:;}void V2ToV(void) //数值转换{TLV = TLV >> 4;THV = THV << 4; //读出的高低位数值移位TMV = TLV | THV; //合并高低位放入TM为实际温度值Sign = 0;if (SetTF || !Key_SET)Sign = TMSetV >> 7; //取符号elseSign = TMV >> 7;if (Sign){if (SetTF || !Key_SET){LED_One = (~(TMSetV-1)) / 100; //SET状态下显示设定值LED_Two = ((~(TMSetV-1)) - LED_One * 100)/10;LED_Three = (~(TMSetV-1)) - LED_One * 100 - LED_Two * 10;}else{LED_One = (~(TMV-1)) / 100; //转换百位值LED_Two = ((~(TMV-1)) - LED_One * 100)/10;LED_Three = (~(TMV-1)) - LED_One * 100 - LED_Two * 10;}}else{if (SetTF || !Key_SET){LED_One = (TMSetV) / 100; //SET状态下显示设定值LED_Two = (TMSetV - LED_One * 100)/10;LED_Three = TMSetV - LED_One * 100 - LED_Two * 10;}else{LED_One = (TMV) / 100; //转换百位值LED_Two = (TMV - LED_One * 100)/10;LED_Three = TMV - LED_One * 100 - LED_Two * 10;}}//转LED字段if (LED_One) //超过百时十位的处理LED_Two = LEDDis[LED_Two];else{if (LED_Two == 0)LED_Two = LEDDis[10];elseLED_Two = LEDDis[LED_Two];}if (Sign)LED_One = LEDDis[11];else{if (LED_One == 0)LED_One = LEDDis[10];elseLED_One = LEDDis[LED_One];}LED_Three = LEDDis[LED_Three];}void InitDS1820(void) //初始化DS1820{TMPort = 1; //拉高TMPort_nop_(); //保持一个周期TMPort = 0; //拉低TMPortDelay_510(); //延时DS1820复位时间要500us的低电平TMPort = 1; //拉高TMPort_nop_(); //保持_nop_();_nop_();Delay_110(); //延时110us 等待DS1820回应if (!TMPort) //回应信号为低电平DS1820ON = 1;elseDS1820ON = 0;Delay_110(); //延时Delay_110();TMPort = 1; //拉高TMPort}void ROMDS1820(void) //跳过ROM匹配{#pragma asmMOV A,#0CCHMOV R2,#8CLR CWR1:CLR P3_7MOV R3,#6DJNZ R3,$RRC AMOV P3_7,CMOV R3,#23DJNZ R3,$SETB P3_7NOPDJNZ R2,WR1SETB P3_7#pragma endasm}void TMVDS1820(void) //温度转换指令{#pragma asmMOV A,#44HMOV R2,#8CLR CWR2:CLR P3_7MOV R3,#6DJNZ R3,$RRC AMOV P3_7,CMOV R3,#23DJNZ R3,$SETB P3_7NOPDJNZ R2,WR2SETB P3_7#pragma endasm}void TMRDS1820(void) //读出温度指令{#pragma asmMOV A,#0BEHMOV R2,#8CLR CWR3:CLR P3_7MOV R3,#6DJNZ R3,$RRC AMOV P3_7,CMOV R3,#23DJNZ R3,$SETB P3_7NOPDJNZ R2,WR3SETB P3_7#pragma endasm}void TMWDS1820(void) //写入温度限制指令{#pragma asmMOV A,#04EHMOV R2,#8CLR CWR13:CLR P3_7MOV R3,#6DJNZ R3,$RRC AMOV P3_7,CMOV R3,#23DJNZ R3,$SETB P3_7NOPDJNZ R2,WR13SETB P3_7#pragma endasm}void TMREDS1820(void) //COPY RAM to E2PRAM {#pragma asmMOV A,#48HMOV R2,#8CLR CWR33:CLR P3_7MOV R3,#6DJNZ R3,$RRC AMOV P3_7,CMOV R3,#23DJNZ R3,$SETB P3_7NOPDJNZ R2,WR33SETB P3_7#pragma endasm}void TMERDS1820(void) //COPY E2PRAM to RAM{#pragma asmMOV A,#0B8HMOV R2,#8CLR CWR43:CLR P3_7MOV R3,#6DJNZ R3,$RRC AMOV P3_7,CMOV R3,#23DJNZ R3,$SETB P3_7NOPDJNZ R2,WR43SETB P3_7#pragma endasm}void WriteDS1820(void) //写入温度限制值{#pragma asmMOV A,26H //发出4EH写ROM指令后连发两个字节分别为上下限MOV R2,#8CLR CWR23:CLR P3_7MOV R3,#6DJNZ R3,$RRC AMOV P3_7,CMOV R3,#23DJNZ R3,$SETB P3_7NOPDJNZ R2,WR23SETB P3_7#pragma endasm}void ReadDS1820(void) //读出温度值{#pragma asmMOV R4,#3 ; 将温度高位和低位,高温限制位从DS18B20中读出MOV R1,#29H ; 低位存入29H(TEMPER_L),高位存入28H(TEMPER_H),高温限制位存入27H(TMRomV)RE00:MOV R2,#8RE01:CLR CSETB P3_7NOPNOPCLR P3_7NOPNOPNOPSETB P3_7MOV R3,#09RE10:DJNZ R3,RE10MOV C,P3_7MOV R3,#23RE20:DJNZ R3,RE20RRC ADJNZ R2,RE01MOV @R1,ADEC R1DJNZ R4,RE00#pragma endasm}void Delay_510(void) //延时510微秒{#pragma asmMOV R0,#7DHMOV R1,#02HTSR1:DJNZ R0,TSR1MOV R0,#7DHDJNZ R1,TSR1#pragma endasm}void Delay_110(void) //延时110微秒{#pragma asmMOV R0,#19HMOV R1,#02HTSR2:DJNZ R0,TSR2MOV R0,#19HDJNZ R1,TSR2#pragma endasm}void Delay_10ms(void) //延时10ms {#pragma asmMOV R0,#19HMOV R1,#0C8HTSR3:DJNZ R0,TSR3MOV R0,#19HDJNZ R1,TSR3#pragma endasm}void Delay_4s(void) //延时4s{#pragma asmMOV R2,#28HTSR5:MOV R0,#0FAHMOV R1,#0C8H TSR4:DJNZ R0,TSR4 MOV R0,#0FAH DJNZ R1,TSR4 DJNZ R2,TSR5 #pragma endasm }。