找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 8646|回复: 8
收起左侧

基于单片机PID控制的自动电阻炉温度控制器设计

  [复制链接]
ID:458245 发表于 2018-12-29 18:49 | 显示全部楼层 |阅读模式
此电阻炉温度控制器主要是以单片机STC89C52为核心,通过S型热电偶采集热端温度并进行冷端温度补偿得到实际温度T,然后经放大电路和ADC0832模数转换,并进行线性化处理,之后经单片机STC89C52进行PID控制,并加入PID参数的调整,最后通过液晶显示器LCD1602实现温度值和PID输出值及参数值的显示。它用最简单的硬件单元和软件编程实现了温度采集、温度PID控制、温度显示、上下限报警、PID参数显示、PID参数修改等功能。
目 录
摘 要
目 录
第一章 前言
1.1热电偶
1.1.1热电偶及其工作原理
1.1.2 热电偶的冷端温度补偿
1.1.3 热电偶的分类
1.2 PID
1.2.1 PID简介
1.2.2 PID算法介绍
1.2.3 位置式PID算法
第二章 电阻炉温度控制器总体设计
2.1功能需求
2.2 硬件设计
2.3 软件设计
第三章 电阻炉温度控制器硬件设计
3.1 S型热电偶
3.1.1 S型热电偶及其分度表
3.1.2 S型热电偶线性化处理
3.2 单片机STC89C52及其外围接口电路
3.2.1 单片机STC89C52
3.2.2 单片机STC89C52外围接口电路
3.3 ADC0832
3.4 LCD1602显示器
第四章 软件设计
4.1电阻炉温度控制器主程序
4.2 ADC0832数据采集子程序
4.3热电偶线性化标度变换程序
4.4 PID控制程序
4.5 PID参数修改子程序
4.6 LCD显示子程序
第五章 总结
参考文献
附录 A
第一章 前言

在使用电阻炉温度控制器之前,我们有必要了解其制作工艺和一些关键器件的概况,以便我们能够自己处理它所出现的一些小问题或者为爱好者学习提供帮助。因此这一章我们就关于电阻炉温度控制器运用的基本知识作一介绍。

1.1热电偶1.1.1热电偶及其工作原理

热电偶是温度测量仪表中得关键性元件,因其具有结构简单,性质稳定,测温范围宽,测量精度高、动态性能好、使用方便以及容易维护等优点,现已经被用于各种行业。特别是由于其性质稳定,在高温环境的测量中,热电偶测温占有相当重要的地位。

热电偶的工作原理主要是利用了热电效应,所谓热电效应,就是指两种不同成份的导体(称为热电偶丝材或热电极)两端接合成回路,当两个接合点的温度不同时,在回路中就会产生电动势。直接测量介质的一端称为工作端,另一端称为冷端。

1.1.2 热电偶的冷端温度补偿

由热电偶的测温原理可知,热电势的大小不仅与热端温度有关,而且与冷端温度有关,只有当冷端温度恒定时,才能通过热电势的大小去判断热端温度的高低。

   冷端温度补偿方法有冰点法,恒温迁移法,计算修正法,电桥补偿法,软件补偿法。我们这里采用计算修正法:

   计算修正法基于中间温度定律,其计算公式如式1.1

             EAB(T,0)=EAB(T,T0)+EAB(T0,0)                (1.1)

1.1.3 热电偶的分类

按照工业标准化的要求,热电偶可以分为标准化热电偶和非标准化热电偶两种。

标准化热电偶指工艺成熟、能批量生产、性能稳定、应用广泛,且具有统一分度表并已列入国际和国家标准文件的热电偶。非标准化热电偶是指研究还不够成熟,虽然已有产品,也能够使用但是没有统一的分度表,需要个别标定,给我们的使用带来不便,因此我们日常不做使用和研究。

标准化热电偶包括铂铑10-铂热电偶(S型)、铂铑30-铂铑6热电偶(B型)、镍镉-镍硅热电偶(K型)、镍镉-铜镍热电偶(E型)、铜-铜镍热电偶(T型)。我们着重介绍K型和S型热电偶:

S型热电偶为贵重金属热电偶,其正极导体的化学成分为铂铑合金,其中,含铑10%,含铂90%。负极为纯铂。

S型热电偶具有准确度高、测温区宽、使用寿命长和稳定性好等优点。特别是其在高温下抗氧化性能好,因此我们的产品电阻炉温度控制器选用热电偶作为温度传感器。

