帮忙看一下我的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是用来控制一个制冷片空调的,高于设定温度制冷,低于设定温度制热
|