louliana 发表于 2025-3-22 07:53

STM32 pid自整定+pid控温+pwm输出

#include "./pid/pid.h"   
#include "./led/bsp_led.h"   
#include "./GeneralTim/bsp_GeneralTim.h"

PID pid; //存放PID算法所需要的数据

uint16_t pw;
uint16_t save_buff = {0}; //保存数据缓存
extern volatile      uint16_t Step_Auto;      
extern volatile      uint32_t PID_cool_cnt;
extern volatile      uint32_t PID_heat_cnt;
extern volatile      uint16_t pid_self_first_status_flag;      //标志位
extern volatile      uint16_t PID_Deal,PID_auto_Deal;
extern volatile      uint16_t zero_across_counter;
extern volatile      uint16_t k_pid_self_counter;
extern volatile      uint16_t CCR4_Val;
extern volatile      uint16_t kkk;
void PID_Calc()//pid计算
{
      float DelEk;      
      float out;
      if (PID_Deal == 1)
      {
                pid.Ek=pid.Sv-pid.Pv;   //得到当前的偏差值
                pid.SEk+=pid.Ek;      //历史偏差总和
                DelEk=pid.Ek-pid.Ek_1;//最近两次偏差之差

                pid.Pout=pid.Kp*pid.Ek;   //比例输出
                pid.Iout=pid.Ki*pid.SEk;                        //积分输出
                pid.Dout=pid.Kd*DelEk;                            //微分输出
                out= pid.Pout+ pid.Iout+ pid.Dout;
                kkk++;
                if(out>255)
                {
                        kkk=0;
                        pid.SEk=0;
                }
                if(out>255)
                {
                        pid.OUT=255;
                }
                else if(out<0)
                {
                        pid.OUT=0;
                }
                else
                {
                        pid.OUT=out;
                }
                pid.Ek_1=pid.Ek;//更新偏差
//                printf ( "\r\n%.1f\r\n",out);      
                PID_out();
               
      }
}
void PID_out()//输出PID运算结果到负载---每1ms被调用1次
{
      uint16_t kk;
      if (pid.Pv>pid.Sv)//当前温度大于用户设定温度
      {
                CCR4_Val=100;
                GENERAL_TIM_Init();
      }
                else
                {
                kk=100-pid.OUT*100/255;
                CCR4_Val=kk;
                GENERAL_TIM_Init();
//      printf ( "\r\n%3d\r\n",kk);
                }
}
void PID_auto()//继电器反馈法自整定pid参数
{

      uint8_t i = 0;
      float KC = 0;
      float TC = 0;
      float V_temp = 0,min_temp = 0,max_temp = 0;
      float TIME_Hight=0,TIME_LOW=0;
      
      
      //第一步进入比较初始温度 确定此时温度处于哪种情况

if (PID_auto_Deal== 0)
{
/******************************************************************************************************/
               
                PID_Deal = 0;//退出pid
               
                //程序第一次进入 查看对比当前温度和设定温度

                if(pid.Pv < pid.Sv1)//当前温度低于设定温度
                {
                        PID_heat_cnt++;                //热
                        PID_cool_cnt = 0;
                        if(PID_heat_cnt >= 3)//连续3次结果
                        {
                              CCR4_Val=0;//加热
                              GENERAL_TIM_Init();

                              if(Step_Auto == 0)               
                              {
                                        Step_Auto = 1;
                                        zero_across_counter++;
//                                        printf ( "\r\n1");      
                              }
                        }
                }
                else//当前温度 大于 设定温度 停止加热
                {
                        PID_cool_cnt++;
                        PID_heat_cnt = 0;
                        if(PID_cool_cnt > 3)
                        {
                              CCR4_Val=100;                //不加热
                              GENERAL_TIM_Init();
                              if(Step_Auto == 1)                //设定温度高于当前温度
                              {
                                        Step_Auto = 0;
                                        zero_across_counter++;
                              }
                        }
                }
                if(PID_heat_cnt >= 65535)//连续3次结果
                {
                        PID_heat_cnt=65535;
                }
                if(PID_cool_cnt >= 65534)//连续3次结果
                {
                        PID_cool_cnt=65534;
                }
               
               
               
                /*****************开始计算强行振荡的周期和幅值****************************/                     

                if((zero_across_counter == 3 ) || (zero_across_counter == 4 ))
                {
                        save_buff = pid.Pv;
                     
                        k_pid_self_counter++;
                     
                        if(k_pid_self_counter >=9000)
                        {
                              k_pid_self_counter = 0;                                       
                        }
                }
                else if(zero_across_counter == 5 )//5次过0 则说明出现了振荡 整定成功
                {
                              PID_Deal = 1;
                              PID_auto_Deal = 1;
                              zero_across_counter = 0;

                                        max_temp=save_buff;
                                        min_temp=save_buff;
                                        for(i = 0;i < k_pid_self_counter;i++)
                                        {
                                                if(save_buff >= max_temp)
                                                {
                                                      max_temp = save_buff;
                                                      TIME_LOW=i;
                                                }
                                                if(save_buff <= min_temp)
                                                {
                                                      min_temp = save_buff;
                                                      TIME_Hight=i;
                                                }
                                        }
                                        V_temp =max_temp - min_temp;                                        //最大减最小就是幅值
                                       
                                       
                              KC = 127/V_temp;
//如果记录了 最低温度 与 最高温度对应的时间 那么沿用这个公式:TC = 2 * (TIME_Hight - TIME_LOW);      
                              TC = k_pid_self_counter;      //TC =2 * (TIME_Hight - TIME_LOW);
                     
                              pid.Kp = 0.6*KC;               
                              pid.Ki = (0.6*KC)/(0.5*TC)/10;
                              pid.Kd = (0.6*KC)*(0.125*TC)/60;
                              printf ( "\r\n整定成功");               
                        }
      }      
}




