[应用相关] stm32+增量式pid+max6675 PWM温度控制

[复制链接]
3119|16
 楼主| 发给她更好fh 发表于 2021-4-27 13:09 | 显示全部楼层 |阅读模式
stm32+增量式pid+max6675 PWM温度控制

本文采用的芯片为STM32F103RCT6
温度芯片为MAX6675
之前spi通讯的max6675代码:
https://blog.csdn.net/answerMack/article/details/83310370
模拟io通讯的max6675代码:
https://blog.csdn.net/answerMack/article/details/83270562

 楼主| 发给她更好fh 发表于 2021-4-27 13:10 | 显示全部楼层
代码写了,具体还没试验过
用电表打过结果,感觉还可以,就粘上来了。

因为选用的热电偶线测温变化太快,所以在中间加了报警,但是里面没有蜂鸣器。后续代码会改进。会加上CAN总线等设置。只是简单实现温控。
 楼主| 发给她更好fh 发表于 2021-4-27 13:10 | 显示全部楼层
  1. pid.h
  1. #ifndef __PID_H
  2. #define __PID_H
  3. #include "sys.h"

  4. typedef struct {
  5.         int Set_temperature;                //期望值
  6.         int Current_temperature;    //当前值
  7.        
  8.         float proportion;                         //比例系数P
  9.         float integral;                         //积分系数I
  10.         float differential;                 //微分系数D
  11.         int T; //采样周期
  12.        
  13.         float error_current;                 //当前误差:浮点数
  14.         int error_last;                     //上一步误差
  15.     int error_sum;              //误差累计
  16.        
  17.         float pid_proportion_out;                   //比例项
  18.         float pid_integral_out;                       //积分项
  19.         float pid_differential_out;                   //微分项
  20.         float pid_out;                           //PID控制输出
  21.        
  22. }PID;

  23. //PID  *Pid;//存放PID算法需要的数据
  24. //void PID_Init(int SETtemp);
  25. float pid_control(PID *PP,float current_temp);
  26. void PWM_CONTROL(float SUM); //占空比计算的
  27. void PWM_Out(u8 m); //按功率输出的

  28. //struct PID  *PP;


  29. #endif
 楼主| 发给她更好fh 发表于 2021-4-27 13:11 | 显示全部楼层
