打印
[应用相关]

stm32+增量式pid+max6675 PWM温度控制

[复制链接]
2533|16
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
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 | 只看该作者
pid.h
#ifndef __PID_H
#define __PID_H
#include "sys.h"

typedef struct {
        int Set_temperature;                //期望值
        int Current_temperature;    //当前值
       
        float proportion;                         //比例系数P
        float integral;                         //积分系数I
        float differential;                 //微分系数D
        int T; //采样周期
       
        float error_current;                 //当前误差:浮点数
        int error_last;                     //上一步误差
    int error_sum;              //误差累计
       
        float pid_proportion_out;                   //比例项
        float pid_integral_out;                       //积分项
        float pid_differential_out;                   //微分项
        float pid_out;                           //PID控制输出
       
}PID;

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

//struct PID  *PP;


#endif

使用特权

评论回复
地板
发给她更好fh|  楼主 | 2021-4-27 13:11 | 只看该作者
可能有错误,请评论帮忙指正。谢谢!!
//

使用特权

评论回复
5
发给她更好fh|  楼主 | 2021-4-27 13:12 | 只看该作者
pid.c
#include "pid.h"
#include "timer.h"
#include "usart.h"

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

        //struct PID *PP,
float pid_control( PID *PP,float current_temp){
static float PID_ZL=0.0;
        float result=0.0;
        float A0,A1,A2;
        PP->error_current = PP->Set_temperature - current_temp;
printf("the PP->error_current is:%.2f\n",PP->error_current);
printf("\n");
    if(PP->error_current>20)PWM_Out(0);
    else if(PP->error_current<-20)PWM_Out(1);
    else if(PP->error_current>10 && PP->error_current<20)PWM_Out(2);
    else if(PP->error_current>-20 && PP->error_current<-10)PWM_Out(3);
    else if(PP->error_current>-20 && PP->error_current<-10)PWM_Out(3);
        /*==============
        增量式PID算法 增量式PID需每次叠加
        ================*/
    else if(PP->error_current<10 && PP->error_current>-10){
         A0=PP->proportion * (1+ PP->T/PP->integral +PP->differential/PP->T);
                 A1=-PP->proportion * (1+ 2*PP->differential/PP->T);
                 A2=PP->proportion * (PP->differential/PP->T);
                result =A0 * PP->error_current + A1 * PP->error_last +A2 * PP->error_sum ;
                result += PID_ZL;
                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);
                }
               
        }
       
       
        PID_ZL=result;
printf("the PID_ZL is:%.2f\n",PID_ZL);
printf("\n");       
        PP->error_sum=PP->error_last;
    PP->error_last=PP->error_current;
        return result;
}


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




void PWM_Out(u8 m){

switch(m)
        {
/*=========================================
                tim_ch3--加热    tim_ch1--冷却
20度差值: 全功:0:加热不冷却  1:冷却不加热
10-20度之间   半功热       
===========================================*/
                 case 0 :
                                TIM_SetCompare3(TIM3,0);
                        TIM_SetCompare1(TIM3,900);
                        break;       
                case 1 :
                                TIM_SetCompare3(TIM3,900);
                        TIM_SetCompare1(TIM3,0);
                                break;       
                case 2 :
                                TIM_SetCompare1(TIM3,800);
                        TIM_SetCompare3(TIM3,449);
                                break;       
                case 3 :
                                TIM_SetCompare1(TIM3,449);
                        TIM_SetCompare3(TIM3,800);
                                break;       
        case 4 : //全关
                                TIM_SetCompare1(TIM3,900);
                        TIM_SetCompare3(TIM3,900);
                                break;       
        case 5 : //全开
                                TIM_SetCompare1(TIM3,0);
                        TIM_SetCompare3(TIM3,0);
                                break;                       
               
        }       

}

使用特权

评论回复
6
发给她更好fh|  楼主 | 2021-4-27 13:12 | 只看该作者
pwm.h

使用特权

评论回复
7
发给她更好fh|  楼主 | 2021-4-27 13:13 | 只看该作者
#ifndef __TIMER_H
#define __TIMER_H
#include "sys.h"
void TIM3_PWM_Init(u16 arr,u16 psc);
#endif

使用特权

评论回复
8
发给她更好fh|  楼主 | 2021-4-27 13:14 | 只看该作者
pwm.c

使用特权