#include "stm32f10x.h"
#include "core_cm3.h"
#include "./systick/bsp_SysTick.h"
#include "./led/bsp_led.h"
#include "./usart/bsp_usart.h"
#include "./ds18b20/bsp_ds18b20.h"
#include "./pid/pid.h"
#include "./timer/timer.h"
#include "./AdvanceTim/bsp_AdvanceTim.h"
#include "./GeneralTim/bsp_GeneralTim.h"

volatile uint32_t time = 0; // ms 计时变量
volatile uint32_t time2 = 0; // ms 计时变量
float TM1,TM2;
volatile uint8_t ucDs18b20Id;

volatile      uint16_t Step_Auto;      
volatile      uint32_t PID_cool_cnt;
volatile      uint32_t PID_heat_cnt;
volatile      uint16_t pid_self_first_status_flag;      //标志位
volatile      uint16_t PID_Deal,PID_auto_Deal;
volatile      uint16_t zero_across_counter;
volatile      uint16_t k_pid_self_counter;
volatile      uint16_t CCR4_Val;
volatile      uint16_t kkk;
//volatile         uint16_t save_buff = {0};
void delay();

void PID_Init()
{
                pid.Sv=30;                //用户设定温度
                pid.OUT0=1;

                zero_across_counter=0;
                PID_cool_cnt=0;
                PID_heat_cnt=0;
                PID_Deal=0;
                PID_auto_Deal=0;
                pid_self_first_status_flag = 0;
                k_pid_self_counter=0;
                if( pid.Pv <= pid.Sv)      //设定温度高于当前温度
                {
                        pid.Sv1=(pid.Sv-pid.Pv)/2+pid.Pv;      
                        pid.Sv1=(pid.Sv-pid.Pv)/2+pid.Pv;      
                        pid.Sv1=(pid.Sv-pid.Pv)/2+pid.Pv;      
                        pid.Sv1=(pid.Sv-pid.Pv)/2+pid.Pv;      
                        pid.Sv1=(pid.Sv-pid.Pv)/2+pid.Pv;      
                        
                }               
//                CCR4_Val=100;
//                PID_auto_Deal=1;
//                PID_Deal=1;
//                pid.Sv=30;
//                pid.Kp=38.0999985;
//                pid.Ki=0.21666673;
//                pid.Kd=2.8575;
               
      
}



/**
* @brief主函数
* @param无
* @retval 无
*/
int main(void)
{      
                delay();
      CCR4_Val=50;
      ADVANCE_TIM_Init();
      GENERAL_TIM_Init();
      
      /* 配置SysTick 为1us中断一次 */
      SysTick_Init();
      
      
//      /* 端口初始化 */
//      LED_GPIO_Config();//初始化了PB1口
      
      

      
      USART_Config();      //初始化串口1
      printf("\r\n this is a ds18b20 test demo \r\n");
      while( DS18B20_Init() )      
      printf("\r\n no ds18b20 exit \r\n");//初始化DS18B20,不初始化就等待这里?
      printf("\r\n ds18b20 exit \r\n");
      DS18B20_ReadId(ucDs18b20Id);
      TM1=DS18B20_GetTemp_MatchRom ( ucDs18b20Id );
      pid.Pv=TM1;
      PID_Init();//参数初始化      
      pid.Sv1=28;      
      while(1)      
      {      
                printf ( "\r\n%.1f",TM1);                // 打印通过 DS18B20 序列号获取的温度值      
                Delay_ms(10);
                TM1=DS18B20_GetTemp_MatchRom ( ucDs18b20Id );
                pid.Pv=TM1;//当前温度         
                pid.Pv=TM1;//当前温度      
                PID_auto();
                PID_Calc(); //pid计算                                                               
//                printf ( "\r\n%.1f",TM1);                // 打印通过 DS18B20 序列号获取的温度值      
//                Delay_ms(1000);
//                if ( time >= 10 ) /* 10 * 1 ms = 10ms 时间到 */
//    {
//      time = 0;
//                        TM1=DS18B20_GetTemp_MatchRom ( ucDs18b20Id );
//                        pid.Pv=TM1;//当前温度      
//    }
//                if ( time2 >= 1000 ) /* 1000 * 1 ms = 1s 时间到 */
//    {
//      time2 = 0;
//                        pid.Pv=TM1;//当前温度      
//                        PID_auto();
//                        PID_Calc(); //pid计算                                                               
//                }               
      }         
}                              
void delay(void)
{
      int i;
      for(i=0; i<10000000; i++)
                ;
}

页: [1]
查看完整版本: STM32 pid自整定+pid控温+pwm输出