云计算百科
云计算领域专业知识百科平台

STM32毕设项目分享:基于STM32的办公环境与健康监控系统

一、成品简介
1.实物成品

   成品展示:

2.物联网成品

手机物联网APP展示:

二、项目简介
1.具体设计内容

        办公环境与健康监控系统可以实现对办公环境中温湿度、甲醛浓度、CO₂浓度、光照强度等核心参数的实时采集;当监测到温湿度、甲醛浓度、CO₂浓度超出预设阈值时,系统自动开窗通风或关闭窗户;当光照强度过暗或过亮时,自动控制开灯或关灯。如果监测到久坐时长、用眼疲劳等用户办公状态,自动触发语音播报提醒,并支持在电脑端同步查看数据,为用户提供个性化健康办公方案。

2.核心任务

1.可以监测办公环境的温湿度、甲醛、CO2浓度、光照强度等;

2.当温湿度、甲醛浓度、CO2浓度超出预设阈值时,系统自动控制开窗或关窗设备进行通风或封闭;

3.当光照强度过暗或过亮时,自动控制照明设备开启或关闭,实现环境参数的自适应调节;

4.实现对用户久坐时长、用眼疲劳状态的实时检测,当检测到用户久坐超过预设时间或用眼过度时,系统触发语音播报模块,发出起身活动、远眺休息等健康提醒;

5.为用户提供个性化健康办公方案,支持电脑端同步查看。

3.系统框图

4.系统流程

5.课题研究目的及意义

        据统计,现代职场人群日均办公时长普遍超过8小时,办公环境质量不佳与不良办公习惯,已成为引发颈椎病、干眼症、呼吸系统不适等各类职业疾病的主要诱因。如何改善办公环境、引导健康办公习惯、降低职业疾病发生风险就显得尤为重要。对职业疾病诱因的分析表明,绝大多数的职场健康问题,都是由于长期处于温湿度失衡、空气质量差的办公环境,以及久坐不动、用眼过度等不良习惯所引起的;而传统办公场景中,超过九成的环境监测依赖人工检测或单一设备报警,健康提醒也缺乏针对性,无法实现全时段、全方位的健康管理。目前,智能办公健康管理系统的研发,成为改善职场办公环境、保障职场人群健康的主要研究对象之一。

        国内外现有的办公环境监测设备与健康管理工具,多数功能单一、集成化程度低,要么只能监测单一环境指标,要么仅能提供笼统的健康提醒,不利于全面推广与应用。因此,研发一套功能集成、成本可控、精准智能的办公环境与健康监控系统,具有重要的现实意义与应用价值。为了尽可能减少由于办公环境与办公习惯引发的职业健康问题,迫切需要对智能办公健康管理技术进行研究,研制出一套行之有效的办公环境与健康监控系统。其中,多技术融合的实时监测与智能响应技术,是当今智能办公健康管理领域研究的关键着眼点。

6.国内研究现状

国内在办公环境监测与健康管理领域已形成多类产品与研究成果:环境监测端出现了温湿度计、甲醛检测仪等单一功能设备,可实现特定参数的实时采集与报警;健康管理端的智能台灯、人体工学椅等设备,也集成了用眼时长、坐姿等基础健康提醒功能。

学者们围绕办公环境健康优化展开多维度研究:焦典等以新奥尔良The Shop办公空间为案例,从空间感知视角梳理出“空间动势激活身体行为、空间构件界定活动边界” 等规律,构建了情感化设计引导的健康办公环境范式 [1];董丽等聚焦后疫情时代需求,从环境织补化、空间弹性化、心理舒适化维度,提出了办公环境健康设计策略[2];刘慧慧等结合夏热冬冷地区工业建筑改造实践,通过被动式设计与主动技术集成,形成了工业楼宇健康性能提升技术体系[3];张静以远洋地产WELL铂金级项目为对象,总结出自然光利用、眩光控制等健康光环境设计路径[4];罗彩姿等针对光环境动态特征,构建了“混合光源+混合视色温”的健康光环境控制模型,实现了照度均匀性与色温可调性的协同优化[5];闫海燕等对比分体式空调办公建筑不同温度模式,发现26℃以上高设定温度更利于降低污染物浓度与提升人体热调节能力[6];李华亮等通过企业办公空间监测,验证了通风、吸附等措施对降低甲醛、苯健康风险的有效性[7];刘慧慧等以烟台某科技园为案例,从污染控制、噪声治理等维度,探索了健康环境技术在绿色园区的应用[8]。

