温度控制的PID算法的C语言程序
- 格式:docx
- 大小:204.81 KB
- 文档页数:18
(* init program *)PIDpara.enable = 1 ;使能端PIDpara.enter = 1 ;当enter为1时,检查参数并转换为内部显示。
;当enter为0时,忽略输入参数的改变并存储计算时间。
PIDpara.Y_max = 32767 ;PID输出最大值(0~~32767)PIDpara.Y_min = 0 ;PID输出最小值(0~~32767)PIDpara.dY_max = 10.0 ;输出最大容许变化量,操作变量斜坡最大值。
为0时ramp不起作用,不需计算时间PIDpara.Kp = 1.0 ;比例PIDpara.Tn = 10.0 ;积分(越小作用越大),为0时第I part和jolt-free切换不起作用且不需要任何计算时间。
= 1 ;微分PIDpara.Tf = 1 ;微分滤波时间。
若Tv不为0必须输入(初值为Tv/10),不应少于(1.4*任务的扫描时间).PIDpara.Kw = 1 ;比例项衰减系数。
Kw为1时设定值不变进行比例项计算,为小于1时,设定值乘Kw后进行比例项计算(此项不能为零)PIDpara.Kfbk = 1 ;抗积分饱和,终结阻尼值。
Kfbk为0时终结保护无效,不需要计算时间PIDpara.fbk_mode = LCPID_FBK_MODE_INTERN ;操作变量的反馈模式:内部模式(一般为内部模式)PIDpara.d_mode = LCPID_D_MODE_E ;微分模式:对偏差值进行微分计算(标准PID控制);X模式:对实际值进行微分计算(一般选次方式)PIDpara.calc_mode= LCPID_CALC_MODE_EXACT ;计算模式:精确(所有计算为双精度浮点型, 如无舍入错误和CPU计算次数过长)(一般选次方式)PIDpara FUB LCPIDpara() ;调用PID参数功能块循环程序中程序如下,此程序只对P、I、D三个参数由变量进行输值,变量可在pid程序运行中实时修改,如果大家还需要某些参数实时修改,方法相同:(* cyclic program *)PIDpara.enable = PIDpara.enablePIDpara FUB LCPIDpara() = D_Ctrl ;积分(越小作用越大),为0时第I part和jolt-free 切换不起作用且不需要任何计算时间。
模糊PID控制温控系统设计C语言程序代码介绍本文介绍了使用模糊PID控制方法来设计温控系统的C语言程序代码。
本温控系统使用传感器读取室内温度,然后根据读取的数值对应调整冷风机的风速和加热器的加热时间,从而控制室内温度达到一个设定值。
系统设计本温控系统采用模糊PID控制方法,具体实现流程如下:1.根据设定温度和当前室内温度计算出误差值2.使用模糊控制方法将误差值转化为温度调节量3.根据模糊控制输出的温度调节量计算出PID控制器的输出4.根据PID控制器的输出调节冷风机的风速和加热器的加热时间系统设计中需要使用的传感器,冷风机和加热器的具体型号及参数需要根据实际情况进行选择。
此处不做详细说明。
程序代码实现以下代码实现了上述系统设计,包括模糊控制和PID控制。
// 温控系统C语言程序代码#include<stdio.h>#include<stdlib.h>// 模糊控制double GetTemperatureByFuzzy(double error){double delta = 0.5; // 设定的温度调节步长double result = 0;if (error <= -5){result = 1;}else if (error > -5 && error < 0){result = (error + 5) / 5.0;}else if (error >= 0 && error < 5){result = (5 - error) / 5.0;}else{result = 0;}return result * delta;}// PID控制double GetTemperatureByPID(double error, double lastError, double integ ral){double Kp = 0.5; // 比例系数double Ki = 0.01; // 积分系数double Kd = 0.1; // 微分系数double deltaT = 0.1; // 采样时间double derivate = (error - lastError) / deltaT;double result = Kp * error + Ki * integral + Kd * derivate;return result;}// 主函数int main(){double setTemp = 25; // 设定温度double curTemp = 24; // 当前温度,需要从传感器读取double lastError = 0; // 上一次的误差值double integral = 0; // 积分项while (1){double error = setTemp - curTemp; // 计算当前误差值double fuzzyTemp = GetTemperatureByFuzzy(error); // 模糊控制integral += error; // 更新积分项double pidTemp = GetTemperatureByPID(error, lastError, integra l); // PID控制lastError = error; // 更新上一次误差值// 根据pidTemp和fuzzyTemp调节冷风机的风速和加热器的加热时间,省略// 读取传感器更新当前温度,省略// curTemp = GetCurTemp();// 采样时间,省略// sleep(1);}}本文介绍了使用模糊PID控制方法来设计温控系统的C语言程序代码。
本文档如对你有帮助,请帮忙下载支持!温度控制与PID 算法温度控制与PID 算法j 较为复杂,下面结合实际浅显易懂的阐述一下 PID 控制理论,将温度控制及PID 算法作一个简单的描述。
1.温度控制的框图asgstiB这是一个典型的闭环控制系统,用于控制加热温区的温度( PV )保持在恒定的温度 设定值(SV )。
系统通过温度采集单元反馈回来的实时温度信号( PV )获取偏差值(EV ),偏差值经过 PID 调节器运算输出,控制发热管的发热功率,以克服偏差,促使偏差趋近 于零。
例如,当某一时刻炉内过PCB 板较多,带走的热量较多时,即导致温区温度下降,这时,通过反馈的调节作用,将使温度迅速回升。
其调节过程如下:温度控制的功率输出采用脉宽调制的方法。
固态继电器电压U ouT 。
当SSR 的触发角触发时,电源电压U AN 通过SSR 的输出端加到发热管的两 端;当SSR 的触发角没有触发信号时,SSR 关断。
因此,发热管两端的平均电压为U d = (t/T )* U AN =K* U AN其中K= t/T ,为一个周期T 中,SSR 触发导通的比率,称为负载电压系数或是占空比, K的变化率在0- 1之间。
一般是周期 T 固定不便,调节t,当t 在0-T 的范围内变化时, 发热管的电压即在 0- U AN 之间变化,这种调节方法称为定频调宽法。
下面将要描述的 PID调节器的算式在这里的实质即是运算求出一个实时变化的,能够保证加热温区在外界干扰的情况下仍能保持温度在一个较小的范围内变化的合理的负载电压系数K 。
甌汕血Ikinl 曲汀 備錢(哉0.1/ 1A『'、、A____ 5^50 工 /it TTVI PID 调节鼬 固憲继电器勻岌恿習 X ?n -Tr-Zn 4f t 沮LEV)*冲端出易度 A 崭1出功率SSR 的输出端为脉宽可调的2.温度控制的两个阶段本文档如对你有帮助,请帮忙下载支持! 本文档如对你有帮助,请帮忙下载支持!温度控制系统是一个惯性较大的系统,也就是说,当给温区开始加热之后, 并不能立即观察得到温区温度的明显上升;同样的,当关闭加热之后, 温区的温度仍然有一定程度的上升。
温度控制与PID算法温度控制与PID算法j较为复杂,下面结合实际浅显易懂的阐述一下PID控制理论,将温度控制及PID算法作一个简单的描述。
1.温度控制的框图这是一个典型的闭环控制系统,用于控制加热温区的温度(PV)保持在恒定的温度设定值(SV)。
系统通过温度采集单元反馈回来的实时温度信号(PV)获取偏差值(EV),偏差值经过PID调节器运算输出,控制发热管的发热功率,以克服偏差,促使偏差趋近于零。
例如,当某一时刻炉内过PCB板较多,带走的热量较多时,即导致温区温度下降,这时,通过反馈的调节作用,将使温度迅速回升。
其调节过程如下:温度控制的功率输出采用脉宽调制的方法。
固态继电器SSR的输出端为脉宽可调的电压U OUT 。
当SSR的触发角触发时,电源电压U AN通过SSR的输出端加到发热管的两端;当SSR的触发角没有触发信号时,SSR关断。
因此,发热管两端的平均电压为U d=(t/T)* U AN=K* U AN其中K=t/T,为一个周期T中,SSR触发导通的比率,称为负载电压系数或是占空比,K 的变化率在0-1之间。
一般是周期T固定不便,调节t, 当t在0-T的范围内变化时,发热管的电压即在0-U AN之间变化,这种调节方法称为定频调宽法。
下面将要描述的PID 调节器的算式在这里的实质即是运算求出一个实时变化的,能够保证加热温区在外界干扰的情况下仍能保持温度在一个较小的范围内变化的合理的负载电压系数K。
2.温度控制的两个阶段温度控制系统是一个惯性较大的系统,也就是说,当给温区开始加热之后,并不能立即观察得到温区温度的明显上升;同样的,当关闭加热之后,温区的温度仍然有一定程度的上升。
另外,热电偶对温度的检测,与实际的温区温度相比较,也存在一定的滞后效应。
这给温度的控制带来了困难。
因此,如果在温度检测值(PV)到达设定值时才关断输出,可能因温度的滞后效应而长时间超出设定值,需要较长时间才能回到设定值;如果在温度检测值(PV)未到设定值时即关断输出,则可能因关断较早而导致温度难以达到设定值。
C语言编写PID温度控制器程序姓名:况武(07421236)班级:自二系别:通控系#include <stdio.h>#include<math.h>struct _pid {int pv; /*integer that contains the process value*/int sp; /*integer that contains the set point*/float integral;float pgain;float igain;float dgain;int deadband;int last_error;};struct _pid warm,*pid;int process_point, set_point,dead_band;float p_gain, i_gain, d_gain, integral_val,new_integ;;/*------------------------------------------------------------------------pid_initDESCRIPTION This function initializes the pointers in the _pid structureto the process variable and the setpoint. *pv and *sp areinteger pointers.------------------------------------------------------------------------*/void pid_init(struct _pid *warm, int process_point, int set_point){struct _pid *pid;pid = warm;pid->pv = process_point;pid->sp = set_point;}/*------------------------------------------------------------------------pid_tuneDESCRIPTION Sets the proportional gain (p_gain), integral gain (i_gain),derivitive gain (d_gain), and the dead band (dead_band) ofa pid control structure _pid.------------------------------------------------------------------------*/void pid_tune(struct _pid *pid, float p_gain, float i_gain, float d_gain, int dead_band){pid->pgain = p_gain;pid->igain = i_gain;pid->dgain = d_gain;pid->deadband = dead_band;pid->integral= integral_val;pid->last_error=0;}/*------------------------------------------------------------------------pid_setintegDESCRIPTION Set a new value for the integral term of the pid equation.This is useful for setting the initial output of thepid controller at start up.------------------------------------------------------------------------*/void pid_setinteg(struct _pid *pid,float new_integ){pid->integral = new_integ;pid->last_error = 0;}/*------------------------------------------------------------------------pid_bumplessDESCRIPTION Bumpless transfer algorithim. When suddenly changingsetpoints, or when restarting the PID equation after anextended pause, the derivative of the equation can causea bump in the controller output. This function will helpsmooth out that bump. The process value in *pv shouldbe the updated just before this function is used.温度PID控制的C语言程序?------------------------------------------------------------------------*/void pid_bumpless(struct _pid *pid){pid->last_error = (pid->sp)-(pid->pv);}/*------------------------------------------------------------------------pid_calcDESCRIPTION Performs PID calculations for the _pid structure *a. This function uses the positional form of the pid equation, and incorporates an integral windup prevention algorithim. Rectangular integration is used, so this function must be repeated on a consistent time basis for accurate control.RETURN V ALUE The new output value for the pid loop.USAGE #include "control.h"*/float pid_calc(struct _pid *pid){int err;float pterm, dterm, result, ferror;err = (pid->sp) - (pid->pv);if (abs(err) > pid->deadband){ferror = (float) err; /*do integer to float conversion only once*/pterm = pid->pgain * ferror;if (pterm > 100 || pterm < -100){pid->integral = 0.0;}else{pid->integral += pid->igain * ferror;if (pid->integral > 100.0){pid->integral = 100.0;}else if (pid->integral < 0.0) pid->integral = 0.0;}dterm = ((float)(err - pid->last_error)) * pid->dgain;result = pterm + pid->integral + dterm;}else result = pid->integral;pid->last_error = err;return (result);}void main(void){float display_value;int count=0;pid = &warm;// printf("Enter the values of Process point, Set point, P gain, I gain, D gain \n");// scanf("%d%d%f%f%f", &process_point, &set_point, &p_gain, &i_gain, &d_gain);process_point = 30;set_point = 40;p_gain = (float)(5.2);i_gain = (float)(0.77);d_gain = (float)(0.18);dead_band = 2;integral_val =(float)(0.01);printf("The values of Process point, Set point, P gain, I gain, D gain \n");printf(" %6d %6d %4f %4f %4f\n", process_point, set_point, p_gain, i_gain, d_gain);printf("Enter the values of Process point\n");while(count<=20){scanf("%d",&process_point);pid_init(&warm, process_point, set_point);pid_tune(&warm, p_gain,i_gain,d_gain,dead_band);pid_setinteg(&warm,0.0); //pid_setinteg(&warm,30.0);//Get input value for process pointpid_bumpless(&warm);// how to display outputdisplay_value = pid_calc(&warm);printf("%f\n", display_value);//printf("\n%f%f%f%f",warm.pv,warm.sp,warm.igain,warm.dgain); count++;}}。
pid算法温度控制c语言程序PID算法是一种常用的温度控制算法,广泛应用于各种温度控制系统中。
在C语言中,我们可以通过编写程序来实现PID算法的温度控制功能。
我们需要了解PID算法的基本原理。
PID算法是通过对系统的反馈信号进行不断调整,使得系统的输出达到期望值。
PID算法由三个部分组成:比例控制、积分控制和微分控制。
比例控制根据反馈信号与期望值的差异来调整输出;积分控制根据反馈信号与期望值的累积差异来调整输出;微分控制根据反馈信号的变化率来调整输出。
在C语言中,我们可以使用变量来表示系统的输入、输出和期望值。
以下是一个简单的示例代码:```c#include <stdio.h>// 定义PID参数float Kp = 1.0; // 比例系数float Ki = 0.5; // 积分系数float Kd = 0.2; // 微分系数// 定义系统变量float setpoint = 25.0; // 期望值float input = 0.0; // 输入值float output = 0.0; // 输出值// 定义误差变量float error = 0.0; // 当前误差float last_error = 0.0; // 上一次误差float integral = 0.0; // 累积误差// PID算法函数float pid_algorithm(float setpoint, float input) {// 计算误差error = setpoint - input;// 计算比例控制float proportional = Kp * error;// 计算积分控制integral += error;float integral_control = Ki * integral;// 计算微分控制float derivative = Kd * (error - last_error); // 计算输出output = proportional + integral_control + derivative;// 更新误差last_error = error;return output;}int main(){// 模拟温度传感器的输入input = 23.5;// 调用PID算法函数output = pid_algorithm(setpoint, input);// 打印输出结果printf("Output: %.2f\n", output);return 0;}```在上述代码中,我们首先定义了PID算法的参数和系统变量。
PID控制当今的自动控制技术都是基于反馈的概念。
反馈理论的要素包括三个部分:测量、比较和执行。
测量关心的变量,与期望值相比较,用这个误差纠正调节控制系统的响应。
这个理论和应用自动控制的关键是,做出正确的测量和比较后,如何才能更好地纠正系统。
比例控制(P):比例控制是最常用的控制手段之一,比方说我们控制一个加热器的恒温100度,当开始加热时,离目标温度相差比较远,这时我们通常会加大加热,使温度快速上升,当温度超过100度时,我们则关闭输出,通常我们会使用这样一个函数e(t) = SP –y(t);u(t) = e(t)*PSP——设定值、e(t)——误差值、y(t)——反馈值、u(t)——输出值、P——比例系数滞后性不是很大的控制对象使用比例控制方式就可以满足控制要求,但很多被控对象中因为有滞后性。
也就是如果设定温度是200度,当采用比例方式控制时,如果P选择比较大,则会出现当温度达到200度输出为0后,温度仍然会止不住的向上爬升,比方说升至230度,当温度超过200度太多后又开始回落,尽管这时输出开始出力加热,但温度仍然会向下跌落一定的温度才会止跌回升,比方说降至170度,最后整个系统会稳定在一定的范围内进行振荡。
如果这个振荡的幅度是允许的比方说家用电器的控制,那则可以选用比例控制.比例积分控制(PI):积分的存在是针对比例控制要不就是有差值要不就是振荡的这种特点提出的改进,它常与比例一块进行控制,也就是PI控制。
其公式有很多种,但大多差别不大,标准公式如下:u(t) = Kp*e(t) + Ki∑e(t) +u0u(t)——输出、Kp——比例放大系数、Ki——积分放大系数、e(t)——误差、u0——控制量基准值(基础偏差)大家可以看到积分项是一个历史误差的累积值,如果光用比例控制时,我们知道要不就是达不到设定值要不就是振荡,在使用了积分项后就可以解决达不到设定值的静态误差问题,比方说一个控制中使用了PI控制后,如果存在静态误差,输出始终达不到设定值,这时积分项的误差累积值会越来越大,这个累积值乘上Ki后会在输出的比重中越占越多,使输出u(t)越来越大,最终达到消除静态误差的目的。
温度控制的PID算法与C程序实现PID (Proportional-Integral-Derivative) 是一种经典的反馈控制算法,被广泛应用于温度控制中。
在温度控制中,PID算法可以根据实际温度与设定温度之间的差异来调整控制器的输出,以达到稳定的温度控制。
下面将介绍PID算法的原理及其在C程序中的实现。
PID算法是通过对三个控制参数的不同组合调整,来实现对控制系统的精确控制。
这三个参数分别是比例项(P),积分项(I)和微分项(D)。
比例项(P)是根据实际温度与设定温度的差异计算出来的,并且与这个差异成比例。
比例项主要用于对系统的快速响应进行调整。
如果比例项过大,可能会导致系统产生震荡,如果比例项过小,则可能导致控制系统响应迟缓。
积分项(I)用于校正持续的误差,通过对误差的积分来进行控制系统的调整。
积分项主要用于对系统的稳定性进行调整。
如果积分项过大,可能会导致系统产生超调和振荡,如果积分项过小,则可能导致系统无法快速地消除误差。
微分项(D)用于预测系统未来变化的趋势,并根据这个趋势来进行控制系统的调整。
微分项主要用于对系统的响应速度进行调整。
如果微分项过大,可能会导致系统产生过度的抖动,如果微分项过小,则可能导致系统响应迟缓。
PID算法的输出是三个控制参数的加权和,即 control = P * error + I * integral + D * derivative。
其中,error为实际温度与设定温度的差异,integral为误差的累积和,derivative为误差的变化率。
下面是一个使用PID算法实现温度控制的C程序的示例:```c#include <stdio.h>//PID参数float Kp = 0.5;float Ki = 0.2;float Kd = 0.1;//温度设定值float setpoint = 50.0;//初始化float errorSum = 0;float lastError = 0;//计算PID控制量float calculateOutput(float currentTemperature) float error = setpoint - currentTemperature; errorSum += error;//计算PID控制量float proportional = Kp * error;float integral = Ki * errorSum;float derivative = Kd * (error - lastError);float output = proportional + integral + derivative; lastError = error;return output;int mai//模拟当前温度float currentTemperature = 40.0;//模拟控制循环while (1)//获取温度传感器读数// float currentTemperature = readTemperature(;//计算PID控制量float controlOutput = calculateOutput(currentTemperature); //执行控制动作,例如根据控制量控制加热器或冷却器// executeControlAction(controlOutput);//模拟温度变化currentTemperature += 0.5;//输出当前温度和控制量printf("Current temperature: %.2f, Control output: %.2f\n", currentTemperature, controlOutput);}return 0;```上述C程序中,首先定义了PID参数Kp、Ki和Kd,以及温度设定值setpoint。
基于PID控制算法的电阻炉温度控制单片机C语言程序#include //函数申明、参数定义#include#include#include#define uchar unsigned char#define uint unsigned intsbit DQ=P2^7; //DS18B20的数据DQ脚sbit BEEP=P2^6; //蜂鸣器控制脚sbit PWM=P2^5; //继电器与单片机的连接sbit lcden=P2^0; //LCD1602的使能端sbit lcdrw=P2^1; //LCD1602的读/写sbit lcdrs=P2^2; //LCD1602的数据/指令uchar dis_buf,temp,key;float kp; // 比例常数uint set_temp; //设定温度uint now_temp; //当前温度float prev_prev_error=0,prev_error=0,error=0;//e(k-2),e(k-1),e(k)float dp; //p(k)-p(k-1)uchar high_pulse,low_pulse; //PWM波形占空比uchar low_time=0,high_time=0; //每个周期里低电平次数,高电平次数uchar code table3[]="0123456789";void delayms(int z); //延时void write_com(uchar com); //向LCD1602写指令void write_dat(uchar dat); //向LCD1602写数据void LCD_init(); //LCD1602初始化void LCD_disp_char(uchar x,uchar y,uchar dat);//在某个屏幕位置上显示一个字符,X (0-15),y(0-1)void LCD_disp_str(uchar x,uchar y,uchar *str); //LCD1602显示字符串函数void DS18B20_init(); //DS18B20初始化uchar tempreadbyte(); //按字节读uint tempread(); //读取温度void tempwritebyte(uchar dat); //按字节写uchar tempreadbit(); //按位写void temp_start(); //温度转化void DS18B20_wait(); //等待void displaylcd(uint now_temp,uint set_temp); //LCD1602显示void keyscan(); //按键扫描void keydown(); //判断按键是否按下uint key_input(); //按键输入void pid(float kp); //PID控制void InitTimer2(void); //T2定时器初始化void delayms(int z) //ms延时函数{int x,y;for(x=z;x>0;x--)for(y=110;y>0;y--);}void LCD_Init(void) //LCD1602初始化{write_com(0x38); //显示模式设置delayms(1);write_com(0x06); //显示光标移到设置delayms(5);write_com(0x01); //显示清屏delayms(1);write_com(0x0C); //显示开及光标设置delayms(5);}void write_com(uchar com) //向LCD1602写指令rs低,rw低{lcdrs=0;lcden=1;lcdrw=0;P0=com;delayms(1);lcden=0;delayms(1);}void write_dat(uchar dat) //向LCD1602写数据rs高,rw低{ lcdrs=1;lcden=1;lcdrw=0;P0=dat;delayms(1);lcden=0;delayms(1);}void displaylcd(uint now_temp,uint set_temp) //LCD1602显示{uint k=0;//第一行显示当前温度k=now_temp/1000;if(k!=0){LCD_disp_char(9,0,table3[k]); //百位k=now_temp%1000/100; //十位k=now_temp%100/10; //个位LCD_disp_char(11,0,table3[k]); LCD_disp_str(12,0,".");k=now_temp%10; //小数LCD_disp_char(13,0,table3[k]); LCD_disp_char(14,0,0xdf);LCD_disp_str(15,0,"C"); //显示℃delayms(5);}else{LCD_disp_char(9,0,' ');k=now_temp%1000/100; //十位LCD_disp_char(10,0,table3[k]);k=now_temp%100/10; //个位LCD_disp_char(11,0,table3[k]); LCD_disp_str(12,0,".");k=now_temp%10; //小数LCD_disp_char(13,0,table3[k]); LCD_disp_char(14,0,0xdf);LCD_disp_str(15,0,"C"); //显示℃delayms(5);}//第二行显示设定温度k=0;k=set_temp/100;if(k!=0){LCD_disp_char(9,1,table3[k]); //百位k=set_temp%100/10; //十位LCD_disp_char(10,1,table3[k]);k=set_temp%10; //个位LCD_disp_char(11,1,table3[k]);LCD_disp_char(12,1,0xdf);LCD_disp_str(13,1,"C"); //显示℃LCD_disp_char(14,1,' ');LCD_disp_char(15,1,' ');delayms(5);}else{LCD_disp_char(9,1,' ');k=set_temp%100/10; //十位k=set_temp%10; //个位LCD_disp_char(11,1,table3[k]);LCD_disp_char(12,1,0xdf);LCD_disp_str(13,1,"C"); //显示℃LCD_disp_char(14,1,' ');LCD_disp_char(15,1,' ');delayms(5);}}void LCD_disp_char(uchar x,uchar y,uchar dat) //显示字符{uchar address;if(y==0)address=0x80+x;elseaddress=0xc0+x;write_com(address);write_dat(dat);}void LCD_disp_str(uchar x,uchar y,uchar *str) //显示字符串{uchar address;if(y==0)address=0x80+x;elseaddress=0xc0+x;write_com(address);while(*str!='\0'){write_dat(*str);str++;}}void DS18B20_init() //DS18B20初始化{//对于11.0592MHz时钟, uint型的i, 作一个i++操作的时间大于8usuint i=0;DQ=0;i=100; //拉低约800us, 符合协议要求的480us以上while(i>0)i--;DQ=1; //产生一个上升沿, 进入等待应答状态while(i>0)i--;}void DS18B20_wait() //等待{uint i;while(DQ);while(~DQ); //检测到应答脉冲i=4;while(i>0)i--;}uchar tempreadbit() //读取一位{uint i=0;bit b;DQ=0;i++; //延时约8us, 符合协议要求至少保持1usDQ=1;i++;i++; //延时约16us, 符合协议要求的至少延时15us以上b=DQ; i=8;while(i>0)i--; //延时约64us, 符合读时隙不低于60us要求return b;}uchar tempreadbyte() //读取一个字节{uint i;uchar j, dat=0;for(i=0; i<8; i++){j = tempreadbit();//最先读出的是最低位数据dat = (j << 7) | (dat >> 1);}return dat;}void tempwritebyte(uchar dat) //写字节{uint i;uchar j;for(j=0; j<8; j++){b=dat&0x01;dat>>=1;//写"1", 将DQ拉低15us后, 在15us~60us内将DQ拉高, 即完成写1if(b){DQ=0;i++;i++; //拉低约16us, 符号要求15~60us内DQ=1;i=8;while(i>0)i--; //延时约64us, 符合写时隙不低于60us要求}else //写"0", 将DQ拉低60us~120us{DQ=0;i=8;while(i>0)i--; //拉低约64us, 符号要求DQ=1;i++;i++; //整个写0时隙过程已经超过60us, 这里就不用像写1那样, 再延时64us了}}}void temp_start() //开始温度转换{DS18B20_init(); //初始化DS18B20, 无论什么命令, 首先都要发起初始化DS18B20_wait(); //等待DS18B20应答delayms(1); //延时1ms, 因为DS18B20会拉低DQ 60~240us 作为应答信号tempwritebyte(0xCC); // 发Skip ROM命令tempwritebyte(0x44); // 发转换命令}uint tempread() //读温度{uint a,b;temp_start();DS18B20_init(); //初始化DS18B20DS18B20_wait(); //等待DS18B20应答delayms(1); //延时1ms, 因为DS18B20会拉低DQ 60~240us 作为应答信号tempwritebyte(0xCC); //发Skip ROM命令tempwritebyte(0xBE); //发read命令a=tempreadbyte(); //低8位b=tempreadbyte(); //高8位b=b<<8;now_temp=((a|b))*0.0625*10.0+0.5;return(now_temp);}void keyscan() //按键扫描{P1=0x0F; //低四位输入delayms(1);temp=P1; //读P1口temp=temp&0x0F;temp=~(temp|0xF0);if(temp==1)key=0;else if(temp==2)key=1;else if(temp==4)key=2;else if(temp==8)key=3;elsekey=0;P1=0xF0; //高四位输入delayms(1);temp=P1; //读P1口temp=temp&0xF0;temp=~((temp>>4)|0xF0); if(temp==1)key=key+0;else if(temp==2)key=key+4;else if(temp==4)key=key+8;else if(temp==8)key=key+12;elsekey=0;dis_buf=key; //键值入显示缓存dis_buf=dis_buf&0x0f;if(dis_buf>11) //转换为ASCII码dis_buf=0x30;else if(dis_buf<10)dis_buf=dis_buf+0x30;elsedis_buf=dis_buf+0x37;}void keydown() //判断按键是否按下{P1=0xF0;while(1){if(P1!=0xF0){keyscan();break;}}}void pid(float kp) //增量型PID算法归一化参数{error=now_temp*1.0-set_temp*10.0; // 偏差u(k) dp=kp*1.0*(2.45*error-3.5*prev_error+1.25*prev_prev_error);//p(k)-p(k-1)=kp*[2.45e(k)-3.5e(k-1)+1.25e(k-2)]prev_prev_error=prev_error;prev_error=error;if(dp<-20.0){high_pulse=1;low_pulse=4;}else if(dp<-15.0){high_pulse=2;low_pulse=3;}else{high_pulse=4;low_pulse=1;}}void InitTimer2() //T2定时器初始化{RCAP2H=(65536-50000)/256; //定时50ms初值RCAP2L=(65536-50000)%256;ET2=1;EA=1;TR2=1;}uint key_input() //按键输入{uint m=0,n=0;do{keydown(); //读取按键值}while(dis_buf<0x30||dis_buf>0x39);m=dis_buf-0x30;LCD_disp_char(0,1,dis_buf); //显示第一个输入delayms(500);do{keydown(); //读取按键值}while(dis_buf<0x30||dis_buf>0x39);n=dis_buf-0x30;LCD_disp_char(1,1,dis_buf); //显示第二个输入set_temp=m*10+n; //设定温度值delayms(500);return set_temp;}void main() //主函数{uint s=0,r=1;LCD_init();delayms(100);LCD_disp_str(0,0," INPUT SET TEMP "); //第一行显示INPUT SET TEMP delayms(500);while(r){key_input(); //输入设定温度keydown(); //确认键和取消键s=dis_buf;if(s==0x41) //A确认键,B取消键{r=0; //确认键按下标志位delayms(500);LCD_disp_str(0,0,"NOW TEMP:"); //显示NOW TEMP:delayms(10);LCD_disp_str(0,1,"SET TEMP:"); //显示SET TEMP:delayms(10);displaylcd(0,set_temp); //显示当前温度0和设定温度}else{write_com(0x01); //清屏delayms(1000);LCD_disp_str(0,0," INPUT SET TEMP "); //第一行显示INPUT SET TEMPr=1;}}BEEP=1; //蜂鸣器默认不响PWM=0; //继电器默认导通while(1){now_temp=tempread();displaylcd(now_temp,set_temp); //显示当前温度和设定温度if(now_temp>10*set_temp) //当前温度大于设定温度的时,给继电器持续的高电平,停止加热{TR2=0; //关闭定时器T2PWM=1; //继电器高电平关断BEEP=0; //蜂鸣器响}else if(now_temp>9*set_temp) //当前温度大于设定温度的90%时,进行PID 控制{BEEP=1;InitTimer2();pid(2.72); //调用增量型PID算法}else{BEEP=1;PWM=0;}}delayms(10);}void Timer2() interrupt 5 //T2定时器中断服务程序{TF2=0;PWM=0;switch(PWM==1){case 0:if(++low_time==low_pulse) //达到低电平脉宽设定值{PWM=1; //输出PWM高电平,继电器断开low_time=0;break;}case 1:if(++high_time==high_pulse) //达到高电平脉宽设定值{PWM=0; //输出PWM低电平,继电器导通high_time=0;break;} } }。
我的题目是:基于PID算法的温度控制系统89C51单片机,通过键盘输入预设值,与DS18B20测得的实际值做比较,然后驱动制冷或加热电路。
用keil C语言来实现PID的控制。
最佳答案7f0f2f1c2f89C89C89C1 L50℃3℃2006-02-172009-04-232009-04-232009-04-242009-04-242009-10-11超低温漂移高精度运算放大器0P07将温度一电压信号进行放大,便于A/D进行转换,以提高温度采集电路的可靠性。
模拟电路硬件部分见图2。
图2 ?温度电压转换电路电控制执行电路的设计??? 由输出来控制电炉,电炉可以近似建立为具有滞后性质的一阶惯性环节数学模型。
其传递函数形式为:??? 可控硅可以认为是线形环节实现对水温的控制。
单片机输出与电炉功率分别属于弱电与强电部分,需要进行隔离处理,这里采用光耦元件TLP521 在控制部分进行光电隔离,此外采用变压器隔离实现弱强电的电源隔离。
??? 单片机PWM 输出电平为0 时,光耦元件导通,从而使三极管形成有效偏置而导通,通过整流桥的电压经过集电极电阻以及射集反向偏压,有7V 左右的电压加在双向可控硅控制端,从而使可控硅导通,交流通路形成,电阻炉工作;反之单片机输出电平为0 时,光耦元件不能导通,三极管不能形成有效偏置而截止,可控硅控制端电压几乎为零,可控硅截止从而截断交流通路,电炉停止工作。
此外,还有越限报警,当温度低于下限时发光二极管亮;高上限时蜂鸣器叫。
控制执行部分的硬件电路如下:图3? 控制执行部分电路3 键盘及显示的设计??? 键盘采用软件查询和外部中断相结合的方法来,低电平有效。
图3 中按键AN1,AN2,AN3,AN4, AN5的功能定义如表1所示。
??? 按键AN3与相连,采用外部中断方式,并且优先级定为最高;按键AN5和AN4分别与和相连,采用软件查询的方式;AN1则为硬件复位键,与R、C构成复位电路。
??????????????????? 表1 按键功能??? 显示采用3位共阳LED静态显示方式,显示内容有温度值的十位、个位及小数点后一位,这样可以只用(RXD)口来输出显示数据,从而节省了单片机端口资源,在口和(TXD)的控制下通过74LS164来实现3位静态显示。
数字电路硬件部分见图:图4? 数字硬件电路示意图三?系统软件设计??? 系统的软件由三大模块组成:主程序模块、功能实现模块和运算控制模块。
1 主程序模块??? 在主程序中首先给定PID算法的参数值,然后通过循环显示当前温度,并且设定键盘外部中断为最高优先级,以便能实时响应键盘处理;软件设定定时器T0为5秒定时,在无键盘响应时每隔5秒响应一次,以用来采集经过A/D转换的温度信号;设定定时器T1为嵌套在T0之中的定时中断,初值由PID算法子程序提供。
在主程序中必须分配好每一部分子程序的起始地址,形式如下:?????????? ORG? 0000H?????????? AJMP? MAIN?????????? ORG? 0003H?????????? AJMP? INTO?????????? ORG? 000BH?????????? AJMP? TT0?????????? ORG? 001BH????????????? AJMP? TT1?主程序流程图见图5。
2 功能实现模块??? 以用来执行对可控硅及电炉的控制。
功能实现模块主要由A/D转换子程序、中断处理子程序、键盘处理子程序、显示子程序等部分组成。
T0中断子程序??? 该中断是单片机内部5s定时中断,优先级设为最低,但却是最重要的子程序。
在该中断响应中,单片机要完成A/D数据采集转换、数字滤波、判断是否越限、标度转换处理、继续显示当前温度、与设定值进行比较,调用PID算法子程序并输出控制信号等功能。
T1中断子程序???? T1定时中断嵌套在T 中断之中,优先级高于T 中断,其定时初值由PID算法子程序提供,T1中断响应的时间用于输出可控硅(电炉)的控制信号。
3? 运算控制模块??? 运算控制模块涉及标度转换、PID算法、以及该算法调用到的乘法子程序等。
标度转换子程序??? 该子程序作用是将温度信号(00H~FFH)转换为对应的温度值,以便送显示或与设定值在相同量纲下进行比较。
所用线形标度变换公式为:式中,Ax:实际测量的温度值;Nx:经过A/D转换的温度量;Am =90; Ao=40; Nm =FEH; No=01H;??? 单片机运算采用定点数运算,并且在高温区和低温区分别用程序作矫正处理,温度计测量值与LED显示见图7。
PID算法子程序??? 系统算法控制采用工业上常用的位置型PID数字控制,并且结合特定的系统加以算法的改进,形成了变速积分PID一积分分离PID控制相结合的自动识别的控制算法。
该方法不仅大大减小了超调量(见图9),而且有效地克服了积分饱和的影响,使控制精度大大提高。
PID控制算法的流程图如图8。
图7? 温度计测量值与报警方式图图8? PID控制算法流程图图9中,初始水温为26 C。
实现思想:Ui(k)为第k次采样温度值,Ur 为设定值。
e(k) ≥ε 使用PD算法;e(k) <ε使用变速积分PID算法。
图9 温度控制曲线图四? 源程序??? 本设计方案软件实现完全使用汇编程序语言。
具体源程序略。
五? 结果分析论述??? 本文针对电热锅炉温度控制系统模型,提出了一种基于单片机AT89S51的设计方案。
设计中运用PID 算法更新T1的定时常数,PWM输出控制可控硅的通断,从而实现对温度的连续控制。
设计结果由图7和图9可以看出:本设计的控制器工作稳定,控制精度高,改进的PID算法超调量大大降低;软件采用模块化结构,提高了通用性。
本设计的目的不仅仅是温度控制本身,主要提供了单片机外围电路及软件包括控制算法设计的思想,应该说,这种思想比控制系统本身更为重要[求助]如果用PID算法控制温度要怎么做?小弟的毕业设计是做个温度控制系统,可PID控制那块儿我是一点不会啊。
眼看时间就要到了,那位大哥,各路高手能不能给段C程序啊。
是以18B20为传感器TOP单片机教授初窥门径••••当前离线2#大中小发表于2009-5-23 19:13?参考下我收藏的#i nclude <>#i nclude<>struct _pid {int pv; /*integer that contains the processvalue*/int sp; /*integer that contains the setpoint*/float integral;float pgain;float igain;float dgain;int deadband;int last_error;};struct _pid warm,*pid;int process_point, set_point,dead_band;float p_gain, i_gain, d_gain,integral_val,new_integ;;/*------------------------------------------------------------------------pid_initDESCRIPTION This function initializes the pointers in the _pid structureto the process variable and the setpoint. *pvand *sp areinteger pointers.------------------------------------------------------------------------*/void pid_init(struct _pid *warm, intprocess_point, int set_point){struct _pid *pid;pid = warm;pid->pv = process_point;pid->sp = set_point;}/*------------------------------------------------------------------------pid_tuneDESCRIPTION Sets the proportional gain(p_gain), integral gain (i_gain),derivitive gain (d_gain), and the dead band(dead_band) ofa pid control structure _pid.------------------------------------------------------------------------*/void pid_tune(struct _pid *pid, float p_gain, float i_gain, float d_gain, intdead_band){pid->pgain = p_gain;pid->igain = i_gain;pid->dgain = d_gain;pid->deadband = dead_band;pid->integral= integral_val;pid->last_error=0;}/*------------------------------------------------------------------------pid_setintegDESCRIPTION Set a new value for the integral term of the pid equation.This is useful for setting the initial outputof thepid controller at start up.------------------------------------------------------------------------*/void pid_setinteg(struct _pid *pid,floatnew_integ){pid->integral = new_integ;pid->last_error = 0;}/*------------------------------------------------------------------------pid_bumplessDESCRIPTION Bumpless transfer algorithim.When suddenly changingsetpoints, or when restarting the PIDequation after anextended pause, the derivative of theequation can causea bump in the controller output. Thisfunction will helpsmooth out that bump. The process value in*pv shouldbe the updated just before this function isused.------------------------------------------------------------------------*/void pid_bumpless(struct _pid *pid){pid->last_error = (pid->sp)-(pid->pv);}/*------------------------------------------------------------------------pid_calcDESCRIPTION Performs PID calculations for the _pid structure *a. This function uses the positional form of the pid equation, andincorporates an integral windup prevention algorithim. Rectangular integration is used, so this function must be repeated on a consistent time basis for accurate control.RETURN VALUE The new output value for the pidloop.USAGE #i nclude ""*/float pid_calc(struct _pid *pid){int err;float pterm, dterm, result, ferror;err = (pid->sp) - (pid->pv);if (abs(err) > pid->deadband){ferror = (float) err; /*do integer to floatconversion only once*/pterm = pid->pgain * ferror;if (pterm > 100 || pterm < -100){pid->integral = ;}else{pid->integral += pid->igain * ferror;if (pid->integral >{pid->integral = ;}else if (pid->integral < pid->integral = ;}dterm = ((float)(err - pid->last_error)) *pid->dgain;result = pterm + pid->integral + dterm;}else result = pid->integral;pid->last_error = err;return (result);}void main(void){float display_value;int count=0;pid = &warm;// printf("Enter the values of Process point, Set point, P gain, I gain, D gain \n");// scanf("%d%d%f%f%f", &process_point, &set_point, &p_gain, &i_gain, &d_gain);process_point = 30;set_point = 40;p_gain = (float);i_gain = (float);d_gain = (float);dead_band = 2;integral_val =(float);printf("The values of Process point, Set point, P gain, I gain, D gain \n");printf(" %6d %6d %4f %4f %4f\n", process_point, set_point, p_gain, i_gain,d_gain);printf("Enter the values of Processpoint\n");while(count<=20){scanf("%d",&process_point);pid_init(&warm, process_point,set_point);pid_tune(&warm,p_gain,i_gain,d_gain,dead_band);pid_setinteg(&warm,;//pid_setinteg(&warm,;//Get input value for process pointpid_bumpless(&warm);// how to display outputdisplay_value = pid_calc(&warm);printf("%f\n", display_value);//printf("\n%f%f%f%f",,,,;count++;}}看贴必回帖TOP单片机高中生••3#大中小发表于2009-5-23 19:49?谢谢••当前离线TOP单片机教授••••当前离线4#大中小发表于2009-5-23 19:49?看看承接:单片机项目及毕业设计QQ? ?:? ? 3TEL :? ?TOP单片机高中生••••当前离线5#大中小发表于2009-6-16 18:26?谢谢,万分感谢。