K型热电偶为目前用量最大的廉价金属热电偶。其正极的化学成分为:Ni:Cr=90:10;负极的化学成分为:Ni:Si=97:3,测量温度为-200℃~1300℃。

1.2 PID1.2.1 PID简介

PID控制是工程应用中最广泛的控制规律,它的主要特点是其结构简单、稳定性好、工作可靠、调整方便。其各种参数的特征如下:

比例调节的作用是按比例反映系统的偏差,系统一旦出现了偏差,比例调节立即产生调节作用以减小偏差。比例作用大,可以加快调节,减小误差,但是过大的比例作用会使系统的稳定性下降,甚至造成系统不稳定。积分调节的作用是使系统消除稳态误差,因为一旦有误差,积分调节就起作用,直至无误差,积分调节的输出维持常量。微分调节的作用是反映系统偏差信号的变化率,具有预见性,能预见偏差变化的趋势,因此能产生超前的控制作用,使偏差还没有形成即被微分调节作用消除,因此微分作用可以改善系统的动态性能。

1.2.2 PID算法介绍

PID算法有位置式和增量式输出两种。增量式PID算法输出得到的结果是增量,也就是说,在上一次的控制量的基础上需要增加(负值意味着减少)的控制量。例如,在晶闸管电动机调速系统中,控制量的增量意味着晶闸管的触发相位在原有的基础上需要提前或滞后的量。位置式算法输出则表现为当前的触发相位应该在什么位置。又如在温度控制系统中,增量式算法表现为在上次通电时间比例的基础上,还需要增加或减少的通电时间比例;位置式算法输出则直接指明本周期内要通电多长时间

1.2.3 位置式PID算法

位置式PID算法可以直接指出需要通电多长时间,因此其受到广泛应用。其计算公式如式1.2下:

                  (1.2)

式中,为基本偏差,表示当前测量值与设定目标值之间的差值,结果可以是正或负。当设定目标作为被减数时,正数表示还没有达到设定值。负数表示已经超过了设定值。累计偏差,它是每次偏差值的代数和。是PID算法的3个控制参数,分别称为比例常数、积分常数和微分常数,对不同的控制对象选择不同的数值,需要经过现场整定才能获得较好的效果。

第二章 电阻炉温度控制器总体设计

此电阻炉温度控制器主要是以单片机STC89C52为核心,通过热电偶采集热端温度并进行冷端温度补偿得到实际温度T,然后经放大电路和ADC0832模数转换,并进行线性化处理,之后经单片机STC89C52进行PID控制,并加入PID参数的调整,最后通过液晶显示器LCD1602实现温度值和PID输出值及参数值的显示。它用最简单的硬件单元和软件编程实现了温度采集、温度PID控制、温度显示、上下限报警、PID参数显示、PID参数修改等功能。

2.1功能需求

电阻炉温度控制器实际上是以单片机为核心,根据设定温度值与采集温度值进行比较求出偏差然后PID运算对电阻炉温度进行控制。

此控制系统可实现以下功能:

温度采集:

温度控制:

温度显示:

上下限报警显示:

参数显示:

PID控制参数设定修改:

其单回路控制系统图2.1如下所示:


图2.1 单片机单回路控制系统

2.2 硬件设计

电阻炉温度控制器主要有单片机AT89C52、A/D转换器、按键、LCD显示、加热炉、传感器、SSR输出控制组成的控制系统。其组成框图如图2.2所示:


图2.2 硬件组成框图

2.3 软件设计

该电阻炉温度控制器采用模块

化的结构设计。其主程序流程图如

图2.3所示:

其软件部分的的设计由ADC0832

采样子程序、中断子程序、LCD初

始化子程序、PID控制子程序、PID

参数按键修改子程序。ADC0832采

集温度信号,信号经A/D转换后送

至单片机STC89C52进行PID处理,

用户可以根据自身条件对PID参数

进行调整,之后LCD显示器显示温

度值和PID处理值,从而控制电阻

炉温度。


图2.3 主程序流程图

第三章 电阻炉温度控制器硬件设计3.1 S型热电偶3.1.1 S型热电偶及其分度表

S型热电偶首先是标准化热电偶,偶丝直径规定为0.5mm,允许偏差-0.015mm,其正极(SP)的名义化学成分为铂铑合金,其中含铑为10%,含铂为90%,负极(SN)为纯铂,故俗称单铂铑热电偶。该热电偶长期最高使用温度为1300℃,短期最高使用温度为1600℃。而且S型热电偶在正常长期使用温度为800~1300℃左右时测量的精度最高,而在800℃以内的测温准确度不高,而长期使用温度在1300℃以上就很容易损坏热电偶。因此我们在对其分度表的计算时温度设定为0~1300℃,因为电阻炉正符合其要求,并为长期使用电器。