评论回复
9
发给她更好fh|  楼主 | 2021-4-27 13:14 | 只看该作者
#include "timer.h"
#include "GPIO.h"
//#include "usart.h"
//#include "stm32f10x.h"
void TIM3_PWM_Init(u16 arr,u16 psc)
{  
        GPIO_InitTypeDef GPIO_InitStructure;
        TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
        TIM_OCInitTypeDef  TIM_OCInitStructure;
       

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

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

使用特权

评论回复
10
发给她更好fh|  楼主 | 2021-4-27 13:15 | 只看该作者
main.c

使用特权

评论回复
11
发给她更好fh|  楼主 | 2021-4-27 13:16 | 只看该作者
#include "stm32f10x.h"
#include "usart.h"       
#include "delay.h"
#include "sys.h"
#include "max6675.h"
#include "spi.h"
#include "led.h"
#include "timer.h"
#include "pid.h"

int main(void){
        PID  temperature;
    temperature.Set_temperature=50;    //用户设定值
        temperature.proportion=20;
        temperature.integral=5000;   //积分系数
        temperature.differential=1200;   //微分系数
        temperature.T=1000;    //temperature计算周期(采样周期)
    temperature.error_current=0.0;
        temperature.error_last=0;
        temperature.error_sum=0;
        temperature.pid_proportion_out=0;
        temperature.pid_integral_out=0;
        temperature.pid_differential_out=0;
        temperature.pid_out=0;
//        float t1;
        float t2,t3;
        float temp_error;
            float pid_result;
            SystemInit();
            LED_init();
            delay_init();
                uart_init(9600);
            max6675_MONI_init();
            SPI2_Init();
            SPI2_SetSpeed(SPI_BaudRatePrescaler_8);//max6675的串行时钟频率为4.3Mhz
            SPI1_Init();
            SPI1_SetSpeed(SPI_BaudRatePrescaler_8);//max6675的串行时钟频率为4.3Mhz
       
//            PID_Init(50);//PID设置温度
       
            TIM3_PWM_Init(900-1,0);//不分频。PWM频率=72000000/9999+1/143+1=50hz
            TIM_SetCompare1(TIM3,449);       
            TIM_SetCompare2(TIM3,300);//
            TIM_SetCompare3(TIM3,0);
            TIM_SetCompare4(TIM3,900);
            while(1)
                {
                       
                       
                       
                GPIO_ResetBits(GPIOA,GPIO_Pin_8);
                GPIO_ResetBits(GPIOC,GPIO_Pin_12);
                GPIO_ResetBits(GPIOD,GPIO_Pin_2);
                /*温度显示模块*/
//                t1=max6675_readTemperature();
//                printf("the I temperature is:%.2f\n",t1);
//                printf("\n");
            t3=max6675_readTemp_III();
                printf("the III temperature is:%.2f\n",t3);
                printf("\n");       
                delay_ms(300);
                t2=max6675_readTemp();
                printf("the II temperature is:%.2f\n",t2);
                printf("\n");       
                temp_error=t2-t3;
/*==================
        报警函数                               
====================*/
if(temp_error>150)        {
    printf("warning");
    printf("\n");
   t2=temperature.Set_temperature;
}               
                pid_result=pid_control(&temperature,t2);
                printf("the pid_result is:%.2f\n",pid_result);
                printf("\n");
                GPIO_SetBits(GPIOA,GPIO_Pin_8);
                GPIO_SetBits(GPIOC,GPIO_Pin_12);
                GPIO_SetBits(GPIOD,GPIO_Pin_2);
                delay_ms(300);       
        }
}

使用特权

评论回复
12
发给她更好fh|  楼主 | 2021-4-27 13:24 | 只看该作者
代码文件:

链接:https://pan.baidu.com/s/1Zg2zt65BZQi3DycBhGHOAw
提取码:a6jd

使用特权

评论回复
13
cr315| | 2021-4-27 15:11 | 只看该作者
支持一下,期待楼主更多作品

使用特权

评论回复
14
yezunfu317| | 2021-7-26 12:01 | 只看该作者
厉害

使用特权

评论回复
15
庞飞彪| | 2021-11-15 09:43 | 只看该作者
您好,我测试了一下您的代码;有个问题想咨询一下,就我自己测试而言,我设定温度是40度,稳定之后的温度是在39 和 40 之间波动;然后累加误差是个负数,假设为(-200);这里就稍微有点问题,39度情况下,误差是正数,会逐步使得累计误差减小(-200+6),趋向于0;而40度不存在误差,所以累加误差不变;然后又降到39度,累加误差继续趋向于0;然后就存在一个瞬间打破平衡;就是当累计误差变为正数时,就变成了PID调节(之前的都是采用case中的占空比),此时温度就会产生较大波动;大概会变成37--43度,然后再平衡为之前的状态;这种情况您认为哪里可以改进;

使用特权

评论回复
16
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 怎么来的呢

使用特权

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

本版积分规则

37

主题

546

帖子

1

粉丝