首页 > 其他分享 >温度的监测与控制(二)

温度的监测与控制(二)

时间:2024-09-18 15:51:08浏览次数:12  
标签:控制 Temperature 加热 OLED Threshold 监测 PWM 温度

一、回顾

           时隔好久才开始补充第二部分的内容,首先总结一下上篇的学习内容:

1、简单了解了NTC热敏电阻的基本概念和使用的原理。

2、对ADC的模拟量取值和代码进行了简单的学习。

3、通过计算公式将ADC转换成电压值,再通过并联电阻的大小进行阻值的计算。

4、最后有了阻值,我能就可以进行温度的查表,通过二分法的方式,一步步找到对应的温度值,可以通过特殊方式进行精确到小数点后几位。

二、控温方式

        接下来进行加热设备的温度控制,因场景不需要很高的精确温度,所以我们使用的是简单的3D打印机中的热床加热垫,因为他既可以进行加温加热,有自带嵌入式NTC的传感器,可以实时监测加热垫中部的实际温度(因加热的时间,NTC的数值可能会慢半拍,还是存在误差,有需要可自行调整)。

                                       

        以下是加热垫相关参数:

        我思考的温度控制有两种方式:

1、一种是最简单的通过24V高电平对加热垫进行发送50%占空比的脉冲,当达到目标温度值+1的温度数值后拉低电平,停止加热垫的工作,当NTC监测到实际温度小于目标温度值-1时,再将对加热垫进行PWM脉冲的发送,使其开始加热,让加热垫始终保持在目标温度上下1度的浮动。(加一减一是为了能减少加热垫的PWM频繁开关)

2、另一种方法是我们自己将PWM占空比所对应的加热垫加热温度测试出来,形成固定的表格(就是一直发送百分之多少的占空比可以将温度控制在多少度,优点是更精确,但是比较麻烦),职中方式后期再做一下吧。

三、具体步骤

        先实现最简单的功能思路(结合上篇笔记中的函数):

1、功能函数

1、我利用了OLED13寸的屏幕进行功能调试所以加入了OLED.c和OLED.h两个文件(后续会放在整个代码中开源),通过OLED屏幕的调试,我们首先将NTC监测到的温度值和当前的目标温度值显示在屏幕上,我直接使用了一个自定义的函数。

//主函数文件的开头定义:

//三个加热垫的目标温度值(全局变量)
uint32_t  Temperature_Threshold_1 = 30;  											//预设的目标温度
uint32_t  Temperature_Threshold_2 = 60;  											//预设的目标温度
uint32_t  Temperature_Threshold_3 = 60;  											//预设的目标温度

//三个加热垫的编号,当做参数使用(可以根据需要显示具体哪一个加热垫)
#define			TIM1_PWM			1				//1号加热板
#define			TIM2_PWM			2				//2号加热板
#define			TIM3_PWM			3				//3号加热板

//--------------------------------------显示函数------------------------------------------
/**
  * 函    数:温度调试显示(Debug用,意义不大)
  * 参    数:Ch 加热垫的对象
  * 参    数:ADC_Channel 多取几次的到平均值
  * 参    数:Ch 加热垫的对象
  * 返 回 值:无
  */
void OLED_Temperature(Channel_Value *Ch,uint8_t ADC_Channel,uint8_t Line)
{
	Ch->ADValue = Get_Adc_Average(5,ADC_Channel);  //获取AD0转换的值(5毫秒采集1次,5次的平均值)(Get_Adc_Average为上篇文章中获取ADC模拟量的函数)
	Ch->Voltage = Get_Vout(Ch->ADValue);  //(Get_Vout为上篇文章中求电压的函数)
	Ch->Resistance = Get_Resistance(Ch->ADValue); //(Get_Resistance为上篇文中求阻值的函数)
	Ch->Temperature = Get_Temperature(Ch->Resistance,Temp_Resistance_Tab_2);  //(Get_Temperature为上篇文章中查表求温度值的函数)
	OLED_ShowString(Line, 2, "T :     C");
	OLED_ShowNum(Line,3,ADC_Channel + 1,1);
	OLED_ShowDouble(Line, 5,Ch->Temperature, 1); 	//显示温度值
	
	OLED_ShowDouble(1,13,Temperature_Threshold_1,0);  //显示当前的温度阈值
	OLED_ShowDouble(2,13,Temperature_Threshold_2,0);  //显示当前的温度阈值
	OLED_ShowDouble(3,13,Temperature_Threshold_3,0);  //显示当前的温度阈值
	OLED_ShowChar(1,16,'C');
	OLED_ShowChar(2,16,'C');
	OLED_ShowChar(3,16,'C');
}

        这样主函数的while循环中我们可以直接调用OLED_Temperature函数显示某个加热板:

OLED_Temperature(&ch1,ADC_Channel_0,1);
OLED_Temperature(&ch2,ADC_Channel_1,2);
OLED_Temperature(&ch3,ADC_Channel_2,3);

2、当前我们只是显示出了温度和程序默认的目标温度值,还没有具体打开加热功能,后面我又写了一个单独打开某个加热垫的加热功能(就是打开PWM不停发脉冲)的函数。

//-------------------------------------加热开关---------------------------------------
/**
  * 函    数:控制加热垫的开关
  * 参    数:ch 加热垫的结构体对象
  * 参    数:TIMX_PWM 要打开的加热垫
  * 返 回 值:无
  */
void OPEN_CLOSE(Channel_Value *ch,uint8_t TIMX_PWM)
{
    //如果是1号加热板
	if(TIMX_PWM == 1)
	{
        //如果1号加热板的NTC温度到达设定的目标温度+1的温度之后
		if(ch->Temperature > Temperature_Threshold_1 + 1)
		{
            //就关掉PWM的占空比,停止加热
			PWM_SetCompare1(TIMX_PWM,0);
		}
        //如果1号加热垫NTC小于等于目标温度值-1,并且和目标温度相差5度以上,则就开启加温(因为温度相差较多,PWM占空比就大一些)
		if(ch->Temperature <= Temperature_Threshold_1 - 1 && ((Temperature_Threshold_1 - ch->Temperature) > 5))
		{
			PWM_SetCompare1(TIMX_PWM,500 - 1);
		}
        //如果1号加热垫NTC小于等于目标温度值-1,并且和目标温度相差5度以内,则就开启加温(因为温度相差很小,PWM占空比就小一些,慢慢加热升温)
		if(ch->Temperature <= Temperature_Threshold_1 - 1 && (Temperature_Threshold_1 - ch->Temperature) <= 5)
		{
			PWM_SetCompare1(TIMX_PWM,100 - 1);
		}
	}
    //2号加热垫与上面同理(没加升温快慢的代码,可自行加上,也可不加)
	else if(TIMX_PWM == 2)
	{
		if(ch->Temperature > Temperature_Threshold_2 + 1)
		{
			PWM_SetCompare1(TIMX_PWM,0);
		}
		if(ch->Temperature <= Temperature_Threshold_2 - 1)
		{
			PWM_SetCompare1(TIMX_PWM,500 - 1);
		}
	}
    //3号加热垫与上面同理(没加升温快慢的代码,可自行加上,也可不加)
	else if(TIMX_PWM == 3)
	{
		if(ch->Temperature > Temperature_Threshold_3 + 1)
		{
			PWM_SetCompare1(TIMX_PWM,0);
		}
		if(ch->Temperature <= Temperature_Threshold_3 - 1)
		{
			PWM_SetCompare1(TIMX_PWM,500 - 1);
		}
	}
}

        这样主函数中就可以循环调用开启OPEN_CLOSE函数,开启各个通道的加热功能了(当然这里面包包含了PWM初始化和其他功能函数,会存放在PWM.c和PWM.h两个文件中,后面会开源自取):

OPEN_CLOSE(&ch1,PWM_TIM1);  //通道1的加热开关开启
OPEN_CLOSE(&ch2,PWM_TIM2);  //通道2的加热开关开启
OPEN_CLOSE(&ch3,PWM_TIM3);  //通道3的加热开关开启

3、现在加热功能也开启了,但是哪个加热设备正在加热哪个加热设备到达或超过目标温度没有在加热,为了能更直观的看出来,我又写了一个显示函数来观察加热垫的开关状态:

//----------------------------------打印当前通道的开关状态-----------------------------------
//这个函数很简单,就是通过TIM_GetCapturex函数来判断当前通道的PWM是否有占空比,如果没有就显示“关”字,反之显示“开”字
void OLED_Show_OPENCLOSE(void)
{
	OLED_ShowString(4,1,"1:");
	OLED_ShowString(4,7,"2:");
	OLED_ShowString(4,13,"3:");
	if(TIM_GetCapture2(TIM3))
	{
		OLED_ShowChar_zh(4,2,STARTA16x16,0);  //STARTA16x16是生成的汉字数组
	}
	if(TIM_GetCapture3(TIM3))
	{
		OLED_ShowChar_zh(4,5,STARTA16x16,0);
	}
	if(TIM_GetCapture4(TIM3))
	{
		OLED_ShowChar_zh(4,8,STARTA16x16,0);
	}
	if(!TIM_GetCapture2(TIM3))
	{
		OLED_ShowChar_zh(4,2,STARTA16x16,2);
	}
	if(!TIM_GetCapture3(TIM3))
	{
		OLED_ShowChar_zh(4,5,STARTA16x16,2);
	}
	if(!TIM_GetCapture4(TIM3))
	{
		OLED_ShowChar_zh(4,8,STARTA16x16,2);
	}
}

可以直接在主函数中循环显示:(函数中的STARTA16x16汉字数组在整个工程的OLED_Font.h文件中,后面开源可自己查看)。

OLED_Show_OPENCLOSE();  //OLED显示加热垫是开启的还是关闭的

2、OLED功能界面

        还有一些功能函数,放在这个模块来写是因为:我们需要通过简单的三个按键来设置每个加热垫所对应的目标温度值,来达到我们想要实现的三个加热设备能分别控制的目的(但后期我有考虑到如果三个加热设备同时给一块空间加热,设置相同的目标温度值会不会使整个空间的温度误差变大,所以整体项目还不够严谨,只能在要求不高的环境下使用,大家有什么好方法也可以分享学习)。

        所以我利用OLED屏幕、结合了SET按键、UP按键、DOWN按键,加入了两个界面分别是:

1、主界面显示:显示三个加热设备的NTC当前温度、目标温度以及开关状态(主函数就是主界面)。

2、设置界面(有三层):

(1)1号加热设备的目标温度设置,可进行上下设置目标温度数值。

(2)2号加热设备的目标温度设置,可进行上下设置目标温度数值。

(3)3号加热设备的目标温度设置,可进行上下设置目标温度数值。

在这就添加了一个设置界面函数:
 

//---------------------------------------设置菜单函数----------------------------------
//因为有三个加热设备,所以设置了三层的设置界面,根据SET按键的键值不同来进行显示具体是哪个设备的设置界面
void OLED_MENU(void)
{
	OLED_ShowChar(3,11,'C');
	while(KeyNum_1)
	{
		if(KeyNum_1 == 1)
		{
			OLED_ShowString(2,6,"NTC_1");
			OLED_ShowDouble(3,6,Temperature_Threshold_1,1);
		}
		else if(KeyNum_1 == 2)
		{
			OLED_ShowString(2,6,"NTC_2");
			OLED_ShowDouble(3,6,Temperature_Threshold_2,1);
		}
		else if(KeyNum_1 == 3)
		{
			OLED_ShowString(2,6,"NTC_3");
			OLED_ShowDouble(3,6,Temperature_Threshold_3,1);
		}
		
		Temperature_Threshold();  //设置各个加热垫的目标温度值
		
		Key_GetNum_1();  //切换要设置的加热垫界面
	}
	OLED_Clear();
}

        大家也能看出来,在这个函数之前,我们需要首先获取到当前SET按键的键值是多少才能显示相应的设置界面(获取SET按键的键值):

//-----------------------------------设置菜单页面标志---------------------------------------
void Key_GetNum_1(void)
{
	if (GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_4) == 0)			//读PB1输入寄存器的状态,如果为0,则代表按键1按下
	{
		Delay_ms(20);											//延时消抖
		while (GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_4) == 0);	//等待按键松手
		Delay_ms(20);											//延时消抖
		if(KeyNum_1 == 0)
		{
			KeyNum_1 = 1;  //NTC1号的设置界面
		}
		else if(KeyNum_1 == 1)
		{
			KeyNum_1 = 2;  //NTC2号的设置界面
		}
		else if(KeyNum_1 == 2)
		{
			KeyNum_1 = 3;  //NTC3号的设置界面
		}
		else if(KeyNum_1 == 3)
		{
			KeyNum_1 = 0;  //回到主界面进行显示
		}
	}
}

        现在我们就可以进入到了三个设备的设置界面,接下来就是要设置这个界面中的目标温度值的大小了,我就用了通过UP按键和DOWN按键的简单加减方法进行设置。以下是这两个按键的功能函数:

//-------------------------------设置目标温度-------------------------------------
void Temperature_Threshold(void)
{
	if (GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_5) == 0)			//读PB11输入寄存器的状态,如果为0,则代表按键2按下
	{
		Delay_ms(20);											//延时消抖
        //长按快加
		while (GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_5) == 0)
		{
			Delay_ms(200);
            //根据SET按键键值的不同,程序会让加减按键设置不同设备的目标温度值
			if(KeyNum_1 == 1)
			{
				Temperature_Threshold_1++;
				OLED_ShowDouble(3,6,Temperature_Threshold_1,1);
			}
			else if(KeyNum_1 == 2)
			{
				Temperature_Threshold_2++;
				OLED_ShowDouble(3,6,Temperature_Threshold_2,1);
			}
			else if(KeyNum_1 == 3)
			{
				Temperature_Threshold_3++;
				OLED_ShowDouble(3,6,Temperature_Threshold_3,1);
			}
		}
	}
	if (GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_6) == 0)			//读PB11输入寄存器的状态,如果为0,则代表按键2按下
	{
		Delay_ms(20);											//延时消抖
		//长按快减
		while (GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_6) == 0)
		{
			Delay_ms(200);
			if(KeyNum_1 == 1)
			{
				Temperature_Threshold_1--;
				OLED_ShowDouble(3,6,Temperature_Threshold_1,1);
			}
			else if(KeyNum_1 == 2)
			{
				Temperature_Threshold_2--;
				OLED_ShowDouble(3,6,Temperature_Threshold_2,1);
			}
			else if(KeyNum_1 == 3)
			{
				Temperature_Threshold_3--;
				OLED_ShowDouble(3,6,Temperature_Threshold_3,1);
			}
		}
	}
}

        当然我们也可以通过其他内容来设置可设置的温度范围,超过范围不允许等代码逻辑(这就不加了)。

        接下来就可以在主函数循环中添加我们的界面函数了:

if(KeyNum_1 > 0)
{
    OLED_Clear();  //屏幕清屏,不清会导致显示重叠
	OLED_MENU();   //设置界面函数
}

        最后,我们可以再将温度显示的慢一些,以至于能用肉眼不到数字:

Delay_ms(300);

        基本就完成了。上面的功能函数很齐全了,下面把整个主函数的内容连接起来:

//-----------------------------------主函数---------------------------------------------
int main(void)
{
	OLED_Init();			//OLED初始化
	AD_Init();				//AD初始化
	PWM_Init();				//加热垫引脚
	Key_Init();				//按键初始化
	
	//开机
	OLED_ShowChar_zh(2,4,STARTA16x16,0);
	OLED_ShowChar_zh(2,5,STARTA16x16,1);
	Delay_ms(1000);	
	OLED_Clear();
	
	while (1)
	{
		Key_GetNum_1();
		
		OLED_Temperature(&ch1,ADC_Channel_0,1);
		OLED_Temperature(&ch2,ADC_Channel_1,2);
		OLED_Temperature(&ch3,ADC_Channel_2,3);
		
		OPEN_CLOSE(&ch1,PWM_TIM1);  //通道1的加热开关开启
		OPEN_CLOSE(&ch2,PWM_TIM2);
		OPEN_CLOSE(&ch3,PWM_TIM3);
		
		OLED_Show_OPENCLOSE();  //OLED显示加热垫是开启的还是关闭的
		
		if(KeyNum_1 > 0)
		{
			OLED_Clear();
			OLED_MENU();   //设置界面
		}
		
		Delay_ms(300);
	}
}

        以上就是整个“温度的监测与控制”的所有程序,中间或许有些逻辑和想法不够严谨,自己也发现了一些问题,但简单实现功能,拿出来练习练习代码和电路还是可以的,有大神能够指出问题或添加更加完善的思维想法和逻辑你就再好不过。后续会找时间在把PCB板的电路图完善一下,让路过的大神只指点一下。

附上工程代码供大家修改使用:

通过网盘分享的文件:测温控温加热垫
链接: https://pan.baidu.com/s/1VGAZZNw4IPr_OVfWIaQf-A?pwd=ya7u                                      提取码: ya7u

标签:控制,Temperature,加热,OLED,Threshold,监测,PWM,温度
From: https://blog.csdn.net/jiahongtang/article/details/142327600

