找回密码
 立即注册
首页 业界区 业界 基于stm32单片机家庭环境监测系统

基于stm32单片机家庭环境监测系统

呼延冰枫 7 天前
 
1.演示视频

基于stm32单片机家庭环境监测系统视频演示_哔哩哔哩_bilibili
2. 项目介绍

本项目基于STM32F103C8T6最小系统板,打造了一个功能强大、显示直观的家庭环境监测系统。系统集成了温湿度、光照强度、多种气体、人体感应等传感器,并通过OLED屏幕本地实时显示数据,同时支持手机蓝牙小程序远程监控与告警。它不仅是一个全面的环境数据采集站,更是一个具备布防/撤防功能的简易家庭安防系统。
3. 系统功能亮点


  • 环境多参数监测​:实时采集温度、湿度、光照强度、空气质量(CO/CO2/烟雾等综合指标)。
  • 人体红外感应​:检测指定区域内是否有人体活动。
  • 双模远程通信​:支持ESP32 Wi-Fi模块​(预留扩展接口)和HC-05/06蓝牙模块与手机连接。
  • 手机小程序监控​:通过自开发的微信小程序,可远程查看所有传感器数据,并进行系统控制。
  • 智能安防布防​:具备“布防”和“撤防”两种模式。在布防模式下,检测到人体入侵将触发本地蜂鸣器高声警报并推送手机提醒。
  • 交互与提示​:配备四个功能按键和一个蜂鸣器,方便本地操作和声音提示。
4.硬件设计

4.1 硬件组成 (BOM List)

模块名称型号/规格通信协议功能​主控芯片​STM32F103C8T6 (最小系统板)-系统核心,负责数据处理与逻辑控制​显示模块​0.96英寸 OLED屏I2C本地实时显示所有传感器数据及系统状态​温湿度传感器​AHT20I2C高精度测量环境温度和湿度​光照传感器​GY-30 (BH1750)I2C检测环境光照强度 (Lux)​气体传感器​MQ-135模拟/数字综合检测空气质量、CO2、CO、烟雾、苯等有害气体​人体红外传感器​HC-SR501数字GPIO检测人体移动​蓝牙模块​HC-05 或 HC-06UART与手机小程序进行串口蓝牙通信​Wi-Fi模块​ESP-01S (ESP8266) 或 ESP32UART预留物联网扩展接口,可接入云平台​声学提示​有源蜂鸣器GPIO发出警报和提示音​输入控制​4x轻触按键GPIO本地切换模式、设置参数等​供电接口​Type-C-5V供电,并配有电源开关4.2主要芯片介绍

STM32F103C8T6介绍
STM32F103C8T6是一款由意法半导体公司(ST)推出的基于Cortex-M3内核的32位微控制器,硬件采用LQFP48封装,属于ST公司微控制器中的STM32系列。
1.png

 
2.png

AHT20温湿度传感器介绍
AHT20是一款高精度数字温湿度传感器,采用I2C通信(地址0x38),供电需3.3V。其温度精度±0.3℃,湿度精度±2%RH,出厂已校准,即插即用。相比DHT11,精度更高、通信更稳定,是环境监测项目的理想选择。
3.png

4.png

 
BH1750光照强度传感器介绍
BH1750FVI​ 是一款数字式环境光强度传感器。它通过 ​I2C​ 接口直接输出光照度值(单位:Lux),测量范围 ​1 - 65535 lx。具有高精度、无需外部元件等优点,是替代光敏电阻的理想选择,广泛应用于自动背光调节和智能照明系统。
5.png

 
6.png

ECB01H2S蓝牙模块介绍
ECB01H2S​ 是一款基于蓝牙5.0的串口透传模块。它将复杂的蓝牙协议封装成简单的串口通信,用户只需通过AT指令进行配置,即可让主控设备(如STM32)通过串口与手机等蓝牙主机实现无线数据双向传输,极大简化了无线通信功能的开发流程,广泛应用于智能硬件和数据传输项目。
7.png

 
8.png

I2C OLED显示屏介绍 
该屏幕拥有128x64高分辨率,采用I2C接口,仅需两根信号线即可驱动。其像素点自发光,显示黑色时功耗极低,无需背光,视觉效果清晰锐利,对比度高,是嵌入式项目中最受欢迎的小型显示方案。
9.png

 
10.png

