基于CW32的PID温度控制系统

BD网盘链接:
https://pan.baidu.com/s/1X-KQgwbwAp57bzcSqg3X2w
提取码:jetf
相关视频:基于CW32的PID温度控制系统

一、简介


1.PID温控系统是一种常用的控制系统,用于实现对温度变量的精确控制。PID算法根据当前的温度误差以及误差的变化率,计算一个控制信号,用于调节加热器的输出。以下是PID算法的三个主要组成部分:

①比例(Proportional)控制:比例控制是根据当前的温度误差来计算控制信号。具体而言,通过将设定温度与实际温度之间的差异称为误差,然后将误差乘以一个比例增益参数,得到一个修正值。这个修正值与控制设备的输出信号相加,以调整温度控制。

②积分(Integral)控制:积分控制用于处理长期的温度误差。它通过对温度误差进行积分来计算一个积分误差。积分误差乘以积分增益参数,并且在一段时间内进行积累,得到一个修正值。积分控制可以帮助消除持续的稳态误差,使系统更快地达到设定温度。

③微分(Derivative)控制:微分控制用于处理温度变化的速率。它通过计算温度误差的变化率,即误差的导数,得到一个微分值。微分值乘以一个微分增益参数,用于调整修正值。微分控制可以帮助系统更快地响应温度变化,以防止过冲。
通过结合比例、积分和微分部分的修正值,PID控制算法可以计算出最终的控制信号。这个控制信号会被传递给加热器,以控制温度的变化。

二、所需物料


本实验用到了CW32-48大学计划开发板OK、温控实验模块及Keil5开发环境。
在这里插入图片描述
在这里插入图片描述

温控模块电路原理图

三、参考文章


PID控制算法的具体原理可参考以下链接中的文章

1)https://zhuanlan.zhihu.com/p/39573490
2)https://zhuanlan.zhihu.com/p/347372624
3)https://zhuanlan.zhihu.com/p/41962512

利用热敏电阻采集温度的原理及方法可参考往期文章及视频。

四、核心代码

mian.c:

#include "config.h"

unsigned char face = 0;       //界面变量
unsigned char face_brush = 0; //界面刷新频率控制

void InitSystem(void)  
{
	RCC_Configuration(); 			 //时钟配置
	ADC_Configuration(); 			 //ADC采集通道配置,采集NTC热敏电阻电压
	PID_Configuration(); 			 //PID参数配置
	GPIO_KEYS_Configuration(); //按键GPIO配置
	PWM_Init();					 			 //两路PWM输出初始化
	Lcd_Init();								 //TFT屏幕初始化
	BTIM_Init();				 			 //定时器初始化
}

void Interface(void)  //人机交互界面
{
	if ( face_brush > 200 )  //200ms刷新一次
	{
		face_brush = 0;
		switch(face)
		{
			case 0://显示PV和SV,该界面下,可以设定SV
				TFTSHOW_STRING_HEADLINE(0,0,"  PID  Control  ");
				TFTSHOW_STRING(2,0,"REAL_Temper(℃):");
				TFTSHOW_STRING(4,0,"   P V:       ");
				TFTSHOW_FLOAT_NUMBER(4,8,pid.Pv);
				TFTSHOW_STRING(6,0,"SET_Temper(℃):");
				TFTSHOW_STRING(8,0,"   S V:       ");
				TFTSHOW_FLOAT_NUMBER(8,8,pid.set_Sv);
				break;
			case 1://该界面下,可以设定P参数
				TFTSHOW_STRING_HEADLINE(0,0,"  PID  Control  ");
				TFTSHOW_STRING(2,0,"SET PID Control:");
				TFTSHOW_STRING(4,0,"    P :       ");
				TFTSHOW_INT_NUMBER(4,8,pid.set_Kp);
				break;
			case 2://该界面下,可以设定I参数
				TFTSHOW_STRING_HEADLINE(0,0,"  PID  Control  ");
				TFTSHOW_STRING(2,0,"SET PID Control:");
				TFTSHOW_STRING(4,0,"    I :       ");
				TFTSHOW_FLOAT_NUMBER(4,8,pid.set_Ki);
				break;
			case 3://该界面下,可以设定D参数
				TFTSHOW_STRING_HEADLINE(0,0,"  PID  Control  ");
				TFTSHOW_STRING(2,0,"SET PID Control:");
				TFTSHOW_STRING(4,0,"    D :       ");
				TFTSHOW_INT_NUMBER(4,8,pid.set_Kd);
				break;
			case 4://该界面下,可以设定Out0,即修正值
				TFTSHOW_STRING_HEADLINE(0,0,"  PID  Control  ");
				TFTSHOW_STRING(2,0,"SET PID Control:");
				TFTSHOW_STRING(4,0,"   OUT0 :      ");
				TFTSHOW_INT_NUMBER(4,10,pid.set_Out0);
				break;
		}
	}
}