单片机凭借低成本、高稳定性成为小型监测系统的核心控制单元,支撑数据采集与设备联动;传感器技术实现了温湿度、人体状态等参数的精准采集;物联网技术则推动了数据的端侧同步共享,支持远程查看。但国内研究与应用仍存不足:产品功能碎片化,缺乏多参数与健康状态的综合联动监测;理论研究多聚焦单一领域,未与智能监测技术深度融合形成一体化方案;系统智能化水平有限,难以生成个性化健康管理方案;部分集成系统成本高、兼容性差,不利于大规模推广。

7.国外研究现状

国外在智能办公与健康监测领域起步较早,部分发达国家已形成成熟技术体系,其系统可实现温湿度、空气质量等多参数全覆盖监测,同时通过人体传感器、动作捕捉技术采集用户办公行为数据。

学者研究聚焦办公环境与人体状态的关,Xi Lin等通过荟萃分析发现,21-25℃是办公最佳温度范围,25℃环境会降低工作精度、延长响应时间,且高认知任务或长时间暴露下温度升高的负面影响更显著,同时指出采暖季降至 17℃节能具有可行性[9];Biswas等针对空调办公环境中的寒冷体质人群研究表明,女性、低BMI个体更易出现该体质,其代谢率低、热感觉差,且调整性别与BMI影响后热感觉的关联性仍显著,强调了热环境评估需结合个体特质[10]。

国外成果与产品也存在短板:产品成本高,终端售价偏高,难以在国内普通办公场景普及;适配性不足,基于本土办公模式设计,缺乏对国内场景的定制化适配;操作逻辑与交互方式不符合国内用户习惯,用户体验较差,这为国内本土系统的研发提供了市场空间。

8.主要器件
  • STM32F103C8T6 单片机
  • ESP8266物联网模块
  • ASR01语音模块
  • AMS1117稳压模块
  • DHT11温湿度模块
  • LED模块
  • 0.96寸OLED模块
  • 独立按键
  • 甲醛二氧化碳检测模块
  • 光敏电阻模块
  • 舵机模块
  • 四节干电池
9.原理图设计

        供电由四节干电池提供,之后经过AMS117模块降压为5V,输入到STM32最小系统板的5V引脚,给系统供电。

三、主要模块
1.STM32单片机

       STM32F103C8T6 是意法半导体推出的 32 位 ARM Cortex‑M3 内核低成本的单片机,工作主频 72MHz,片内自带 64KB Flash 程序存储、20KB SRAM 运行内存,具备多路 GPIO、ADC、I2C、SPI、USART 外设接口。

2. ASR01 语音识别模块

        ASR01 是款离线语音识别控制模块,内置语音识别算法,通过串口与主控芯片通信,识别成功后向 STM32 发送信息,实现语音交互控制功能。

3. AMS1117 稳压模块

        AMS1117 低压差线性稳压芯片,为单片机、传感器提供安全稳定的供电。

4. DHT11 温湿度模块

        DHT11 是款数字式温湿度复合传感器,单总线通信方式,能够采集环境温度与相对湿度输。

5. 甲醛二氧化碳检测模块

       模块集成电化学 气体传感单元,可以对空气中甲醛、二氧化碳浓度进行检测,使用串口输出浓度信息。

6 舵机模块

        舵机模块是PWM 控制的伺服执行器件,单片机输出 PWM 信号控制舵机旋转指定角度,完成机械执行动作。

7 .物联网模块

        ESP8266物联网通信模块,串口与 STM32 通信,实现 WiFi 联网。可上传环境数据到云平台实现远程查看,也可接收远程指令控制设备。

五、项目主要源码 
5.1.单片机源码
5.1.1主程序

