(开源项目)立创电赛-桌面温湿度检测仪

时间:2024-10-20 15:21:13

温湿度检测仪-显示屏无线充电版

一、项目概述

(一)背景与目的

最近一直在参加嘉立创举办的一些训练营和比赛来学习一些硬件方面的东西,正巧发现了由盛思瑞传感器冠名赞助的第九届立创电子设计开源大赛。
在这里插入图片描述
并且立创也开展了对应的训练营项目,提供了大量的元器件优惠券\3D打印券,以及每个月两次的PCB免费打样券。
在这里插入图片描述
在这里插入图片描述

也跟随训练营制作了简单的温湿度检测仪

在这里插入图片描述

但是实际使用体验下来效果不是很好,因为采用的一次性电池,没电时候需要更换电池较为麻烦,并且整体重量偏重,数据显示也是用的两个三位8段数码管显示,需要搭配面板设计才能更好的区分温湿度。

后面对其进行升级优化,升级后的功能如下所示。
项目已开源,资料下载可以在立创开源社区获取
点击获取项目资料
https://oshwhub.com/hewei7157/temperature-and-humidity-detector

(二)主要特点和功能

一、精准测量

该温湿度检测仪使用SHT40温湿度传感器模块,能够对环境中的温度和湿度进行极为精准的测量。无论是细微的变化还是较大幅度的波动,都能被敏锐地捕捉到,为你提供可靠的环境数据。
在这里插入图片描述

因为主办方给了传感器模块代金券,所以当前设计的使用SHT传感器模块,并使用1.27*4P的排母进行连接,后面可以改成板载模块进行设计。大概的设计如下图所示。

在这里插入图片描述

在芯片的IIC接口连接10KR的上拉电阻,确保IIC的正常通信,其他注意事项参考SHT40的数据手册。

二、实时显示

检测仪配备1.8寸TFT高清彩屏,能够实时呈现当前环境的温度和湿度数值。你可以随时掌握环境状况的最新动态,无需等待。无论是放置在桌面、挂在墙上还是携带在身边,都能方便快捷地查看温湿度信息。

在这里插入图片描述

三、温度显示单位切换

充分考虑到不同用户的习惯和需求,具备温度显示单位切换功能。你可以轻松在摄氏度(℃)和华氏度(℉)之间进行切换,满足不同地区和使用场景的计量标准要求。

在这里插入图片描述
在这里插入图片描述

四、多种模式可选

为了满足大部分人不同场景的需求,预设了多种不同的工作模式,通过设置不同的工作模式能够快速修改多个设置选项。

例如,

正常模式下各设置选项为:背光时间30s\背光亮度50%\数据刷新间隔10s,可以满足室内日常使用;

监测模式下各设置选项为:背光时间常亮\背光亮度100%\数据刷新间隔1s,以全功率运行持续精准测量并实时显示数据;

节能模式下各设置选项为:背光时间10s\背光亮度25%\数据刷新间隔1分钟,可以最大程度上延长无外部电源的情况下的续航时间。

你可以根据实际情况灵活选择合适的模式,实现最佳的使用效果。
在这里插入图片描述

在这里插入图片描述

五、功能自定义

为了满足用户的个性化需求,这款温湿度检测仪支持功能自定义。你可以根据自己的喜好和使用习惯,设置不同的参数和功能。如背光时间、背光亮度、数据刷新时间等。通过功能自定义,你可以将检测仪打造成最适合自己的工具,提高工作效率和使用体验。
在这里插入图片描述

六、Type-C 供电

支持 Type-C 供电方式,更加通用和便捷。你可以使用常见的 Type-C 充电线连接电源适配器、电脑或移动电源进行充电,为你的使用提供更多便利。
在这里插入图片描述

在这里插入图片描述

七、无线充电

采用先进的无线充电技术,摆脱传统充电线的束缚。使用NU1680无线充电接收IC,支持QI协议最大5W的无线充电,适用于市面上大部分无线充电器。只需将检测仪放置在无线充电器底座上,即可实现便捷充电。

在这里插入图片描述

八、电池供电

