基于PID的温度控制系统设计
摘要
温度是工业上最基本的参数,与人们的生活紧密相关,实时测量温度在工业生产中越来越受到重视,离不开温度测量所带来的好处,因此研究控制和测量温度具有及其重要的意义。
目录
摘 要
Abstract
1绪论
1.1课题的来源
1.2课题的意义
1.3课题研究的主要内容
2硬件设计
2.1单片机控制模块的设计
2.1.1 AT89C52单片机简介
2.1.2 单片机的引脚功能
2.1.3 单片机控制模块的电路设计
2.1.4 电源设计
2.2温度采集模块的设计
2.2.1 DS18B20芯片的简介
2.2.2 DS18B20的内部结构
2.2.3 DS18B20的供电方式
2.2.4 DS18B20的引脚功能
2.3温度控制模块的设计
2.4按键及显示模块的设计
2.4.1 LCD1602的参数和引脚功能
2.4.2 LCD1602的特点
2.4.3 按键电路的设计
2.5报警模块的设计
3软件设计
3.1主程序的设计
3.2DS18B20读温度程序的设计
3.3键盘扫描程序的设计
3.4报警处理程序的设计
3.5PID控制算法
4系统仿真
参考文献
致谢
附录
1
基于PID的温度控制系统设计
1绪论1.1课题的来源
1.2课题的意义
1.3课题研究的主要内容
2硬件设计
- 单片机控制模块;
- 温度采集模块;
- 温度控制模块;
- 按键及显示模块;
- 报警模块。
图2-1 硬件设计方框图
2.1单片机控制模块的设计
2.1.1 AT89C52单片机简介
- 可靠性高;
- 抗干扰能力强;
- 控制能力强;
- 性价比高;
- 低电压;
- 能扩展了多种串行口。
2.1.2 单片机的引脚功能
图2-2 AT89C52引脚图
- 电源引脚VCC和VSS
- 外接晶体引脚XTAL 2和XTAL 1
- 控制信号引脚RST、ALE、PSEN、EA
- 输入/输出端口P0、P1、P2和P3
表2-1 P3各口线与第2功能表
口线 |
替代的第2功能 |
P3.0 |
RXD(串行口输入) |
P3.1 |
TXD(串行口输出) |
P3.2 |
INT0(外部中断0输入) |
P3.3 |
INT1(外部中断1输入) |
P3.4 |
T0(定时器0的外部输入) |
P3.5 |
T1(定时器1的外部输入) |
P3.6 |
WR(片外数据存储器“写选通控制”输出) |
P3.7 |
RD(片外数据存储器“读选通控制”输出) |
2.1.3 单片机控制模块的电路设计
图2-3 单片机的最小系统图
2.1.4 电源设计
图2-4 5V直流电电源设计图
- 变压器:将220V交流电变成9V左右,由此可知变压器变比为220/9=25/1;
- 桥式整流电路:经过滤波整流后,电压有效值增大为10V。如图2-5所示为桥式整流电路电压波形图;
- 三端稳压器:一般用于直流电路的保护电路,起到降压、稳压的作用。
图2-5 桥式整流电路电压波形图
2.2温度采集模块的设计
2.2.1 DS18B20芯片的简介
2.2.2 DS18B20的内部结构
图2-6 DS18B20芯片的内部结构图
表2-2 DS18B20温度数字对应关系表
温度/℃
|
二进制表示
|
十六进制表示
|
+125
|
0000 0111 1101 0000
|
07D0H
|
+85
|
0000 0101 0101 0000
|
0550H
|
+25.0625
|
0000 0001 1001 0000
|
0191H
|
+10.125
|
0000 0000 1010 0001
|
00A2H
|
+0.5
|
0000 0000 0000 0010
|
0008H
|
0
|
0000 0000 0000 1000
|
0000H
|
-0.5
|
1111 1111 1111 0000
|
FFF8H
|
表2-3 DS18B20温度值格式表
高字节 |
15 |
14 |
13 |
12 |
11 |
10 |
9 |
8 |
S |
S |
S |
S |
S |
2 6 |
2 5 |
2 4 | |
1/0 |
1/0 |
1/0 |
1/0 |
1/0 |
64 |
32 |
16 | |
低字节 |
7 |
6 |
5 |
4 |
3 |
2 |
1 |
0 |
2 3 |
2 2 |
2 1 |
2 0 |
2_1 |
2_2 |
2_3 |
2_4 | |
8 |
4 |
2 |
1 |
0.5 |
0.25 |
0.125 |
0.0625 |
- 发复位DS18B20的负脉冲;
- 收DS18B20的回应脉冲;
- 发ROM命令(33H);
- 发储存和控制命令。
表2-4 DS18B20 存储器控制指令
指令 |
约定代码 |
复制 |
48H |
读数据 |
BEH |
读电源供电方式 |
B4H |
温度转换 |
44H |
读EERAM |
B8H |
写数据 |
4EH |
表2-5 DS18B20的ROM指令
指令 |
约定代码 |
读ROM |
33H |
匹配ROM |
55H |
跳过ROM |
CCH |
搜索ROM |
0F0H |
报警搜索 |
ECH |
- 初始化;
- 执行ROM命令,用于定位;
- 执行DS18B20的储存控制命令,用于转换和读数据;
- DS18B20的I/O信号有回应脉冲、复位脉冲、写0,读0,写1,读1等几种。
2.2.3 DS18B20的供电方式
图2-7 DS18B20外部电源供电方式图
2.2.4 DS18B20的引脚功能
- GND为地;
- I/O是数据输入/输出脚(单线接口,可作寄生供电);
- UDD为外接供电电源输入端(在寄生电源接线方式时接地)。
图2-8 DS18B20引脚图
- 采用单总线技术,与单片机通信只需要一根I/O线,在一根线上可以挂接多个DS18B20。
- 每只DS18B20具有一个独有的,不可修改的64位序列号,根据序列号访问相应的器件。
- 低压供电,电源范围从3.0~5.5V,可以本地供电,也可以直接从数据线窃取电源(寄生电源方式)。
- 测温范围为-55℃~+125℃,在-10℃~+85℃范围内误差为±0.5℃。
- 可编辑数据为9~12位,转换12位温度时间为750ms(最大)。
- 用户可自设定报警上下限温度。
- 报警搜索命令可识别和寻址超过程序限定温度(温度报警条件)的器件。
- DS18B20的分辨率由用户通过EEPROM设置为9~12位。
- DS18B20可将检测到温度值直接转化为数字量,并通过串行通信的方式与主控制器进行数据通信。
- 负电压特性,电源极性接反时,温度计不会因为发热而烧毁,只是不能正常工作。
2.3温度控制模块的设计
2.4按键及显示模块的设计
图2-11 LCD1602电路图
2.4.1 LCD1602的参数和引脚功能
表2-6 LCD1602引脚功能表
编号 | 符号 | 引脚说明 | 编号 | 符号 | 引脚说明 |
1 | VSS | 电源地 | 9 | D2 | 数据 |
2 | VDD | 电源正极 | 10 | D3 | 数据 |
3 | VL | 显示偏压 | 11 | D4 | 数据 |
4 | RS | 数据/命令选择 | 12 | D5 | 数据 |
5 | R/W | 读/写选择 | 13 | D6 | 数据 |
6 | E | 使能信号 | 14 | D7 | 数据 |
7 | D0 | 数据 | 15 | BLA | 正极背光源 |
8 | D1 | 数据 | 16 | BLK | 负极背光源 |
2.4.2 LCD1602的特点
2.4.3 按键电路的设计
图2-12 独立式按键电路图
2.5报警模块的设计
图2-13 蜂鸣器电路图
3软件设计
3.1主程序的设计
图3-1 主程序流程图
3.2DS18B20读温度程序的设计
- 读时序包括读0和读1的时序。
- 读时序是在拉低单总线之后,在15us之内释放单总线,让DS18B20把数据传送到单总线上。读时序的过程至少需要60us。
- 写时序包括写0和写1的时序。
- 写0和写1时序略有不同。当写0时序时,单总线至少要被拉低60us。保证DS18B20能够采到数据线上的“0”电平,在15us到45us之间;当写1时序时,拉低单总线,并在15us之内释放单总线。
图3-2 DS18B20读温度程序流程图
3.3键盘扫描程序的设计
图3-3 键盘扫描程序流程图
3.4报警处理程序的设计
图3-4 声光报警程序流程图
3.5PID控制算法
PID调节器是一种线性调节器,它将给定值r(t)与实际输出值c(t)的偏差的比例(P)、积分(I)、微分(D)的组合组成控制量,从而达到对控制对象的控制目的。控制偏差
表3-1 模拟PID控制规律的离散化
模拟形式 |
离散化形式 |
|
|
|
|
|
|
(3-4)
为积分系数。
为微分系数。
式中
称为比例项。
称为积分项。
称为微分项。
常用的控制方式:
1、P控制
2、PI控制
3、PD控制
4、PID控制
图3-5 模拟PID控制系统原理框图
- 比例环节:把调节器的输入偏差乘以一个系数,作为调节器的输出,比例环节的作用是放大误差的幅值。当仅有比例控制环节时系统输出存在稳态误差。
- 积分环节:调节器加入积分环节后达到消除稳态误差的目的。积分项随着时间的增加而增大,积分项对稳态误差的消除取决于时间的积分。PI调节器可以使系统在进入稳态后无稳态误差。
- 微分环节:调节器的输入、输出误差信号的微分成正比关系。微分环节能反应偏差信号的变化趋势,从而可以实现超前调节。 控制器中仅有比例环节是不行的,还需要增加微分项,因为它能预测误差变化的趋势。
- PID控制算法的两种类型
- 位置型控制
- 增量型控制
- 理论计算法――依赖被控对象准确的数学模型。
- 工程整定法――不依赖被控对象准确的数学模型,直接在控制系统中进行现场整定。
=
(3-7)
图3-6 增量式PID控制算法程序框图
4系统仿真
- 汇编语言
- C语言
- 对微控制器的指令系统不需要了解,只是有一个初步的了解单片机的存储结构。
- 具有规范的程序,通过不同的函数,是程序变得结构化。
- 寄存器分配,不同的内存地址和数据类型和其他细节可以由编译器管理。
- 大大缩短了编程和调试的时间,提高了编程的效率。
图4-1 Keil软件界面
图4-2 生成Hex文件图
图4-3 Proteus软件界面
图4-4 温度低于上限时仿真图
图4-5 温度低于上限时仿真图
结论
参考文献
致谢
本设计在***老师的严格要求和悉心指导下才完成,从课题选择、总体方案设计、硬件软件设计到系统仿真,无不凝聚着程老师的汗水和心血,导师无私的关怀和悉心的指导,令我受益匪浅。在此特向程老师表示深深的感谢和崇高的敬意。
附录
- #include <at89x51.h>
- #include <absacc.h>
- #include <ctype.h>
- #include <math.h>
- #include <stdio.h>
- #include <string.h>
- #include <DS18B20.h>
- #include "LCD1602.h" 液晶显示头文件
- #define uchar unsigned char
- #define uint unsigned int
- sbit Key1=P1^0;
- sbit Key2=P1^1;
- sbit Up =P1^2;
- sbit Down=P1^3;
- uchar t[2],*pt; //这是用来存放温度值的,测温程序通过这个数组与主函数通信
- uchar TempBuffer1[9]={0x2b,0x31,0x32,0x32,0x2e,0x30,0x30,0x43,'\0'};
- //显示实时的温度,上电时显示+125.00C
- uchar TempBuffer0[17]={0x54,0x48,0x3a,0x2b,0x31,0x32,0x35,0x20,
- 0x54,0x4c,0x3a,0x2b,0x31,0x32,0x34,0x43,'\0'};
- //显示温度上下限,上电时显示TH:+125 TL:+124C
- uchar code dotcode[4]={0,25,50,75};
- uchar set;//温度初始值
- uchar count,high_time=0; //调节占空比的参数
- uint rout;// PID输出
- /查表法*******
- 将表值分离出的十位和个位送到十分位和百分位********************/
- struct PID
- {
- uint SetPoint; // 设定目标 Desired Value
- uint Proportion; // 比例常数 Proportional Const
- uint Integral; // 积分常数 Integral Const
- uint Derivative; // 微分常数 Derivative Const
- signed int LastError; // 错误Error[-1]
- signed int PrevError; // 错误Error[-2]
- signed int SumError; // Sums of Errors
- };
- struct PID spid; // PID控制结构体
- void init_pid()
- //PID初始化
- {
- high_time=50;
- spid.Proportion = 23; // Set PID Coefficients
- spid.Integral = 2;
- spid.Derivative =6;
- spid.SetPoint = set; // Set PID Setpoint
- }
- unsigned int PIDCalc( struct PID *pp, unsigned int NextPoint )
- //PID算法
- {
- signed int dError,Error;
- Error = pp->SetPoint - NextPoint; // 偏差
- pp->SumError += Error; // 积分
- dError = pp->LastError - pp->PrevError; // 当前微分
- pp->PrevError = pp->LastError;
- pp->LastError = Error;
- return (pp->Proportion * Error+ pp->Integral * pp->SumError + pp->Derivative * dError);
- }
- void duty_cycle(uint t)
- // 占空比
- {
- uchar s;
- t=t/10;
- s=set;
- if(s>t)
- {
- if(s-t>2)
- high_time=100;
- else
- {
- rout = PIDCalc ( &spid,t ); // Perform PID Interation
- if(high_time<=100)
- high_time=(uchar)(rout/600);
- else
- high_time=100;
- }
- }
- else
- high_time=0;
- }
- void covert0( unsigned char TH, unsigned char TL) //将温度上下限转换为LCD显示的数据
- {
- if(TH>0x7F) //判断正负,如果为负温,将其转化为其绝对值
- {
- TempBuffer0[3]=0x2d; //0x2d为"-"的ASCII码
- TH=~TH;
- TH++;
- }
- else TempBuffer0[3]=0x2b; //0x2B为"+"的ASCII码
- if(TL>0x7f)
- {
- TempBuffer0[11]=0x2d; //0x2d为"-"的ASCII码
- TL=~TL+1;
- }
- else
- TempBuffer0[11]=0x2b; //0x2B为"+"的ASCII码
- TempBuffer0[4]=TH/100+0x30; //分离出TH的百十个位
- if( TempBuffer0[4]==0x30)
- TempBuffer0[4]=0xfe; //百位数消隐
- TempBuffer0[5]=(TH%100)/10+0x30; //分离出十位
- TempBuffer0[6]=(TH%100)%10+0x30; //分离出个位
- TempBuffer0[12]=TL/100+0x30; //分离出TL的百十个位
- if( TempBuffer0[12]==0x30)
- TempBuffer0[12]=0xfe; //百位数消隐
- TempBuffer0[13]=(TL%100)/10+0x30; //分离出十位
- TempBuffer0[14]=(TL%100)%10+0x30; //分离出个位
- }
- void covert1(void) //将温度转换为LCD显示的数据
- {
- unsigned char x=0x00,y=0x00;
- t[0]=*pt;
- pt++;
- t[1]=*pt;
- if(t[1]>0x07) //判断正负温度
- {
- TempBuffer1[0]=0x2d; //0x2d为"-"的ASCII码
- t[1]=~t[1]; /*下面几句把负数的补码*/
- t[0]=~t[0]; /* 换算成绝对值*********/
- x=t[0]+1; /***********************/
- t[0]=x; /***********************/
- if(x>255) /**********************/
- t[1]++; /*********************/
- }
- else
- TempBuffer1[0]=0x2b; //0xfe为变"+"的ASCII码
- t[1]<<=4; //将高字节左移4位
- t[1]=t[1]&0x70; //取出高字节的3个有效数字位
- x=t[0]; //将t[0]暂存到X,因为取小数部分还要用到它
- x>>=4; //右移4位
- x=x&0x0f; //和前面两句就是取出t[0]的高四位
- t[1]=t[1]|x; //将高低字节的有效值的整数部分拼成一个字节
- TempBuffer1[1]=t[1]/100+0x30; //+0x30 为变 0~9 ASCII码
- if( TempBuffer1[1]==0x30)
- TempBuffer1[1]=0xfe; //百位数消隐
- TempBuffer1[2]=(t[1]%100)/10+0x30; //分离出十位
- TempBuffer1[3]=(t[1]%100)%10+0x30; //分离出个位
- t[0]=t[0]&0x0c; //取有效的两位小数
- t[0]>>=2; //左移两位,以便查表
- x=t[0];
- y=dotcode[x]; //查表换算成实际的小数
- TempBuffer1[5]=y/10+0x30; //分离出十分位
- TempBuffer1[6]=y%10+0x30; //分离出百分位
- }
- void delay(unsigned int i)
- {
- while(i--);
- }
- void t0_int(void) interrupt 1 //PWM波输出
- {
- if(++count<=(high_time))
- Relay=0;
- else if(count<=100)
- Relay=1;
- else
- count=0;
- TH0=0X20;
- TL0=0X00;
- }
- main()
- {
- unsigned char TH=50,TL=10,temp=0; //下一步扩展时可能通过这两个变量,调节上下限
- //测温函数返回这个数组的头地址
- TMOD=0X01;
- TH0=0X20;
- TL0=0X00;
- EA=1;
- ET0=1;
- TR0=1;
- set=60;//目标温度
- Beep=0;Relay=0;
- init_pid();
- while(1)
- {
- if(Up==0)
- {
- while(!Up);
- TH++;
- }
- if(Down==0)
- {
- while(!Down);
- TL--;
- }
- pt=ReadTemperature(TH,TL,0x3f); //上限温度-22,下限-24,分辨率10位,也就是0.25C
- //读取温度,温度值存放在一个两个字节的数组
- if((t[1]>TH)|(t[1]<TL))
- {
- Beep=1;
- // Relay=1;
- }
- else
- {
- Beep=0;
- // Relay=0;
- }
- delay(10000);
- covert1();
- covert0(TH,TL);
- LCD_Initial(); //第一个参数列号,第二个为行号,为0表示第一行
- //为1表示第二行,第三个参数为显示数据的首地址
- LCD_Print(0,0,TempBuffer0);
- LCD_Print(0,1,TempBuffer1);
- }
- }