资源描述
专业课程设计电阻炉炉温控制系统
电阻炉炉温控制系统设计
1 课程设计要求
1.1 课题内容
应用计算机的实时监控和温度测量技术,采用单片机、温度检测电路、温度控制电路等,采用比例环反馈、数字PID闭环调节两种方式实现电阻炉炉温的实时监控。
1.2 要求及技术指标
用单片机及相应的组成部件组成电阻炉温的自动控制系统,要求测温范围0~100℃,使其控制系统控制的温度保温值的变化范围为30~60℃。
要求:
(1)完成电阻炉温度控制系统设计,包括硬件电路设计和软件程序设计;
(2)采用LED实时显示控温时的实际炉温和设定炉温,如将炉温加热并控制在60℃;当炉温工作至设定温度时,蜂鸣器每2秒报警一次,绿色LED灯常亮。当炉温超过设定温度5℃,过温保护电路动作,蜂鸣器常鸣,红色LED常亮。
(3)对其主电路和控制电路设计相应的保护电路,使其安全可靠地工作。
(4)具有防干烧功能。
(5)具有定时功能,设定一段时间自动加温,如1分钟。
1.3 元器件清单
元件名称
数量
电热杯
1个
SL-1型51单片机综合实验箱
1个
DS18B20温度传感器
1片
STC89C52单片机
1片
S8550三极管放大器
2片
USB下载线
1条
单线固态继电器
1个
二极管
1个
导线
若干
另有剪刀、镊子等工具
表1.1 元器件清单
2 电路设计
2.1 总体设计方案
基本方案:利用温度变送器及温度检测电路将电阻炉实际温度转换成对应的数字信号,送入单片机,进行数据处理后,通过显示器显示温度,并判断是否报警,同时将实际炉温与设定温度比较,根据相应的算法(如PID)计算出控制量,通过控制相应的加热电路实现对炉温的控制。
本系统采用STC89C52作为系统的主控芯片,负责加热炉的温度检测与控制。其主要任务是:
1、读取DS18B20的温度数据;
2、控制继电器通断,保证温度达到设定值并保温;
3、读取键盘设置的温度值;
4、在LED上显示设置的温度、当前温度以及恒温时间;
5、当温度到达警戒值的时候控制蜂鸣器报警。
图2.1 总体结构图
由于加热炉仅能通过通断电路控制,不具备良好的可控性,且加热所需的速度和精度要求并不高,这里无需使用PID算法这样的高速跟踪算法,只要使用二次线性化的方法控制,就可以很好地实现炉子的加热和恒温控制了。
3 硬件电路设计
3.1 SL-I型51单片机综合实验箱
3.1.1 单片机最小系统
STC89C52系列单片机是宏晶科技生产的单时钟/机器周期(1T)的单片机,是高速/低功耗/超强抗干扰的新一代8051单片机,指令代码完全兼容传统8051,但速度快8-12倍。内部集成MAX810专用复位电路,2路PWM,8路高速10位A/D转换(250K/S),针对电机控制,强干扰场合。
最小系统如图4.1所示:
图3.1 单片机最小系统
3.1.2 数码管显示模块
数码管的显示原理不论是共阴还是共阳,其基本原理是一样的,都是靠点亮内部的LED来发光。一位数码管的引脚是十个,显示一个8字需要7个小段,另外还有一个小数点。
图4.2 数码管内部原理图
实验时为了保证编程的方便,通常将数码管的数字所对应的八位数字记录在数组中,程序中直接使用查表的方法,可以提高程序的效率,也使程序的编写更加简单方便。
符号
编码
符号
编码
0
0xC0
8
0x80
1
0xF9
9
0x90
2
0xA4
A
0x88
3
0xB0
B
0xC7
4
0x99
C
0xC6
5
0x92
D
0xA1
6
0x82
E
0x86
7
0xF8
F
0x8E
我们实验箱中的LED数码管是四位数码管,因此为了控制方便,四个数码管的“段选端”是连在一起的,他们的GND或VCC端作为“位选端”来输入控制信号,这样单片机就可以通过程序来控制显示的字符。
下图是实验箱开发板中的数码管电路图:
STC89C52的Px1口作为段选(任意口)
Px2口作为位选(任意口)
图4.3 实验箱数码管电路
3.1.3 按键模块
弹性按键被按下时闭合,松手后自动断开。单片机检测按键的原理是:单片机的I/O口既可以作为输出也可作为输入使用,当检测按键时使用的是它的输入功能,把按键的一端接地,另一端与单片机的某一个I/O口相连,开始时先给I/O口赋一高电平,然后让单片机不断地检测该I/O口是否变成低电平,当按键闭合时,即相当于该I/O口通过按键与地相连,变成低电平,程序一旦检测到I/O口变为低电平则说明按键被按下,然后执行相应的指令。
图4.5 按键检测流程图
无论独立键盘还是矩阵键盘,单片机检测其是否被按下的依据都是一样的,也就是检测该键对应的I/O口是否为低电平。独立键盘有一端固定为低电平,单片机写程序检测时比较方便。而矩阵键盘两端都与单片机I/O口连接,因此在检测时需人为通过单片机I/O口送出低电平。检测时,先送一列为低电平,其余几列为高电平,然后立即轮流检测一次各行是否有低电平,若检测到某一行为低电平,就可以确定当前被按下的按键是哪一行哪一列的,用同样的方法轮流各列送一次低电平,再轮流检测一次各行是否变为低电平,这样即可检测完所有的按键。
图4.6 矩阵键盘按键电路图
3.1.4 4.1.4报警模块
报警模块的结构比较简单,只是一个蜂鸣器模块,当温度高于设定值较大时,单片机在I/O口上输入一个低电平,就可以使蜂鸣器报警。
图4.7报警电路
4.2温度采集电路
DS18B20温度传感器是将半导体温敏器件、A/D转换器、存储器等做在一个很小的集成电路芯片上。测温范围为-55℃~+125℃ ,测温精度为士0.5℃;温度转换精度9~12位可变,能够直接将温度转换值以16位二进制数码的方式串行输出;12位精度转换的最大时间为750ms;可以通过数据线供电,具有超低功耗工作方式。
图4.8
DS18B20温度传感器只有三根外引线:单线数据传输总线端口DQ ,外供电源线VDD,共用地线GND。DS18B20有两种供电方式:一种为数据线供电方式,此时VDD接地,它是通过内部电容在空闲时从数据线获取能量,来完成温度转换,相应的完成温度转换的时间较长。这种情况下,用单片机的一个I/O口来完成对DS18B20总线的上拉。另一种是外部供电方式(VDD接+5V),相应的完成温度测量的时间较短。
在本设计中采用外部供电方式实现DS18B20传感器与单片机的连接,其接口电路如图4所示。
4.3继电器电路设计
本系统采用单相固态继电器SSR/1P-10A,当单片机给继电器供5V电压时,继电器导通。可以通过这个原理将加热炉的电源线火线分别接入继电器两端,所以单片机的I/O口供给低电平,继电器就可以导通,这样就可以控制加热炉的加热了。
如图所示:
图4.14 继电器结构
由于考虑到单片机引脚的驱动能力可能不足,因此制作了驱动电路,放大驱动电流,并在继电器两端加上续流二极管保证加热时间够长。
电路如下:
图4.15 驱动电路
4 软件程序设计
/*
2014年1月6日
课程设计
内容: 温度控制系统
硬件: 5110 + DS18B20 + 键盘*/
#include <reg52.h>
#include <stdio.h>
#define uchar unsigned char
#define uint unsigned int
sbit ds = P2^5; /*温度传感器信号线*/
sbit beep = P2^7; /*蜂鸣器*/
sbit jdq = P2^6; /*继电器*/
sbit led_green = P2^4; /*绿灯*/
sbit led_red = P2^2; /*红灯*/
uint temp; /*读取的温度值*/
float f_temp;
uint warn_l = 300; /*低温30*/
uint warn_h1 = 600; /*高温60*/
uint warn_h2 = 650; /*高温65*/
uchar warn_flag = 0; /*超过60报警标志*/
uchar time = 0; /*time计数器*/
uchar time_1 = 0; /*time计数器1*/
uint time_2 = 0; /*time计数器2*/
uint time_3 = 0; /*time计数器3*/
uchar dis_page = 0; /*数码管页面*/
uchar key_num = 0; /*键盘值*/
uint working_time = 0; /*预设加热时间*/
uchar heating_flag = 0; /*开始加热标志*/
uchar key_input_temp; /*键盘输入TEMP值*/
uchar set_temp = 30; /*设置温度 初始化为30度*/
uchar keep_flag = 0; /*保持设置温度标志位*/
unsigned char code table[]=
{
0x3f, 0x06, 0x5b, 0x4f, 0x66, /* 不带点的编码 */
0x6d, 0x7d, 0x07, 0x7f, 0x6f,
0xbf, 0x86, 0xdb, 0xcf, 0xe6, /* 带小数点的编码 */
0xed, 0xfd, 0x87, 0xff, 0xef
};
/*****************DS18B20部分********************/
void delay(uint z) /*延时函数 */
{
uint x,y;
for(x=z;x>0;x--)
for(y=110;y>0;y--);
}
void dsreset(void) /* 18B20复位,初始化函数 */
{
uint i;
ds = 0;
i = 103;
while(i > 0) i --;
ds = 1;
i = 4;
while(i > 0) i --;
}
bit tempreadbit(void) /* 读1位函数 */
{
uint i;
bit dat;
ds = 0;
i ++; /* i++ 起延时作用 */
ds = 1;
i ++; i ++;
dat = ds;
i = 8;
while(i > 0) i --;
return (dat);
}
uchar tempread(void) /* 读1个字节 */
{
uchar i,j,dat;
dat=0;
for(i = 1;i <= 8;i ++)
{
j = tempreadbit();
dat=(j << 7) | (dat >> 1); /*读出的数据最低位在最前面,这样刚好一个字节在DAT里*/
}
return(dat);
}
void tempwritebyte(uchar dat)/*向18B20写一个字节数据*/
{
uint i;
uchar j;
bit testb;
for(j = 1;j <= 8;j ++)
{
testb = dat & 0x01;
dat = dat >> 1;
if(testb) //写 1
{
ds = 0;
i ++; i ++;
ds = 1;
i = 8;
while(i > 0) i --;
}
else
{
ds = 0; //写 0
i = 8;
while(i > 0) i --;
ds = 1;
i ++; i ++;
}
}
}
void tempchange(void) /*DS18B20 开始获取温度并转换*/
{
dsreset();
delay(1);
tempwritebyte(0xcc); // 写跳过读ROM指令
tempwritebyte(0x44); // 写温度转换指令
}
uint get_temp() /*读取寄存器中存储的温度数据*/
{
uchar a,b;
dsreset();
delay(1);
tempwritebyte(0xcc);
tempwritebyte(0xbe);
a = tempread(); //读低8位
b = tempread(); //读高8位
temp = b;
temp <<= 8; //两个字节组合为1个字
temp = temp | a;
f_temp = temp * 0.0625; //温度在寄存器中为12位 分辨率位0.0625°
temp = f_temp * 10 + 0.5; //乘以10表示小数点后面只取1位,加0.5是四舍五入
f_temp = f_temp + 0.05;
return temp; //temp是整型
}
/*******************显示部分*****I****************/
void display(uchar num, uchar dat) /*显示字符*/
{
uchar i;
P0 = ~table[dat]; //数码管段选
i = 0xff;
i = i & ( ~(0x01 << num));
P1 = i; //数码管位选
delay(1);
}
void display_heating() /*显示字符"H"*/
{
uchar i;
P0 = 0x89;
i = 0xff;
i = i & (~0x01);
P1 = i;
delay(1);
}
void dis_temp(uint t) /*显示实时温度*/
{
uchar i;
i = t / 100;
display(1, i);
i = t % 100 / 10;
display(2, i + 10);
i = t % 100 % 10;
display(3, i);
}
void dis_working(void) /*显示定时加热的时间*/
{
uchar i ;
i = working_time / 100;
display(1, i);
i = working_time % 100 / 10;
display(2, i);
i = working_time % 100 % 10;
display(3, i);
}
void dis_set_temp(void)
{
uchar i ;
i = set_temp / 100;
display(1, i);
i = set_temp % 100 / 10;
display(2, i);
i = set_temp % 100 % 10;
display(3, i);
}
void deal(uint t) /*温度处理函数*/
{
warn_h1=set_temp*10;//将当前设定的温度赋给报警温度
warn_h2=(set_temp+5)*10;
if(( t > warn_h1) && ( t < warn_h2 )) /*大于设置温度小于设置温度+5度*/
{
led_green = 0;
led_red = 1;
warn_flag = 1; /*报警标志 */
}
else if(t >= warn_h2) /*大于设置温度+5度 */
{
led_red = 0;
led_green = 1;
beep = 0;
warn_flag = 0; /*消除报警标志*/
}
else /*小于设置温度*/
{
led_green = 1;
led_red = 1;
beep = 1;
warn_flag = 0; /*消除报警标志*/
}
}
void init_com(void) /*定时器初始化*/
{
TMOD = 0x01;
TH0 = (65536 - 39000) / 256;
TL1 = (65536 - 39000) % 256;
EA = 1;
ET0 = 1;
TR0 = 1;
}
uchar test_keyinput(void) /*检测按键输入*/
{
uchar key_temp;
key_input_temp = ~P3 & 0xf0;
if(key_input_temp != 0x00)
{
delay(30);
if((key_input_temp) != 0x00)
{
switch(key_input_temp)
{
case 0x10 : key_temp = 1; break;
case 0x20 : key_temp = 2; break;
case 0x40 : key_temp = 3; break;
case 0x80 : key_temp = 4; break;
default:break;
}
return key_temp;
}
}
return 0;
}
void display_page(void) /*捕捉按键输入 定义显示的dis_page*/
{
key_num = test_keyinput();/*扫描键盘 独立键盘按下为低电平*/
switch(key_num)
{
case 0: break;
case 1: dis_page ++; //进入设置界面
if(dis_page > 2)
dis_page = 0; /*预留三个页面*/
if(heating_flag == 1) /*加热过程中按1号键停止加热*/
{
heating_flag =0;
}
keep_flag = 0; /*取消保持温度标志位*/
heating_flag = 0; /*取消加热温度标志位*/
break;
case 2: if(dis_page == 1) /*最大加热时间600s /////////////// 设置加热时间 可以不用设置*/
{
if(working_time < 600) working_time ++;
else working_time = 600;
}
else if(dis_page == 2)///////////////////////////////////设置加热温度
{
if(set_temp < 60) set_temp ++;
else set_temp = 60;
}
break;
case 3: if(dis_page == 1)
{
if(working_time > 1) working_time --;
else working_time = 1;
}
else if(dis_page == 2)
{
if(set_temp > 30) set_temp --;
else set_temp = 30;
}
break;
case 4: if(dis_page == 1) /*按4号键开始加热*/
{
heating_flag = 1;
}
else if(dis_page == 2)
{
keep_flag = 1; /*按4号键开始加热 显示当前温度*/
}
break;
default: break;
}
}
void main()
{
init_com();/*定时器初始化50ms中断*/
jdq = 1; /*关继电器*/
beep = 1; /*关蜂鸣器*/
while(1)
{
switch(dis_page) /*显示的页面*/
{
case 0:
tempchange(); /*转换温度*/
dis_temp(get_temp()); /*显示温度*/
break;
case 1:
dis_working(); /*显示设置时间*/
break;
case 2:
tempchange(); /*转化温度*/
if( keep_flag )
dis_temp(get_temp()); /*显示温度*/
else
dis_set_temp(); /*显示设置温度*/
display_heating(); /*显示“H”*/
break;
default: break;
}
}
}
void Timer0_ISR(void) interrupt 1 /*50ms中断服务程序*/
{
TH0 = (65536 - 39000) / 256;
TL0 = (65536 - 39000) % 256; /*重装初值*/
time ++;
time_1 ++;
if(time_1 > 5) /*250ms任务 每秒钟转换4次*/
{
time_1 = 0;
display_page();
deal(temp);
time_2 ++;
if(time_2 > 4) /*1S任务*/
{
deal(temp);
time_2 = 0;
time_3 ++;
if(heating_flag == 1 && working_time != 0) /*定时加热状态下 时间不为0继续加热*/
{
working_time --;
jdq = 0; /*继电器加热*/
if( working_time ==0)
{
jdq = 1; /*继电器停止*/
heating_flag = 0; /*继电器标志位归0 */
}
}
}
if(dis_page == 2) /*控温状态下*/
{
if(get_temp() < (set_temp* 10))
jdq = 0;
else /*超过set_temp断电*/
jdq =1;
}
}
if(warn_flag) /*报警2s*/
{
if((time_3 % 3) == 1)
beep = ~beep;
else
beep = 1;
}
}
展开阅读全文