Altium Designer画的原理图和PCB图如下:


制作出来的恒温控制电路实物图如下:

电路原理图,我加了7805就不需要双电源了,PCB版没有
仿真原理图如下

元件清单:
0.1uF(104)瓷片电容 1 C3
10K 碳膜电阻 4 R2, R9, R10,R5
12.00MHz 晶体振荡器 1 CRY1
1N4007 二极管 2 D1, D2
0.47uF(1uF) 电解电容 1 CE1
100uF(220uF) 电解电容 1 CE2
22pF 瓷片电容 2 C1, C2
4.7K 碳膜电阻 1 R3
1K 碳膜电阻 4 R4, R6, R7, R8
5K 电位器 1 RP1
5V DC蜂鸣器 1 BZ1
S8550三极管 1 Q1
6x6轻触按键 4 S1,S2,S3,S4
DS18B20 温度传感器 1 J1
SRD-05VDC 继电器 2 RELAY1, RELAY2
LCD1602 液晶屏 1 LCD1
IDC-3P 2.54mm 单排排针 1 J1
IDC-16P 2.54mm 单排排针 1 LCD1
S9014 三极管 2 Q2, Q3
STC89C52 单片机 1 IC1
XH-2P 2.54mm插座 1 J2
KF25-6P-7.62mm 接线座 1 J6
红色LED 2 LD2,LD3, LD4
绿色LED 1 LD1
万能板(洞洞板) 1
锡线 1份
连线 1份
单片机源程序如下:
#include <reg52.h>#include <intrins.h> #define uint unsigned int #define uchar unsigned char sbit DQ=P2^3;//ds18b20与单片机连接口 sbit RS=P2^5;//液晶控制线接口 sbit RW=P2^6; sbit EN=P2^7; uchar data disdata[5]; uint tvalue,CurrentT=0;//温度值 uchar tflag;//温度正负标志 #define LCD_BUS P0 sbit SetKey = P2^2;//设置按键 sbit UpKey = P2^1; //加按键 sbit DnKey = P2^0;//减按键 sbit BEEP = P2^4;//蜂鸣器 sbit Heat = P1^0;//加热继电器控制 sbit Cool = P1^1;//降温继电器控制 unsigned char AlarmTempLow=10,AlarmTempTop=40,Set=0; void delayms(uint ms) //延时xx毫秒 { uchar i; while(ms--) { for(i=0;i<120;i++); } } void command(uint com) //LCD写指令 { RS=0; //RS为0 LCD_BUS=com; //装载指令 delayms(5); //延时5ms EN=1; //LCD使能 delayms(5); //延时5ms EN=0; //LCD不使能 } void write_dat(uchar dat) //LCD写数据 { RS=1; //RS为1 LCD_BUS=dat; //装载数据 delayms(5); //延时5ms EN=1; //LCD使能 delayms(5); //延时5ms EN=0; //LCD不使能 } void writestring(uchar x,uchar y,uchar *s) //LCD 写字符串 { if (y == 0) command(0x80 + x); //表示第一行 else command(0xC0 + x); //表示第二行 while (*s) //判断是否字符串的结尾 { write_dat( *s); //显示当前字符 s ++; //字符串地址加1 } } void writeChar(uchar x,uchar y,uchar s) //LCD 写字符串 { if (y == 0) command(0x80 + x); //表示第一行 else command(0xC0 + x); //表示第二行 { write_dat( s); //显示当前字符 } } void LCD_Initial() //LCD初始化 { EN=0; //LCD不使能 RW=0; //RW为0 command(0x38); //发送初始化指令 command(0x0c); //发送初始化指令 command(0x06); //发送初始化指令 command(0x01); //发送初始化指令 command(0x80+0x02); //发送LCD初始位置 } /*************************DS1820程序****************************/ void delay_18B20(unsigned int i)//延时1微秒 { while(i--); } void ds1820rst(void)/*ds1820复位*/ { unsigned char x=0; DQ = 1; //DQ复位 delay_18B20(4); //延时 DQ = 0; //DQ拉低 delay_18B20(100); //精确延时大于480us DQ = 1; //拉高 delay_18B20(40); } uchar ds1820rd(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_18B20(10); } return(dat); } void ds1820wr(uchar wdata)/*写数据*/ { unsigned char i=0; for (i=8; i>0; i--) //写一个字节数据到DS18B20 { DQ = 0; DQ = wdata&0x01; //写一位数据 delay_18B20(10); //延时 DQ = 1; //拉高数据线 wdata>>=1;//准备下一位 } } unsigned int Read_Temperature(void)/*读取温度值并转换*/ { uchar a,b; ds1820rst(); ds1820wr(0xcc);//*跳过读序列号*/ ds1820wr(0x44);//*启动温度转换*/ ds1820rst(); ds1820wr(0xcc);//*跳过读序列号*/ ds1820wr(0xbe);//*读取温度*/ a=ds1820rd(); //读取低位数据 b=ds1820rd(); //读取高位数据 tvalue=b; tvalue<<=8; tvalue=tvalue|a;//取得16位数据 if(tvalue<0x0fff) tflag=0; //判断是否正温度 else {tvalue=~tvalue+1;tflag=1;} //负温度,数据取反,温度标志位为1 tvalue=tvalue*(0.625);//温度值扩大10倍,精确到1位小数 CurrentT=tvalue;//保存当前温度 return(tvalue);//返回温度值 } void Display_Temperature() //显示温度 { uchar flagdat; disdata[0]=tvalue/1000+0x30;//百位数 disdata[1]=tvalue%1000/100+0x30;//十位数 disdata[2]=tvalue%100/10+0x30;//个位数 disdata[3]=tvalue%10+0x30;//小数位 if(tflag==0) flagdat=0x20;//正温度不显示符号 else flagdat=0x2d;//负温度显示负号:- if(tflag==1) { writeChar(10,0,flagdat);//显示符号位 writeChar(11,0,disdata[0]);//显示百位 writeChar(12,0,disdata[1]);//显示十位 writeChar(13,0,disdata[2]);//显示个位 writeChar(14,0,0X2E);//显示小数点 writeChar(15,0,disdata[3]);//显示小数位 } else { writeChar(10,0,disdata[0]);//显示百位 writeChar(11,0,disdata[1]);//显示十位 writeChar(12,0,disdata[2]);//显示个位 writeChar(13,0,0X2e);//显示小数点 writeChar(14,0,disdata[3]);//显示小数位 writeChar(15,0,' ');//显示小数位 } } void SetFun(void) //进入设置参数子函数 { unsigned char i1=0,i2=0,i3=0,i4=0,i5=0,i6=0; if(SetKey==0) //设置按键 { delayms(20); //延时防抖 if(SetKey==0) //设置按键 { if(Set<2) Set++; //设置按键次数累计 else Set=0; } switch(Set) //根据设置按键次数,指向对应设置位置 { case 0: writestring(0,1," ");writestring(8,1," ");break;//清除设置符号 case 1: writestring(0,1,">");writestring(8,1," ");break;//指向设置下限 case 2: writestring(0,1," ");writestring(8,1,">");break;//指向设置上限 } while(SetKey==0);//等待按键松开 } if((UpKey==0)&&(Set!=0))//加按键按下 { delayms(20);//延时防抖 if(UpKey==0)//加按键按下 { switch(Set)//根据设置按键次数,设置上下限 { case 1: if(AlarmTempLow<99) AlarmTempLow++;else AlarmTempLow=99; break;//设置下限 case 2: if(AlarmTempTop<99) AlarmTempTop++;else AlarmTempTop=99; break;//设置上限 } i1 = AlarmTempLow/100; //获得下限温度值的百位 i2 = AlarmTempLow%100/10; //获得下限温度值的十位 i3 = AlarmTempLow%10; //获得下限温度值的个位 i4 = AlarmTempTop/100; //获得上限温度值的百位 i5 = AlarmTempTop%100/10; //获得上限温度值的十位 i6 = AlarmTempTop%10; //获得上限温度值的个位 writestring(5,1," "); //清除之前的内容 writestring(13,1," ");//清除之前的内容 if(i1!=0) writeChar(5,1,i1+'0');//在第二行第5位 ,显示下限温度值的百位 if((i1==0)&&(i2!=0)) writeChar(5,1,i2+'0');//在第二行第5位 ,显示下限温度值的十位 if(i1!=0) writeChar(6,1,i2+'0');//在第二行第6位 ,显示下限温度值的十位 if((i1==0)&&(i2==0)) writeChar(5,1,i3+'0');//在第二行第5位 ,显示下限温度值的个位 else if((i1==0)&&(i2!=0)) writeChar(6,1,i3+'0');//在第二行第6位 ,显示下限温度值的个位 if((i1!=0)) writeChar(7,1,i3+'0');//在第二行第7位 ,显示下限温度值的个位 if(i4!=0) writeChar(13,1,i4+'0');//在第二行第13位 ,显示上限温度值的百位 if((i4==0)&&(i5!=0)) writeChar(13,1,i5+'0');//在第二行第13位 ,显示上限温度值的十位 if(i4!=0) writeChar(14,1,i5+'0');//在第二行第14位 ,显示上限温度值的十位 if((i4==0)&&(i5==0)) writeChar(13,1,i6+'0');//在第二行第13位 ,显示上限温度值的个位 else if((i4==0)&&(i5!=0)) writeChar(14,1,i6+'0');//在第二行第14位 ,显示上限温度值的个位 if((i4!=0)) writeChar(15,1,i6+'0');//在第二行第15位 ,显示上限温度值的个位 while(UpKey==0);//等待按键松开 } } if((DnKey==0)&&(Set!=0))//减按键 { delayms(20); if(DnKey==0)//减按键 { switch(Set)//根据设置按键次数,设置上下限 { case 1: if(AlarmTempLow>0) AlarmTempLow--;else AlarmTempLow=0; break;//设置下限 case 2: if(AlarmTempTop>0) AlarmTempTop--;else AlarmTempTop=0; break;//设置上限 } i1 = AlarmTempLow/100; //获得下限温度值的百位 i2 = AlarmTempLow%100/10; //获得下限温度值的十位 i3 = AlarmTempLow%10; //获得下限温度值的个位 i4 = AlarmTempTop/100; //获得上限温度值的百位 i5 = AlarmTempTop%100/10; //获得上限温度值的十位 i6 = AlarmTempTop%10; //获得上限温度值的个位 writestring(5,1," "); //清除之前的内容 writestring(13,1," ");//清除之前的内容 if(i1!=0) writeChar(5,1,i1+'0');//在第二行第5位 ,显示下限温度值的百位 if((i1==0)&&(i2!=0)) writeChar(5,1,i2+'0');//在第二行第5位 ,显示下限温度值的十位 if(i1!=0) writeChar(6,1,i2+'0');//在第二行第6位 ,显示下限温度值的十位 if((i1==0)&&(i2==0)) writeChar(5,1,i3+'0');//在第二行第5位 ,显示下限温度值的个位 else if((i1==0)&&(i2!=0)) writeChar(6,1,i3+'0');//在第二行第6位 ,显示下限温度值的个位 if((i1!=0)) writeChar(7,1,i3+'0');//在第二行第7位 ,显示下限温度值的个位 if(i4!=0) writeChar(13,1,i4+'0');//在第二行第13位 ,显示上限温度值的百位 if((i4==0)&&(i5!=0)) writeChar(13,1,i5+'0');//在第二行第13位 ,显示上限温度值的十位 if(i4!=0) writeChar(14,1,i5+'0');//在第二行第14位 ,显示上限温度值的十位 if((i4==0)&&(i5==0)) writeChar(13,1,i6+'0');//在第二行第13位 ,显示上限温度值的个位 else if((i4==0)&&(i5!=0)) writeChar(14,1,i6+'0');//在第二行第14位 ,显示上限温度值的个位 if((i4!=0)) writeChar(15,1,i6+'0');//在第二行第15位 ,显示上限温度值的个位 while(DnKey==0); } } } void Alarm(void)//报警子函数 { if((CurrentT>=(AlarmTempTop*10))||(CurrentT<=(AlarmTempLow*10))||(tflag==1)) //超出设定范围 { BEEP=0;//启动报警 } else //在设定范围内 { BEEP=1;//取消报警 } }
复制代码