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

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

你可能感兴趣的:(STM32)