ESP8266WiFi模块介绍
ESP8266​ 是一款低成本、高性能的Wi-Fi SOC芯片模块。其核心功能是通过串口AT指令与单片机通信,轻松实现设备联网。它内置了TCP/IP协议栈,可作为独立MCU或Wi-Fi适配器使用,是物联网项目中实现无线连接最经典、性价比最高的解决方案之一。
11.png

 
12.png


5.系统设计与实现

5.1整体系统设计

13.png

 
5.2 数据流与工作逻辑


  • 数据采集层​:STM32主控循环读取各个传感器的数据。
  • 数据处理层​:对原始数据进行滤波、校准和计算,得到有意义的物理量(如℃、%RH、Lux、空气质量等级)。
  • 本地显示层​:处理后的数据通过I2C协议发送到OLED屏幕进行刷新显示。
  • 远程通信层​:STM32通过串口将数据按照自定义协议格式发送给蓝牙模块,再由蓝牙传输至手机小程序。手机下发的控制指令(如布防)也通过此路径逆向传输给STM32。
逻辑控制层​:主控根据当前系统模式(布防/撤防)和传感器状态(是否检测到人)执行相应的动作,如控制蜂鸣器。
14.png


  • 本地显示效果:
 
    屏幕第一页显示:温度: 26.5℃, 湿度: 45%, 光照: 256 Lux。
    屏幕循环显示气体数据:Air Q: Good, Gas: None, PM2.5: 15, Smoke: Low。
    人体检测状态:P: Yes (有人) 或 P: No (无人)。
    安防状态:Security On (布防) 或 Security Off (撤防)。
 

  • 手机监控​:
 
    手机小程序成功连接蓝牙后,界面同步显示所有环境数据。
    设有“布防/撤防”切换按钮。
    在布防状态下,若检测到人体,手机端会弹出弹窗警报,并显示“警戒中!”。
 

  • 安防联动​:
 