/*
可监测办公环境,如温湿度、甲醛、CO2 浓度、光照强度等;
当室内温湿度、甲醛浓度、CO2 浓度异常时,系统自动开窗通风或关闭窗户,当室内光线过暗或过亮时,系统自动控制开灯或关灯;
可检测监测久坐时长、用眼疲劳等用户办公状态,久坐、用眼过度时触语音播报提醒,建议起身活动、远眺休息;
TVOC 三合一: CO2\\ 甲醛 UART1 PA10-RX PA9-TX
DHT11: 温湿度 PB0
0.96oled: 显示 IIC1 SDA-PB7 SCL-PB6
光敏电阻:亮度 PA5
LED: 灯 PA7
舵机:窗户 TIME2-PA0
asr01 – 语音模块 UART2 PA2-TX PA3-RX
esp8266-app UART3 PB10-TX PB11-RX
按键 PB12 13 14 15
// 温度偏离设定 5℃极为异常
// 湿度偏离设定 10 极为异常
// 甲醛以及二氧化碳超浓度为异常

// 模式 甲醛 温度
// 手 / 自动 xxxppm xx
// 湿度 时长 提醒
//xxx xxx 是 / 否
//CO2 甲醛 温度
//XXXppm xxxppm xx
// 湿度 窗户 时长
//xx% 开 / 关 xxx
// 发送 0xaa 您当前使用时长过长,建议您起身活动、远眺休息
// 发送 0xbb 当前甲醛浓度超标
// 发送 0xcc 当前二氧化碳浓度超标
// 发送 0xdd 当前温度异常
// 发送 0xee 当前湿度异常
// 接收到 0x11 开启久坐提醒
// 接收到 0x22 关闭久坐提醒

// 接收到 0x55 切换自动模式
// 接收到 0x66 切换手动模式

wifi:leo 123456789
设置界面修改参数,之后切换到参数显示界面才会进行一些控制以及播报
手动模式下不会天黑天亮开关灯以及甲醛二氧化碳异常开关窗户
自动模式下天黑开灯 天亮关灯 二氧化碳以及甲醛异常自动开窗户
当温度设定+-5 提醒:温度异常
当湿度设定+-10提醒:湿度异常
当二氧化碳和甲醛高于预定提醒:二氧化碳超标以及甲醛浓度超标
当开启提醒之后且时间超过设定时间提醒:您当前使用时长过长,建议您起身活动、远眺休息
也可以通过语音去 ①开启久坐提醒 ②关闭久坐提醒 ③切换手动模式 ④切换自动模式

*/
#include "bsp.h"
char oled_buffers[25];
extern uint8_t rx1;
extern uint8_t rx2;
extern uint8_t rx3;
uint8_t mode;//0-手动 1-自动
uint8_t set_mode;//需要设置的模式
uint8_t set_inter;//0-设置界面 1-显示界面
uint16_t jiaquan_thre=200;
uint16_t co2_thre=800;
uint16_t temp_thre=20;
uint16_t humi_thre=50;
uint16_t tixing;//是否开启提醒到时间
uint16_t times_thre=10;//计时的时间阈值
uint16_t times_jishi;//当前计时时间
uint16_t co2_dat;
uint16_t jiaquan_dat;
uint16_t temp_dat;
uint16_t humi_dat;
uint8_t windows_state;
extern uint16_t formaldehyde_concentration; // 甲醛浓度 (ug/m³)
extern uint16_t eco2_concentration ; // 等效eCO2浓度 (PPM)
uint32_t tim_dly;

