看一下我的pid

[复制链接]
985|2
手机看帖
扫描二维码
随时随地手机跟帖
宜夏|  楼主 | 2017-7-11 16:08 | 显示全部楼层 |阅读模式
帮忙看一下我的pid有没有写错或者其他建议,用的是增量式pid
#include "pid.h"
#include "sys.h"       
#include "usart.h"
int DoPID(PID *pid)
{
        static int pid_ctrl = 0,flag=0;
        int P,I,D;
       
        pid->Err1 = pid->Set_Temp - pid->Temperature;                        //误差
        printf("%d\r\n",pid->Err1);
       
/*******************pwm+=Kp[e(k)-e(k-1)]+Ki*e(k)+Kd[e(k)-2e(k-1)+e(k-2)]********************************/
       
        P = pid->KP*(pid->Err1 - pid->Err2);
        I = pid->KI*pid->Err1;
        D = pid->KD*(pid->Err1 - 2*pid->Err2+pid->Err3);
       
       
        if(pid->Err1 < (-3))                                //制冷       
        {
                flag = cold;                                                        //制冷标志
                printf("cold\r\n");
                printf("%f\r\n",pid->KP);
                printf("%f\r\n",pid->KI);
                printf("%f\r\n",pid->KD);
                pid_ctrl += P+I+D;                                //PID增量
        }
       
        else if(pid->Err1 > 3)                        //制热
        {
                flag = hot;                                                                //制热标志
                printf("hot\r\n");
                printf("%f\r\n",pid->KP);
                printf("%f\r\n",pid->KI);
                printf("%f\r\n",pid->KD);               
                pid_ctrl += P+I+D;                                //PID增量
        }
       
        else                                                                                                //温度偏差在0.3℃以内,不做pid运算
        {
                printf("last\r\n");
                printf("%f\r\n",pid->KP);
                printf("%f\r\n",pid->KI);
                printf("%f\r\n",pid->KD);               
                pid->pid_status = flag;                //上次的制冷制热标志位
                return pid_ctrl;                                        //返回上次的pid增量值
        }
               

        if(pid_ctrl > PWM_Max)                        //限幅
                pid_ctrl = PWM_Max;
        if(pid_ctrl < PWM_Min)
                pid_ctrl = PWM_Min;
       
        pid->Err3 = pid->Err2;                        //保存误差               
        pid->Err2 = pid->Err1;       
       
        pid->pid_status = flag;                                        //制冷制热标志位               
               
        return pid_ctrl;
}





#ifndef _PID_H
#define _PID_H
#include "sys.h"

#define PWM_Max 900
#define PWM_Min 300
#define cold 0
#define hot 1

typedef struct pid
{
        short Temperature;        //现在温度
        short Set_Temp;                        //设定温度
        int Err1;                                                //本次误差               
        int Err2;                                                //上次误差
        int Err3;                                                //上上次误差
        u8 H_flag;                                        //H桥转换标志位
        u8 pid_status;                        //制冷制热标志位
        float KP;                       
        float KI;
        float KD;
}PID;

int DoPID(PID *pid);

#endif



#include "stm32f10x.h"
#include "stm32f10x_tim.h"
#include "led.h"
#include "timer.h"
#include "delay.h"
#include "sys.h"
#include "oled.h"
#include "ds18b20.h"
#include "key.h"
#include "pwm.h"
#include "pid.h"
#include "usart.h"
#include "deal.h"

int main(void)
  {       
                u8 Key_Status,i=1;
                int PWM_Value;       
                _oled My_oled ={
                        .Air_Speed = 1,                                        //风速
                        .Set_Temp = 300,                                //设定温度
                        .Temperature = 0,                                //风口温度
                };
               
                PID My_pid ={
                        .Temperature = 0,                //风口温度
                        .Set_Temp = 0,                        //指定温度
                        .Err1 = 0,                                        //误差值
                        .Err2 = 0,                                        //上次误差值
                        .Err3 = 0,                                        //上上次误差值
                        .H_flag = 0,                        //H桥转换标志位
                        .pid_status = cold,        //制冷制热标志位,默认制冷
                        .KP = 0,                       
                        .KI = 0,
                        .KD = 0,
                };
               
                _Delay pid_delay = {        //pid采样时间延时
                        .Mark = 1,
                        .Start = 1,
                        .Time_Storage = 0,
                        .answer = 0,
                };
               
                delay_init();
                NVIC_Configuration();                                //设置NVIC中断分组2:2位抢占优先级,2位响应优先级
                Uart1_Init(9600);                                                //串口一初始化
                Uart2_Init(9600);                                                //串口二初始化       
                TIM2_Int_Init(1000,71);                        //1ms进一次中断
                TIM3_PWM_Init(1000,72);                        //PWM初始化 1000Hz
                PWMIO_Init();                                 //初始化PWM端口
                LED_Init();                             //LED端口初始化
                KEY_Init();                                         //按键初始化
                OLED_Init();                                 //oled初始化
                DS18B20_Init();
                LED0 = 0;
                LED1 = 0;
                while(1)
                {       
                        Uart2_Receive(&My_pid);
                        Key_Status = KEY_Scan(0,&My_oled);                                //获取按键状态
                        My_oled.Temperature = DS18B20_Get_Temp();        //获取温度
                        My_pid.Temperature = My_oled.Temperature;        //pid获取温度
                        My_pid.Set_Temp = My_oled.Set_Temp;                                //pid获取设定温度
                   Display_Oled(&My_oled);                                                                                //显示oled       
                        VisualScope_Output(My_oled.Temperature,0,0,0);                //串口发送温度值
                                       
                        my_delay(2000,&pid_delay);                                //pid采样时间2s
                        if(pid_delay.Mark)
                        {
                                LED0 = !LED0;
                                PWM_Value = DoPID(&My_pid);
                                switch(My_pid.pid_status)
                                {
                                        case cold:TIM_SetCompare3(TIM3,0);                        //关闭制热片
                                                                                TIM_SetCompare1(TIM3,PWM_Value);        //开启制冷片
                                                                                printf("PWM_Value:%d\r\n",PWM_Value);
                                                                                break;
                                        case hot: TIM_SetCompare1(TIM3,0);                        //关闭制冷片
                                                                                TIM_SetCompare3(TIM3,PWM_Value);        //开启制热片
                                                                                printf("PWM_Value:%d\r\n",PWM_Value);
                                                                                break;
                                }
                        }
                       
                       
                       
                }
}
       

这个pid是用来控制一个制冷片空调的,高于设定温度制冷,低于设定温度制热

相关帖子

宜夏|  楼主 | 2017-7-11 16:20 | 显示全部楼层
现在在整定参数,开始用纯比例调节,设定温度比环境温度高时,用纯比例调节可以让误差稳定在1度以内。当设定温度比环境温度低时,要制冷的时候,pid计算出的PWM值总是不够,温度达不到设定温度。

使用特权

评论回复
宜夏|  楼主 | 2017-7-11 16:21 | 显示全部楼层
误差越小,计算出的pid增量越大,这是正常情况吗?

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

1

主题

4

帖子

1

粉丝