int main()           //主函数
{
	InitSystem();      //系统初始化
	while(1)
	{
		PID_Calc();      //PID运算
		Interface();	   //人机交互界面
		Keys_Function(); //按键控制		
	}
}

pwm.c:

#include "pwm.h"

void PWM_Init(void)
{
	RCC_APBPeriphClk_Enable1(RCC_APB1_PERIPH_GTIM2,ENABLE); //使能GTIM2时钟
	
	__RCC_GPIOA_CLK_ENABLE();   //使能GPIOA时钟
	
	PA01_AFx_GTIM2CH2();        //打开PWM输出通道
	PA02_AFx_GTIM2CH3();
	
	GPIO_InitTypeDef GPIO_InitStruct;

  GPIO_InitStruct.IT = GPIO_IT_NONE; 
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;  //推挽输出模式
  GPIO_InitStruct.Pins = GPIO_PIN_1|GPIO_PIN_2;
  GPIO_InitStruct.Speed = GPIO_SPEED_HIGH;
  GPIO_Init(CW_GPIOA, &GPIO_InitStruct);
	
	GTIM_InitTypeDef GTIM_Initstructure;     //通用定时器
	GTIM_Initstructure.Mode=GTIM_MODE_TIME;  //计数模式
	GTIM_Initstructure.OneShotMode=GTIM_COUNT_CONTINUE; //连续计数
	GTIM_Initstructure.Prescaler=GTIM_PRESCALER_DIV64; //预分频
	GTIM_Initstructure.ReloadValue=2000-1; //ARR,计数重载周期2000
	GTIM_Initstructure.ToggleOutState=DISABLE;
	GTIM_TimeBaseInit(CW_GTIM2,&GTIM_Initstructure);
	
	GTIM_OCInit(CW_GTIM2,GTIM_CHANNEL3,GTIM_OC_OUTPUT_PWM_LOW); //GTIM2输出比较,CH3、CH2
	GTIM_OCInit(CW_GTIM2,GTIM_CHANNEL2,GTIM_OC_OUTPUT_PWM_LOW); //有效占空比为低电平
	GTIM_Cmd(CW_GTIM2,ENABLE); //使能GTIM2
}

void PWM1_Output(uint32_t value)
{
	GTIM_SetCompare3(CW_GTIM2,value);  //设置GTIM2通道3的CCR
}

void PWM2_Output(uint32_t value)
{
	GTIM_SetCompare2(CW_GTIM2,value);  //设置GTIM2通道2的CCR
}

void PWM_ALL_Output(uint32_t value)  //PWM1、2同步输出
{
	PWM1_Output(value);
	PWM2_Output(value);
}

pid.c:

#include "pid.h"

PID pid;    //定义PID结构体变量pid

void PID_Configuration(void)   //PID参数初始化配置 
{
	pid.Sv     = 55;
	
	pid.Kp     = 350;  //比例系数
	pid.Ki     = 10;   //积分系数
	pid.Kd     = 38;   //微分系数
	
	pid.Ek_1   = 0;    //上一次偏差
	pid.T      = 400;  //PID计算周期

	pid.cnt    = 0;    
	pid.cycle  = 2000; //PWM周期
	pid.Out0   = 500;  //PID修正值
	
	pid.set_Sv = pid.Sv;
	pid.set_Kp = pid.Kp;
	pid.set_Ki = pid.Ki;
	pid.set_Kd = pid.Kd;
	pid.set_Out0 = pid.Out0;
}

float Get_Pv(void)  //Pv意为当前测量值,即当前温度
{
	return Get_Temperture();
}

void PID_Calc(void)    //PID算法
{
	float Pout,Iout,Dout;
	float out;
	
	if ( pid.cnt > pid.T )   //控制计算周期
	{
		pid.cnt = 0;
		
		pid.Pv = Get_Pv();       
		pid.Ek = pid.Sv - pid.Pv; //计算偏差
		pid.SumEk += pid.Ek;  //偏差累积
		
		
		Pout = pid.Kp * pid.Ek;  //比例控制
			
		Dout = pid.Kd * (pid.Ek - pid.Ek_1);  //微分控制
		
		if(pid.Pv>(pid.Sv-1))   //当测量值非常接近目标值的时候加入积分控制
		{
			Iout = pid.Ki * pid.SumEk;           //积分控制
			out = Pout + Iout + Dout + pid.Out0; 
		}
		else 	out  = Pout + Dout + pid.Out0;  //测量值距离目标值较远时只使用PD控制
		if ( out > pid.cycle ) pid.Out = pid.cycle; //限幅
		else if ( out < 0 )    pid.Out = 0;
		else                   pid.Out = out;
		PWM_ALL_Output(pid.Out);  //控制PWM输出
		pid.Ek_1 = pid.Ek;  //进行下一次PID运算之前,将本次偏差变为上次偏差
	}
}

五、实验最终现象

在这里插入图片描述

  • 23
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值