void bsp_init()
{
MG90_Init();MG90_Set_Angle(0);
OLED_Init();
co2_init();
esp8266_rx_init();
HAL_UART_Receive_IT(&huart2, &rx2, 1);//asr-2
co2_init();//uart1
//ESP8266 未调试
OLED_NewFrame();
OLED_PrintString(0, 0, (char *) "OneNetConnect…", &font16x16, OLED_COLOR_NORMAL);
OLED_ShowFrame();
wifi_init();
OLED_PrintString(0, 16,(char *) "WIFI_OK!", &font16x16, OLED_COLOR_NORMAL);
OLED_ShowFrame();
mqtt_init();
OLED_PrintString(0, 32,(char *) "MQTT_OK!", &font16x16, OLED_COLOR_NORMAL);
OLED_ShowFrame();
HAL_Delay(500);

}
uint8_t key;
DHT11_Data_TypeDef DH11;
static uint16_t oled_rest=0;
void loop()
{

if(++oled_rest>=50) {oled_rest=0; OLED_Init();}
//OLED
OLED_NewFrame();
if(set_inter==0)
{
sprintf((char *)oled_buffers,"模式");//OLED_COLOR_REVERSED
OLED_PrintString(0,0,oled_buffers,&font16x16, set_mode==0?OLED_COLOR_REVERSED:OLED_COLOR_NORMAL);
sprintf((char *)oled_buffers,"甲醛");
OLED_PrintString(42,0,oled_buffers,&font16x16,set_mode==1?OLED_COLOR_REVERSED:OLED_COLOR_NORMAL);
sprintf((char *)oled_buffers,"温度");
OLED_PrintString(84,0,oled_buffers,&font16x16, set_mode==2?OLED_COLOR_REVERSED:OLED_COLOR_NORMAL);

sprintf((char *)oled_buffers,"湿度");
OLED_PrintString(0,32,oled_buffers,&font16x16, set_mode==3?OLED_COLOR_REVERSED:OLED_COLOR_NORMAL);
sprintf((char *)oled_buffers,"时长");
OLED_PrintString(42,32,oled_buffers,&font16x16, set_mode==4?OLED_COLOR_REVERSED:OLED_COLOR_NORMAL);
sprintf((char *)oled_buffers,"提醒");
OLED_PrintString(84,32,oled_buffers,&font16x16, set_mode==5?OLED_COLOR_REVERSED:OLED_COLOR_NORMAL);

sprintf((char *)oled_buffers,"%s",mode==0?"手动":"自动");
OLED_PrintString(0,16,oled_buffers,&font16x16, OLED_COLOR_NORMAL);
sprintf((char *)oled_buffers,"%03dppm",jiaquan_thre);
OLED_PrintString(38,16,oled_buffers,&font16x16, OLED_COLOR_NORMAL);
sprintf((char *)oled_buffers,"%02d",temp_thre);
OLED_PrintString(90,16,oled_buffers,&font16x16, OLED_COLOR_NORMAL);

sprintf((char *)oled_buffers,"%02d",humi_thre);
OLED_PrintString(5,48,oled_buffers,&font16x16, OLED_COLOR_NORMAL);
sprintf((char *)oled_buffers,"%03d",times_thre);
OLED_PrintString(42,48,oled_buffers,&font16x16, OLED_COLOR_NORMAL);
sprintf((char *)oled_buffers,"%s",tixing==0?"否":"是");
OLED_PrintString(90,48,oled_buffers,&font16x16, OLED_COLOR_NORMAL);
}
if(set_inter==1)
{
sprintf((char *)oled_buffers,"CO2");
OLED_PrintString(0,0,oled_buffers,&font16x16, OLED_COLOR_NORMAL);
sprintf((char *)oled_buffers,"甲醛");
OLED_PrintString(42,0,oled_buffers,&font16x16, OLED_COLOR_NORMAL);
sprintf((char *)oled_buffers,"温度");
OLED_PrintString(84,0,oled_buffers,&font16x16, OLED_COLOR_NORMAL);

sprintf((char *)oled_buffers,"%3d",co2_dat);
OLED_PrintString(0,16,oled_buffers,&font16x16, OLED_COLOR_NORMAL);
sprintf((char *)oled_buffers,"%3d",jiaquan_dat);
OLED_PrintString(38,16,oled_buffers,&font16x16, OLED_COLOR_NORMAL);
sprintf((char *)oled_buffers,"%2d",temp_dat);
OLED_PrintString(90,16,oled_buffers,&font16x16, OLED_COLOR_NORMAL);

sprintf((char *)oled_buffers,"湿度");
OLED_PrintString(0,32,oled_buffers,&font16x16, OLED_COLOR_NORMAL);
sprintf((char *)oled_buffers,"窗户");
OLED_PrintString(42,32,oled_buffers,&font16x16, OLED_COLOR_NORMAL);
sprintf((char *)oled_buffers,"时长");
OLED_PrintString(84,32,oled_buffers,&font16x16, OLED_COLOR_NORMAL);

sprintf((char *)oled_buffers,"%2d",humi_dat);
OLED_PrintString(0,48,oled_buffers,&font16x16, OLED_COLOR_NORMAL);
sprintf((char *)oled_buffers,"%s",windows_state==0?"关":"开");
OLED_PrintString(50,48,oled_buffers,&font16x16, OLED_COLOR_NORMAL);
sprintf((char *)oled_buffers,"%3d",times_jishi);
OLED_PrintString(84,48,oled_buffers,&font16x16, OLED_COLOR_NORMAL);
}
OLED_ShowFrame();
//DH11
DHT11_ReadData(&DH11);
humi_dat=DH11.humi_int;
temp_dat=DH11.temp_int;
//co2
jiaquan_dat=formaldehyde_concentration;
co2_dat=eco2_concentration ;
//判断逻辑
// 温度偏离设定 5℃极为异常
// 湿度偏离设定 10 极为异常
// 甲醛以及二氧化碳超浓度为异常
// 发送 0xaa 您当前使用时长过长,建议您起身活动、远眺休息
// 发送 0xbb 当前甲醛浓度超标
// 发送 0xcc 当前二氧化碳浓度超标
// 发送 0xdd 当前温度异常
// 发送 0xee 当前湿度异常
static uint8_t times_alarm;
if(set_inter==1)//语音提醒
{
times_alarm++;if(times_alarm%30==0)
{
if(temp_dat>temp_thre+5 ||temp_dat<temp_thre-5)
{uint8_t dat1=0xdd; HAL_UART_Transmit(&huart2,&dat1,1, 100);}
if(humi_dat>humi_thre+10 ||humi_dat<humi_thre-10)
{uint8_t dat2=0xee; HAL_UART_Transmit(&huart2,&dat2,1, 100);}
if(jiaquan_dat>jiaquan_thre )
{uint8_t dat3=0xbb; HAL_UART_Transmit(&huart2,&dat3,1, 100);}
if(co2_dat>co2_thre)
{uint8_t dat4=0xcc; HAL_UART_Transmit(&huart2,&dat4,1, 100);}
}
}
if(set_inter==0){times_alarm=0;}
//时间超过 提醒活动
static uint8_t times_dly;
if(times_jishi>times_thre &&tixing==1){times_dly++;if(times_dly<4){ uint8_t dat5=0xaa; HAL_UART_Transmit(&huart2,&dat5,1, 100);}}
else{times_dly=0;}
//天黑开灯 天亮关灯 甲醛 二氧化碳异常自动开窗户 MG90_Set_Angle(uint8_t angle);
if(mode==1&&set_inter==1)
{
if(jiaquan_dat>jiaquan_thre ){windows_state=1;MG90_Set_Angle(60);}//
if(co2_dat>co2_thre ){windows_state=1;MG90_Set_Angle(60);}
if(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_5))
{HAL_GPIO_WritePin(LED_GPIO_Port, LED_Pin, GPIO_PIN_RESET);}
else {HAL_GPIO_WritePin(LED_GPIO_Port, LED_Pin, GPIO_PIN_SET);}
}
//asr01 – 语音模块 UART2 PA2-TX PA3-RX
//esp8266-app UART3 PB10-TX PB11-RX
//ESP8266 Humi Temp JiaQuan CO2
static uint8_t send_times=0;
send_times++;
if(send_times==1){esp8266_connect_send("Humi", humi_dat,100) ;}
if(send_times==45){esp8266_connect_send("Temp", temp_dat,100) ;}
if(send_times==80){esp8266_connect_send("JiaQuan", jiaquan_dat,100) ;}
if(send_times==110){send_times=0;esp8266_connect_send("CO2", co2_dat,100) ;}
//计时
HAL_Delay(7);tim_dly++;
if(tim_dly>60){tim_dly=0;times_jishi=times_jishi+1;}
//KEY
key=key_scan();
switch(key)
{
case 1:if(set_inter==0){set_mode=(set_mode+1)%6;} break;//参数修改
case 2:if(set_inter==0&&set_mode==0){mode=(mode+1)%2;}
if(set_inter==0&&set_mode==1){jiaquan_thre=jiaquan_thre+5;if(jiaquan_thre>800)jiaquan_thre=0;}
if(set_inter==0&&set_mode==2){temp_thre=temp_thre+1;if(temp_thre>35)temp_thre=5;}
if(set_inter==0&&set_mode==3){humi_thre=humi_thre+1;if(humi_thre>80)humi_thre=10;}
if(set_inter==0&&set_mode==4){times_thre=times_thre+2;if(times_thre>60)times_thre=2;}
if(set_inter==0&&set_mode==5){tixing=(tixing+1)%2;}break;//-

case 3:if(set_inter==0&&set_mode==0){mode=(mode+1)%2;}
if(set_inter==0&&set_mode==1){jiaquan_thre=jiaquan_thre-5;if(jiaquan_thre<50)jiaquan_thre=500;}
if(set_inter==0&&set_mode==2){temp_thre=temp_thre-1;if(temp_thre<5)temp_thre=35;}
if(set_inter==0&&set_mode==3){humi_thre=humi_thre-1;if(humi_thre<10)humi_thre=80;}
if(set_inter==0&&set_mode==4){times_thre=times_thre-2;if(times_thre<2)times_thre=60;}
if(set_inter==0&&set_mode==5){tixing=(tixing+1)%2;} break;//+

case 4: set_inter=(set_inter+1)%2;break;//界面修改
}

}
void asr_rx(uint8_t data )
{
if(data==0x11){ tixing=1; }
if(data==0x22){ tixing=0;}
//if(data==0x33){ windows_state=1;MG90_Set_Angle(30); }
//if(data==0x44){windows_state=0;MG90_Set_Angle(0); }
if(data==0x55){ mode =0;}
if(data==0x66){ mode =1;}
HAL_UART_Receive_IT(&huart2, &rx2, 1);
}

