打印
[STM32F1]

STM32 pid自整定

[复制链接]
91|1
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
hearstnorman323|  楼主 | 2024-3-10 08:04 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式



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

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

uint16_t pw;
uint16_t save_buff[9000] = {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[k_pid_self_counter] = 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[0];
                                        min_temp=save_buff[0];
                                        for(i = 0;i < k_pid_self_counter;i++)
                                        {
                                                if(save_buff[i] >= max_temp)
                                                {
                                                        max_temp = save_buff[i];
                                                        TIME_LOW=i;
                                                }
                                                if(save_buff[i] <= min_temp)
                                                {
                                                        min_temp = save_buff[i];
                                                        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[8];

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[9000] = {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;
               
        
}



/**
  * [url=home.php?mod=space&uid=247401]@brief[/url]  主函数
  * @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++)
                ;
}


使用特权

评论回复
沙发
micoccd| | 2024-3-11 13:32 | 只看该作者
这个很实用吗PID的用处很广

使用特权

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

本版积分规则

9

主题

1101

帖子

1

粉丝