基于51单片机的PID温控算法仿真

1、PID原理

PID(Proportional-Integral-Derivative)控制 是一种经典的闭环反馈控制算法,广泛应用于工业控制、机器人、自动化系统等领域。其核心是通过误差的比例、积分和微分三个环节的组合,调整系统输出,使被控量(如温度、速度、位置等)快速、稳定地达到目标值。

PID 控制器结构

PID 控制器的输出由三部分组成:

PID 调节实例

温度控制系统
  • 目标:将水温稳定在 50°C。

  • 调节过程

    1. 比例控制(P):增大 Kp​ 使水温快速接近目标,但可能出现超调。

    2. 加入积分(I):消除稳态误差(如恒定的 2°C 偏差)。

    3. 加入微分(D):抑制超调,平滑温度变化。

2、硬件结构

该硬件系统使用proteus软件进行搭建与仿真。如下图。

3、C语言程序部分

,本次编程使用模块化编程,项目树如下:

以下仅列举关键代码

a、PID.c

#define uchar unsigned char 
#define uint unsigned int
float uk ,uk1 ,duk ;//声明目前总偏差值变量、之后偏差值总变量、偏差值总变量
typedef struct PID_Para
{
    float Kp;//比例系数
    float Ki;//积分增益
    float Kd;//微分增益

    int Err;//误差
    int Err_Last;//上一次误差

    float Un;//输出
    float Yn;//当前温度
    float Rn;//期望值
    float SumOfErr;//误差求和项
    
    float KpVal;
    float KiVal;
    float KdVal;
    
}PID_Para;

PID_Para PIDRaise={2,40,5,0,0,0,0,0,0,0,0,0};

//PID算法函数//位置型
int PID_Calu(float SetPara,RealPara)
{
    int PID_Out;
    PIDRaise.Err = SetPara - RealPara;
    PIDRaise.SumOfErr += PIDRaise.Err;
    PIDRaise.KpVal = PIDRaise.Kp * PIDRaise.Err;
    //PIDRaise.KiVal = PIDRaise.Ki * PIDRaise.SumOfErr;
    PIDRaise.KdVal = PIDRaise.Kd * (PIDRaise.Err - PIDRaise.Err_Last);
    PID_Out = PIDRaise.KpVal + PIDRaise.KiVal + PIDRaise.KdVal;    
    if(PIDRaise.Err >-5 && PIDRaise.Err <5)//只在温差小于5度时才开启积分项,积分限幅
    {
        PID_Out += PIDRaise.KiVal;
    }
    else
    {
        PIDRaise.SumOfErr = 0;
    }    
    if(PID_Out >= 100)
    {
        PID_Out = 100;
    }
    else if(PID_Out <= 0)
    {
        PID_Out = 0;
    }    
    PIDRaise.Err_Last = PIDRaise.Err;
    return (int)PID_Out;
}

b、主函数

#include <REGX52.H>
#include "LCD1602.h"
#include "Key.h" 
#include "Delay.h"
#include "Timer0.h"
#include "ADC0808.h"
#include "PID.h"

sbit DAC = P3^4;
sbit LED = P3^0;
//实际温度换算//ADC值,实际最大,实际最小,,电压最大,电压最小,比例系数(分压比例11)
float GetRealTemp(unsigned char ADC,RealMax,RealMin,VolMax,VolMin,Kpara);
unsigned char Counter1,Counter2;    //计数值和比较值,用于输出PWM
unsigned char i;
unsigned char KeyNum;
unsigned char ADC_Data;
int Compare;
float RealTemp;
unsigned int SetTemp,UpLmtTemp,DownLmtTemp;
unsigned char IntPart,FloatPart;

void main()
{
    LCD_Init();
    Timer0_Init();
    SetTemp = 50;//预设温度为60°
    UpLmtTemp = 90;//温度上限设置为90°
    DownLmtTemp = 10;//温度下限设置为10°
    LCD_ShowString(1,1,"S:");
    LCD_ShowString(2,1,"A:");
    LCD_ShowNum(1,3,SetTemp*10,3);
    while(1)
    {
        KeyNum = Key();
        if(KeyNum)
        {
            LCD_ShowNum(2,1,KeyNum,1);    
            if(KeyNum == 1)
            {
                SetTemp += 10;            
            }    
            else if(KeyNum == 2)
            {
                SetTemp -= 10;
            }                    
            if(SetTemp>=100)    SetTemp = 100;    
            if(SetTemp<=0)     SetTemp = 0;
            LCD_ShowNum(1,3,SetTemp,2);
        }        
        ADC_Data = GetADC_Data();
        RealTemp = GetRealTemp(ADC_Data,255,0,10,0,10);    //计算实际温度
        LCD_ShowNum(2,3,(uchar)RealTemp*10,3);
        LCD_ShowNum(2,8,Compare,3);
    }
}

//实际温度换算//ADC值,实际最大,实际最小,,电压最大,电压最小,比例系数(分压比例11)
float GetRealTemp(unsigned char ADC,DigMax,DigMin,VolMax,VolMin,Kpara)
{
    float res = 0;
    res = (float)(ADC) / (DigMax-DigMin)*(VolMax-VolMin)*Kpara;
    return res;
}

/*定时器中断函数模板*///100us、、1ms
void Timer0_Routine() interrupt 1
{
    //若呼吸灯闪烁,看是否定时器时钟设置为12T
    TL0 = 0x66;        //设置定时初值
    TH0 = 0xFC;        //设置定时初值

    Counter1++;
    Counter2++;
    Counter1%=100;    //计数值变化范围限制在0~99,PWM周期10ms,100Hz
    if(Counter1<Compare)
    {
        DAC = 0;
    }
    else
    {
        DAC = 1;
    }
    if(Counter2>=50)//5ms进行一次PID
    {
        Compare = PID_Calu(SetTemp*10,RealTemp*10)/10;
        Counter2 = 0;        
        LED = ~LED;
    }
}

单片机通过PWM实现加热器的控制。

运行实际效果:

需要更好地效果需要进一步调节PID的各项参数。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值