5.1.2 二氧化碳甲醛检测模块

#include "co2.h"
uint8_t co2_rx; // 存储每次中断接收的字节
uint16_t tvoc_concentration = 0; // TVOC浓度 (ug/m³)
uint16_t formaldehyde_concentration = 0; // 甲醛浓度 (ug/m³)
uint16_t eco2_concentration = 0; // 等效eCO2浓度 (PPM)
uint8_t co2_data_ready = 0; // 数据解析完成标志

void co2_init(void)
{
HAL_UART_Receive_IT(&huart1, &co2_rx, 1);
}

void co2_it_get(void)
{
static uint8_t co2_state = 0;
static uint8_t tvoc_temp[2]; // TVOC高低字节
static uint8_t formaldehyde_temp[2]; // 甲醛高低字节
static uint8_t eco2_temp[2]; // eCO2高低字节
static uint8_t sum = 0; // 校验和(只保留低8位)

switch (co2_state)
{
case 0: // 等待帧头 0x2C
if (co2_rx == 0x2C) {
sum = 0x2C;
co2_state = 1;
}
break;

case 1: // 等待 0xE4
if (co2_rx == 0xE4) {
sum += 0xE4;
co2_state = 2;
} else {
co2_state = 0; // 帧头错误,重置
}
break;

case 2: // TVOC 高字节
tvoc_temp[0] = co2_rx;
sum += co2_rx;
co2_state = 3;
break;

case 3: // TVOC 低字节
tvoc_temp[1] = co2_rx;
sum += co2_rx;
co2_state = 4;
break;

case 4: // 甲醛 高字节
formaldehyde_temp[0] = co2_rx;
sum += co2_rx;
co2_state = 5;
break;

case 5: // 甲醛 低字节
formaldehyde_temp[1] = co2_rx;
sum += co2_rx;
co2_state = 6;
break;

case 6: // eCO2 高字节
eco2_temp[0] = co2_rx;
sum += co2_rx;
co2_state = 7;
break;

case 7: // eCO2 低字节
eco2_temp[1] = co2_rx;
sum += co2_rx;
co2_state = 8;
break;

case 8: // 校验和(第9字节)
sum &= 0xFF; // 只保留低8位(重要!)
if (sum == co2_rx) {
// 解析成功
tvoc_concentration = (tvoc_temp[0] << 8) | tvoc_temp[1];
formaldehyde_concentration = (formaldehyde_temp[0] << 8) | formaldehyde_temp[1];
eco2_concentration = (eco2_temp[0] << 8) | eco2_temp[1];
co2_data_ready = 1;
} else {
co2_data_ready = 0; // 校验失败
}
// 重置状态,准备下一帧
co2_state = 0;
sum = 0;
break;

default:
co2_state = 0;
sum = 0;
break;
}

//debug_send("%c",co2_rx);
HAL_UART_Receive_IT(&huart1, &co2_rx, 1); // 启动下一次中断接收
}