​    撤防模式​:检测到人体,仅在屏幕和手机端显示“有人”,无声音警报。​​(适合家中有人时)​
​    布防模式​:检测到人体,​蜂鸣器立即鸣叫,同时手机端弹出警报。​​(适合出门或夜间)​​​
6.代码展示
  1. /* USER CODE BEGIN Header */
  2. /**
  3.   ******************************************************************************
  4.   * @file           : main.c
  5.   * @brief          : Main program body - 简化版
  6.   ******************************************************************************
  7.   */
  8. /* USER CODE END Header */
  9. /* Includes ------------------------------------------------------------------*/
  10. #include "main.h"
  11. #include "oled.h"
  12. #include "temp_humi.h"
  13. #include "gas_sensor.h"
  14. #include "light_sensor.h"
  15. #include "bluetooth.h"
  16. #include "gas_display.h"
  17. #include "buzzer.h"
  18. #include <stdio.h>
  19. #include <string.h>
  20. /* Private variables ---------------------------------------------------------*/
  21. I2C_HandleTypeDef hi2c1;
  22. ADC_HandleTypeDef hadc1;
  23. UART_HandleTypeDef huart1;
  24. /* Private function prototypes -----------------------------------------------*/
  25. void SystemClock_Config(void);
  26. void MX_GPIO_Init(void);
  27. void MX_I2C1_Init(void);
  28. void MX_ADC1_Init(void);
  29. void MX_USART1_UART_Init(void);
  30. /**
  31.   * @brief  IR传感器初始化 - 简化版
  32.   * @param  None
  33.   * @retval None
  34.   */
  35. void IR_Sensor_Init(void)
  36. {
  37.   GPIO_InitTypeDef GPIO_InitStruct = {0};
  38.   
  39.   __HAL_RCC_GPIOB_CLK_ENABLE();
  40.   
  41.   GPIO_InitStruct.Pin = GPIO_PIN_9;
  42.   GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
  43.   GPIO_InitStruct.Pull = GPIO_PULLUP;
  44.   GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
  45.   HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
  46. }
  47. /**
  48.   * @brief  检测人体存在 - 简化版
  49.   * @param  None
  50.   * @retval 1: 检测到人体, 0: 未检测到人体
  51.   */
  52. uint8_t IR_Sensor_Detect(void)
  53. {
  54.   return (HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_9) == GPIO_PIN_RESET) ? 1 : 0;
  55. }
  56. /**
  57.   * @brief  应用程序入口点
  58.   * @retval int
  59.   */
  60. int main(void)
  61. {
  62.   /* 初始化HAL库 */
  63.   HAL_Init();
  64.   
  65.   /* 配置系统时钟 */
  66.   SystemClock_Config();
  67.   
  68.   /* 初始化所有外设 */
  69.   MX_GPIO_Init();
  70.   MX_I2C1_Init();
  71.   MX_ADC1_Init();
  72.   MX_USART1_UART_Init();
  73.   
  74.   /* 初始化所有传感器和外设 */
  75.   OLED_Init();
  76.   TEMP_HUMI_Init();
  77.   GAS_SENSOR_Init();
  78.   LIGHT_SENSOR_Init();
  79.   IR_Sensor_Init();
  80.   Bluetooth_Init();
  81.   BUZZER_Init();
  82.   
  83.   /* 显示初始屏幕 */
  84.   OLED_Clear();
  85.   OLED_ShowString(0, 0, "Starting...", 12);
  86.   OLED_Refresh();
  87.   
  88.   /* 初始化变量 */
  89.   float temperature = 0.0f;
  90.   float humidity = 0.0f;
  91.   float light = 0.0f;
  92.   uint8_t ir_status = 0;
  93.   uint8_t last_ir_status = 0;
  94.   uint8_t bt_send_counter = 0;
  95.   
  96.   /* 创建气体数据结构 */
  97.   GAS_DATA gas_data = {0};
  98.   
  99.   /* 气体传感器初始校准 */
  100.   GAS_SENSOR_Calibrate(400.0f);
  101.   
  102.   /* 手动设置一些初始值,确保数据不为空 */
  103.   gas_data.raw_ppm = 500.0f;
  104.   gas_data.co2_equivalent = 400.0f;
  105.   gas_data.combustible_gas = 150.0f;
  106.   gas_data.smoke_density = 75.0f;
  107.   gas_data.pm25 = 50.0f;
  108.   gas_data.aqi = 100;
  109.   gas_data.change_rate = 0.5f;
  110.   gas_data.gas_type = GAS_TYPE_NORMAL;
  111.   gas_data.safety_level = SAFETY_LEVEL_SAFE;
  112.   gas_data.leak_detected = 0;
  113.   gas_data.fire_risk = 2;
  114.   
  115.   /* 无限循环 */
  116.   while (1)
  117.   {
  118.     /* 检查布防/撤防状态是否改变 */
  119.     if (Bluetooth_GetAndClearStatusChanged()) {
  120.       uint8_t armed_status = Bluetooth_GetArmedStatus();
  121.       DISPLAY_ArmedStatus(armed_status, 3000);
  122.       
  123.       if (armed_status) {
  124.         BUZZER_LoudAlarm();
  125.       } else {
  126.         BUZZER_Beep(100);
  127.       }
  128.     }
  129.    
  130.     /* 读取传感器数据 */
  131.     TEMP_HUMI_ReadData(&temperature, &humidity);
  132.     if (LIGHT_SENSOR_IsConnected()) {
  133.       LIGHT_SENSOR_ReadLight(&light);
  134.     }
  135.     ir_status = IR_Sensor_Detect();
  136.    
  137.     /* 更新气体传感器数据 - 确保每次循环都更新 */
  138.     uint16_t adc_value = GAS_SENSOR_Read();
  139.     if (adc_value > 0) {
  140.       GAS_SENSOR_UpdateData(&gas_data);
  141.     }
  142.    
  143.     /* 人体检测处理 */
  144.     if (ir_status && !last_ir_status) {
  145.       /* 更新显示 */
  146.       DISPLAY_UpdateEnvData(temperature, humidity, light, ir_status);
  147.       DISPLAY_GasData(&gas_data);
  148.       
  149.       /* 发送数据到蓝牙 - 恢复原来的两次发送格式 */
  150.       /* 第一次发送基本环境数据 */
  151.       char bt_data1[150];
  152.       sprintf(bt_data1, "{"temp":%.1f,"humi":%.1f,"light":%.1f,"human":%d,"aqi":%d,"pm25":%.1f}\r\n",
  153.               temperature, humidity, light, ir_status, gas_data.aqi, gas_data.pm25);
  154.       Bluetooth_SendString(bt_data1);
  155.       
  156.       /* 短暂延时,确保第一条数据发送完成 */
  157.       HAL_Delay(20);
  158.       
  159.       /* 第二次发送气体详细数据 */
  160.       char bt_data2[150];
  161.       sprintf(bt_data2, "{"co2":%.1f,"ppm":%.1f,"gas_type":%d,"safety":%d,"leak":%d,"fire":%d,"rate":%.2f}\r\n",
  162.               gas_data.co2_equivalent, gas_data.raw_ppm, gas_data.gas_type,
  163.               gas_data.safety_level, gas_data.leak_detected, gas_data.fire_risk, gas_data.change_rate);
  164.       Bluetooth_SendString(bt_data2);
  165.       
  166.       /* 布防状态下发出警报 */
  167.       if (Bluetooth_GetArmedStatus()) {
  168.         BUZZER_EmergencyAlarm();
  169.       }
  170.     }
  171.     last_ir_status = ir_status;
  172.    
  173.     /* 更新显示 */
  174.     DISPLAY_UpdateEnvData(temperature, humidity, light, ir_status);
  175.     DISPLAY_GasData(&gas_data);
  176.    
  177.     /* 处理蓝牙数据 */
  178.     Bluetooth_Process();
  179.    
  180.     /* 每5秒通过蓝牙发送环境数据 */
  181.     if (++bt_send_counter >= 5) {
  182.       bt_send_counter = 0;
  183.       
  184.       /* 恢复原来的两次发送格式 */
  185.       /* 第一次发送基本环境数据 */
  186.       char bt_data1[150];
  187.       sprintf(bt_data1, "{"temp":%.1f,"humi":%.1f,"light":%.1f,"human":%d,"aqi":%d,"pm25":%.1f}\r\n",
  188.               temperature, humidity, light, ir_status, gas_data.aqi, gas_data.pm25);
  189.       Bluetooth_SendString(bt_data1);
  190.       
  191.       /* 短暂延时,确保第一条数据发送完成 */
  192.       HAL_Delay(50);
  193.       
  194.       /* 第二次发送气体详细数据 */
  195.       char bt_data2[150];
  196.       sprintf(bt_data2, "{"co2":%.1f,"ppm":%.1f,"gas_type":%d,"safety":%d,"leak":%d,"fire":%d,"rate":%.2f}\r\n",
  197.               gas_data.co2_equivalent, gas_data.raw_ppm, gas_data.gas_type,
  198.               gas_data.safety_level, gas_data.leak_detected, gas_data.fire_risk, gas_data.change_rate);
  199.       Bluetooth_SendString(bt_data2);
  200.     }
  201.    
  202.     /* 切换LED指示灯状态 */
  203.     HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_13);
  204.    
  205.     /* 延时1秒 */
  206.     HAL_Delay(1000);
  207.   }
  208. }
  209. /**
  210.   * @brief 系统时钟配置
  211.   * @retval None
  212.   */
  213. void SystemClock_Config(void)
  214. {
  215.   RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  216.   RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
  217.   RCC_PeriphCLKInitTypeDef PeriphClkInit = {0};
  218.   RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
  219.   RCC_OscInitStruct.HSEState = RCC_HSE_ON;
  220.   RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;
  221.   RCC_OscInitStruct.HSIState = RCC_HSI_ON;
  222.   RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  223.   RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
  224.   RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9;
  225.   HAL_RCC_OscConfig(&RCC_OscInitStruct);
  226.   RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
  227.                               |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
  228.   RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  229.   RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  230.   RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
  231.   RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
  232.   HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2);
  233.   
  234.   /* 配置ADC时钟 */
  235.   PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_ADC;
  236.   PeriphClkInit.AdcClockSelection = RCC_ADCPCLK2_DIV6;
  237.   HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit);
  238. }
  239. /**
  240.   * @brief GPIO初始化函数
  241.   * @param None
  242.   * @retval None
  243.   */
  244. void MX_GPIO_Init(void)
  245. {
  246.   GPIO_InitTypeDef GPIO_InitStruct = {0};
  247.   /* 使能GPIO时钟 */
  248.   __HAL_RCC_GPIOC_CLK_ENABLE();
  249.   __HAL_RCC_GPIOD_CLK_ENABLE();
  250.   __HAL_RCC_GPIOA_CLK_ENABLE();
  251.   __HAL_RCC_GPIOB_CLK_ENABLE();
  252.   /* 配置PC13引脚为输出 */
  253.   HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_RESET);
  254.   GPIO_InitStruct.Pin = GPIO_PIN_13;
  255.   GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  256.   GPIO_InitStruct.Pull = GPIO_NOPULL;
  257.   GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
  258.   HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
  259.   
  260.   /* 配置PA0引脚为模拟输入(气体传感器) */
  261.   GPIO_InitStruct.Pin = GPIO_PIN_0;
  262.   GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
  263.   GPIO_InitStruct.Pull = GPIO_NOPULL;
  264.   HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
  265. }
  266. /**
  267.   * @brief I2C1初始化函数
  268.   * @param None
  269.   * @retval None
  270.   */
  271. void MX_I2C1_Init(void)
  272. {
  273.   hi2c1.Instance = I2C1;
  274.   hi2c1.Init.ClockSpeed = 100000;
  275.   hi2c1.Init.DutyCycle = I2C_DUTYCYCLE_2;
  276.   hi2c1.Init.OwnAddress1 = 0;
  277.   hi2c1.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
  278.   hi2c1.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
  279.   hi2c1.Init.OwnAddress2 = 0;
  280.   hi2c1.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
  281.   hi2c1.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;
  282.   
  283.   HAL_I2C_Init(&hi2c1);
  284. }
  285. /**
  286.   * @brief ADC1初始化函数
  287.   * @param None
  288.   * @retval None
  289.   */
  290. void MX_ADC1_Init(void)
  291. {
  292.   ADC_ChannelConfTypeDef sConfig = {0};
  293.   /* ADC1基本配置 */
  294.   hadc1.Instance = ADC1;
  295.   hadc1.Init.ScanConvMode = ADC_SCAN_DISABLE;
  296.   hadc1.Init.ContinuousConvMode = DISABLE;
  297.   hadc1.Init.DiscontinuousConvMode = DISABLE;
  298.   hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START;
  299.   hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;
  300.   hadc1.Init.NbrOfConversion = 1;
  301.   HAL_ADC_Init(&hadc1);
  302.   /* 配置ADC通道0(PA0引脚)- 气体传感器 */
  303.   sConfig.Channel = ADC_CHANNEL_0;
  304.   sConfig.Rank = ADC_REGULAR_RANK_1;
  305.   sConfig.SamplingTime = ADC_SAMPLETIME_55CYCLES_5;
  306.   HAL_ADC_ConfigChannel(&hadc1, &sConfig);
  307.   
  308.   /* 校准ADC */
  309.   HAL_ADCEx_Calibration_Start(&hadc1);
  310. }
  311. /**
  312.   * @brief USART1初始化函数
  313.   * @param None
  314.   * @retval None
  315.   */
  316. void MX_USART1_UART_Init(void)
  317. {
  318.   huart1.Instance = USART1;
  319.   huart1.Init.BaudRate = 9600;
  320.   huart1.Init.WordLength = UART_WORDLENGTH_8B;
  321.   huart1.Init.StopBits = UART_STOPBITS_1;
  322.   huart1.Init.Parity = UART_PARITY_NONE;
  323.   huart1.Init.Mode = UART_MODE_TX_RX;
  324.   huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
  325.   huart1.Init.OverSampling = UART_OVERSAMPLING_16;
  326.   
  327.   HAL_UART_Init(&huart1);
  328.   
  329.   /* 启用UART接收中断 */
  330.   HAL_NVIC_SetPriority(USART1_IRQn, 0, 0);
  331.   HAL_NVIC_EnableIRQ(USART1_IRQn);
  332. }
  333. /**
  334.   * @brief 错误处理函数
  335.   * @retval None
  336.   */
  337. void Error_Handler(void)
  338. {
  339.   __disable_irq();
  340.   while (1)
  341.   {
  342.   }
  343. }
  344. #ifdef  USE_FULL_ASSERT
  345. void assert_failed(uint8_t *file, uint32_t line)
  346. {
  347.   /* 用户可以添加自己的实现来报告文件名和行号 */
  348. }
  349. #endif /* USE_FULL_ASSERT */
复制代码
 
15.png
7.​原理图

16.png


 
17.png

欢迎在评论区交流讨论!​
 
来源:豆瓜网用户自行投稿发布,如果侵权,请联系站长删除

相关推荐

您需要登录后才可以回帖 登录 | 立即注册