可能有错误,请评论帮忙指正。谢谢!!
//

 楼主| 发给她更好fh 发表于 2021-4-27 13:12 | 显示全部楼层
  1. pid.c
  1. #include "pid.h"
  2. #include "timer.h"
  3. #include "usart.h"

  4. //void PID_Init(int SETtemp)  //启动时,PID的参数值应该从保存上次值的存储器空间读取出来。在此直接设定
  5. //{
  6. //    Pid->Set_temperature=SETtemp;    //用户设定值
  7. //        Pid->proportion=20;
  8. //        Pid->integral=5000;   //积分系数
  9. //        Pid->differential=1200;   //微分系数
  10. //        Pid->T=1000;    //Pid计算周期(采样周期)
  11. //    Pid->error_current=0.0;
  12. //        Pid->error_last=0;
  13. //        Pid->error_sum=0;
  14. //        Pid->pid_proportion_out=0;
  15. //        Pid->pid_integral_out=0;
  16. //        Pid->pid_differential_out=0;
  17. //        Pid->pid_out=0;
  18. //}       

  19.         //struct PID *PP,
  20. float pid_control( PID *PP,float current_temp){
  21. static float PID_ZL=0.0;
  22.         float result=0.0;
  23.         float A0,A1,A2;
  24.         PP->error_current = PP->Set_temperature - current_temp;
  25. printf("the PP->error_current is:%.2f\n",PP->error_current);
  26. printf("\n");
  27.     if(PP->error_current>20)PWM_Out(0);
  28.     else if(PP->error_current<-20)PWM_Out(1);
  29.     else if(PP->error_current>10 && PP->error_current<20)PWM_Out(2);
  30.     else if(PP->error_current>-20 && PP->error_current<-10)PWM_Out(3);
  31.     else if(PP->error_current>-20 && PP->error_current<-10)PWM_Out(3);
  32.         /*==============
  33.         增量式PID算法 增量式PID需每次叠加
  34.         ================*/
  35.     else if(PP->error_current<10 && PP->error_current>-10){
  36.          A0=PP->proportion * (1+ PP->T/PP->integral +PP->differential/PP->T);
  37.                  A1=-PP->proportion * (1+ 2*PP->differential/PP->T);
  38.                  A2=PP->proportion * (PP->differential/PP->T);
  39.                 result =A0 * PP->error_current + A1 * PP->error_last +A2 * PP->error_sum ;
  40.                 result += PID_ZL;
  41.                 if (result>900){
  42.                        if(PP->error_current>0)PWM_Out(0);
  43.                            else PWM_Out(1);
  44.                 }
  45.                 else if (result<-5){
  46.                        if(PP->error_current>0)PWM_Out(0);
  47.                            else PWM_Out(1);
  48.                 }
  49.                 else if (-5<result&&result<5){
  50.                         PWM_Out(4);
  51.                 }       
  52.                 else if (result>5&&result<900){
  53.                         if(PP->error_current>0)PWM_CONTROL(result);
  54.                         else PWM_CONTROL(-result);
  55.                 }
  56.                
  57.         }
  58.        
  59.        
  60.         PID_ZL=result;
  61. printf("the PID_ZL is:%.2f\n",PID_ZL);
  62. printf("\n");       
  63.         PP->error_sum=PP->error_last;
  64.     PP->error_last=PP->error_current;
  65.         return result;
  66. }


  67. /*==============
  68. 10度以内  PID控制        判断result范围,确定占空比       
  69. =============*/
  70. void PWM_CONTROL(float SUM){
  71. int a=0;
  72.         a=SUM;
  73. printf("the ccrx<ten is:%d\n",a);
  74. printf("\n");
  75. if (a>0)TIM_SetCompare3(TIM3,a);
  76. else TIM_SetCompare1(TIM3,-a);
  77. }




  78. void PWM_Out(u8 m){

  79. switch(m)
  80.         {
  81. /*=========================================
  82.                 tim_ch3--加热    tim_ch1--冷却
  83. 20度差值: 全功:0:加热不冷却  1:冷却不加热
  84. 10-20度之间   半功热       
  85. ===========================================*/
  86.                  case 0 :
  87.                                 TIM_SetCompare3(TIM3,0);
  88.                         TIM_SetCompare1(TIM3,900);
  89.                         break;       
  90.                 case 1 :
  91.                                 TIM_SetCompare3(TIM3,900);
  92.                         TIM_SetCompare1(TIM3,0);
  93.                                 break;       
  94.                 case 2 :
  95.                                 TIM_SetCompare1(TIM3,800);
  96.                         TIM_SetCompare3(TIM3,449);
  97.                                 break;       
  98.                 case 3 :
  99.                                 TIM_SetCompare1(TIM3,449);
  100.                         TIM_SetCompare3(TIM3,800);
  101.                                 break;       
  102.         case 4 : //全关
  103.                                 TIM_SetCompare1(TIM3,900);
  104.                         TIM_SetCompare3(TIM3,900);
  105.                                 break;       
  106.         case 5 : //全开
  107.                                 TIM_SetCompare1(TIM3,0);
  108.                         TIM_SetCompare3(TIM3,0);
  109.                                 break;                       
  110.                
  111.         }       

  112. }
 楼主| 发给她更好fh 发表于 2021-4-27 13:12 | 显示全部楼层
 楼主| 发给她更好fh 发表于 2021-4-27 13:13 | 显示全部楼层
  1. #ifndef __TIMER_H
  2. #define __TIMER_H
  3. #include "sys.h"
  4. void TIM3_PWM_Init(u16 arr,u16 psc);
  5. #endif
 楼主| 发给她更好fh 发表于 2021-4-27 13:14 | 显示全部楼层
 楼主| 发给她更好fh 发表于 2021-4-27 13:14 | 显示全部楼层
  1. #include "timer.h"
  2. #include "GPIO.h"
  3. //#include "usart.h"
  4. //#include "stm32f10x.h"
  5. void TIM3_PWM_Init(u16 arr,u16 psc)
  6. {  
  7.         GPIO_InitTypeDef GPIO_InitStructure;
  8.         TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
  9.         TIM_OCInitTypeDef  TIM_OCInitStructure;
  10.        

  11.         RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);        //使能定时器3时钟
  12.         RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC  | RCC_APB2Periph_AFIO, ENABLE);  //使能GPIO外设和AFIO复用功能模块时钟
  13.        
  14.         GPIO_PinRemapConfig(GPIO_FullRemap_TIM3, ENABLE); //Timer3完全重映射   
  15.     /* FULL REMAP  ---   PC6/7/8/9  TIM_CH1/2/3/4*/
  16.    //设置该引脚为复用输出功能,
  17.         GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6|GPIO_Pin_7|GPIO_Pin_8|GPIO_Pin_9; //TIM_CH2
  18.         GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;  //复用推挽输出
  19.         GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  20.         GPIO_Init(GPIOC, &GPIO_InitStructure);//初始化GPIO

  21.    //初始化TIM3
  22.         TIM_TimeBaseStructure.TIM_Period = arr; //设置在下一个更新事件装入活动的自动重装载寄存器周期的值
  23.         TIM_TimeBaseStructure.TIM_Prescaler =psc; //设置用来作为TIMx时钟频率除数的预分频值
  24.         TIM_TimeBaseStructure.TIM_ClockDivision = 0; //设置时钟分割:TDTS = Tck_tim
  25.         TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  //TIM向上计数模式
  26.         TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); //根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位
  27.        
  28.         //初始化TIM3 Channel2 PWM模式         
  29.         TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2; //选择定时器模式:TIM脉冲宽度调制模式2
  30.         TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //比较输出使能
  31.         TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; //输出极性:TIM输出比较极性高
  32.        
  33.        
  34.         TIM_OC1Init(TIM3, &TIM_OCInitStructure);
  35.         TIM_OC1PreloadConfig(TIM3,TIM_OCPreload_Enable);//比较预装载
  36.        
  37.         TIM_OC2Init(TIM3, &TIM_OCInitStructure);  //根据T指定的参数初始化外设TIM3 OC2
  38.         TIM_OC2PreloadConfig(TIM3, TIM_OCPreload_Enable);  //使能TIM3在CCR2上的预装载寄存器
  39.        
  40.         TIM_OC3Init(TIM3, &TIM_OCInitStructure);  //根据TIM_OCInitStruct中指定的参数初始化外设TIMx
  41.     TIM_OC3PreloadConfig(TIM3, TIM_OCPreload_Enable);  //使能TIMx在CCR3上的预装载寄存器
  42.        
  43.         TIM_OC4Init(TIM3, &TIM_OCInitStructure);  //根据TIM_OCInitStruct中指定的参数初始化外设TIMx
  44.     TIM_OC4PreloadConfig(TIM3, TIM_OCPreload_Enable);  //使能TIMx在CCR4上的预装载寄存器
  45.        
  46.     TIM_ARRPreloadConfig(TIM3,ENABLE);//自动重装载
  47.         TIM_Cmd(TIM3, ENABLE);  //使能TIM3
  48. }

 楼主| 发给她更好fh 发表于 2021-4-27 13:15 | 显示全部楼层
 楼主| 发给她更好fh 发表于 2021-4-27 13:16 | 显示全部楼层
  1. #include "stm32f10x.h"
  2. #include "usart.h"       
  3. #include "delay.h"
  4. #include "sys.h"
  5. #include "max6675.h"
  6. #include "spi.h"
  7. #include "led.h"
  8. #include "timer.h"
  9. #include "pid.h"

  10. int main(void){
  11.         PID  temperature;
  12.     temperature.Set_temperature=50;    //用户设定值
  13.         temperature.proportion=20;
  14.         temperature.integral=5000;   //积分系数
  15.         temperature.differential=1200;   //微分系数
  16.         temperature.T=1000;    //temperature计算周期(采样周期)
  17.     temperature.error_current=0.0;
  18.         temperature.error_last=0;
  19.         temperature.error_sum=0;
  20.         temperature.pid_proportion_out=0;
  21.         temperature.pid_integral_out=0;
  22.         temperature.pid_differential_out=0;
  23.         temperature.pid_out=0;
  24. //        float t1;
  25.         float t2,t3;
  26.         float temp_error;
  27.             float pid_result;
  28.             SystemInit();
  29.             LED_init();
  30.             delay_init();
  31.                 uart_init(9600);
  32.             max6675_MONI_init();
  33.             SPI2_Init();
  34.             SPI2_SetSpeed(SPI_BaudRatePrescaler_8);//max6675的串行时钟频率为4.3Mhz
  35.             SPI1_Init();
  36.             SPI1_SetSpeed(SPI_BaudRatePrescaler_8);//max6675的串行时钟频率为4.3Mhz
  37.        
  38. //            PID_Init(50);//PID设置温度
  39.        
  40.             TIM3_PWM_Init(900-1,0);//不分频。PWM频率=72000000/9999+1/143+1=50hz
  41.             TIM_SetCompare1(TIM3,449);       
  42.             TIM_SetCompare2(TIM3,300);//
  43.             TIM_SetCompare3(TIM3,0);
  44.             TIM_SetCompare4(TIM3,900);
  45.             while(1)
  46.                 {
  47.                        
  48.                        
  49.                        
  50.                 GPIO_ResetBits(GPIOA,GPIO_Pin_8);
  51.                 GPIO_ResetBits(GPIOC,GPIO_Pin_12);
  52.                 GPIO_ResetBits(GPIOD,GPIO_Pin_2);
  53.                 /*温度显示模块*/
  54. //                t1=max6675_readTemperature();
  55. //                printf("the I temperature is:%.2f\n",t1);
  56. //                printf("\n");
  57.             t3=max6675_readTemp_III();
  58.                 printf("the III temperature is:%.2f\n",t3);
  59.                 printf("\n");       
  60.                 delay_ms(300);
  61.                 t2=max6675_readTemp();
  62.                 printf("the II temperature is:%.2f\n",t2);
  63.                 printf("\n");       
  64.                 temp_error=t2-t3;
  65. /*==================
  66.         报警函数                               
  67. ====================*/
  68. if(temp_error>150)        {
  69.     printf("warning");
  70.     printf("\n");
  71.    t2=temperature.Set_temperature;
  72. }               
  73.                 pid_result=pid_control(&temperature,t2);
  74.                 printf("the pid_result is:%.2f\n",pid_result);
  75.                 printf("\n");
  76.                 GPIO_SetBits(GPIOA,GPIO_Pin_8);
  77.                 GPIO_SetBits(GPIOC,GPIO_Pin_12);
  78.                 GPIO_SetBits(GPIOD,GPIO_Pin_2);
  79.                 delay_ms(300);       
  80.         }
  81. }
 楼主| 发给她更好fh 发表于 2021-4-27 13:24 | 显示全部楼层