相关文章

  • 合宙Air201模组LuatOS:PWRKEY控制,一键解决解决关机难问题
    不知不觉间,我们已经发布拉期课程:helloworld初体验,点灯、远程控制、定位和扩展功能,你学的怎么样?很多伙伴表示已经有点上瘾啦!合宙Air201,如同我们一路升级打怪的得力法器,让开发愈发得心应手。本期,我们将进一步学习合宙Air201应用示例——PWRKEY控制关机功能 PWRKEY控制关机功能 编......
  • 制导弹药(导弹) 中制导律+末制导律+导引头控制 打击目标弹道程序
    声明:本文仅用于学习交流用途1.引言最近用matlab写了一个空地导弹的有控弹道程序,现在把它分写出来:导弹从空中发射后,分别经过(1)中制导段;(2)末制导段,,,两个部分。在这里,中制导律的俯仰和偏航通道用的是程序角控制,末制导律俯仰通道用的弹道成型制导律,偏航通道用的比例导引。......
  • 在 MySQL InnoDB 中,允许开发人员在 MySQL 事务中手动控制锁 - 称之为“用户级锁”。
    在MySQLInnoDB中,允许开发人员在MySQL事务中手动控制锁-称之为“用户级锁”。用户级锁不直接与InnoDB的内部行或表锁定机制交互。用户级锁使用GET_LOCK()、RELEASE_LOCK()函数进行管理。用户级锁提供了更细粒度的控制,让你能在应用层实施自定义加锁策略。主要函数包括:GET_L......
  • 器件:PT2258音量控制器
    1序  PT2258为台湾普诚电子于2000年7月开发出的由iic总线控制的音量控制IC;音量调节范围[-79,0]dB,调节步长1dB;2工作原理  2.1工作原理    PT2258内部集成了可编程电阻网络,通过对Vin进行分压处理后输出Vout,实现音量控制;    当音量放大倍数为0dB时,Vin=Vout音量最......
  • 解决软件在windows11控制面板、电脑软件管家中图标显示不正确的问题
    解决软件在windows11控制面板、电脑软件管家中图标显示不正确的问题问题描述:在windows11控制面板显示错误的问题是innosetup的iss文件配置错误。需要在[Setup]下添加UninstallDisplayIcon,如下:#defineMyAppIconName"D:\VUE_projects\Alarm\pack\appIcon2.ico"[Setup]//设......
  • 5、SAP定义科目组和字段控制
    定义解释用于创建科目组,并进行输入控制,即在输入科目时,哪些自动允许输入,哪些自动隐藏等。科目组是将性质类似的科目分类,组要维护前台会计科目主数据。(统驭科目–字段状态组–凭证输入)。后台配置路径:SPRO-财务会计-总帐会计-总帐科目-主数据-准备-定义科目组事务代码:OBD4-......
  • 内涝积水监测系统为应急防汛工作提供信息化支持
    随着又一轮台风的来临,各大城市纷纷进入了防汛防涝的紧急状态。面对暴雨天气带来的挑战,相关部门需要积极采取措施,全力以赴确保人民群众的生命财产安全。 城市化、工业化的发展,使得城市人口越来越密集,自然排水能力也越来越差,十分依赖排水系统建设。然而当暴雨来临时,下穿隧道、下沉式......
  • go实战全家桶优化goweb实现权限控制
    UML开源water/goweb控制端typeIrpcCheckAllowedinterface{   //测试开关、是否检查权限,方便测试可以关闭   IfCheckRes()bool   IfCheckSession()bool   //根据token获取useid的实现   RpcUserIdGetBySession(ctx*gin.Context,token......
  • 数据控制语言(DCL,Data Control Language)
    目录GRANT语句REVOKE语句权限类型数据控制语言(DCL,DataControlLanguage)用于管理数据库中的权限和访问控制。DCL语句主要用于控制用户对数据库对象的访问权限。常见的DCL语句有GRANT和REVOKE。GRANT语句GRANT语句用于授予用户或角色对数据库对象(如表、视图......
  • 【视频教程】手把手AppWizard轻松制作一个emWin滑动主界面控制框架,任意跳转控制(2024-0
    现在的新版AppWizard已经比较好用,用户可以轻松的创建各种项目常规界面。比如早期创建一个支持滑动的主界面框架,并且可以跳转各种子界面,仅仅界面布局和各种图片格式转换都要花不少时间,而现在使用AppWizard,可以说轻轻松松,毫不费力。用户唯一要做的就是根据自己的芯片性能做一定的速度......