stm32+增量式pid+max6675 PWM温度控制
发布日期:2022-01-20 01:07:35 浏览次数:2 分类:技术文章

本文共 7984 字,大约阅读时间需要 26 分钟。

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

本文采用的芯片为STM32F103RCT6

温度芯片为MAX6675
之前spi通讯的max6675代码:
模拟io通讯的max6675代码:

代码写了,具体还没试验过

用电表打过结果,感觉还可以,就粘上来了。

因为选用的热电偶线测温变化太快,所以在中间加了报警,但是里面没有蜂鸣器。后续代码会改进。会加上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
<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
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); }}

代码文件:

链接:

提取码:a6jd

转载地址:https://blog.csdn.net/answerMack/article/details/83900027 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:Ubuntu升级GCC版本教程--支持C++14等cpp代码
下一篇:STM32+MAX6675利用SPI获取实时温度数据程序及代码

发表评论

最新留言

哈哈,博客排版真的漂亮呢~
[***.90.31.176]2024年04月16日 21时57分09秒