代码文件:

链接:https://pan.baidu.com/s/1Zg2zt65BZQi3DycBhGHOAw
提取码:a6jd
cr315 发表于 2021-4-27 15:11 | 显示全部楼层
支持一下,期待楼主更多作品
yezunfu317 发表于 2021-7-26 12:01 | 显示全部楼层
庞飞彪 发表于 2021-11-15 09:43 | 显示全部楼层
您好,我测试了一下您的代码;有个问题想咨询一下,就我自己测试而言,我设定温度是40度,稳定之后的温度是在39 和 40 之间波动;然后累加误差是个负数,假设为(-200);这里就稍微有点问题,39度情况下,误差是正数,会逐步使得累计误差减小(-200+6),趋向于0;而40度不存在误差,所以累加误差不变;然后又降到39度,累加误差继续趋向于0;然后就存在一个瞬间打破平衡;就是当累计误差变为正数时,就变成了PID调节(之前的都是采用case中的占空比),此时温度就会产生较大波动;大概会变成37--43度,然后再平衡为之前的状态;这种情况您认为哪里可以改进;
4546044060 发表于 2022-5-28 16:04 | 显示全部楼层
#技术资源# if (result>900){
                       if(PP->error_current>0)PWM_Out(0);
                           else PWM_Out(1);
                }
                else if (result<-5){
                       if(PP->error_current>0)PWM_Out(0);
                           else PWM_Out(1);
                }
                else if (-5<result&&result<5){
                        PWM_Out(4);
                }        
                else if (result>5&&result<900){
                        if(PP->error_current>0)PWM_CONTROL(result);
                        else PWM_CONTROL(-result);
                }
               
        }
大佬这个900 5 -5 怎么来的呢
您需要登录后才可以回帖 登录 | 注册

本版积分规则

43

主题

563

帖子

1

粉丝
快速回复 在线客服 返回列表 返回顶部