5.1.3温湿度读取代码

#include "dh11.h"

static void DHT11_PP_OUT(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
GPIO_InitStruct.Pin = DHT11_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(DHT11_PORT, &GPIO_InitStruct);
}

/**
* ************************************************************************
* @brief 将DHT11配置为上拉输入模式
* ************************************************************************
*/
static void DHT11_UP_IN(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
GPIO_InitStruct.Pin = DHT11_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_PULLUP;//上拉
HAL_GPIO_Init(DHT11_PORT, &GPIO_InitStruct);
}

/**
* ************************************************************************
* @brief 读取字节
* @return temp
* ************************************************************************
*/
uint8_t DHT11_ReadByte(void)
{
uint8_t i, temp = 0;

for (i = 0; i < 8; i++)
{
while (DHT11_ReadPin == 0);// 等待低电平结束

delay_us(40);//延时 40 微秒

if (DHT11_ReadPin == 1)
{
while (DHT11_ReadPin == 1);// 等待高电平结束

temp |= (uint8_t)(0X01 << (7 – i));// 先发送高位
}
else
{
temp &= (uint8_t)~(0X01 << (7 – i));
}
}
return temp;
}

/**
* ************************************************************************
* @brief 读取一次数据
* @param[in] DHT11_Data 定义的结构体变量
* @return 0或1(数据校验是否成功)
* @note 它首先向DHT11发送启动信号,然后等待DHT11的应答。如果DHT11正确应答,
* 则继续读取湿度整数、湿度小数、温度整数、温度小数和校验和数据,
* 并计算校验和以进行数据校验
* ************************************************************************
*/
uint8_t DHT11_ReadData(DHT11_Data_TypeDef *DHT11_Data)
{
DHT11_PP_OUT();// 主机输出,主机拉低
DHT11_PULL_0;
HAL_Delay(18);// 延时 18 ms

DHT11_PULL_1;// 主机拉高,延时 30 us
delay_us(30);

DHT11_UP_IN();// 主机输入,获取 DHT11 数据

if (DHT11_ReadPin == 0)// 收到从机应答
{
while (DHT11_ReadPin == 0);// 等待从机应答的低电平结束

while (DHT11_ReadPin == 1);// 等待从机应答的高电平结束

/*开始接收数据*/
DHT11_Data->humi_int = DHT11_ReadByte();
DHT11_Data->humi_dec = DHT11_ReadByte();
DHT11_Data->temp_int = DHT11_ReadByte();
DHT11_Data->temp_dec = DHT11_ReadByte();
DHT11_Data->check_sum = DHT11_ReadByte();

DHT11_PP_OUT();// 读取结束,主机拉高
DHT11_PULL_1;

// 数据校验
if (DHT11_Data->check_sum == DHT11_Data->humi_int + DHT11_Data->humi_dec + DHT11_Data->temp_int + DHT11_Data->temp_dec)
{
return 1;
}
else
{
return 0;
}
}
else// 未收到从机应答
{
return 0;
}
}
//任务
//extern uint16_t dt11_update_add;
//DHT11_Data_TypeDef DHT11_Data;
//void dt11_task()
//{
//if(dt11_update_add<500) return;
//dt11_update_add=0;
//DHT11_ReadData(&DHT11_Data);
//}
//////if (DHT11_ReadData(&DHT11_Data))
////// {
////// printf("湿度:%d RH ,温度:%d ℃ \\n", DHT11_Data.humi_int, DHT11_Data.temp_int);
////// }