S型热电偶分度表如下表3.1所示:


表3.1 S型热电偶分度表


3.1.2 S型热电偶线性化处理

此电阻炉温度传感器中S型热电偶温度传感器采集0-1300℃的温度进行显示控制,根据S型热电偶分度表列出其对应的mv电压,由于所用单片机STC89C52能够控制的电压信号为0-5V,以及编程转换值,因此根据以上进行标度变换处理得表3.2所示:


表3.2 标度变换表

温度值(℃)
分度表值(mv)
A/D采样值(v)
转换值
0
0
0
0
300
2.323
0.883
45
600
5.237
1.99
101
900
8.448
3.211
164
1300
13.155
5
255
3.2 单片机STC89C52及其外围接口电路3.2.1 单片机STC89C52

STC89C52是一种低功耗、高性能CMOS8位微控制器,具有 8K 在系统可编程Flash 存储器。在单芯片上,拥有灵巧的8 位CPU 和在系统可编程Flash,使得STC89C52为众多嵌入式控制应用系统提供高灵活、超有效的解决方案

STC89C52的引脚分布如图3.1所示,各部分引脚功能如下

1. P0.0~P0.7引脚:作为I/O引脚使用时,P0口是漏极开路双向口,向口锁存器写入1时,I/O引脚将悬空,是高阻输入引脚;在读写外部存储器时P0口作低8位数据/地址总线。

2. P1.0—P1.7引脚:内部带有弱上拉的准双向I/O口,作输入引脚使用前,先向P1口锁存器写入1,使P1口引脚上拉至高电平;另外,P1.0与P1.1还有第二功能:T2(P1.0)—定时器T2的计数输入端或定时器T2的时钟输出端,T2EX(P1.1)—定时器T2的外部触发输入端。


图3.1 STC89C52引脚分布图

3. P2.0—P2.7引脚: 内部带有弱上拉的准双向I/O口,作输入引脚使用前,先向P2口锁存器写入1,使P2口引脚上拉至高电平;在读/写外部存储器时,P2口输出高8位地址信号A15—A8。

4. P3.0—P3.7引脚:内部带有弱上拉的准双向I/O口,作输入引脚使用前,先向P3口锁存器写入1,使P3口引脚上拉至高电平;另外,P3口还有第二功能:RXD(P3.0)——串行数据接收(输入)端;

TXD(P3.1)——串行数据发送(输出)端;

(P3.2)——外中断0输入端;

(P3.3)——外中断1输入端;

T0(P3.4)——定时/计数T0的外部输入端;

T1(P3.5)——定时/计数T1的外部输入端;

(P3.6)——外部数据存储器写选通信号,低电平有效;

(P3.7)——外部数据存储器读选通信号,低电平有效;

5. 引脚:外部程序存储器选择信号,低电平有效;在复位期间CPU检测并锁存引脚的电平状态,当读引脚为高电平时,从片内程序存储器取指令,只有当程序计数器PC超出片内程序存储器地址编码范围时,才转到外部程序存储器中取指令;当该引脚位低电平时,一律从外部程序存储器中取指令。

6. :外部程序存储器读选通信号,低电平有效。

7.ALE:低8位地址锁存信号,在访问外部程序存储器时,ALE下降沿锁存从P0口输出的低8位地址信息A7—A0,以便随后将P0口作为数据总线使用;

在正常情况下,ALE输出信号为1/6振荡频率,并可用作外部时钟或定时信号。

8. XTAL1:片内晶振电路反向放大器输入端,接CPU内部时钟电路;

  XTAL2:片内晶振电路反向放大器输出端;

9. RST:复位信号输入端,高电平有效;

10. VCC:电源引脚,VSS:电源地。

STC89C52系列单片机属于MCS—51型系列单片机,它们的存储器在组织结构上有4个物理上相互独立的空间:片内程序存储器和片外程序存储器,内部数据存储器和片外数据存储器。其中片外数据存储区共64KB,相应的地址空间为0000F—FFFFH;片内数据存储区共256B,其中80H—FFH为SFR(特殊功能寄存器区),20H—2FH为位寻址区,00H—1FH为R0—R7工作寄存器区,

30H—7FH为用户存储数据用的存储区,共80个字节;片内程序存储区有4KB,通过=1进行选通;片外程序存储区有64KB是通过=0进行选通。

