专注电子技术学习与研究
当前位置:单片机教程网 >> MCU设计实例 >> 浏览文章

51单片机-温度控制器设计详解+电路+代码

作者:佚名   来源:本站原创   点击数:  更新时间:2013年12月14日   【字体:
这个51单片机电路里面,需要用到:
 

 
AT89C51   x1 主要控制单片机

 
AT24C02   x1 EEPROM-2K储存器

 
DS180B2   x1 温度传感器

 
10uF x1 , 47uF x1 有极电容

 
104[0.1uF] x3 , 30pF x2 无极电容

 
12MHz x1 石英晶体振荡器

 
1K[1千欧姆] x2 电阻

 
7cmx9cm x1 万能洞洞电路板

 
继电器若干[根据需要用到的继电器数目安装到电路上,主控芯片设计可以控制八位继电器(整一个P1端口)]

 
总价好像12块左右吧,建议淘宝一下,不同的商家出售器件的价格不同..

 

 

 
Q1:EEPROM的作用

 
A1:因为EEPROM[电压式可擦写ROM]可以让单片机进行IIC读写外部储存数据,也方便以后换一个控制电路温度值,单片机不可能每换一个控制温

 
度值的时候就重新对主控芯片进行编程..

 
Q2:为什么EEPROM要2K大小呢?

 
A2:太大的储存空间没有实质上的意义,最多使用的数据只用26位数据位,而且更大的储存空间的EEPROM造价也贵,AT24C02-DIP8[直插八个引

 
脚]需要0.8元左右,AT24C512-DIP8[数据存储空间512KB]需要17元左右..

 
Q3:主控芯片可以用其它的51系列代替吗?

 
A3:完全可以的,只需要在原代码文件中修改一下头文件就可以把程序移植到另一个型号的芯片,同理也可以把程序移植到AT89C2051中,

AT89C2051比AT89C51的一个好处就是C2051系列的芯片体积比C51系列的芯片小,可以把电路更小化,如果还要求电路更小化的话选用SOP封

装[贴片型封装]的电子元件是一个不错的选择,不过太小的SOP元件焊接到电路上会另你很头疼,电路布局一定程度上也会影响电路板的整体大

小..

 

 
EEPROM储存数据的方式解析:


 

下面是EEPROM里面的数据储存结构[嘻嘻,图画得有点不好,技术问题请见谅啦..] 


 

首先从主控入口代码处进行分析:


 

 

#define EEPROM_StartAddr 0x4E

#define EEPROM_StartFlag 0xB0

 


 


 

 LED=1;
 

 

BitData=read_add(EEPROM_StartAddr);


 

if (BitData!=EEPROM_StartFlag) while(1); 


 

ListTotal=read_add(EEPROM_StartAddr+1);

for(i=0;i<ListTotal;i++)

{

CtrlList[i].AlarmTemp=read_add((EEPROM_StartAddr+2)+i*3);

CtrlList[i].CtrlPort =read_add((EEPROM_StartAddr+2)+i*3+1);

}  

 

 

LED=0;
 


 

代码首先会从EEPROM里面读取0x4E位里面的数据来和EEPROM起始数据位标志进行对比,判断这个EEPROM的数据格式的正确性,由于没有让


 

主控芯片对每一个数据位进行校验,那么这就是一个简单的验证方法,要是对每一位数据都要进行的验证的话得需要一个可靠,高效的算法,这样虽


 

然安全,不过会对主控芯片初始化有一定的性能影响


 

判断起始数据位失败后,主控芯片会进入到卡死状态[见代码 while(1); ,死循环,处理器永远也跳不出这个循环到外面]


 

判断起始数据位成功后,下一步就从EEPROM的0x4F位读取出需要控制温度的项目总数,然后再按照这个项目总数来进行数据位偏移来读取将要


 

控制的温度数值和警报控制端口,注意两个控制数据结构中间需要用一个NULL[即0x00]来隔开来,防止数据结构被打乱


 

从EEPROM里面读取完成数据后,主控芯片工作指示灯发光,开始进入温度控制


 

主要代码:


 

 

while(1)

{

TempData=get_temp();

BitData=(TempData%1000/100)*10;//十位温度。

              BitData=(TempData%1000%100/10)+BitData;//个位温度。

for(i=0;i<ListTotal;i++)

         {

 CtrlElec=(CtrlList[i].AlarmTemp>=BitData)?0:1;

 CtrlListPort=CtrlList[i].CtrlPort;

 CtrlPort(CtrlListPort,CtrlElec);     //符合条件输出底电,不符合输出高电

 delayb(100);

         }

delayb(200);      

}

 


 

这个可不像SetTimer()一样,用SetTimer()指定了的函数不需要加上while 循环,仅且把上面的代码当作线程来看待,让这个线程运行的代码段永远


 

都是这个,假如线程的代码一旦执行完毕[也就是说跳出了while 死循环],那么它就会关闭掉自己和释放属于自己的TLS[线程本地储存]


 

先从DS18B02里面读取出来温度值,然后再对温度进行转换,把转换好的温度再和从EEPROM里面读取出来的数据结构进行比较


 

一个温度控制判断周期约一秒[以12MHz来计算的话,应该是略大于一秒而不会小于一秒]..


 


 


 

下面是温度控制器的电路:


 


 

5V供电电路:

 


 


 

主控芯片及外围器件电路:

 


 


 

电路中用继电器来控制外部电路的开闭,G[公共端] B[常闭端] K[常开端] 就是让继电器控制外部电路的开关,5V电压和P1^0端口是用来控制继电器


 

