本帖最后由 二哲科技 于 2021-7-18 15:36 编辑

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

2.png

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

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


元件清单:
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;//取消报警
  •                 }
  • }
  • 复制代码