设计采用PH2.0-2P端子连接电池,方面后续的更换。内部预留空间可以支持使用最大尺寸为50x30x8mm的3.7V电池供电,在没有外部电源的情况下,可靠的电池可以为检测仪提供持续的电力支持。无论是在户外偏远地区还是在临时没有充电条件的场所,都能确保温湿度检测工作的正常进行。

在这里插入图片描述
在这里插入图片描述

九、电量显示

为了让你随时了解检测仪的电量状态,设计了电压采样电路,通过ADC采集分压电阻数据并根据电池数据转换成不同的电量图标,来直观显示电池的剩余电量。在使用过程中,你可以清楚地看到剩余电量,以便及时进行充电或更换电池,确保检测仪始终处于可用状态。
在这里插入图片描述

十、电池充电

设备搭载TP4054电池管理芯片,支持最大500mA的充电电流。当电池电量不足时,可以通过多种方式进行充电,如 Type-C 供电或无线充电,确保电池能够及时恢复电量,为检测仪的持续使用提供保障。

在这里插入图片描述

十一、多供电自动切换

这款检测仪具备多供电自动切换功能,通过两个MOS管(MOSFET)实现无线充电和Type-C的选择切换;另外一个MOS管实现外部供电和电池供电的选择切换。当使用Type-C或无线充电器供电时,会自动断开电池供电并给电池进行充电。在断开外部供电时它会自动切换到电池供电,确保检测工作的不间断进行。这种智能切换设计,为你的使用提供了极大的便利,确保在断开外部供电后电池有足够的电量,无需担心因电量问题而影响检测。

在这里插入图片描述
在这里插入图片描述

十二、便携设计

小巧轻便的外形设计,PCB尺寸为55mm*35mm,成品含外壳尺寸仅为58x27x39mm,使得这款温湿度检测仪易于携带。无论是出差旅行、户外探险,还是在不同工作场所之间移动,你都可以轻松将它放入口袋、背包或者挂在钥匙链上,随时随地进行温湿度测量。
在这里插入图片描述
在这里插入图片描述

十三、低功耗设计

主控芯片使用STM32G030K8T6,这款芯片相较于常用的STM32F103C8T6采用了低功耗、高能效的内核ARM Cortex-M0+,具有较低的功耗和较高的能效比。并且可以通过PWM对屏幕亮度进行调节,以及设置定时自动息屏,可以极大的延迟无外接电源情况下的续航时间。实测在使用3.7V 200mAH电池的情况下,在全功率运行的情况下续航时间大约为12小时。

二、硬件选择

(一)温湿度传感器

选择了 SHT40温湿度传感器,其具有尺寸小,测量精度高、响应速度快、稳定性好等特点。该传感器能够输出数字信号,方便与微控制器进行连接和数据处理。

在这里插入图片描述

(二)微控制器

采用了 STM32G030K8T6作为核心控制单元。这款微控制器具有丰富的资源和强大的处理能力,能够满足温湿度检测仪的各种功能需求。它可以快速读取传感器数据,并进行数据处理和控制显示等操作。并且相较于STM32F103C8T6具有更高的能效比,更适合电池供电设备使用。

在这里插入图片描述
在这里插入图片描述

注: STM32G030K8T6是 STM32G030K6T6的FLASH容量升级版

(三)显示屏

显示屏选用1.8寸TFT高清彩屏,分辨率128*160,支持显示16位RGB真彩色,能够清晰地显示温湿度数值,方便用户查看。
在这里插入图片描述
在这里插入图片描述

(四)无线充电接收IC

使用NU1680无线充电接收芯片,具有集成度高,芯片体积小/脚位少,外围器件简单等优点。

在这里插入图片描述
在这里插入图片描述

(五)电池管理芯片

使用TP4054作为电池充电管理芯片,具有集成度高,芯片体积小/脚位少,外围器件简单等优点,并且可以支持最大600mA的充电电流。

在这里插入图片描述
在这里插入图片描述

(五)LDO

因为主控设备采用3.3V供电,所以需要将外部输入的5V、电池供电的3.7V转换成3.3V。XC6206P332PR支持最大500mA的电流输出,并且压差电压仅为160mV,适用于电池3.7V的供电情况。

