pid调节过程出现数据跳变

2019-07-20 03:30发布

本帖最后由 fktry 于 2019-2-25 21:32 编辑

在做一个恒温控制系统,使用灯泡加热温度,DS18B20采集实时温度。

下面这张图片是在出现超调之后,温度自然下降的过程当中,出现的一个问题。像是程序出现的bug。

PID参数参数值 PID参数参数值
从左到右第一个数值是PID的最终输出,P代表P值,依次类推。

这是主函数:
#include "sys.h"
#include "delay.h"
#include "usart.h"
#include "led.h"
#include "lcd.h"
#include "ds18b20.h"
#include "pid.h"
#include "timer.h"
#include "key.h"
#include "exti.h"

u8 SetValue=30;
PID pid;

int main(void)
{
        u8 t=0,key;
        short temperature;
  float temperature1;  
        NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置系统中断优先级分组2
        delay_init(168);  //初始化延时函数
        uart_init(115200);                //初始化串口波特率为115200
  TIM3_Int_Init(100,8400-1);  //定时器3初始化,每两百毫秒更新一次数据
        KEY_Init();       //按键初始化
        EXTIX_Init();     //中断初始化
        PID_Init();       //PID初始化
        LED_Init();                                //初始化LED
         LCD_Init();       //LCD初始化
  POINT_COLOR=RED;  //设置字体为红 {MOD}
  LCD_ShowString(30,70,200,16,16,"Set Value:");    //显示设置值提示字母
  LCD_ShowString(30,110,200,16,16,"Current Value:");        //显示当前值提示字母
        LCD_ShowString(30,150,200,16,16,"PID OUT:");  //显示PID值
         while(DS18B20_Init())        //DS18B20初始化        
        {
                LCD_ShowString(30,30,200,16,16,"DS18B20 Error");
                delay_ms(200);
                LCD_Fill(30,30,239,130+16,WHITE);
                 delay_ms(200);
        }   
        LCD_ShowString(30,30,200,16,16,"DS18B20 OK");
        POINT_COLOR=BLUE;//设置字体为蓝 {MOD}
         LCD_ShowString(140,110,200,16,16,"   . C");         
        while(1)
        {                    
                key=KEY_Scan(0);
                if(key)
                        {
                                        switch(key)
                                        {
                                                case 1: SetValue+=5; break;   //设定值自加5
                                                
                                                case 2: SetValue-=5; break;   //设定值自减5
                                                
                                                case 3:  SetValue=30; break;        //回到原来的设定值
                                        }
                        }
                        
                        pid.Sv=SetValue;   //将设定值赋给结构体
               
                LCD_ShowNum(110,70,SetValue,2,16);        //显示设定值
                 if(t%10==0)//每100ms读取一次
                {                                                                          
                        temperature=DS18B20_Get_Temp();
                        
      temperature1=        DS18B20_Get_Temp();                //将当前值赋给结构体
                        pid.Pv=temperature1/10;
                        
                        if(temperature<0)
                        {
                                LCD_ShowChar(100+40,110,'-',16,0);                        //显示负号
                                temperature=-temperature;                                        //转为正数
                        }else LCD_ShowChar(100+40,110,' ',16,0);                        //去掉负号
                        LCD_ShowNum(100+40+8,110,temperature/10,2,16);        //显示正数部分            
                           LCD_ShowNum(100+40+32,110,temperature%10,1,16);        //显示小数部分                    
                }                                   
                 delay_ms(10);
                t++;
                if(t==40)
                {
                        t=0;
                        LED0=!LED0;
                        PID_Calc();    //每200毫秒,计算PID
                        LCD_ShowNum(100,150,pid.OUT,2,16);  //显示整数部分
//                        LCD_ShowNum(100,190,pid.Iout,2,16);
                        printf("%2.1F ",pid.OUT);
                        printf("  P:%2.2F ",pid.Pout);
                        printf("  I:%2.2F ",pid.Iout);
                        printf("  D:%2.2F ",pid.Dout);
                }
        }
}


这是PID.C里边的代码
#include "pid.h"
#include "sys.h"

void PID_Init(void)//PID参数初始化函数
{
        pid.Kp=50;   //比例系数
        pid.T=500;    //PID计算周期
        pid.Ti=5000; //积分时间
        pid.Td=1500; //微分时间
        pid.OUT0=2;
}


void PID_Calc(void) //pid计算函数
{
        float Dk;
        float OUT;
        
        pid.Ek=pid.Sv-pid.Pv;   //得到当前偏差值
        
        pid.Pout=pid.Kp*pid.Ek;     //比例输出
        
        pid.SEk+=pid.Ek;        //历史偏差总和
        
        Dk=pid.Ek-pid.Ek_1;     //最近两次偏差之差
        
        pid.Iout=pid.Kp*pid.T/pid.Ti*pid.SEk;  //积分输出
        
        pid.Dout=pid.Kp*pid.Td/pid.T*Dk;       //微分输出
//        
        OUT=pid.Pout+pid.Iout+pid.Dout+pid.OUT0;   //本次的计算结果
        
        if(OUT>90)   //PID输出限幅
        {
                OUT=90;
        }
        
        if(OUT<10)
        {
                OUT=10;
        }
        
        pid.OUT=OUT;
        
        pid.Ek_1=pid.Ek;  // 更新偏差
}





友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。