OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 3385|回复: 2

pid调节过程出现数据跳变

[复制链接]

4

主题

21

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
2039
金钱
2039
注册时间
2018-1-5
在线时间
144 小时
发表于 2019-2-25 21:28:58 | 显示全部楼层 |阅读模式
10金钱
本帖最后由 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;  //设置字体为红色
  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;//设置字体为蓝色
         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\n",pid.OUT);
                        printf("  P:%2.2F\n",pid.Pout);
                        printf("  I:%2.2F\n",pid.Iout);
                        printf("  D:%2.2F\n",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;  // 更新偏差
}





最佳答案

查看完整内容[请看2#楼]

已经解决了,是DS18B20不稳定导致的,有时DS18B20会采集到一个数值非常大的错误数据,导致所有的数据该变。对DS18B20采集到的数据进行限幅就OK了
正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

4

主题

21

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
2039
金钱
2039
注册时间
2018-1-5
在线时间
144 小时
 楼主| 发表于 2019-2-25 21:28:59 | 显示全部楼层
已经解决了,是DS18B20不稳定导致的,有时DS18B20会采集到一个数值非常大的错误数据,导致所有的数据该变。对DS18B20采集到的数据进行限幅就OK了
回复

使用道具 举报

6

主题

46

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
211
金钱
211
注册时间
2018-10-30
在线时间
32 小时
发表于 2019-3-6 17:01:03 | 显示全部楼层
你个傻子,这是正常现象,你家个滤波试试
发怒是用别人的错误来惩罚自己
烦恼是用自己的过失折磨自己
后悔是用无奈的往事来摧残自己
回复

使用道具 举报

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

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2025-6-9 22:22

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

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