3.2.2 单片机STC89C52外围接口电路

该电阻炉温度控制器中使用了STC89C52单片机,以及ADC0832A/D转换器、晶振电路、复位电路、按键、LCD1602液晶显示器。其连接原理图如图3.2:

3.3 ADC0832

该电阻炉温度控制器所用的A/D转换器是ADC0832, ADC0832 为8位分辨率A/D转换芯片,其最高分辨可达256级,可以适应一般的模拟量转换要求。其内部电源输入与参考电压的复用,使得芯片的模拟电压输入在0~5V之间。芯片转换时间仅为32μS,据有双数据输出可作为数据校验,以减少数据误差,转换速度快且稳定性能强。独立的芯片使能输入,使多器件挂接和处理器控制变的更加方便。通过DI 数据输入端,可以轻易的实现通道功能的选择。

                    图3.2 STC89C52外围接口电路图

其封装及引脚如图3.3所示,引脚介绍如下:

CS_ 片选使能,低电平芯片使能

CH0 模拟输入通道0,或作为IN+/-使用  

CH1 模拟输入通道1,或作为IN+/-使用   

GND 芯片参考0 电位(地)

DI 数据信号输入,选择通道控制

DO 数据信号输出,转换数据输出

图3.3  ADC0832引脚图

3.4 LCD1602显示器

LCD,又称液晶显示器(Liquid Crystal Display),为平面超薄的显示设备,它由一定数量的彩色或黑白像素组成,放置于光源或者反射面前方。LCD功耗很低,因此倍受工程师青睐,适用于使用电池的电子设备。它的主要原理是以电流刺激液晶分子产生点、线、面配合背部灯管构成画面。

LCD与单片机连接如图3.4所示


图3.4  LCD1602与单片机连接图


其引脚介绍如表3.3所示:


表3.3 LCD1602引脚介绍表

编号
符号
引脚说明
编号
符号
引脚说明
1
VSS
电源地
9
D2
双向数据线
2
VDD
5v电源正极
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
背光源负极

其主要技术参数如下:

显示容量:16*2个字符

芯片工作电压:4.5-5.5V

工作电流:2.0mA(5.0V)

模块最佳工作电压:5.0V

字符尺寸:2.95*4.35(W*H)mm


第四章 软件设计4.1电阻炉温度控制器主程序

电阻炉温度控制器主程序首先进行液晶初始化,然后判断1s标志是否执行;如果是,进行AD采样,执行AD处理子程序,ADC0832采集电压信号;之后判断是否有按键按下,执行按键处理子程序;若没有按键按下,计算PID值;随后对数据显示处理,显示PID值,结束。其主程序流程图如图4.1所示


图4.1 主程序流程图

4.2 ADC0832数据采集子程序

按照ADC0832的工作方式

,可以得到如图4.2所示的程序

流程图。

在将ADC0832的端口定义

好后,用CS=0选通ADC0832,

之后,将DI端置1,开始AD

转换,然后送入通道0或者1

的选择信息,在DO端先输出

D7-D0数据,再输出D0-D7数

据,然后比较两次输出的数据

值是否相等,若不相等,继续

采样,若相等,返回采样值。  


图4.2 ADC0832数据采集子程序

4.3热电偶线性化标度变换程序

性标度变换是热电偶采集温度与A/D转换器之间的桥梁,是关键性环节,流程图如图4.3所示

在程序中,DAT代表A/D线性标度变换值,首先DAT与转换值进行比较,判断其符合哪一个段内;MDAT表示显示温度值,当DAT判断其处于哪一个段内,这样根据线性标度变换公式,即可求出其采集的温度值;之后返回温度值MDAT,以备LCD显示器显示。


图4.3 线性标度变换子程序

4.4 PID控制程序

单片机对A/D采集的温度需要进行

与设定温度值进行比较,然后经过

PID控制,其PID控制流程图如图4.4所示

首先,定义偏差et= Indat-Tedat

(Indat表示测量值,Tedat表示设定

值),偏差之和sumet,连续两偏差之

差et_temp;然后判断20ms标志flag2

是否为1,若是,进行PID计算,算出

pout,若否,输出上次pout。此PID

为了显示方便,保证输出为正,因

此判定pout是否为负。


图4.4 PID控制程序

4.5 PID参数修改子程序

为了能够满足用户的需要,电阻炉温度控制器能偶调整不同的PID参数,以便控制温度。其PID参数修改子程序流程图如图4.5所示:

简单介绍这几个按键功能:

1键—功能键:选择修改kp、ki、kd

2键—加1键

3键—减1键

4键—确定键

图4.5 PID参数修改子程序

4.6 LCD显示子程序

根据设计要求,进行LCD显示

程序的编写,流程如图4.6所示。

液晶显示模块是一个慢显示器

件,所以在执行每条指令之前一定

要确认模块的忙标志为低电平,表

示不忙,否则此指令失效。设置显

示的字符模式,显示字符时要先输

入显示字符地址,也就是告诉模块

在哪里显示字符,最后将字符码写

入到指定位置。


图4.6 LCD显示程序



第五章 总结

这次智能仪器设计,我们在王老师的指导下,做了关于自制电阻炉温度控制器的设计。虽然,由于某些硬件的短缺,没能做成一个完整的电阻炉温度控制器,但是基本上做出了温度的采集、PID控制、显示等。在这次设计中,我们通过自己查阅资料,和同学老师交流辩论,加深了对热电偶、A/D转换器、PID控制、单片机中断等好多理论知识理解。同时,再做这个设计我们需要学会protel99

画原理图、visio画流程图、如鹏版Keil进行软件编程、STC_ISP_V4.7.9软件下载.这些东西对于我来说是第一次接触,但是通过这次设计的亲自完成,虽然不敢说已经全部掌握,但至少我能够自己在以后的运用的轻松操纵。

对于我们所做得这个电阻炉温度控制器的设计,首先,在硬件方面我们选的是STC89C52作为单片机对温度进行PID控制,ADC0832作为A/D转换器进行A/D采样,热电偶作为温度传感器,LCD显示器作为温度和其他参数显示。对于硬件的连接不成问题。其次,在软件方面,我们用到了ADC0832采集子程序、线性标注变换子程序、PID控制子程序、PID参数修改子程序、LCD显示子程序、以及最重要的主程序。这些程序经过我们的努力基本上实现了其各自的功能,也和主程序密切连接。最后,我们的设计基本上符合了老师规定的要求,但是在细节方面也许有许多的不足和漏洞,我们会不断的改进,也希望大家给我们指正,我们将会不断完善我们的作品。

总的来说,这次设计让我学习了不少东西。第一、理论学习是必须的,我们必须一直注重自己的理论学习,踏踏实实把理论知识学习好,才能顺利实践。第二、理论固然重要,但是没有实践的演练,理论永远只是一纸空文,学习理论的最终目的是为了实践,因此我们应该不断实践。第三、在这个网络发达的时代,我们应该学会运用网上的知识,目的就是学会学习,高效做事。