5.1.4ESP8266物联网模块

#include "esp8266.h"
/*

*/
#define TX_SIZE 245
char at_txbuffer[TX_SIZE]={0};
#define RX_SIZE 245
char at_rxbuffer[RX_SIZE]={0};
uint8_t at_rxindex;
uint8_t at_rx;
#define WIFI_SSID "leo"
#define WIFI_PASSWORD "123456789"
#define WIFI_ONENET_PRODUCT_ID "h1pDm19B6T"
#define WIFI_ONENET_DEVICE_NAME "XX"
#define WIFI_ONENET_TOKEN version=2018-10-31&res=products%XX%XXX&et=1851106542&method=md5&sign=XX%3D%3D
#define MQTT_HOST_URL "mqtts.heclouds.com"
#define MQTT_HOST_PORT 1883
const char* topic1 = "$sys/" WIFI_ONENET_PRODUCT_ID "/" WIFI_ONENET_DEVICE_NAME "/thing/property/post/reply";
const char* topic2 = "$sys/" WIFI_ONENET_PRODUCT_ID "/" WIFI_ONENET_DEVICE_NAME "/thing/property/set";
// 串口接收中断处理(增加缓冲区溢出保护)
void uart_rx_esp8266()
{
if(at_rxindex < RX_SIZE – 1) // 留1个位置给结束符
{
at_rxbuffer[at_rxindex++] = at_rx;
at_rxbuffer[at_rxindex] = '\\0'; // 实时添加结束符,确保strstr正常工作
}
else
{
at_rxindex = 0; // 溢出则重置
memset(at_rxbuffer, 0, RX_SIZE);
}
HAL_UART_Receive_IT(&huart3, &at_rx, 1);
}
void esp8266_printf(char* fmt, …)
{ memset(at_txbuffer, 0, TX_SIZE);
va_list ap;
va_start(ap, fmt);
vsprintf(at_txbuffer, fmt, ap);
va_end(ap);

uint16_t length = strlen(at_txbuffer);
HAL_UART_Transmit(&huart3, (uint8_t*)at_txbuffer, length, 2000);
}
void esp8266_rx_init()
{
at_rxindex = 0;
memset(at_rxbuffer, 0, RX_SIZE);
HAL_UART_Receive_IT(&huart3, &at_rx, 1);
}
// 发送AT指令(通用函数,确保指令以\\r\\n结尾)
char esp8266_send_cmd(char *cmd, int timeout)
{
at_rxindex = 0;
memset(at_rxbuffer, 0, RX_SIZE);
esp8266_printf("%s\\r\\n", cmd); // 所有指令必须加\\r\\n
HAL_UART_Transmit(&huart1, (uint8_t*)cmd, strlen(cmd), 2000);
while(timeout–)
{
HAL_Delay(1); // 每次等待10ms
if(strstr(at_rxbuffer, "OK") != NULL) // 找到OK表示成功
{

return 0; // 成功
}
else if(strstr(at_rxbuffer, "ready") != NULL)//ready
{

return 0; // 成功
}
else if(strstr(at_rxbuffer, ">") != NULL)
{

return 0; // 成功
}//MQTTCONNECTED

// 增加错误判断(如出现ERROR也返回失败)
else if(strstr(at_rxbuffer, "ERROR") != NULL)
{

}
}
return -1; // 超时失败
}

