资源描述
摘 要
随着微机测量和控制技术的迅速发展与广泛应用,以单片机为核心的温度采集与控制系统的研发与应用在很大程度上提高了生产生活中对温度的控制水平。本设计论述了一种以STC12C5A60S2单片机为主控制单元,以DS18B20为温度传感器的温度控制系统。通过PID算法和PWM脉宽调制实现温度的精确控制,由温度传感器返回温度值,再与设定温度比较,经过单片机的处理后发出相应的控制信号从而将温度控制在设定的范围之内。硬件电路主要包括STC12C5A60S2单片机最小系统,测温电路、LCD液晶显示电路以及加热控制电路等。系统程序主要包括主程序,读出温度子程序,PID控制温度子程序、PWM子程序、按键处理程序、LCD显示程序以及模式选择程序等。
[关键词] STC12C5A60S2单片机;DS18B20;显示电路
Abstract: Along with the computer measurement and control technology of the rapid development and wide application, based on singlechip temperature gathering and control system development and application greatly improve the production of temperature in life level of control. This design STC12C5A60S2describes a kind of mainly by MCU control unit, for temperature sensor DS18B20 temperature control system. The control system can real-time storage temperature data and record related to the current time. System design related hardware circuit and related applications. STC12C5A60S2 microcontroller hardware circuit include temperature detection circuit smallest system, and real-time clock circuit, LCD display circuit, communication module circuit, etc. System programming mainly include main program, read temperature subroutine, the calculation of temperature subroutines, key processing procedures, LCD display procedures and data storage procedures, etc.
[Keywords] STC12C5A60S2 microcontroller;DS18B20;display circuit
选题依据及研究意义
选题依据:随着社会的发展,科技的进步,以及测温仪器在各个领域的应用,智能化已是现在温度控制系统发展的主流方向。特别是近年来,温度控制系统已深入应用到人们生活的各个方面,但温度控制一直是一个潜在开发的领域,其又是与人们息息相关的一个实际问题。针对这种情况,设计一个温度控制系统具有广泛的应用于实际意义。
研究意义:温度是科学技术中最基本的物理量之一,物理,化学,生物等学科都离不开温度。在工业生产和实验研究中,温度常常是表征对象和过程状态的最重要的参数之一。比如:发电厂锅炉的温度必须控制在一定范围内;许多化学反应的工艺过程必须在适当的温度下才能正常进行;炼油工程中,原油必须在不同的温度和压力条件下进行分流才能得到汽油,柴油,煤油等产品。没有合适的温度环境,许多电子设备就不能正常工作,粮仓的储粮就会变质霉烂,就累得品质就没有保障。因此,各行各业对温度控制的要求越来越高。可见。温度的测量和控制是非常重要的。
选题的研究现状
研究现状:自18世纪工业革命以来,工业发展对是否能掌握温度有着绝对的联系。在冶金,钢铁,石化,水泥,玻璃,医药等等行业,可以说几乎80%的工业部门都不得不考虑着温度的因素。在人类的生活环境中,温度扮演着极其重要的角色。温度是工业生产中常见的工艺参数之一,任何物理变化和化学反应过程都与温度密切相关,因此温度控制是生产自动化的重要任务。比如温室,水池,发酵缸,电源等场所的温度控制。而以往温度控制是由人工完成的而且不够重视,其实在很多场所温度都需要监控以防意外发生。对于不同生产情况和工艺要求下的温度控制,所采用的加热方式,燃料,控制方案也有所不同。无论你生活在哪里,从事什么工作,无时不刻不在与温度打着交道。
单片微型计算机是随着超大规模集成电路技术的发展而诞生的,由于它具有体积小、功能强、性价比高等特点,所以广泛应用于电子仪表、家用电器、节能装置、军事装置、机器人、工业控制等诸多领域,使产品小型化、智能化、既提高了产品的功能和质量,又降低了成本,简化了设计。本文主要介绍单片机在温度控制中的应用。
基本设计思路
单
片
机
温度控制驱动模块
显示模块
温度信号
采集模块
键盘处理模块
电热元件
由题目要求可知,本系统对温度控制的精度要求较高,因此考虑使用PID控制来控制系统温度,而热源的控制采用PWM波来进行精确控制。由温度传感器来传回温度数据,由单片机处理数据并发出相应的动作,从而保证温度在控制范围之内。系统图如下:
图1 系统设计框架
方案论证
(1)温度传感器
方案一: DS18B20是达拉斯公司生产的数字温度传感器,测温范围在-55℃~+125℃,采用单总线通信微处理器连接时仅需要一条口线即可实现微处理器与DS18B20的双向通讯,精度可以达到0.0625℃。具体接口如下:
图2 DS18B20接口电路
方案二: 采用AD590作温度传感器,AD590是一种恒流源形式的温度传感器,只要在其两端加上一定工作电压,则其输出电流随温度变化而变化,其线性电流输出为1uA/K,电流信号再由运放转换为电压信号,通过A/D转换器将输入的模拟电压量转换为数字量,并通过并行接口芯片将数字量送给计算机。具体接口电路如下:
图3 AD950接口电路
由以上来看我们选用方案一DS18B20足以满足系统要求而且使设计更加简单可行。
(2)主控芯片
方案一: 51系列AT89C51。
方案二:增强型8051单片机STC12C5A60S2,STC12C5A60S2具有1个时钟/机器周期,速度比普通8051快8~12倍。兼容普通8051定时器T0/T1,2路PCA实现两个定时器,内含2通道捕获/比较单元(PWM/PCA/CCP)。
本系统中需要通过调节PWM波的占空比来控制加热电路的通断时间,STC12C5A60S2中含有PWM特殊功能寄存器,不需要独立设计PWM产生电路,AT89C51则无此功能,故选用方案二。
(3)显示及键盘
方案一:八位数码管显示。
方案二:12864液晶显示。
由于需要显示的数据比较多且数码管不能显示曲线,为电路设计简便起见,我们选用方案二
又因为所需按键较多,故选用4*4键盘。键盘功能布置如下:
一、 硬件电路设计
(一)单片机最小系统电路
在温度控制系统设计中,控制核心是STC12C5A60S2单时钟/机器周期(1T)单片机,该单片机有32个I/O口,其外部晶振为12MHz,一个指令周期为1/12μS。使用该单片机完全可以完成设计任务,其最小系统主要包括:复位电路、震荡电路等,电路如下图4所示:
(
图 4 STC12C5A60S2最小系统图
(二)LCD显示电路
本设计的温度控制系统是采用液晶屏无字库型12864作为显示模块,此液晶共有8页,64行,128列,含有两个液晶驱动器C1和C2。其接口电路图如下图5所示:
图 5 LCD显示接口
(三)加热驱动电路
本设计中的加热元件使用固态继电器SSR-1P/45A及加热棒,由P1.3口输出PWM波形,从而控制固态继电器的通断。电路如下图6所示:
图 6 温度控制驱动电路
二、软件程序设计
(一) 总体设计
为了实现控制功能,本系统采用通过按键来设置控制温度并进行模式选择,通过LCD液晶显示屏显示实际温度和设置温度以及实际温度变化曲线。设定模式1为基本控制加热模式,模式2为分段恒温控制模式,模式3为恒速控制模式。主流程图如图7所示:
图 7 程序主流程图
其中通过键盘设置控制温度,采用按位直接给定数值并可进行多次设置,使得操作简单方便。在键盘扫描程序中1—9键设置标志位,用以判断设定位。具体流程图如图8所示:
图 8 设定控制温度流程图
模式1:基本温度控制模式。当实际温度与设定温度相差大于5℃时采用PWM全速加热,小于5℃时采用PID控制调节PWM占空比,流程图如图9所示:
图 9 模式1流程图
模式2:分段恒温控制模式。将设定温度给定为50度,当温度为50度时,定时中断恒温控制3分钟,再将设定温度给定为70度。流程图如图10所示:
图 10 模式2流程图
模式3:恒速温度控制模式。如下图所示:
附录:
#include <reg51.h>
#include <intrins.h>//_nop_();延时函数用
#include<math.h>
#include<string.h>
#define unchar unsigned char
#define unint unsigned int
sfr CCON = 0xD8; //PCA控制寄存器
sfr CMOD = 0xD9; //PCA模式寄存器
sfr CCAPM0 = 0xDA; //PCA模块0模式寄存器 //模块0对应P1.3/CEX0/PCA0/PWM0(STC12C5A60S2系列)
sfr CL = 0xE9; //PCA 定时寄存器 低位
sfr CH = 0xF9; //PCA 定时寄存器 高位
sfr CCAP0L = 0xEA; //PCA模块0的 捕获寄存器 低位
sfr CCAP0H = 0xFA; //PCA模块0的 捕获寄存器 高位
sfr AUXR=0x8e;
sbit CR = CCON^6; //PCA计数器 运行控制位
sbit E=P3^0;
sbit RW=P3^1;
sbit RS=P3^2;
sbit CS1=P3^6;
sbit CS2=P3^7;
sbit DQ=P1^0;
sbit M1=P1^5;
sbit M2=P1^6;
sbit M3=P1^7;
sbit p=P1^3;
char code tablenum[][16]={
0x00,0xE0,0x10,0x08,0x08,0x10,0xE0,0x00,
0x00,0x0F,0x10,0x20,0x20,0x10,0x0F,0x00, // 0
0x00,0x10,0x10,0xF8,0x00,0x00,0x00,0x00,
0x00,0x20,0x20,0x3F,0x20,0x20,0x00,0x00, //1
0x00,0x70,0x08,0x08,0x08,0x88,0x70,0x00,
0x00,0x30,0x28,0x24,0x22,0x21,0x30,0x00, //2
0x00,0x30,0x08,0x88,0x88,0x48,0x30,0x00,
0x00,0x18,0x20,0x20,0x20,0x11,0x0E,0x00, //3
0x00,0x00,0xC0,0x20,0x10,0xF8,0x00,0x00,
0x00,0x07,0x04,0x24,0x24,0x3F,0x24,0x00, //4
0x00,0xF8,0x08,0x88,0x88,0x08,0x08,0x00,
0x00,0x19,0x21,0x20,0x20,0x11,0x0E,0x00, //5
0x00,0xE0,0x10,0x88,0x88,0x18,0x00,0x00,
0x00,0x0F,0x11,0x20,0x20,0x11,0x0E,0x00, //6
0x00,0x38,0x08,0x08,0xC8,0x38,0x08,0x00,
0x00,0x00,0x00,0x3F,0x00,0x00,0x00,0x00, //7
0x00,0x70,0x88,0x08,0x08,0x88,0x70,0x00,
0x00,0x1C,0x22,0x21,0x21,0x22,0x1C,0x00, //8
0x00,0xE0,0x10,0x08,0x08,0x10,0xE0,0x00,
0x00,0x00,0x31,0x22,0x22,0x11,0x0F,0x00, //9
0x00,0x00,0x00,0xC0,0xC0,0x00,0x00,0x00,
0x00,0x00,0x00,0x30,0x30,0x00,0x00,0x00, //:
0x08,0xF8,0x88,0x88,0x88,0x88,0x70,0x00,
0x20,0x3F,0x20,0x00,0x03,0x0C,0x30,0x20, //R
0x00,0x70,0x88,0x08,0x08,0x08,0x38,0x00,
0x00,0x38,0x20,0x21,0x21,0x22,0x1C,0x00, //S
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x30,0x30,0x00,0x00,0x00,0x00,0x00, //.
};
char code tablesnum[][4]={
0x00,0x7c,0x44,0x7c,//小0
0x00,0x00,0x7c,0x00,//小1
0x00,0x74,0x54,0x5c,//小2
0x00,0x54,0x54,0x7c,//小3
0x00,0x3c,0x20,0x7c,//小4
0x00,0x5c,0x54,0x74,//小5
0x00,0x7c,0x54,0x74,//小6
0x00,0x04,0x04,0x7c,//小7
0x00,0x7c,0x54,0x7c,//小8
0x00,0x5c,0x54,0x7c,//小9
0x08,0x08,0x08,0x08,
};
unint bz0,bz1,bz2,t1=180,t2=200,t3=12,bj=1,bj1=0;
unint num,ql=13,qp=1,Temperature;
unint Ten,One,Dot1,sa,sb,sc,js,set_temper, rout;
struct PID
{
unint Proportion; // 比例常数 Proportional Const
unint Integral; // 积分常数 Integral Const
unint Derivative; // 微分常数 Derivative Const
unint LastError; // Error[-1]
unint PrevError; // Error[-2]
};
struct PID spid; // PID Control Structure
// PID Response (Output) uk rin 实温
//****定时初始化
intids()
{AUXR=0x80;
EA=1;
ET0=1;
TMOD=0x01;
TR0=1;
TH0=(65536-5000)/256;
TL0=(65536-5000)%256;
}
//********所有温度采集程序******
//**************延时11us函数
void delay(unint t)
{
for(;t>0;t--);
}
//****************复位程序
void reset()
{
DQ=1;
delay(56);//22us
DQ=0;
delay(630);//55us
DQ=1;
delay(100);
}
//*************检测应答脉冲子程序
void yingda()
{
while(DQ);
while(~DQ)
{
delay(16);//88us
break;
}
}
//***********写命令函数,写一个字节
void write_byte(unchar val)
{
unchar i;
for(i=8;i>0;i--)
{
DQ=1;
// _nop_();
// _nop_();
_nop_();
// _nop_();
_nop_();
_nop_();
DQ=0;
_nop_();
_nop_();
// _nop_();
// _nop_();
// _nop_();//5us
//_nop_();
// _nop_();
// _nop_();
// _nop_();
// _nop_();
//
// _nop_();
//_nop_();
// _nop_();
_nop_();
_nop_();
DQ=val&0x01;//取操作命令字节的每一枚数值,必须由低到高进行,
//最低位移出,对于数据的传输均为串行输入,先输入val的最低位,
delay(50); //66us//30
val=val>>1; //右移1位,先为低位后为高位
}
DQ=1;
delay(1);
}
//**************读一字节函数
unchar read_byte(void)//无参函数
{
unchar i;
unchar value=0;
for(i=8;i>0;i--)
{
DQ=1;
//_nop_();
// _nop_();
// _nop_();
//_/nop_();
//_nop_();
//_nop_();
//_nop_();
_nop_();
_nop_();
value=value>>1;//value>>=1;
DQ=0;
// _nop_();
// _nop_();
/// _nop_();
_nop_(); //4us
//_nop_();
_nop_();
//_nop_();
//_nop_();
//_nop_();
_nop_();
//_nop_();
//_nop_();
DQ=1;
_nop_();
// _nop_();
_nop_();
// _nop_(); //4us
//_nop_();
//_nop_();
//_nop_();
//_nop_();
//_nop_();
//_nop_();
//_nop_();
_nop_();
if(DQ) //若DQ=1,则读取的位即为1,若DQ=0,则直接右移一位,
{
value|=0x80;
}
delay(60); //66us,至少需要60us才能完成后一个读程序的过程
}
DQ=1;
return(value);
}
//**********处理采集温度
void chuli(unchar gaowei,unchar diwei)
{
Temperature = (diwei + gaowei *256) * (0.0625*10); //Temperature=125
Ten=Temperature/100; //1
One=Temperature/10%10; //0
Dot1= Temperature%10; //1
}
//**********采集温度并处理
void caijiwendu()
{
unchar wenh,wenl; //存高低温度
reset();//芯片初始化指令,在每一次温度采集时都需要进行复位,初始化
yingda();
write_byte(0xcc); //R0M操作指令,功能为跳过读DS18B20的ROM的编码,
//跳过读ROM指令,直接温度转换
write_byte(0x44); //存储器操作命令,启动温度转换,结果存于9字节的内容中
reset();
yingda();
write_byte(0xcc);
write_byte(0xbe); //发读命令,存储器操作指令,读内部RAM中的九字节的内容
wenl=read_byte(); //温度低八位
wenh=read_byte(); //温度高八位
chuli(wenh,wenl); //数据处理
}
//**************************************************************
//************LCD显示程序
//**************是否忙碌
void readbusy()
{
P0=0x00;
RS=0;
RW=1;
E=1;
while(P0&0x80);
E=0;
}
//***********写命令
void writecommand(unchar command)
{
readbusy();
RS=0;
RW=0;
P0=command;
E=1;
_nop_();
_nop_();
E=0;
}
//***********写数据
void writedate(unchar date)
{
readbusy();
RS=1;
RW=0;
P0=date;
E=1;
_nop_();
_nop_();
E=0;
}
//**********设置页
void setpage(unchar page)
{
page=0xb8|page;
writecommand(page);
}
//*************设置行
void setline(unchar line)
{
line=0xc0|line;
writecommand(line);
}
//**************设置列
void setcolumn(unchar column)
{
column=column&0x3f;
column=0x40|column;
writecommand(column);
}
void setonoff(unchar onoff)
{
onoff=0x3e|onoff;
writecommand(onoff);
}
//**************选屏
void selectscreen(unchar screen)
{
switch(screen)
{case 0:CS1=1;CS2=1;break;
case 1:CS1=1;CS2=0;break;
case 2:CS1=0;CS2=1;break;
default: break;
}
}
//************清屏
void clearscreen(unchar screen)
{
unchar i,j;
selectscreen(screen);
for(i=0;i<8;i++)
{
setpage(i);
setcolumn(0);
for(j=0;j<64;j++)
{
writedate(0x00);
}
}
}
//************初始化
void InitLCD()
{
readbusy();
selectscreen(0);
setonoff(0);
selectscreen(0);
setonoff(1);
selectscreen(0);
clearscreen(0);
setline(0);
clearscreen(0);
writecommand(0xc0);
}
//***************显示数据
void display(unchar ss,unchar page,unchar column,unchar j)
{
unchar i;
selectscreen(ss);
setpage(page);
setcolumn(column);
for(i=0;i<8;i++)
{
writedate(tablenum[j][i]);
}
setpage(page+1);
setcolumn(column);
for(i=0;i<8;i++)
{
writedate(tablenum[j][i+8]);
}
}
//****************显示小数据
void displays(unchar ss,unchar page,unchar column,unchar j)
{
unchar i;
selectscreen(ss);
setpage(page);
setcolumn(column);
for(i=0;i<4;i++)
{
writedate(tablesnum[j][i]);
}
}
//**********显示坐标数据
void dissnum()
{
displays(1,3,0*4,7);
displays(1,3,1*4,5);
displays(1,5,0*4,4);
displays(1,5,1*4,5);
displays(1,7,0*4,1);
displays(1,7,1*4,5);
}
//*************坐标轴
void diszhou()
{unchar i,b;
selectscreen(1);
for(i=2;i<7;i++)
{
setcolumn(11);
setpage(i);
writedate(0xff);
}
setcolumn(11);
setpage(7);
writedate(0x0f);
for(b=2;b<8;b++)
{
setcolumn(12);
setpage(b);
writedate(0x08);
}
}
//************************************************************************
//**************************键盘处理程序
//*******************延时
void delay1(unint z)
{
unint x,y;
for(x=z;x>0;x--)
for(y=110;y>0;y--);
}
//***********扫描键盘
void keyscan()
{unchar temp;
P2=0xfe;
temp=P2;
temp=temp&0xf0;
while(temp!=0xf0)
{
delay1(5);
temp=P2;
temp=temp&0xf0;
while(temp!=0xf0)
{
temp=P2;
switch(temp)
{
case 0xee:num=0;js++;
break;
case 0xde:num=1;js++;
break;
case 0xbe:num=2;js++;
break;
case 0x7e:num=3;js++;
break;
}
while(temp!=0xf0)
{
temp=P2;
temp=temp&0xf0;
}
}
}
P2=0xfd;
temp=P2;
temp=temp&0xf0;
while(temp!=0xf0)
{
delay1(5);
temp=P2;
temp=temp&0xf0;
while(temp!=0xf0)
{
temp=P2;
switch(temp)
{
case 0xed:num=4;js++;
break;
case 0xdd:num=5;js++;
break;
case 0xbd:num=6;js++;
break;
case 0x7d:num=7;js++;
break;
}
while(temp!=0xf0)
{
temp=P2;
temp=temp&0xf0;
}
}
}
P2=0xfb;
temp=P2;
temp=temp&0xf0;
while(temp!=0xf0)
{
delay1(5);
temp=P2;
temp=temp&0xf0;
while(temp!=0xf0)
{
temp=P2;
switch(temp)
{
case 0xeb:num=8; js++;
break;
case 0xdb:num=9; js++;
break;
case 0xbb:num=10;
break;
case 0x7b:num=11;
break;
}
while(temp!=0xf0)
{
temp=P2;
temp=temp&0xf0;
}
}
}
P2=0xf7;
temp=P2;
temp=temp&0xf0;
while(temp!=0xf0)
{
delay1(5);
temp=P2;
temp=temp&0xf0;
while(temp!=0xf0)
{
temp=P2;
switch(temp)
{
case 0xe7:num=12;
break;
case 0xd7:num=13;
break;
case 0xb7:num=14;
break;
case 0x77:num=15;
break;
}
while(temp!=0xf0)
{
temp=P2;
temp=temp&0xf0;
}
}
}
}
//**************************************************
//***************pid 控制
void PIDInit (struct PID *pp)
{
memset ( pp,0,sizeof(struct PID)); //全部初始化为0
}
unint PIDCalc( struct PID *pp )
{
unint dError,Error,pError;
Error = set_temper - Temperature; // 偏差 ek
pError=Error-pp->LastError;
展开阅读全文