单片机源码:


  1. #include<reg52.h> //包含头文件,一般情况不需要改动,头文件包含特殊功能寄存器的定义
  2. #include "intrins.h"
  3. sbit RS = P1^0; //Pin4
  4. sbit RW = P1^1; //Pin5
  5. sbit EN = P1^2; //Pin6

  6. sbit key1 = P1^4; //Pin6
  7. sbit key2 = P1^5; //Pin6
  8. sbit key3 = P1^6; //Pin6
  9. sbit key4 = P1^7; //Pin6
  10. //ADC0832的引脚
  11. sbit ADCS =P2^0;  //ADC0832 chip seclect
  12. sbit ADDI =P3^7;  //ADC0832 k in
  13. sbit ADDO =P3^7;  //ADC0832 k out
  14. sbit ADCLK =P3^6;  //ADC0832 clock signal


  15. #define uchar  unsigned char
  16. #define uint  unsigned int

  17. #define date  P0
  18. #define RS_CLR RS=0
  19. #define RS_SET RS=1
  20. #define RW_CLR RW=0
  21. #define RW_SET RW=1
  22. #define EN_CLR EN=0
  23. #define EN_SET EN=1
  24. #define INIT_TEMP 800
  25. #define MIN_TEMP 100
  26. #define MAX_TEMP 900
  27. //#define MAX 1500
  28. uchar code Temp_Data[]={"0123456789"};
  29. uchar code Temp_Min[]={"Temp is most Min"};
  30. uchar code Temp_Max[]={"Temp is most Max"};
  31. uchar tem1[10]={0,45,101,164,255};
  32. uchar tem2[10]={0,300,600,900,1300};                                                                                                                                                                                                   
  33. uchar temp1[18]={"WD:     PID:    "},temp2[16]={"P=   I=   D=    "};
  34. uchar getdata; //获取ADC转换回来的值
  35. bit flag,flag2;
  36. uchar time_20ms,time_ms,time_1s,Bottem,data1,data2,kemp;
  37. char et,sumet,et_temp;
  38. int pout,OUT;
  39. char KP=5;KI=10;KD=15;
  40. int Init_PID( uchar Indat,uchar Tedat,char et_old);
  41. /************
  42. 读ADC0832函数
  43. ************/
  44. //采集并返回
  45. unsigned int Adc0832(unsigned char channel)     //AD转换,返回结果
  46. {
  47.     uchar i=0;
  48.     uchar j;
  49.     uint dat=0;
  50.     uchar ndat=0;

  51.     if(channel==0)channel=2;
  52.     if(channel==1)channel=3;
  53.     ADDI=1;
  54.     _nop_();
  55.     _nop_();
  56.     ADCS=0;//拉低CS端
  57.     _nop_();
  58.     _nop_();
  59.     ADCLK=1;//拉高CLK端
  60.     _nop_();
  61.     _nop_();
  62.     ADCLK=0;//拉低CLK端,形成下降沿1
  63.     _nop_();
  64.     _nop_();
  65.     ADCLK=1;//拉高CLK端
  66.     ADDI=channel&0x1;
  67.     _nop_();
  68.     _nop_();
  69.     ADCLK=0;//拉低CLK端,形成下降沿2
  70.     _nop_();
  71.     _nop_();
  72.     ADCLK=1;//拉高CLK端
  73.     ADDI=(channel>>1)&0x1;
  74.     _nop_();
  75.     _nop_();
  76.     ADCLK=0;//拉低CLK端,形成下降沿3
  77.     ADDI=1;//控制命令结束
  78.     _nop_();
  79.     _nop_();
  80.     dat=0;
  81.     for(i=0;i<8;i++)
  82.     {
  83.         dat|=ADDO;//收数据
  84.         ADCLK=1;
  85.         _nop_();
  86.         _nop_();
  87.         ADCLK=0;//形成一次时钟脉冲
  88.         _nop_();
  89.         _nop_();
  90.         dat<<=1;
  91.         if(i==7)dat|=ADDO;
  92.     }
  93.     for(i=0;i<8;i++)
  94.     {
  95.         j=0;
  96.         j=j|ADDO;//收数据
  97.         ADCLK=1;
  98.         _nop_();
  99.         _nop_();
  100.         ADCLK=0;//形成一次时钟脉冲
  101.         _nop_();
  102.         _nop_();
  103.         j=j<<7;
  104.         ndat=ndat|j;
  105.         if(i<7)ndat>>=1;
  106.     }
  107.     ADCS=1;//拉低CS端
  108.     ADCLK=0;//拉低CLK端
  109.     ADDO=1;//拉高数据端,回到初始状态
  110.     dat<<=8;
  111.     dat|=ndat;
  112.     return(dat);            //return ad k
  113. }
  114. /**中断**/
  115. void Init_Time()
  116. {
  117. TMOD=0X10;
  118. TH1=(65536-20000)/256;
  119. TL1=(65536-20000)%256;
  120. EA=1;
  121. ET1=1;
  122. TR1=1;
  123. }
  124. /******************************************************************/
  125. /*                    微秒延时函数                                */
  126. /******************************************************************/
  127. void delay_us(unsigned int n) //延时 如果需要高精度延时 请嵌入汇编
  128. {
  129. if (n == 0)
  130.   {
  131.   return ;
  132.   }
  133.   while (--n);
  134. }
  135. /******************************************************************/
  136. /*                    毫秒函数声明                                */
  137. /******************************************************************/
  138. void delay_ms(unsigned char i)
  139. {
  140. unsigned char a, b;
  141. for (a = 1; a < i; a++)
  142. {
  143.    for (b = 1; b; b++)
  144.    {   ;   }
  145.     }
  146. }
  147. /******************************************************************/
  148. /*                   写入命令函数                                 */
  149. /******************************************************************/
  150. void LCD_write_com(unsigned char com)
  151. {
  152. RS_CLR;
  153. RW_CLR;
  154. EN_SET;
  155. date = com;
  156. delay_us(5);
  157. EN_CLR;
  158. }
  159. /******************************************************************/
  160. /*                   写入数据函数                                 */
  161. /******************************************************************/
  162. void LCD_write_Data(unsigned char Data)
  163. {
  164. RS_SET;
  165. RW_CLR;
  166. EN_SET;
  167. date = Data;
  168. delay_us(5);
  169. EN_CLR;
  170. }                                                                                                                             
  171. /******************************************************************/
  172. /*                   写入字符串函数                               */
  173. /******************************************************************/
  174. void LCD_write_str(unsigned char x,unsigned char y,unsigned char *s)
  175. {   
  176. if (y == 0)
  177. {   
  178. LCD_write_com(0x80 + x);   
  179. }
  180. else
  181. {   
  182. LCD_write_com(0xC0 + x);   
  183. }      
  184. while (*s)
  185. {   
  186. LCD_write_Data( *s);   
  187. s ++;   
  188. }
  189. if(Bottem==1)
  190. {
  191.             
  192.               LCD_write_com(0x0f);            
  193.               LCD_write_com(0xC0);            
  194. }
  195. if(Bottem==2)
  196. {
  197.             
  198.               LCD_write_com(0x0f);            
  199.               LCD_write_com(0xC5);            
  200. }
  201. if(Bottem==3)
  202. {
  203.             
  204.               LCD_write_com(0x0f);            
  205.               LCD_write_com(0xCA);            
  206. }

  207. }
  208. /******************************************************************/
  209. /*                   初始化函数                                   */
  210. /******************************************************************/
  211. void LCD_init(void)
  212. {
  213.    LCD_write_com(0x38);    /*显示模式设置*/
  214.    delay_ms(5);
  215.    LCD_write_com(0x38);
  216.    delay_ms(5);
  217.    LCD_write_com(0x38);
  218.    delay_ms(5);
  219.    LCD_write_com(0x38);
  220.    LCD_write_com(0x08);    /*显示关闭*/
  221.    LCD_write_com(0x01);    /*显示清屏*/
  222.    LCD_write_com(0x06);    /*显示光标移动设置*/
  223.    delay_ms(5);
  224.    LCD_write_com(0x0C);    /*显示开及光标设置*/
  225.    }
  226. int  spdat(uchar DAT)
  227. {
  228.               uchar i;
  229.               int MDAT;
  230.               for(i=0;i<5;i++)
  231.               {
  232.                             if(DAT>tem1[i]&&DAT<tem1[i+1])
  233.                             {
  234.                                           MDAT=tem2[i]+((float)DAT/tem1[i])*tem2[i];                                         
  235.                             }
  236.               }
  237.               return MDAT;
  238. }
  239. void Make_Data(uchar WDAT)
  240. {
  241.               int WD,i,k,j,n;
  242.               //WD=((float)WDAT/255)*MAX;
  243.               WD=spdat(WDAT);
  244.               if(WD<=MIN_TEMP)
  245.               kemp=1;
  246.               if(WD>=MAX_TEMP)
  247.               kemp=2;
  248.               if(WD>MIN_TEMP&&WD<MAX_TEMP)
  249.               kemp=0;
  250.               OUT=Init_PID(INIT_TEMP,WD,et);
  251.               temp1[3]=Temp_Data[WD/1000];
  252.               i=WD%1000;
  253.               temp1[4]=Temp_Data[i/100];
  254.               k=i%100;
  255.               temp1[5]=Temp_Data[k/10];
  256.               temp1[6]=Temp_Data[k%10];
  257.                                                                                                                   

  258.               temp1[12]=Temp_Data[OUT/1000];            
  259.               j=OUT%1000;
  260.               temp1[13]=Temp_Data[j/100];
  261.               n=j%100;
  262.               temp1[14]=Temp_Data[n/10];
  263.               temp1[15]=Temp_Data[n%10];
  264.             
  265.               temp2[2]=Temp_Data[KP/10];
  266.               temp2[3]=Temp_Data[KP%10];

  267.               temp2[7]=Temp_Data[KI/10];
  268.               temp2[8]=Temp_Data[KI%10];

  269.               temp2[12]=Temp_Data[KD/10];
  270.               temp2[13]=Temp_Data[KD%10];

  271.                            
  272. }
  273.    /****PID****/
  274. int Init_PID( uchar Indat,uchar Tedat,char et_old)
  275. {
  276.               et= Indat-Tedat;
  277.               sumet+=et;
  278.               et_temp=et-et_old;
  279.               if(flag2)
  280.               {                           
  281.                             flag2=0;
  282.                             pout=KP*et+KI*sumet+KD*et_temp;
  283.                             if(pout<0)
  284.                             pout=0-pout;
  285.                             return pout;
  286.               }
  287.               else
  288.               {                           
  289.                             return pout;
  290.               }                                                      
  291. }
  292. void Make_Key()
  293. {
  294.               if(key1==0)
  295.               {
  296.                             Bottem++;
  297.                             if(Bottem>=4)
  298.                             Bottem=1;
  299.               }
  300.               if(Bottem==1)
  301.               {
  302.                             if(key2==0)
  303.                             {
  304.                                           KP++;
  305.                                           if(KP>=50)
  306.                                           KP=50;
  307.                             }
  308.                             if(key3==0)
  309.                             {
  310.                                           KP--;
  311.                                           if(KP<=0)
  312.                                           KP=0;
  313.                             }
  314.               }
  315.               if(Bottem==2)
  316.               {
  317.                             if(key2==0)
  318.                             {
  319.                                           KI++;
  320.                                           if(KI>=50)
  321.                                           KI=50;
  322.                             }
  323.                             if(key3==0)
  324.                             {
  325.                                           KI--;
  326.                                           if(KI<=0)
  327.                                           KI=0;
  328.                             }
  329.               }
  330.               if(Bottem==3)
  331.               {
  332.                             if(key2==0)
  333.                             {
  334.                                           KD++;
  335.                                           if(KD>=50)
  336.                                           KD=50;
  337.                             }
  338.                             if(key3==0)
  339.                             {
  340.                                           KD--;
  341.                                           if(KD<=0)
  342.                                           KD=0;
  343.                             }
  344.               }
  345.               if(key4==0)
  346.               {
  347.                             Bottem=0;            
  348.               }
  349. }
  350. /******************************************************************/
  351. /*                   主函数                                       */
  352. /******************************************************************/  

  353. void main(void)
  354. {
  355.               LCD_init();
  356.               Init_Time();
  357.               while (1)
  358.               {                                                                       
  359.                             //Init_PID();
  360.                             if(time_ms==10)
  361.                             {
  362.                                           time_ms=0;
  363.                                           Make_Key();
  364.                                           LCD_write_str(0,0,temp1);                                         
  365.                                           LCD_write_str(0,1,temp2);
  366.                                           if(kemp==1)
  367.                                           LCD_write_str(0,1,Temp_Min);
  368.                                           if(kemp==2)
  369.                                           LCD_write_str(0,1,Temp_Max);                                         
  370.                                           Make_Data(getdata);
  371.                             }
  372.                             if(flag)
  373.                             {
  374.                                              flag=0;                                         
  375.                                           getdata=Adc0832(0);
  376.                                           Make_Data(getdata);
  377.                             }
  378.                            
  379.                                          
  380.               }
  381. }

  382. void T1_time() interrupt 3
  383. {
  384.               time_20ms++;
  385.               time_ms++;
  386.               TH1=(65536-20000)/256;
  387.               TL1=(65536-20000)%256;
  388.               if(time_20ms==50)
  389.               {
  390.                             time_20ms=0;
  391.                             time_1s++;
  392.                             if(time_1s==2)
  393.                             {
  394.                                           time_1s=0;
  395.                                           flag2=1;
  396.                             }
  397.                             flag=1;

  398.               }

  399. }