char wifi_init()
{
HAL_Delay(2500);
esp8266_printf("AT+RESTORE\\r\\n" );
HAL_Delay(2500);
while(1)
{
int8_t connect;
connect=esp8266_send_cmd("AT+CWMODE=1",1500);
if(connect!=-1){break;}
}

while(1)
{
int8_t connect;
connect=esp8266_send_cmd("AT+CWJAP=\\"leo\\",\\"123456789\\"",5000);
if(connect!=-1){break;}
}
return 0;
}
char mqtt_init()
{

while(1)
{
int8_t connect;
connect=esp8266_send_cmd("AT+MQTTUSERCFG=0,1,\\"XX\\",\\"XXX\\",\\"version=2018-10-31&res=products%2Fh1pDm19B6T%2Fdevices%XXX&et=1821354075&XXX=md5&sign=XXX%2BA%3D%3D\\",0,0,\\"\\"",4000);
if(connect!=-1){break;}
}

while(1)
{
int8_t connect;
connect=esp8266_send_cmd("AT+MQTTCONN=0,\\"mqtts.heclouds.com\\",1883,1",4000);//
if(connect!=-1){break;}
}

while(1)
{
int8_t connect;
connect=esp8266_send_cmd("AT+MQTTSUB=0,\\"$sys/XX//XX/thing/property/post/reply\\",0",4000);
if(connect!=-1){break;}
}

while(1)
{
int8_t connect;
connect=esp8266_send_cmd("AT+MQTTSUB=0,\\"$sys/XX//XX/thing/property/set\\",0",1500);
if(connect!=-1){break;}
}
return 0;
}

char esp8266_connect_send(const char* paramName, int value, int timeout)
{
char cmd[256];
// 在逗号前添加反斜杠转义符:用\\\\\\"\\\\,\\\\\\" 生成 \\",\\" 的效果
sprintf(cmd, "AT+MQTTPUB=0,\\"$sys/%s/%s/thing/property/post\\",\\"{\\\\\\"id\\\\\\":\\\\\\"123\\\\\\"\\\\,\\\\\\"params\\\\\\":{\\\\\\"%s\\\\\\":{\\\\\\"value\\\\\\":%d}}}\\",0,0",
WIFI_ONENET_PRODUCT_ID,
WIFI_ONENET_DEVICE_NAME,
paramName,
value);
return esp8266_send_cmd(cmd, timeout);
}

5.1.5 按键检测代码

#include "key.h"
//KEY1-5:PA6 PA7 PB0 PB1 pb10
#define KEY1 HAL_GPIO_ReadPin(KEY1_GPIO_Port, KEY1_Pin)
#define KEY2 HAL_GPIO_ReadPin(KEY2_GPIO_Port, KEY2_Pin)
#define KEY3 HAL_GPIO_ReadPin(KEY3_GPIO_Port, KEY3_Pin)
#define KEY4 HAL_GPIO_ReadPin(KEY4_GPIO_Port, KEY4_Pin)

uint8_t key_scan()
{
static uint8_t key_up=1;
if(key_up==1&&(KEY1==0||KEY2==0||KEY3==0||KEY4==0))
{
key_up=0;
if(KEY1==0) return 1;
if(KEY2==0) return 2;
if(KEY3==0) return 3;
if(KEY4==0) return 4;

}
else if(KEY1==1&&KEY2==1&&KEY3==1&&KEY4==1)
{
key_up=1;
}
return 0;
}

六、工程主要内容

   工程的具体内容包括但不限于原理图、程序代码、流程图等等。完整工程、原理图、APP 源码我已经开源到 Gitee,需要的同学可以评论区留言或者私信,A01-基于STM32的办公环境与健康监控系统

赞(0)
未经允许不得转载:网硕互联帮助中心 » STM32毕设项目分享:基于STM32的办公环境与健康监控系统
分享到: 更多 (0)

评论 抢沙发

评论前必须登录!