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
代码写了,具体还没试验过
用电表打过结果,感觉还可以,就粘上来了。
因为选用的热电偶线测温变化太快,所以在中间加了报警,但是里面没有蜂鸣器。后续代码会改进。会加上CAN总线等设置。只是简单实现温控。
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
////////////////////////////////////////////////////////////////////////////
可能有错误,请评论帮忙指正。谢谢!!
//////////////////////////////////////////////////////////////////////////
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,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;
}
}
pwm.h
#ifndef __TIMER_H
#define __TIMER_H
#include "sys.h"
void TIM3_PWM_Init(u16 arr,u16 psc);
#endif
pwm.c
#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
}
main.c
#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);
}
}
代码文件:
链接:https://pan.baidu.com/s/1Zg2zt65BZQi3DycBhGHOAw
提取码:a6jd