复制代码

以上的Word格式文档51黑下载地址:

炉温.zip (370.11 KB, 下载次数: 333)

评分

参与人数 3黑币 +110 收起 理由
songhetai + 30 很给力!
zhangshanqiao + 30 真仔细。
admin + 50 共享资料的黑币奖励!

查看全部评分

回复

使用道具 举报

ID:553941 发表于 2020-12-11 14:03 | 显示全部楼层
只有一个word文档,没有仿真,文档中贴了源码,也不是完整的pid程序。想学习的省省黑币吧
回复

使用道具 举报

ID:508509 发表于 2019-4-19 17:18 | 显示全部楼层
不对吗,怎么坑了
回复

使用道具 举报

ID:626231 发表于 2019-10-18 15:48 | 显示全部楼层
支持一下
回复

使用道具 举报

ID:682979 发表于 2020-1-8 13:05 | 显示全部楼层

你好  在吗  里面东西全吗
回复

使用道具 举报

ID:226319 发表于 2020-5-10 12:47 | 显示全部楼层
支持一下,感谢分享
回复

使用道具 举报

ID:187802 发表于 2020-5-12 12:17 | 显示全部楼层

很棒的资料,下载学习,谢谢提供
回复

使用道具 举报

ID:462629 发表于 2021-12-28 09:55 | 显示全部楼层
能补全电路原理图,源码吗
回复

使用道具 举报

ID:1002058 发表于 2022-7-1 17:20 | 显示全部楼层
写出来,总是好的。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表