摘要:
本设计采用了 STC89C52 单片机组成温度控制系统,可以实现对常温的水加热到最大
100oC 的较快而精确的控制。温度传感器采用了数字式温度传感器 DS18B20,对温度进行实
时采样。设置的键盘各显示模块可以预设加热的最终保持水温并进行实时显示预设温度和
当前温度。单片机采用 PID 算法的控制输出宽度可调的 PWM 波方式控制双向可控硅的导通
和关断用以调整输出加热功率,使之切断或接通加热器,从而控制水温稳定在预值上。根
据温控的单回路 PID 数字调节器完成实时测量(传感采样),实时决策(PID 控制运算)和
实时控制(调功)三部分功能。
一、 设计任务
1. 基本要求:
设计制作一套单片机温度控制系统,包括:
(1),硬件原理图
(2),印制板 PCB 图
(3),硬件测试程序
(4),元件焊接调试
2.主要性能指标:
(1),温度设定在常温到 100oC,最小区分度为 1oC
(2),温度控制的静态误差<1oC
(3),用 LCD 液晶显示水的实测温度和预设温度
二、系统硬件原理设计
1.系统总体框图
温度传感器
DS18B20
采集
电 炉 加 热
器
双向可控硅
STC
89C52
单 片 机 基 本
控制系统
LCD 显示
键盘
1
2. 系统功能实现的设计
(1)温度采集
本设计采用数字传感器 DS18B20,DS18B20 是一种可组网的单线数字温度传感器,它采
用单线总线结构,集温度测量和 A/D 转换于一体,直接输出数字量,用一根 I/O 线就可以
传送数据与命令,其温度测量范围为-55oC~+125oC,精度为+/-0.5oC,使用中无需外部器件,
可利用数据线或外部电源提供电能,供电电压范围为 3.3~5.5V,通过编程实现 9~12 位分
辨率读出温度数据。
使用时,将 DS18B20 的数据 DQ 与单片机的一位具有三态功能的双向口连接就可以实现
数据传输,为保证在有效的时钟周期内提供足够电流,采用外部电源单独供电,在数据线
上加一个 6.8KΩ的上拉电阻。
具体接线如下:
(2)显示与键盘
设计中显示的实现采用 LCD 液晶集成模块 TJDM1602,由 STC 89C52 单片机 P0 的 8 个
数据端口与其连接,中间加上拉电阻来完成对实时采集温度的显示。1602 为 16 位两行字
符显示,所以设计中定义第一行显示设定温度 ST,第二行显示实测温度 PT,下面是 1602
的 RAM 地址映射图:
2
读时序:
写时序:
此设计中键盘使用 STC 89C52 单片机 P1 口,采用独立式 7 键结构(此次只使用 4 个按
键),操作更具多样化且满足设计中设定温度的要求。
(3)输出控制
由于被控对象是水的温度,故算法控制采用 P 调节,由主控单片机运算输出脉冲宽度
可调的 PWM 波用于双向可控硅在 1s 内的导通和关断数从而调节输出给电炉的功率,这样
使得水温稳定在设定值上。设计中使用 MOC3021 光耦隔离输出给双向可控硅 BTA06 后与电
炉串联。下面是接线图:
3
(4)主控单片机
设计中选用 STC 89C52 单片机,共有四个 8 位的 I/O
口,外加 12MHz 晶振提供时钟信号,采用上电复位模式,P2.2
口号和温度采样与处理器件 DS18B20 通讯,直接输入 12 位
数字量到 89C51 内进行处理,P2.0 口输出控制信号与外接
电源构成回路来控制固态继电器的输入信号,P0 口与 LCD
液晶显示模块 1602 连接,用于实时温度和设定温度的显示。
三、 系统软件原理设计
控制系统加电后主控单片机、LCD 显示、温度传感器
DS18B20 复位,然后初始化单片机和温度传感器,初始化完
成之后,程序开始扫描键盘等待设定目标温度值,设定完成
后,程序则立即开始通过扫描温度传感器 DS18B20 来实时采
集当前水温并显示。控制算法中,当设定值与实际水温值相
差大于 10oC 时,控制电炉的输出功率为全功率,当两者相差小于 10OC 时采用比例控制,并
在相差 10~5oC 时采用不同参数的比例控制,小于 5oC 时采用比例积分控制,直至实际水温与
设定水温相同时停止控制,程序进入等待控制状态,如果水温降到设定值以下则又开始控
制。
(1),按键功能定义
本次设计中定义 4 个按键:设定、加、减、复位键。复位键由主控单片机的复位来实
现,其余各键由 P1 口采集控制,分别为:P1.4、P1.1、P1.2 口。设定初始值时默认从高
位到低位依次设定,用加减键实现数字的选择,按下设定键直接确认并跳到下一位,三位
设定完成后主程序开始进行实时数据的采集和对输出的控制。
(2),温度传感器实时数据采集
设计中选用数字传感器 DS18B20,其内部可自动完成对温度模拟量到数字量的转换和
放大,通过一根信号即可将实时温度参数读入主控单片机进行控制处理。本设计中通过 P2.2
口进行信号传输,控制程序中只要对 DS18B20 初始化完毕就可以实时读取采集温度信号。
(3),LCD 液晶集成模块 TJDM1602 初始化
TJDM1602 通过主控单片机的 P0 口连接,外接上拉电阻,其显示最多达 16 位,设计
使用上下两行来分别实现设定值与实测值的共同显示,P2.3、P2.4、P2.5 分别实现 TJDM1602
的复位、读写和使能,主程序中参考其时序来实现数据的显示。
4
(4),调功输出控制
主控单片机运算输出脉冲宽度可调的 PWM 波用于双向可控硅在 1s 内的导通和关断数从
而调节输出给电炉的功率。控制算法采用比例控制,当设定值与实际水温值相差大于 20oC
时,控制电炉的输出功率为全功率,当两者相差小于 10oC 时采用比例控制,当两者相差小
于 5oC 时采用比例积分控制,直至实际水温与设定水温相同后间歇控制,程序进入等待控制
状态,如果水温降到设定值以下则又开始控制。
四、 主控程序
在控制算法中采用比例和比例积分相结合的方法,温度设定值与实际水温相小于 20oC
就开始介入比例控制,这样可以很好的抑制住水温上升的惯性,并在相差 10~5oC 时采用不
同参数的比例控制,最大限度的达到控制系统的快速性,小于 5oC 时采用比例积分控制,
使得水温逐渐向设定值稳定地逼近。
设计中采用位置式 PID 模型,将微分项置为 0 即可实现 PI 控制。参考 PID 算法如下:
// 积分
SumError += Error;
dError = LastError - PrevError;
PrevError = LastError;
LastError = Error;
Final_error = (Proportion*Error+ Integral*SumError+ Derivative*dError);
// 当前微分
主控算法程序结合按键程序如下:
#include
#include"delay.h"
#include"LCD_1602.h"
#include"ds18b20.h"
#define uchar unsigned char
#define uint unsigned int
sbit kaitong=P2^0;
int aa,set_value=500,cc,dd;
int SetPoint=900,PrevError=0,LastError=0,Error=0,dError=0;
long int SumError=0;
float Proportion=0.1,Integral=0.005,Derivative=0.0;
float Final_error;
/*==============PID 计算部分===================*/
void duty(int z)
{
cc=z;
5
}
void adjust(int set_p,int now_value)
{
Error = set_p - now_value;
if(Error>=200)
duty(20);
// 偏差
else if((Error<200)&&(Error>=100))
{
duty(Error/20+5);
}
else if((Error<100)&&(Error>=50))
{
duty(Error/30+3);
}
else if(Error<50)
{
// 积分
SumError += Error;
dError = LastError - PrevError;
PrevError = LastError;
LastError = Error;
Final_error = (Proportion*Error+ Integral*SumError+ Derivative*dError);
duty ((int)(Final_error+0.5));
// 当前微分
}
else
duty (0);
}
uchar keyscan()
{
uchar temp,num;
num=0;
P1=0xff;
temp=P1;
if(P1!=0xff)
{
delayl(5);
P1=0xff;
6
temp=P1;
if(temp!=0xff)
{
temp=P1&0xff;
switch(temp)
{
case 0xf7:num=4;break;
case 0xef:num=5;break;
case 0xfe:num=1;break;
case 0xfd:num=2;break;
case 0xfb:num=3;break;
case 0xdf:num=6;break;
default:num=0;break;
}
}
}
return num;
}
//====================单片机上电显示==================//
void main()
{
int i,set_p=0;
uchar num=0,temp,flag,temp_p=0;
LCD_init();
setPosition(1,3);
prints("Loading...");
delayl(2000);
write_com(0x01);
kaitong=1;
/**********************温度设定**********************/
setPosition(1,3);
prints("ST:00.0");
printc(0xDF);
printc('C');
7
temp=0XFF;
P1=0xff;
while(temp==0xff)
{
temp=P1;
}
flag=1;
while(flag)
{
flag=2;
while(flag==2)
{
num=keyscan();
if(num==1) temp_p++;
if(temp_p==10) temp_p=0;
setPosition(1,6);
delayl(100);
printc(temp_p+'0');
if(num==2) temp_p--;
if(temp_p==-1) temp_p=9;
setPosition(1,6);
delayl(100);
printc(temp_p+'0');
num=keyscan();
if(num==5)
{
flag=3;
set_p=100*temp_p;
}
}
temp_p=0;
while(flag==3)
{
num=keyscan();
if(num==1) temp_p++;
if(temp_p==10) temp_p=0;
8