在这里插入图片描述
在这里插入图片描述

(六)按键设计

板载设计3个轻触按键,规格为4.5x4.5x5.5,如下图所示。通过选用不同高度的按键,可以实现不同的效果,目前的设计使得按键刚好略低于顶盖平面。在不同的显示界面、不同的状态下具有不同的功能,在此不进行赘述,在软件编程部分的-代码结构与功能模块中的-3.按键操作当中会详细介绍操作。

在这里插入图片描述

在这里插入图片描述

三、电路设计与 PCB 制作

原理图与PCB使用嘉立创EDA(专业版)绘制,PCB制作通过嘉立创每月免费两次打印制作。

(一)电路设计

在这里插入图片描述

(二)PCB 实物展示

在这里插入图片描述
在这里插入图片描述

四、软件编程

(一)编程环境和语言

通过STM32CubeMX配置引脚等功能并生成项目文件

在这里插入图片描述

使用KEIL MDK 进行编程,采用C 语言编写程序代码,使用HAL(Hardware Abstraction Layer,硬件抽象层)软件开发库。

在这里插入图片描述

(二)代码结构与功能模块

1.传感器数据读取

数据获取代码位置

通过IIC协议读取温湿度传感器的数据,并将返回数据处理
在这里插入图片描述
在这里插入图片描述

数据获取及处理代码
#define SHT40_Write (0x44<<1)   		//写入地址
#define SHT40_Read  ((0x44<<1)+1)   	//读出地址

uint8_t writeData[1] = {0xFD};
uint8_t readData[6] = {0};
double Temperature = 0;
double Humidity = 0;
uint16_t temp = 0;
uint16_t humi = 0;

//SHT40数据获取
HAL_I2C_Master_Transmit(&hi2c1, (uint16_t)SHT40_Write, (uint8_t *)writeData, 1, IIC_MAX_DELAY);
HAL_Delay(10);
HAL_I2C_Master_Receive(&hi2c1, (uint16_t)SHT40_Read, (uint8_t *)readData, 6, IIC_MAX_DELAY);//接收数据
Temperature = (1.0 * 175 * (readData[0] * 256 + readData[1])) / 65535.0 - 45;//数据处理
Humidity = (1.0 * 125 * (readData[3] * 256 + readData[4])) / 65535.0 - 6.0;	
temp = (uint16_t)(Temperature * 10);	//将小数转换成整数
humi = (uint16_t)(Humidity * 10);		

//上述仅作演示用,具体参考项目源码
数据处理参考

具体的数据处理参考下图所示

在这里插入图片描述

2.屏幕数据显示

屏幕显示设计为两个界面:数据显示界面设置界面,分别从两个界面来介绍相应代码。

数据显示界面
数据显示界面设计

如下图所示,数据显示界面分别包括:“温湿度检测仪”、温度图标、温度数据、温度单位、湿度图标、湿度数据、湿度单位以及电量百分比图标。

在这里插入图片描述

数据刷新代码位置

数据显示函数在while中判断,当满足刷新时间到\显示界面改变\未初始化等任一条件时,执行数据获取,并执行数据显示函数

在这里插入图片描述

数据显示逻辑

显示数据函数整体如下图所示,整体的逻辑为:

标题图标单位电量图标显示界面改变时、未初始化时进行显示。

数据显示界面改变时、未初始化时以及数据刷新时间到时进行显示。

显示温度数据时会根据需要显示的数据单位执行不同的操作,例如在显示为华氏度℉时会将测得的数据转换成华氏度,并判断转换后的数据是否大于100,因为设计的屏幕显示区域只能显示4位数字,所以当的数据大于100时将舍去小数位。同时也添加了每个位置的数据改变判断,显示的数据与上一次显示的数据发生改变时才进行刷新,这样既可以减少数据的刷新次数,也可以避免重复刷新影响显示效果。

在这里插入图片描述

数据显示函数

具体的数据显示函数如下所示:

void showData_SHT40(void)//显示SHT40温湿度数据
{
	if(!data_Refresh_Flag || display_Change_Flag)//未初始化或显示界面改变
	{
		Gui_DrawFont_GBK24(TEMP_X + 8,TEMP_Y - 28,BLUE1,BACKGROUND_COLOR,(uint8_t *)"温湿度检测仪");
		showIcon(gImage_temp,TEMP_X + 2,TEMP_Y,TEMP_X + 39,TEMP_Y + 39);//TEMP图标	
	}
	if(tempSetting.option_now == SHOW_UNIT_F)//显示华氏度
	{ 
		fahrenheit  = (temp / 10.0) * 9.0 / 5.0 + 32;//转换为华氏度	
		fahrenheit_int = (int) fahrenheit; //直接舍去小数位
		int fahrenheit_temp = (int)(fahrenheit * 10);
		
		if(fahrenheit_int > 100)//大于100显示三位数
		{
			if( ((fahrenheit_int / 100) !=  fahrenheit_hundreds)|| !data_Init_Flag)//数据改变或界面改变则刷新数据		
			{
				fahrenheit_hundreds = fahrenheit_int / 100;
				Gui_DrawFont_Num32(TEMP_X + 39 + 2,TEMP_Y + 4,RED,BACKGROUND_COLOR,fahrenheit_hundreds);				
			}
			if(((fahrenheit_int % 100 / 10) !=  fahrenheit_ten)|| !data_Init_Flag)//数据改变或界面改变则刷新数据		
			{
				fahrenheit_ten = fahrenheit_int % 100 / 10;
				Gui_DrawFont_Num32(TEMP_X + 39 + 2 + 24,TEMP_Y + 4,RED,BACKGROUND_COLOR,fahrenheit_ten);
			}	
			if(((fahrenheit_int % 10) !=  fahrenheit_one)|| !data_Init_Flag)//数据改变或界面改变则刷新数据		
			{
				fahrenheit_one = fahrenheit_int % 10;				
				Gui_DrawFont_Num32(TEMP_X + 39 + 2 + 24 + 24 + 16,TEMP_Y + 4,RED,BACKGROUND_COLOR,fahrenheit_one);
			}				
		}
		else{ //显示2位数+小数 
			if(((fahrenheit_temp / 100) !=  fahrenheit_ten)|| !data_Init_Flag)//数据改变则刷新数据		
			{
				fahrenheit_ten = fahrenheit_temp / 100;
				Gui_DrawFont_Num32(TEMP_X + 39 + 2 ,TEMP_Y + 4,RED,BACKGROUND_COLOR,fahrenheit_ten);				
			}
			if(((fahrenheit_temp % 100 / 10) !=  fahrenheit_one)|| !data_Init_Flag)//数据改变则刷新数据		
			{
				fahrenheit_one = fahrenheit_temp % 100 / 10;
				Gui_DrawFont_Num32(TEMP_X + 39 + 2 + 24 ,TEMP_Y + 4,RED,BACKGROUND_COLOR,fahrenheit_one);
			}	
			if(!data_Init_Flag || display_Change_Flag){				
				Gui_DrawFont_Num32(TEMP_X + 39 + 2 + 24 + 24,TEMP_Y + 4,RED,BACKGROUND_COLOR,10); //.
			}
			if(((fahrenheit_temp % 10) !=  fahrenheit_decimal)|| !data_Init_Flag)//数据改变则刷新数据	
			{	
				fahrenheit_decimal = fahrenheit_temp % 10;
				Gui_DrawFont_Num32(TEMP_X + 39 + 2 + 24 + 24 + 16,TEMP_Y + 4,RED,BACKGROUND_COLOR,fahrenheit_decimal);			
			}			
		}

	}
	else//显示摄氏度
	{ 
		if((temp/100 != temp_ten )|| !data_Init_Flag)//数据改变则刷新数据
		{ 
			if( 0 <= (temp/100) && (temp/100) <= 9)//判断数据是否正常
			{ 
				Gui_DrawFont_Num32(TEMP_X + 39 + 2,TEMP_Y + 4,RED,BACKGROUND_COLOR,temp/100);
				temp_ten = temp/100;//更新数据			
			}
			else//数据有误 显示上次正常数据
			{ 
				Gui_DrawFont_Num32(TEMP_X + 39 + 2,TEMP_Y + 4,RED,BACKGROUND_COLOR,temp_ten);
			}
		}
		if((temp/10%10 != temp_one)|| !data_Init_Flag)//数据改变则刷新数据
		{ 
			if( 0 <= (temp/10%10) && (temp/10%10) <= 9)//判断数据是否正常
			{
				Gui_DrawFont_Num32(TEMP_X + 39 + 2 + 24,TEMP_Y + 4,RED,BACKGROUND_COLOR,temp/10%10);
				temp_one = temp/10%10;//更新数据	
			}
			else//数据有误 显示上次正常数据
			{ 
				Gui_DrawFont_Num32(TEMP_X + 39 + 2 + 24,TEMP_Y + 4,RED,BACKGROUND_COLOR,temp_one);
			}		
		}
		if(!data_Init_Flag || display_Change_Flag == 1)
		{
			Gui_DrawFont_Num32(TEMP_X + 39 + 2 + 24 + 24,TEMP_Y + 4,RED,BACKGROUND_COLOR,10); //.
		}
		if((temp % 10 != temp_decimal)|| !data_Init_Flag)//数据改变则刷新数据
		{ 
			if( 0 <= (temp % 10) && (temp % 10) <= 9)//判断数据是否正常
			{
				Gui_DrawFont_Num32(TEMP_X + 39 + 2 + 24 + 24 +16,TEMP_Y + 4,RED,BACKGROUND_COLOR,temp % 10);
				temp_decimal = temp % 10;//更新数据	
			}
			else//数据有误 显示上次正常数据
			{ 
				Gui_DrawFont_Num32(TEMP_X + 39 + 2 + 24 + 24 +16,TEMP_Y + 4,RED,BACKGROUND_COLOR,temp_decimal);
			}		
			Gui_DrawFont_Num32(TEMP_X + 39 + 2 + 24 + 24 + 16 + 24,TEMP_Y  + 4,RED,BACKGROUND_COLOR,13 + tempSetting.option_now);//℃\℉
		}
		
	}	
	if(!data_Init_Flag || display_Change_Flag)//未初始化时或显示界面改变时刷新单位
	{	
		Gui_DrawFont_Num32(TEMP_X + 39 + 2 + 24 + 24 + 16 + 24,TEMP_Y  + 4,RED,BACKGROUND_COLOR,13 + tempSetting.option_now);//℃\℉
		showIcon(gImage_humi,HUMI_X + 2,HUMI_Y,HUMI_X + 39,HUMI_Y + 39);//HUMI图标
	}
//	showIcon(gImage_humi,HUMI_X + 2,HUMI_Y,HUMI_X + 39,HUMI_Y + 39);//HUMI图标
	if((humi/100 != humi_ten)|| !data_Init_Flag)//数据改变则刷新数据
	{ 
		if( 0 <= (humi/100) && (humi/100) <= 9)//判断数据是否正常
		{ 
			Gui_DrawFont_Num32(HUMI_X + 39 + 2,HUMI_Y + 4,BLUE,BACKGROUND_COLOR,humi/100);
			humi_ten = humi/100;//更新数据
		}
		else//数据有误 显示上次正常数据
		{ 
			Gui_DrawFont_Num32(HUMI_X + 39 + 2,HUMI_Y + 4,BLUE,BACKGROUND_COLOR,humi_ten);
		}				
	}
	if((humi/10%10 != humi_one)|| !data_Init_Flag)//数据改变则刷新数据
	{ 
		if( 0 <= (humi/100) && (humi/100) <= 9)//判断数据是否正常
		{
			Gui_DrawFont_Num32(HUMI_X + 39 + 2 + 24,HUMI_Y + 4,BLUE,BACKGROUND_COLOR,humi/10%10);
			humi_one = humi/10%10;//更新数据			
		}
		else//数据有误 显示上次正常数据
		{
			Gui_DrawFont_Num32(HUMI_X + 39 + 2 + 24,HUMI_Y + 4,BLUE,BACKGROUND_COLOR,humi_one);
		}			

	}
	if(display_Change_Flag || !data_Init_Flag )	Gui_DrawFont_Num3