的G端和B,K端通路.原理如下:


 

单片机通过引脚输出 1 0来实现控制外围电路,以P1^0[P1端口的第1位引脚]为例,当P1^0输出1的时候,引脚会产生一个5V的高电平.当P1^0输出0


 

的时候,引脚会产生一个0V的低电平


 

 

 


 


 

注:继电器原理图来自百度百科-> http://baike.baidu.com/view/39560.htm


 

继电器原理:当控制电路两端有电流通过时,电和金属发生电磁感应,使得衔铁被磁力吸引而控制工作电路的开关

 
继电器和P1^0引脚之间的关系电路图如下:
 

 

 
 

 
当P1^0输出1[即5V]时,控制电路两端没有电流通过,因为没有电压差的缘故,所以继电器还是把开关B G 通路,但是当P1^0输出0的时候,左边的电

 
压为5V,右边的电压位0V,于是电流就从左向右流过,这个时候继电器会把开关K G 变为通路

 
同理,主控芯片的工作指示灯也是这个原理,你可以去看看上面的EEPROM读取数据代码和主控芯片及外围器件电路结合起来一起看看,相信你也

把这个原理给弄明白

 

 
八路温度控制器实物图如下[八路只使用了其中一路,程序也实地运行过,由于室内温度调节问题,继电器没有反应,因为给EEPROM设置30度报警

 
温度,而且还有零下报警代码没有写和报警温度小数位判断没有写]:

 

 


 

 

实物图和电路原理图基本一致,这个大家不用担心

 

 
代码和大家分享,可以再这个基础上再加以改进,也欢迎你们在使用代码的时候找到BUG然后修改..

 
代码及其电路图下载: http://www.51hei.com/f/DS18B20+EEPROM.rar

下面是main.c 文件:
#include <reg51.h>
#define uchar unsigned char 
#define uint unsigned int

#define EEPROM_StartAddr 0x4E
#define EEPROM_StartFlag 0xB0
/*
#define EEPROM_EndFlag  0xC0
#define EEPROM_EndAddr  0x4E+2+24 //8个数据总数x3个数据位
//EEPROM_EndAddr=0x4E+2+8x03 每个数据占3字节(两个主要数据和一个NULL),0x49系获得数据项目总数
*/
typedef int CTRL_TOTAL;//列表总项目

typedef struct EEPROM_DataList//EEPROM数据结构
{
  int  AlarmTemp;//报警温度
  int  CtrlPort; //控制端口
} CTRL_DATALIST;

uint    get_temp();
void    tmpchange(void);
void    delayb(uint count);
void    init(); 
void    write_add(uchar address,uchar date);
uchar   read_add(uchar address);

void CtrlPort(int PortCode,int Ctrl);

sbit Beep=P3^4;    // 测试用,可略
sbit LED=P2^7;

sbit CtrlPort1=P1^0;
sbit CtrlPort2=P1^1;
sbit CtrlPort3=P1^2;
sbit CtrlPort4=P1^3;
sbit CtrlPort5=P1^4;
sbit CtrlPort6=P1^5;
sbit CtrlPort7=P1^6;
sbit CtrlPort8=P1^7;

CTRL_TOTAL     ListTotal;
CTRL_DATALIST  CtrlList[8];
void delayb(uint count) ;
void main()

  int BitData;       // EEPROM位数据缓存 
  int i;    // 计数循环变量
  int TempData;  // 当前温度值
  int CtrlListPort; // 将要控制的引脚
  int CtrlElec;  // 将要控制的引脚输出电平

  LED=1;
  init();
  BitData=read_add(EEPROM_StartAddr);

  if (BitData!=EEPROM_StartFlag){while(1);} // 卡住它,不要让它重新运行
  // 关于EEPROM获取数据信息可以从同文件夹中图片有指导
  ListTotal=read_add(EEPROM_StartAddr+1);
  for(i=0;i<ListTotal;i++)
  {
   CtrlList[i].AlarmTemp=read_add((EEPROM_StartAddr+2)+i*3);
   CtrlList[i].CtrlPort =read_add((EEPROM_StartAddr+2)+i*3+1);
  } 
  tmpchange();
 
  for(i=0;i<=7;i++) CtrlPort(i,1);   //输出高电位
  LED=0;          //工作指示灯开启

  while(1)
  {
   TempData=get_temp();
   BitData=(TempData%1000/100)*10;  //十位温度。
       BitData=(TempData%1000%100/10)+BitData;//个位温度。
   for(i=0;i<ListTotal;i++)
      {
     CtrlElec=(CtrlList[i].AlarmTemp>=BitData)?0:1;
     CtrlListPort=CtrlList[i].CtrlPort;
     CtrlPort(CtrlListPort,CtrlElec); //符合条件输出底电,不符合输出高电
     delayb(100);
      }
   delayb(200);                  
  }
}

void CtrlPort(int PortCode,int Ctrl)//控制P1.0-P1-7
{
     switch(PortCode)
  {
      case 1: CtrlPort1=Ctrl;
       case 2: CtrlPort2=Ctrl;
      case 3: CtrlPort3=Ctrl;
       case 4: CtrlPort4=Ctrl;
      case 5: CtrlPort5=Ctrl;
      case 6: CtrlPort6=Ctrl;
      case 7: CtrlPort7=Ctrl;
      case 8: CtrlPort8=Ctrl;
     }
}

 

关闭窗口

相关文章