基于stm单片机家庭环境监测系统
基于STM单片机家庭环境监测系统一、引言从零开始构建您的智能环境监测系统在现代家庭中环境质量对健康和生活舒适度至关重要。温度、湿度、空气质量等参数需要我们实时监控。本教程将引导您使用STM32单片机从基础概念到高级应用一步步构建一个完整的家庭环境监测系统。您不需要深厚的嵌入式经验只需跟随我们的步伐就能掌握核心技能。## 二、基础概念STM单片机与传感器入门### 2.1 什么是STM单片机STM32是意法半导体推出的基于ARM Cortex-M内核的32位微控制器系列。它具有高性能、低功耗、丰富外设接口的特点非常适合物联网和嵌入式项目。在本系统中我们将使用STM32F103C8T6俗称“蓝色药丸”作为主控芯片。### 2.2 环境监测常用传感器-DHT11温湿度传感器数字输出单总线协议测量范围0-50°C20-90%RH-MQ-135空气质量传感器模拟输出检测氨气、苯、烟雾等-BH1750光照传感器I2C接口高精度数字光照强度检测### 2.3 核心概念ADC与通信协议-ADC模数转换将模拟电压信号转换为数字值用于读取MQ-135等模拟传感器-I2C协议两线制串行通信用于连接BH1750等数字传感器-单总线协议DHT11使用的通信方式一根数据线完成读写## 三、硬件搭建与电路连接### 3.1 所需材料清单| 组件 | 数量 | 说明 ||------|------|------|| STM32F103C8T6开发板 | 1 | 主控 || DHT11传感器 | 1 | 温湿度检测 || MQ-135传感器模块 | 1 | 空气质量检测 || BH1750光照传感器 | 1 | 光照检测 || 0.96寸OLED显示屏 | 1 | I2C接口显示 || 面包板、杜邦线 | 若干 | 连接电路 |### 3.2 电路连接图文字描述STM32引脚分配- PA0: DHT11数据线单总线- PA1: MQ-135模拟输出ADC通道- PB6: I2C1_SCL (连接OLED和BH1750)- PB7: I2C1_SDA (连接OLED和BH1750)- PA9: USART1_TX (串口打印数据)- PA10: USART1_RX## 四、基础代码实现读取温湿度传感器### 4.1 初始化与DHT11驱动以下代码展示了如何初始化GPIO并读取DHT11数据。这是整个系统的基础请仔细理解注释。c// dht11.h#ifndef __DHT11_H#define __DHT11_H#include stm32f10x.h// DHT11数据引脚定义#define DHT11_GPIO_PORT GPIOA#define DHT11_GPIO_PIN GPIO_Pin_0#define DHT11_RCC RCC_APB2Periph_GPIOA// 函数声明void DHT11_Init(void);uint8_t DHT11_ReadData(uint8_t *temperature, uint8_t *humidity);#endifc// dht11.c#include dht11.h#include delay.h // 需要自己实现毫秒和微秒延时函数/** * brief 初始化DHT11引脚为推挽输出模式 */void DHT11_Init(void){ GPIO_InitTypeDef GPIO_InitStructure; RCC_APB2PeriphClockCmd(DHT11_RCC, ENABLE); GPIO_InitStructure.GPIO_Pin DHT11_GPIO_PIN; GPIO_InitStructure.GPIO_Mode GPIO_Mode_Out_PP; // 推挽输出 GPIO_InitStructure.GPIO_Speed GPIO_Speed_50MHz; GPIO_Init(DHT11_GPIO_PORT, GPIO_InitStructure); // 初始状态拉高 GPIO_SetBits(DHT11_GPIO_PORT, DHT11_GPIO_PIN);}/** * brief 读取DHT11温湿度数据 * param temperature: 温度值指针单位°C * param humidity: 湿度值指针单位%RH * retval 0:成功 1:失败 */uint8_t DHT11_ReadData(uint8_t *temperature, uint8_t *humidity){ uint8_t buf[5]; uint8_t i; uint8_t data; // 1. 主机发送起始信号拉低至少18ms GPIO_ResetBits(DHT11_GPIO_PORT, DHT11_GPIO_PIN); delay_ms(20); // 延时20ms GPIO_SetBits(DHT11_GPIO_PORT, DHT11_GPIO_PIN); delay_us(30); // 等待30us // 2. 配置为输入模式等待DHT11响应 GPIO_InitStructure.GPIO_Mode GPIO_Mode_IPU; // 上拉输入 GPIO_Init(DHT11_GPIO_PORT, GPIO_InitStructure); // 3. 检查响应信号低电平80us 高电平80us if(GPIO_ReadInputDataBit(DHT11_GPIO_PORT, DHT11_GPIO_PIN) 0) { while(GPIO_ReadInputDataBit(DHT11_GPIO_PORT, DHT11_GPIO_PIN) 0); // 等待低电平结束 while(GPIO_ReadInputDataBit(DHT11_GPIO_PORT, DHT11_GPIO_PIN) 1); // 等待高电平结束 // 4. 读取40位数据5字节 for(i 0; i 5; i) { data 0; for(uint8_t j 0; j 8; j) { while(GPIO_ReadInputDataBit(DHT11_GPIO_PORT, DHT11_GPIO_PIN) 0); // 等待低电平 delay_us(40); // 延时40us判断电平 if(GPIO_ReadInputDataBit(DHT11_GPIO_PORT, DHT11_GPIO_PIN) 1) { data | (1 (7 - j)); // 高位在前 } while(GPIO_ReadInputDataBit(DHT11_GPIO_PORT, DHT11_GPIO_PIN) 1); // 等待高电平结束 } buf[i] data; } // 5. 校验和验证 (前4字节之和等于第5字节) if((buf[0] buf[1] buf[2] buf[3]) buf[4]) { *humidity buf[0]; // 湿度整数部分 *temperature buf[2]; // 温度整数部分 return 0; // 成功 } } // 恢复为输出模式 GPIO_InitStructure.GPIO_Mode GPIO_Mode_Out_PP; GPIO_Init(DHT11_GPIO_PORT, GPIO_InitStructure); return 1; // 失败}## 五、进阶应用集成多传感器与数据融合### 5.1 使用I2C读取BH1750光照传感器BH1750支持I2C通信分辨率可达1 lux。以下代码实现初始化与读取。c// bh1750.c#include bh1750.h#define BH1750_ADDR 0x23 // ADDR引脚接GND时的地址#define BH1750_I2C I2C1/** * brief 初始化BH1750设置为连续高分辨率模式 */void BH1750_Init(void){ uint8_t cmd 0x10; // 连续高分辨率模式 I2C_Start(BH1750_I2C); I2C_SendByte(BH1750_I2C, BH1750_ADDR 1 | 0); // 写地址 I2C_WaitAck(BH1750_I2C); I2C_SendByte(BH1750_I2C, cmd); I2C_WaitAck(BH1750_I2C); I2C_Stop(BH1750_I2C); delay_ms(120); // 等待第一次测量完成}/** * brief 读取光照强度值 * param lux: 光照强度指针单位lux * retval 0:成功 1:失败 */uint8_t BH1750_ReadLight(uint16_t *lux){ uint8_t buf[2]; // 读取2字节数据 I2C_Start(BH1750_I2C); I2C_SendByte(BH1750_I2C, BH1750_ADDR 1 | 1); // 读地址 I2C_WaitAck(BH1750_I2C); buf[0] I2C_ReadByte(BH1750_I2C); // 高位 I2C_Ack(BH1750_I2C); buf[1] I2C_ReadByte(BH1750_I2C); // 低位 I2C_NAck(BH1750_I2C); I2C_Stop(BH1750_I2C); // 计算光照值 (高分辨率模式下每单位1 lux) *lux (buf[0] 8) | buf[1]; return 0;}### 5.2 ADC读取MQ-135空气质量MQ-135输出模拟电压通过STM32的ADC1通道1读取。c// adc.c - 初始化ADC1void ADC1_Init(void){ ADC_InitTypeDef ADC_InitStructure; GPIO_InitTypeDef GPIO_InitStructure; // 使能ADC1和GPIOA时钟 RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1 | RCC_APB2Periph_GPIOA, ENABLE); // 配置PA1为模拟输入 GPIO_InitStructure.GPIO_Pin GPIO_Pin_1; GPIO_InitStructure.GPIO_Mode GPIO_Mode_AIN; GPIO_Init(GPIOA, GPIO_InitStructure); // ADC配置 ADC_DeInit(ADC1); ADC_InitStructure.ADC_Mode ADC_Mode_Independent; ADC_InitStructure.ADC_ScanConvMode DISABLE; ADC_InitStructure.ADC_ContinuousConvMode DISABLE; ADC_InitStructure.ADC_ExternalTrigConv ADC_ExternalTrigConv_None; ADC_InitStructure.ADC_DataAlign ADC_DataAlign_Right; ADC_InitStructure.ADC_NbrOfChannel 1; ADC_Init(ADC1, ADC_InitStructure); // 配置通道1采样时间 ADC_RegularChannelConfig(ADC1, ADC_Channel_1, 1, ADC_SampleTime_239Cycles5); // 使能ADC ADC_Cmd(ADC1, ENABLE); ADC_ResetCalibration(ADC1); while(ADC_GetResetCalibrationStatus(ADC1)); ADC_StartCalibration(ADC1); while(ADC_GetCalibrationStatus(ADC1));}// 读取ADC值返回0-4095uint16_t ADC_ReadValue(void){ ADC_SoftwareStartConvCmd(ADC1, ENABLE); while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC)); return ADC_GetConversionValue(ADC1);}## 六、系统集成主循环与数据显示### 6.1 主程序框架将所有传感器数据汇总通过OLED显示并通过串口发送到上位机。c// main.c#include stm32f10x.h#include delay.h#include dht11.h#include bh1750.h#include adc.h#include oled.h#include usart.hint main(void){ uint8_t temp, humi; uint16_t lux, adc_value; char display_buf[32]; // 初始化各模块 delay_init(72); // 系统时钟72MHz USART1_Init(9600); // 串口1初始化 DHT11_Init(); BH1750_Init(); ADC1_Init(); OLED_Init(); // I2C OLED初始化 OLED_ShowString(0, 0, System Init OK); while(1) { // 1. 读取温湿度 if(DHT11_ReadData(temp, humi) 0) { // 2. 读取光照强度 BH1750_ReadLight(lux); // 3. 读取空气质量ADC值 adc_value ADC_ReadValue(); // 4. 在OLED上显示 OLED_Clear(); sprintf(display_buf, Temp: %dC, temp); OLED_ShowString(0, 0, display_buf); sprintf(display_buf, Humi: %d%%, humi); OLED_ShowString(0, 2, display_buf); sprintf(display_buf, Light: %d lux, lux); OLED_ShowString(0, 4, display_buf); sprintf(display_buf, Air: %d, adc_value); OLED_ShowString(0, 6, display_buf); // 5. 通过串口发送到PC printf(Temp%d, Humi%d, Light%d, Air%d\r\n, temp, humi, lux, adc_value); } delay_ms(2000); // 每2秒采集一次 }}### 6.2 数据融合与告警逻辑在实际应用中我们通常需要设定阈值并触发告警。例如当温度超过35°C或空气质量变差时通过蜂鸣器报警。cvoid CheckAlarm(uint8_t temp, uint16_t adc_value){ static uint8_t alarm_active 0; // 温度过高或空气质量差ADC值3000表示空气质量不佳 if(temp 35 || adc_value 3000) { if(!alarm_active) { GPIO_SetBits(GPIOB, GPIO_Pin_12); // 开启蜂鸣器 alarm_active 1; printf(ALARM: Environmental issue detected!\r\n); } } else { if(alarm_active) { GPIO_ResetBits(GPIOB, GPIO_Pin_12); // 关闭蜂鸣器 alarm_active 0; } }}## 七、高级功能扩展### 7.1 数据上传至云端通过ESP8266 Wi-Fi模块可以将数据上传到阿里云或OneNET平台。STM32通过AT指令控制ESP8266实现MQTT协议通信。### 7.2 低功耗设计使用STM32的待机模式配合RTC定时唤醒可将系统功耗降至微安级别。在采集间隙进入睡眠模式是电池供电系统的关键。### 7.3 传感器校准每个传感器都有个体差异可以通过软件校准。例如将BH1750的原始值乘以一个校准系数或者对DHT11进行温度偏移修正。## 八、总结通过本教程您从零开始构建了一个基于STM32的家庭环境监测系统。我们学习了- STM32单片机的基础知识和外设配置- DHT11、BH1750、MQ-135等传感器的驱动编写- ADC、I2C、单总线等通信协议的实际应用- 数据融合、告警逻辑和系统集成方法这个系统具有很强的可扩展性您可以添加更多传感器如PM2.5、甲醛检测增加Wi-Fi联网功能甚至通过手机App远程查看数据。记住嵌入式开发的核心在于实践——动手焊接电路、调试代码、优化逻辑每一次失败都是进步的阶梯。现在拿起您的STM32开发板开始构建属于自己的家庭环境监测系统吧当您看到OLED屏幕上实时显示的温度、湿度和光照数据时那种成就感将是无与伦比的。