温度PID控制
一、实验名称:51系列单片机闭环温度控制实验
——基于Protuse仿真实验平台实现 基本情况:
1. 学生姓名:
号: 2. 学
3. 班 级:
4. 实验项目组长:
5. 同组其他成员:
序号 姓 名 班 级 学 号 分工系数 1 2 6. 具体分工:
组长 电路设计仿真 整合实验报告
组员 相关
资料
新概念英语资料下载李居明饿命改运学pdf成本会计期末资料社会工作导论资料工程结算所需资料清单
收集
组员 程序编写
7. 本人在项目组的作用描述:
主要负责实验
方案
气瓶 现场处置方案 .pdf气瓶 现场处置方案 .doc见习基地管理方案.doc关于群访事件的化解方案建筑工地扬尘治理专项方案下载
的确定,电路设计仿真和实验报告的整理及完成
主要负责实验前相关资料的收集和试验中主要原理的收集
主要负责C语言程序编写,根据电路仿真图及实验要求,编写程序
1
二、实验内容(实验原理介绍):
1、实验原理
利用AT89C51单片机可以方使地实现对PID参数的选择与设定;也可以通过计算机与单片机的串行通讯,实现工业过程中的交互式PID控制。它是用温度传感器将检测到的实际炉温A/D转换,送入计算机中,与设定值进行比较,得出偏差。对此偏差按PID算法进行修正,求得对应的控制量控制可控硅驱动器,调节电炉的加热功率,从而实现对炉温的控制。因此采集的炉温数据精度至关重要。利用89C51单片机实现温度智能控制,能自动完成数据采集、处理、缓冲、转换、并进行PID实施控制和键盘终端处理及显示,包括各参数数值的修正。但在控制过程中应该注意,采样周期不能太短,否则使调节过于频繁,不但执行机构不能
也是不合适,因为干扰无反应,而且计算机的利用率大为降低。采样周期太长,
法及时消除,使调节品质下降。随着单片机在各行业控制系统中的普遍采用,其构成的实时控制系统日臻完善,使该温度控制系统的总体性能大大提高,功能更趋完善,并详细介绍了该系统的软、硬件实施手段及系统特点。同时可以通过键盘对PID的参数进行设定,把实时的速度反馈回来经过PID进行调节,并将调节后的转速通过显示界面液晶1602显示出来。
2、元件简介
2.1、TLC2543
TLC2543是是一种数模转换器芯片,是TI公司的12位串行模数转换器,使用开关电容逐次逼近技术完成A/D转换过程。由于是串行输入结构,能够节省51系列单片机I/O资源;且价格适中,分辨率较高,因此在仪器仪表中有较为广泛的应用。
TLC2543具有以下特点:
(1)12位分辩率A/D转换器;
(2)在工作温度范围内10μs转换时间;
(3)11个模拟输入通道;
2
(4)3路内置自测试方式;
(5)采样率为66kbps;
(6)线性误差?1LSBmax;
(7)有转换结束输出EOC;
(8)具有单、双极性输出;
(9)可编程的MSB或LSB前导;
(10)可编程输出数据长度。
2.2 AT89C51
AT89C51是一个低电压,高性能CMOS 8位单片机,片内含8k bytes的可反复擦写的Flash只读程序存储器和256 bytes的随机存取数据存储器(RAM),器件采用ATMEL公司的高密度、非易失性存储技术生产,兼容
标准
excel标准偏差excel标准偏差函数exl标准差函数国标检验抽样标准表免费下载红头文件格式标准下载
MCS-51指令系统,片内置通用8位中央处理器和Flash存储
单元
初级会计实务单元训练题天津单元检测卷六年级下册数学单元教学设计框架单元教学设计的基本步骤主题单元教学设计
,AT89C52单片机在电子行业中有着广泛的应用。
AT89C51为8 位通用微处理器,采用工业标准的C51内核,在内部功能及管脚排布上与通用的8xc52 相同,其主要用于会聚调整时的功能控制。功能包括对会聚主IC 内部寄存器、数据RAM及外部接口等功能部件的初始化,会聚调整控制,会聚测试图控制,红外遥控信号IR的接收解码及与主板CPU通信等。主要管脚有:XTAL1(19 脚)和XTAL2(18 脚)为振荡器输入输出端口,外接12MHz 晶振。RST/Vpd(9 脚)为复位输入端口,外接电阻电容组成的复位电路。VCC(40 脚)和VSS(20 脚)为供电端口,分别接+5V电源的正负端。P0~P3 为可编程通用I/O 脚,其功能用途由软件定义,在本设计中,P0 端口(32~39 脚)被定义为N1 功能控制端口,分别与N1的相应功能管脚相连接,13 脚定义为IR输入端,10 脚和11脚定义为I2C总线控制端口,分别连接N1的SDAS(18脚)和SCLS(19脚)端口,12 脚、27 脚及28 脚定义为握手信号功能端口,连接主板CPU 的相应功能端,用于当前制式的检测及会聚调整状态进入的控制功能。2.3、Proteus基本操作
(一)启动Proteus仿真软件:双击“isis”图标,出现isis操作页面。
3
(二)搭建单片机系统仿真电路:分“器件选取”、“器件放置”和“电路连接” 三大步来操作。
〖第一步器件选取〗:
isis操作页面的左侧中下部分是电路和器件操作的导航区域,器件选取前“Devices”栏目下为空,器件选取操作的目的是将从器件库中分拣出需要的器件,这些器件排列在“Devices”栏目下。
A:先选择“器件和仪器工具栏”的“放大器符号样”图标(该工具栏的第一个图标),再单击“P”键即弹出“Pick Devices”窗口。Pick Devices窗口左侧可以输入器件类型名称,或者选择器件类型,窗口中部即出现相应类型的器件,若鼠标选中器件,窗口右侧会出现该器件的引脚图和封装图。 B:在Pick Devices窗口中,先选中器件,后点击窗口右下脚的“确定”按钮,即将器件排列在“Devices”栏目下了。或者直接双击被选的器件,也能收到同样的操作结果。
C:对于电源、地、输入和输出端等特殊器件,不在“Pick Devices”窗口中选取而在“Pick Terminals”窗口中选取。只要选择“器件和仪器工具栏”的“输入输出符号样”图标(该工具栏的第八个图标),即变“Devices”栏目为“Terminals” 栏目,“Terminals” 栏目下已经将电源、地、输入和输出端等特殊器件列出了一部分,如还要增加时,单击“P”键即弹出“Pick Terminals”窗口供选取。
〖第二步器件放置〗:
isis操作页面的中右侧是搭建硬件电路系统原理图和显示系统运行状态的区域。器件放置前或选择“New Design”文件后,器件放置区域同导航区一样栏目内容为空,器件放置操作是把导航区的器件排列在放置区的适当位置,以便于搭建硬件电路系统原理图。
A:器件放置的基本操作:是将导航区的器件选中(左键),然后把鼠标移到放置区中适当位置,再点击左键,即放置了器件。若多次点击左键,则会放置多个相同的器件。
B:器件的移动、翻转和删除操作:在放置区中选中器件的方法是用右键点击一
4
次,被选中的器件变成红色,然后用鼠标选中红色的器件再按住左键移动鼠标即移动了器件位置,移动后器件仍然是红色,移动完成后将鼠标移开器件至空白处再点击右键,红色器件变回黑色。器件翻转的方法是右键选中器件使之变红,然后将鼠标移至导航区下方,点击红色的翻转图标,即可实现器件的翻转,完成后将鼠标移回放置区空白处再点击右键,红色器件变回黑色。器件删除的的方法是右键选中器件使之变红,再对变红的器件点击右键,即删除了相应的器件。 C:器件和图形的复制操作:在放置区中,按住鼠标右键适当移动鼠标即画出一个矩形方框,方框内部的器件和图形变成红色,这时再点击菜单下的复制图标和粘贴图标,即会复制出一个相同的方框图形,移动鼠标即可将复制的图形移到适当的位置,再点击左键定位,若定位之前点击右键即删除复制的图形。 D:器件属性的设置:在放置区中右键选中器件后器件变红,再点击左键即弹出“Edit Component”对话框,该对话框内容即器件的属性,其中的一些内容可以选择隐藏不被显示出来。
〖第三步电路连接〗:
搭建硬件电路系统原理图需要把器件的引脚连接起来,其操作比较简单。 A:电路连接操作方法:将鼠标移至一个引脚或一条连线上点击左键,再移动鼠标即拉出一条红色导线,导线要拐弯时,则点击左键再移动鼠标即拉出拐弯的导线,最后导线的另一端通常要接到另一个引脚或另一条连线上,再点击左键导线变回黑色完成连接。若只对导线两端要求正确连接,对导线路由不作要求,则鼠标只需对连接导线始端和末端的引脚进行点击左键,便自动完成布线。 B:电路连接快速操作方法:若需要连接的两个器件的引脚都按照一个方向的顺序、等距离地排列,那么只需对第一条导线进行人工布线,从第二条导线开始顺序双击连接导线始端的引脚即可完成对应的导线连接。
C:导线的删除操作:右键选中导线后导线变红,再对变红的导线点击右键即删除了导线。
D:导线属性的设置:右键选中导线后导线变红,再点击左键即弹出“Edit Wire Style”对话框,即可对导线的属性进行设置。
(三)创建和导入ASM源文件
5
进入菜单栏,选择“Source”下“Add/Remove Source files„”,即弹出“Add/Remove Source Code Files”对话框。再点击“New”按键,弹出“New Source Files”对话框,即可以创建(只在文件名栏目输入一个文件名,后缀为ASM)或导入ASM源文件。确定后,“Add/Remove Source Code Files”对话框中“Source Code Filename”栏目即有ASM源文件名及路径,然后在“Code Generation Tool”栏目中选择“ASEM51”,最后点击“OK”按键,即完成了创建和导入ASM源文件。此后“Source”下即可以看到相应的ASM源文件。
(四)编译ASM和导入HEX文件
编译ASM文件的前提是已导入ASM文件,启动编译的方法有两种: 方法一:进入菜单栏,选择“Source”下“Build All”,即弹出“BUILD LOG”提示框,提示编译ASM文件的结果。
方法二:直接点击器件放置和运行区下方的“运行”按键,若ASM文件内容有变化,即自动对其编译,若问
题
快递公司问题件快递公司问题件货款处理关于圆的周长面积重点题型关于解方程组的题及答案关于南海问题
即弹出“SOURCE CODE BUILD ERRORS”提示框,提示编译ASM文件的结果。
编译ASM文件成功后即生成HEX文件,单片机导入HEX文件的方法是,打开单片机器件属性对话框,在“Program Files”栏目里打开文件目录,选择装入HEX文件即可。单片机此后按照该HEX文件的代码运行程序。
【特别注意】单片机运行速度与晶振频率有关,目前PROTEUS的版本不支持晶振器属性里所设置的频率值,单片机晶振频率必须在单片机器件本身的属性里设置,即打开单片机器件属性对话框,在其“Clock Frequency” 栏目里输入频率值。
(五)软件调试菜单
进入菜单栏,选择“Debug”下“Start/Resart Debugging”,即进入调试状态,此后可以进行单步运行、全速运行、断点设置等功能。
【特别提示】:调试期间,即可看到电路系统的运行结果和状态细节。可在电路中进行电压、电流和波形测试,其测试操作基本方法是选择“器件和仪器工具栏”的测试工具或测试信号图标,将测试工具和测试信号放置到电路的相应位置,并与测试点连接起来(放置和连接方法同电路器件一样),然后再调试运行即可看
6
到测试结果。
3、模块简介
3.1、温度检测模块
采用铂电阻温度传感器,运用放大电路,把温度的变化转换成铂电阻的变化,该电压经放大进行模数(A/D)转换,放大电路选用单一运放构成差动放大器,放大倍数约200倍左右,运放内设补偿,可承受大的差动输入电压且输入阻抗较高,具体电路如图所示
图1 温度检测模块
3.2、数据采集模块
图2 数据采集
7
44,3.3、键盘控制PID参数的设定模块
图3 矩阵键盘
在键盘中按键数量较多时,为了减少I/O口的占用,通常将按键排列成矩阵形式,如图1所示。在矩阵式键盘中,每条水平线和垂直线在交叉处不直接连通,而是通过一个按键加以连接。这样,一个端口(如P1口)就可以构成4*4=16个按键,比之直接将端口线用于键盘多出了一倍,而且线数越多,区别越明显,比如再多加一条线就可以构成20键的键盘,而直接用端口线则只能多出一键(9键)。由此可见,在需要的键数比较多时,采用矩阵法来做键盘是合理的。
通过键盘可以设置一定量的PID参数,点击“P”“I”“D”,对其进行参数设置,设置完之后,点击“确定”,运行。
三、实验结果分析(含程序、数据记录及分析和实验总结等,可附页): 实验仿真图:
8
实验数据记录如表:
实验数据记录
实验次设定温
数据设定次数 PID MAX MIN
数 度
P I D
1 2 0.1 0 100 98
1 99
2 12 0.1 0 103 98
3 2 3.3 0 99 99
1 2 0.1 0 400 399
2 2 399 12 0.1 0 160 148
3 2 3.3 0 401 399 实验结果分析:
当PID值维持在较小的数值是,温度控制得比较稳定,当增大相对应的参数值到一定的范围内时,温度就会出现较大的波动。尤其是当I至增大时,温度的变化巨大,以至于不能正确反映温度的真实值。
9
编写程序:
#include "Type_Data.h"
#include "1602.h" #include "TLC2543.h" #include "Key.h" #include "PID.h" #include "stdio.h" INT32U Count_Num; INT32U Time_count; INT8U Flag_SC;
sbit we = P3^7;
void SystemInit(void) {
TMOD |= 0x21;
SCON |= 0x50;
TH0 = (65536 - 45073) / 256;
TL0 = (65536 - 45073) % 256;
TR0 = 1;
ET0 = 1;
TH1 = 0xfd;
TL1 = 0xfd;
TR1 = 1;
TI = 1;//利用printf 要置此为1
EA=1;
}
void main(void) {
SystemInit();
IncPIDInit();
Init_1602();
Init_Display();
while (1)
{
if (!Flag_SC)
PWMOUT();
else
PWM = 0;
}
10
}
void Interrupt_Time0(void) interrupt 1 {
TH0 = (65536 - 44083) / 256;
TL0 = (65536 - 44083) % 256;
Time_count++;
if (Time_count > 1)
{
Time_count = 0;
if (!Flag_Key)
{
Count_Num = Read_TLC2435(1)*0.245-0.308;
Diaplay_Num_1602(Line1_Address+13,Count_Num);
printf("%d C\n",(INT16U)(Count_Num));
sPID.SetPoint = Set_Speed();
Diaplay_Num_1602(Line1_Address+3,sPID.SetPoint);
if (Count_Num > sPID.SetPoint)
{
Flag_SC = 1;
}
else
{
Flag_SC = 0;
}
Speed = Count_Num;
PID_Adjust();
}
Key_Option();
}
}
/***********************
filename:1602.c
data:2013/3/26
/************************/
#include "1602.h"
INT8U code LcdBuf[]= { //自定义汉字 5X7;最大能存储64个字节
0x0c,0x12,0x12,0x0c,0x00,0x00,0x00,0x00, 0x0f,0x10,0x10,0x10,0x10,0x10,0x0f,0x00, };
11
/*********************************** 函数名称:Delay_1602(INT8U time) 函数功能:1602延迟
日期:2013/3/26
备注:无
/***********************************/ void Delay_1602(INT8U time)
{
while (time--);
}
/*********************************** 函数名称:Write_Order_1602(INT8U order) 函数功能:1602写命令
日期:2013/3/26
备注:无
/***********************************/ void Write_Order_1602(INT8U order) {
RS_1602 = L;
RW_1602 = L;
E_1602 = L;
Data_1602 = order;
//Write_Read(order);
E_1602 = H;
Delay_1602(10);
E_1602 = L;
}
/*********************************** 函数名称:Write_Order_1602(INT8U order) 函数功能:1602写数据
日期:2013/3/26
备注:无
/***********************************/ void Write_Data_1602(INT8U dat) {
RS_1602 = H;
RW_1602 = L;
E_1602 = L;
Data_1602 = dat;
//Write_Read(dat);
12
E_1602 = H;
Delay_1602(10);
E_1602 = L;
}
/*********************************** 函数名称:Set_xy_1602(INT8U x,INT8U y) 函数功能:1602设置坐标
日期:2013/3/26
备注:无
/***********************************/ void Set_xy_1602(INT8U x,INT8U y) {
INT8U address = 0;
if (y == 1)
address = 0x80 + x;//第一行
else
address = 0xc0 + x;//第二行
Write_Order_1602(address);//写入地址
}
/*********************************** 函数名称:Display_String_1602(INT8U x,INT8U y,INT8U *s)
函数功能:1602指定位置显示字符串
日期:2013/3/26
备注:无
/***********************************/ void Display_String_1602(INT8U x,INT8U y,INT8U *s)
{
Set_xy_1602(x,y);
while (*s)
{
Write_Data_1602(*s);
s++;
}
}
/*********************************** 函数名称:Write_Order_1602(INT8U order) 函数功能:1602初始化
日期:2013/3/26
备注:无
13
/***********************************/ void Init_1602(void)
{
Write_Order_1602(Set_Display_Mode);
Write_Order_1602(Close_Screen);
//Write_Order_1602(Open_Cursor_Flicker);
Write_Order_1602(Open_Ucursor); }
/*********************************** 函数名称:Diaplay_Num_1602(INT16U num) 函数功能:1602显示数
日期:2013/3/26
备注:无
/***********************************/ void Diaplay_Num_1602(INT8U line,INT32U num) {
Write_Order_1602(line);
Write_Data_1602(0x30 + num/100%10);
Write_Data_1602(0x30 + num/10%10);
Write_Data_1602(0x30 + num/1%10);
}
void Diaplay_Key_Num_1602(INT8U line,INT32U num)
{
Write_Order_1602(line);
Write_Data_1602(0x30 + num/10%10);
Write_Data_1602(0x30 + num/1%10);
}
void Write_CGRAM(INT8U *p)
{
INT8U i,j,kk;
INT8U tmp=0x40; //操作CGRAM的命令码
kk=0;
for(j=0;j<2;j++) //64 字节存储空间,可以生成 8 个自定义字符点阵 64X8
{
for(i=0;i<8;i++) // 8 个字节生成 1 个字符点阵
{
Write_Order_1602(tmp+i); //操作CGRAM的命令码+写入CGRAM地址.
Write_Data_1602(p[kk]); //写入数据
kk++;
14
}
tmp += 8;
}
}
void set_xy(INT8U x,INT8U y) {
switch (x)
{
case 0: y+=0x80; break;
case 1: y+=0xc0; break;
}
Write_Order_1602(y); }
void display_onechar(INT8U x,INT8U y,INT8U wdate)
{
set_xy(x,y);
Write_Data_1602(wdate); }
void Init_Display(void) {
Write_CGRAM(LcdBuf); //向CGRAM写入自定义的摄氏度符号
Display_String_1602(0,1,"SV:000 PV:000");
Display_String_1602(0,2,"P:02 I:0.1 D:00 ");
display_onechar(0,6,0); //显示自定义的摄氏度符号
display_onechar(0,7,1); //显示自定义的摄氏度符号
}
/*********************** filename:Key.c
data:2013/3/10
/************************/ #include "Key.h"
#include "PID.h"
BOOL Flag_Key = 0;
BOOL Flag_P,Flag_I,Flag_D; INT8U temp;
INT8U k = 0;
INT8U Num[3][2];
void Delay(INT8U count)
15
{
INT8U x,y;
for (x=count; x>0; x--)
for (y=110; y>0; y--); }
/***********************************
函数名称:Key_Num(void)
函数功能:返回键值
调用函数:无
输入值:Key_num
返回值:无
日期:2013/3/10
备注:无
/***********************************/
INT8U Key_Num(void)//返回键值
{
INT8U Buffer[] = {0xfe,0xfd,0xfb,0xf7};//行编码
INT8U i,j,temp;
INT8U Key_num;
Key_Port = 0x0f;//消抖
if (Key_Port != 0x0f)
{
Delay(10);
if (Key_Port != 0x0f)
{
for (i=0; i<4; i++)
{
Key_Port = Buffer[i];
Delay(200);
temp = 0x10;//中间变量
for (j=0; j<4; j++)//列扫描
{
if (!(temp&Key_Port))
Key_num = i*4+j+1;
temp<<=1;
}
}
}
return Key_num-1;
}
16
else
return 20;
}
void Key_Option(void)
{
INT8U KeySet = 20;
switch(Key_Num())
{
case 0 :KeySet = 21;break;//P
case 1 :KeySet = 0 ;break;
case 2 :KeySet = 1 ;break;
case 3 :KeySet = 2 ;break;
case 4 :KeySet = 22 ;break;//I
case 5 :KeySet = 3 ;break;
case 6 :KeySet = 4 ;break;
case 7 :KeySet = 5 ;break;
case 8 :KeySet = 23 ;break;//D
case 9 :KeySet = 6 ;break;
case 10 :KeySet = 7 ;break;
case 11 :KeySet = 8 ;break;
case 12 :KeySet = 24 ;break;//OK
case 13 :KeySet = 9 ;break;
case 14 :KeySet = 25 ;break;//.
case 15 :KeySet = 20 ;break;
case 20 :KeySet = 20 ;break;
}
//Diaplay_Num_1602(Line2_Address+13,KeySet);
if (KeySet == 21)
{
Flag_Key = 1;
Flag_P = 1;
Flag_I = 0;
Flag_D = 0;
Write_Order_1602(Open_Cursor_Flicker);
Write_Order_1602(Line2_Address);
}
17
if (Flag_P)
{
if (KeySet >= 0 && KeySet<=9)
{
temp = KeySet;
Num[0][k] = KeySet;
k++;
if (k==2)
k=0;
Diaplay_Key_Num_1602(Line2_Address+2,Num[0][0]*10+Num[0][1]);
Write_Order_1602(Line2_Address);
}
P_DATA = Num[0][0]*10+Num[0][1];
}
if (KeySet == 22)
{
Flag_Key = 1;
Flag_P = 0;
Flag_I = 1;
Flag_D = 0;
Write_Order_1602(Open_Cursor_Flicker);
Write_Order_1602(Line2_Address+5);
}
if (Flag_I)
{
if (KeySet >= 0 && KeySet<=9)
{
temp = KeySet;
Num[1][k] = KeySet;
k++;
if (k==2)
k=0;
Write_Order_1602(Line2_Address+7);
Write_Data_1602(0x30 + Num[1][0]);
Write_Order_1602(Line2_Address+9);
Write_Data_1602(0x30 + Num[1][1]);
Write_Order_1602(Line2_Address+5);
}
I_DATA = Num[1][0] + 0.1*Num[1][1];
18
}
if (KeySet == 23)
{
Flag_Key = 1;
Flag_P = 0;
Flag_I = 0;
Flag_D = 1;
Write_Order_1602(Open_Cursor_Flicker);
Write_Order_1602(Line2_Address+11);
}
if (Flag_D)
{
if (KeySet >= 0 && KeySet<=9)
{
temp = KeySet;
Num[2][k] = KeySet;
k++;
if (k==2)
k=0;
Diaplay_Key_Num_1602(Line2_Address+13,Num[2][0]*10+Num[2][1]);
Write_Order_1602(Line2_Address+11);
}
D_DATA = Num[2][0]*10+Num[2][1];
}
if (KeySet == 24)
{
Flag_Key = 0;
Flag_P = 0;
Flag_I = 0;
Flag_D = 0;
sPID.Proportion =P_DATA; //比例常数Proportional Const
sPID.Integral =I_DATA; //积分常数Integral Const
sPID.Derivative =D_DATA; //微分常数Derivative Const
Write_Order_1602(Open_Ucursor);
}
}
/***********************
filename:1602.c
data:2013/3/26
19
/************************/ #include "TLC2543.h"
void mdelay(INT8U n) {
while (n--);
}
/**************************************
名称:read2543
功能:TLC2543驱动模块
输入参数:port通道号
输出参数:ad转换值
*************************************/
INT16U Read_TLC2435(INT8U port)
{
INT16U ad=0,i;
CLOCK=0;
_CS=0;
port<<=4;//通道号左移4位
for(i=0;i<12;i++)//没有设置控制字,默认输出数据为12位,高位先送出,输出数据
的格式为2进制
{
后的值高位先送出 if(D_OUT) ad|=0x01;//转换
D_IN=(bit)(port&0x80);//通道值高位先送出
CLOCK=1;
mdelay(3);
CLOCK=0;
mdelay(3);
port<<=1;
ad<<=1;
}
_CS=1;
ad>>=1;//循环中多左移了一位
return ad;
}
INT16U Set_Speed(void) {
return (INT16U)(1000 * (Read_TLC2435(0)/4096.0));
}
20