ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

STM32图书馆环境监测系统:温湿度、烟雾、光照监测与报警,附Proteus仿真及全套源码

STM32图书馆环境监测系统:温湿度、烟雾、光照监测与报警,附Proteus仿真及全套源码 手头攒了挺久的一套STM32资料最近终于抽出时间整理完整了——图书馆环境监测系统基于STM32F103C8T6代码、原理图、Proteus仿真一次放全。这套项目早先是给朋友应急做课设用的后来我自己回炉了几个版本把原来松散的模块重新捋了一遍又把调试过程中踩过的坑都记了下来。现在把它开源出来就是想着给正在选毕业设计题目、或者初学32想找个完整项目练手的兄弟们一个能直接跑起来的东西。图书馆环境监测系统这个名字听起来挺学院派其实干的事很直白实时采集温湿度、光照强度、烟雾浓度把数据显示在OLED或LCD上参数越界就触发蜂鸣器报警同时按键可以切换显示页面和调整阈值。整套东西拆开看就是STM32最典型的GPIO、定时器、ADC、I2C、外部中断这些外设的综合练习难度不大但五脏俱全非常适合用来把单片机知识串成一条线。下面我从整体设计、硬件原理图、软件代码、Proteus仿真到调试经验按一条完整做项目的思路全部讲透资料包在文末说明获取方式。1. 系统整体设计与架构拆解1.1 需求分析图书馆为什么需要环境监测做项目之前先把需求想清楚这是很多初学者容易跳过的步骤。图书馆不是普通仓库它对环境是有硬指标的纸质藏书对温湿度非常敏感温度过高会加速纸张老化和油墨褪色湿度过大容易发霉生虫湿度太低纸张又会变脆古籍善本区的要求更苛刻。阅览区光照太强会影响读者阅读体验太暗则伤眼睛。另外图书馆里电气设备多——照明、电脑、空调、插座线路——火灾隐患并不小烟雾检测属于刚需。传统的人工巡检方式有几个明显短板一是频次上不去不可能一天24小时每小时都有人拿温湿度计去测一遍二是发现问题有滞后性等人工发现的时候环境可能已经超标一段时间了三是数据留不下来没法做趋势分析。所以做一个自动化的环境监测终端把传感器数据实时采集、超限报警、可视化展示一次搞定这就是整个系统的核心需求。这套项目做下来你学到的不是某个孤立的知识点而是从需求出发倒推方案选型、硬件设计、软件编码、仿真验证的完整链路。这一套能力比单纯背十个寄存器要有价值得多。1.2 监测参数与传感器选型确定需求之后就要定监测哪些参数、用什么传感器。我这套方案一共做了四路采集温度、湿度用DHT11数字温湿度传感器单总线协议一条IO口就能读数据电路极其简单工程实践里最常见的入门选择。温度量程0-50℃湿度20-90%RH精度分别是±2℃和±5%RH对于环境监测这个场景完全够用。如果你要更高精度可以换SHT30I2C接口程序逻辑会更简单但价格贵几块钱。烟雾浓度用MQ-2半导体气敏传感器对液化气、丙烷、氢气、烟雾都比较敏感响应时间在10秒以内。MQ-2模块有两种输出一种是数字量输出板载LM393比较器旋钮调阈值一种是模拟量输出直接输出0-5V电压。我这个项目用的是模拟量输出接STM32的ADC这样可以测到连续变化的数据报警阈值在软件里可以随意设置灵活性高很多。光照强度不搞高端的BH1750数字光照传感器直接用一个光敏电阻加一个10K电阻分压进ADC采样。简单可靠成本几毛钱还能练到ADC多通道采集。从实际测量看这个分压电路在图书馆室内环境下区分“明亮”“正常”“较暗”三个等级完全没问题。还有一路是预留按键输入用于切换显示页面和调整报警阈值算不上监测参数但它是交互的基础。1.3 主控选型为什么是STM32F103C8T6选STM32F103C8T6不是因为它最强而是因为它处在“学习性价比”和“工程实用性”的交叉点上。跟你对比一下就知道如果选51单片机那是在用上个时代的工具链外设资源太少连ADC多通道都要自己用软件模拟上手容易但做完项目会觉得自己什么都没学到。如果选ESP8266或ESP32确实自带WiFi很高级但会引入联网、协议栈这些额外复杂度而且很多学校实验室的Proteus仿真环境根本不支持这些芯片做仿真就得换方案。Arduino就更不用说了封装太狠写完程序都不知道底层在干什么。STM32F103C8T6的优势就出来了64KB Flash20KB SRAM3个USART2个SPI2个I2C10个12位ADC通道这些资源做这个项目只用了不到一半余量非常充裕。库函数和HAL库资料满天飞遇到问题随处可查。价格在国产替代和翻新片盛行的今天几块钱一片。而且Proteus 8.x 版本内置了STM32F103C8T6模型仿真可以直接做。这个选择兼顾了学习深度、工程实践和毕设演示效果。1.4 系统架构与数据流整套系统的数据流是这样的传感器把物理量转换成电信号STM32通过GPIO读取DHT11的温湿度数据通过ADC1的CH0和CH1分别读取烟雾浓度和光照强度的模拟电压然后主控做数据处理、阈值比较、页面渲染把结果显示到OLED屏幕I2C接口上超限时通过GPIO拉高蜂鸣器驱动电路。用户按键通过外部中断或轮询方式输入负责切换页面和调整阈值。Proteus仿真部分和硬件电路是两套独立文件但逻辑一一对应仿真里用虚拟的DHT11模型、滑动变阻器模拟传感器电压输出来验证代码逻辑的正确性。这样你在没有实物的情况下也能先把整个系统的逻辑验证通再去焊板子能省下大量调试时间。2. 硬件原理图拆解从最小系统到各模块电路2.1 STM32最小系统能跑起来的基础原理图里最小系统是重中之重这部分电路错了后面全白搭。F103C8T6的最小系统包含五个部分电源、晶振、复位、BOOT配置、下载电路。供电部分F103C8T6工作电压是2.0-3.6V典型3.3V我是用USB的5V输入经过AMS1117-3.3线性稳压芯片降到3.3V。AMS1117输入端接一个100uF电解电容和0.1uF陶瓷电容输出端接一个10uF钽电容和0.1uF陶瓷电容用于去耦和稳压。芯片的每一个电源引脚旁边都就近放一个100nF去耦电容这是PCB布线的铁律不是可选项。晶振电路F103C8T6主晶振用8MHz无源晶振两个引脚各接一个22pF负载电容到地。为什么是22pF因为STM32数据手册给出的晶振负载电容推荐范围是10-20pF实践上22pF也能稳定起振。注意这两个电容要离晶振引脚越近越好走线要短。另外还有一颗32.768kHz的RTC晶振这个项目没有用到RTC功能所以我没画用内部RC振荡器就够了。复位电路NRST引脚上接一个10K电阻到3.3V做上拉再并联一个100nF电容到地按键按下时把NRST拉到低电平实现复位。这个100nF电容的作用是滤除复位引脚的干扰防止误复位。BOOT配置BOOT0和BOOT1引脚各接一个10K下拉电阻到地确保默认从主Flash启动。这样程序下载到Flash后才能正常运行。下载电路强烈推荐用SWD只占用SWDIO、SWCLK两根线加GND4根线搞定下载和调试比JTAG省一半引脚。SWDIO和SWCLK各接一个10K上拉电阻防止干扰。用ST-Link V2下载便宜好用兼容性好。2.2 DHT11与OLED模块电路上拉电阻别省DHT11的数据线接在STM32的某个GPIO上我用的PA6仿真和实物代码保持一致DATA引脚必须接一个4.7K上拉电阻到3.3V。这个上拉电阻不是可选项因为DHT11的通信协议是靠主机和数据线之间的电平拉高拉低实现的DHT11本身是开漏输出没有上拉电阻电平就没法定下来数据位会乱。很多同学DHT11读取失败根源就是漏了这个4.7K电阻。另外DHT11的VCC和GND之间就近放一个100nF去耦电容。OLED显示屏我选的是I2C接口的0.96寸SSD1306方案四根线VCC、GND、SCL、SDA。I2C总线上SCL和SDA各接一个4.7K上拉电阻到3.3V。I2C协议本身就是开漏结构必须靠上拉电阻才能把总线拉到高电平。很多同学OLED白屏检查来检查去最后发现是上拉电阻没焊或者焊了不匹配的阻值。I2C的上拉电阻阻值在1K-10K之间都能工作4.7K是最通用的。这里我额外说一个细节OLED的VCC一般是3.3V还是5V要看具体模块我用的模块是3.3V供电。如果买的是5V版本要注意逻辑电平兼容问题STM32的引脚是3.3V电平理论上OLED的I2C引脚如果是5V容忍的话没问题但稳妥起见还是选3.3V供电版本省心。2.3 MQ-2烟雾传感器电路模拟量分压与ADC采集MQ-2模块的模拟量输出引脚输出0-5V的模拟电压但STM32的ADC输入范围是0-3.3V直接接上去会把ADC输入引脚烧坏或者即使不烧坏超过3.3V的部分也采不到。所以原理图里我加了一级电阻分压模拟量输出串联一个1K电阻到ADC采样点采样点再接一个2K电阻到GND把0-5V映射到0-3.33V左右。这个分压比是1K:2K分压系数是2/(12)2/35V×2/3≈3.33V刚刚好压在3.3V附近既不会超量程又能用满ADC的采样范围。ADC采样点还要加一个100nF电容到GND做低通滤波滤除高频噪声。这个电容对稳定性帮助非常大不加的话ADC采出来的数据会跳得很厉害。MQ-2模块本身有个问题容易忽略它的内部有一个加热电阻丝通电后需要预热几分钟让传感器内部电化学反应达到平衡后再开始采样数值才相对稳定。实际使用中我是在系统初始化时加了3秒的预热延时然后取后面连续采样的平均值作为初始基准值。MQ-2的功耗也值得注意它的加热丝功耗在150mW左右加上其他电路整套系统电流大概有80-100mA。用USB供电或者5V适配器供电都够但如果你打算用电池供电就要考虑这个功耗可能需要选低功耗的替代方案。2.4 蜂鸣器驱动电路为什么不能直接接GPIO报警用的蜂鸣器是有源蜂鸣器内部带振荡源给电就响工作电压3.3-5V。但注意STM32的GPIO最大输出电流只有±25mA实际上是数据手册推荐的绝对最大额定值实际设计建议不超过20mA直接驱动蜂鸣器不仅电流不够蜂鸣器工作时的反电动势还可能倒灌损坏MCU引脚。所以原理图里我用三极管做开关驱动。我用的是S8050 NPN三极管集电极接蜂鸣器负极蜂鸣器正极接3.3V发射极接地基极串联一个1K限流电阻接STM32的GPIO。GPIO输出高电平3.3V时经过1K电阻的基极电流大约是(3.3-0.7)/1000≈2.6mA这个电流足以让S8050进入饱和导通状态蜂鸣器通电发声。GPIO输出低电平时三极管截止蜂鸣器不响。蜂鸣器两端还并联了一个1N4148开关二极管方向是负极接蜂鸣器正极、正极接蜂鸣器负极。这个二极管叫续流二极管它给蜂鸣器线圈在断电瞬间产生的反向电动势提供一个泄放回路防止这个反向高压把三极管击穿。这个细节很多入门教程都不讲但工程上必须要有。2.5 按键与PCB布局心得按键我做了三个KEY1、KEY2、KEY3对应“页面切换”“阈值加”“阈值减”。按键一端接GPIO另一端接地GPIO内部开启上拉按键按下时引脚被拉低读取到低电平表示按下。这种接法省掉了外部上拉电阻但对程序有个要求——必须做按键消抖一般是延时10-20ms再重新读取确认电平。PCB布局说几个实用心得第一晶振电路、去耦电容这些高速或敏感部分要优先布局离MCU越近越好第二电源走线要宽至少1mm以上模拟信号线ADC采样线要短远离电源和蜂鸣器这样的干扰源第三预留测试点3.3V、GND、每个传感器信号线都留一个过孔或者焊盘方便调试时飞线、量波形第四如果条件允许数字地和模拟地单点连接可以从根本上减少ADC噪声。3. 软件代码实现与关键逻辑3.1 开发环境与代码工程结构我用的开发环境是Keil MDK5配合ST-Link下载调试。关于标准外设库还是HAL库的选择我这次用的是标准外设库。原因有三第一这个项目用到的外设都是最基础的GPIO、ADC、I2C、定时器没有复杂到需要HAL库的CubeMX图形化配置的程度第二标准库的代码阅读起来更直白初始化过程能看到寄存器层面是怎么设置的更适合学习第三从网上参考的资料和代码量来看标准库版本的资料更多遇到问题好排查。当然你用HAL库也没问题逻辑是一样的只是API名字不同。工程目录我按功能模块划分清晰方便查找USERmain.c、stm32f10x_it.c、系统时钟配置HARDWAREdht11.c、adc.c、oled.c、beep.c、key.c、mq2.c、light.cSYSTEMdelay.c、sys.c、usart.cCORE启动文件和内核相关文件OBJ编译输出每个硬件模块一个.c和一个.h文件接口尽量对上——这个习惯在团队协作和后期维护里能省很多事。3.2 DHT11驱动时序是关键DHT11的单总线时序是整个项目里最容易写崩的部分。我先说协议流程再给出代码关键部分。主机发送起始信号主机先拉低数据线至少18ms我延时20ms然后释放并拉高20-40us我延时30us等待DHT11响应。DHT11响应DHT11检测到起始信号后拉低80us然后拉高80us表示“我准备好了马上发数据”。主机在这个阶段要切换GPIO为输入模式读取后续的数据位。数据位读取每一位数据都从低电平50us开始然后拉高高电平持续26-28us表示“0”持续70us表示“1”。判断方法是在数据位信号的高电平期间延时40us后再次读取引脚电平如果还是高电平就是“1”如果已经变低就是“0”。数据格式40位数据顺序是8位湿度整数 8位湿度小数 8位温度整数 8位温度小数 8位校验和。校验和是前四个字节相加取低8位如果校验不通过这帧数据就丢弃重读。代码核心是GPIO模式切换和延时准确性。我贴一下读取单字节的核心逻辑uint8_t DHT11_ReadByte(void) { uint8_t i, data 0; for(i 0; i 8; i) { while(DHT11_DQ_READ() 0); // 等待50us低电平结束 delay_us(40); // 高电平中段采样 if(DHT11_DQ_READ() 1) // 采样到高电平 { data | (0x01 (7 - i)); // 是数据位1 while(DHT11_DQ_READ() 1); // 等待高电平结束 } // 否则该位为0无需处理 } return data; }这里有两个坑。第一个是while等待循环要加超时退出如果DHT11没接好或损坏引脚一直处于某种状态程序会死循环卡死整个系统无响应。我给所有while等待都加了超时计数超时直接返回错误标志。第二个是delay_us的精度。标准库下的delay_us通常是用SysTick实现的精度够用。但不能用HAL_Delay或者简单的空循环代替因为DHT11的时序单位是微秒级别用毫秒延时代码必然读不出数据。如果你是拿现成代码改的一定要注意延时函数的实现方式。3.3 ADC多通道采集与数据处理ADC部分我用的是ADC1的通道0PA0采光照、通道1PA1采烟雾。配置要点是ADC时钟分频设为6即72MHz/612MHz这是ADC最大允许时钟采样周期我设成55.5个周期适当长一点能降低采样阻抗对结果的影响使用扫描模式、连续转换模式配合DMA把两个通道的数据自动搬运到内存数组中CPU不用一直在中断里等ADC完成。有人会问为什么不用规则组的单次转换手动切换通道用DMA的好处是CPU负载低数据自动更新主循环里只读缓存数组就行代码更简洁。这个项目里DMA的配置很基础用标准库也就十几行。ADC采集到的是12位数字量0-4095要换算成实际电压值电压 ADC值 × 3.3V / 4095。比如MQ-2分压后输入到PA1的电压是1.65V那么ADC值大约就是2048。接下来是关键的处理环节——滤波。硬件上我加了100nF滤波电容但软件滤波同样必要。我用的是中值滤波加滑动平均的组合连续采5次去掉最大最小值剩下3个求平均。这个组合对脉冲干扰的抑制效果很好实际测试下来ADC数据跳变幅度能从±50降到±10以内。这在报警系统中很重要不然阈值附近的临界值会导致蜂鸣器反复鸣叫。光照等级的划分我的做法是ADC值小于800约0.65V判定为“明亮”800-1800判定为“正常”大于1800判定为“较暗”。这几个值不是拍脑袋定的是根据我手头的光敏电阻在室内不同光照条件下的实测数据定下来的。你做实物的时候这三个阈值要根据自己的光敏电阻实测重新标定。3.4 主流程与状态机设计主程序的架构我用了经典的单循环加状态机模式。初始化完成后主循环按固定顺序执行读取传感器数据、处理按键事件、更新报警状态、刷新显示。伪代码结构如下int main(void) { SystemInit(); delay_init(72); OLED_Init(); ADC_Init(); DHT11_Init(); BEEP_Init(); KEY_Init(); while(1) { DHT11_ReadData(temp, humi); // 读取温湿度含校验 smoke_value Get_ADC_Average(ADC_CH1); // 烟雾ADC滤波值 light_value Get_ADC_Average(ADC_CH0); // 光照ADC滤波值 KEY_Scan(); // 按键处理含消抖 Alarm_Process(); // 报警判断逻辑 Display_Update(); // 刷新显示 } }报警逻辑我是这样设计的每个参数有两级阈值。以温度为例正常值范围比如18℃-26℃超过这个范围第一级触发LCD上显示警告标志超过更严重的阈值比如30℃第二级触发蜂鸣器持续鸣叫。并且设置了一个“报警确认”机制按键按下后蜂鸣器静音但如果状态依然超限几秒后会再次响起。这个设计防的是夜间无人值守时蜂鸣器因为一个瞬时波动一直响个不停又防了单纯静音后无人处理风险依然存在。类似的逻辑放在湿度、烟雾上也都适用。按键扫描我放在主循环里用状态机处理短按、长按配合10-20ms延时消抖。因为按键在这个项目里不是高频操作放主循环完全够不用上外部中断反而逻辑更简单不容易出错。3.5 OLED显示页面设计OLED是0.96寸128x64分辨率的SSD1306驱动我用I2C接口。显示内容分三页第一页是温湿度大号数字显示第二页是烟雾浓度和光照等级第三页是阈值设置页。按键切换页面。显示刷新的一个省心技巧不要每帧全屏刷新。SSD1306的显存是1KB128x64/8全屏刷新需要的I2C传输量不小频繁刷新会有闪烁感。我的做法是只在特定区域做局部更新比如只更新变化区域的字符页面切换时再全屏清屏重绘。这样刷新率可以提到20Hz以上肉眼看起来非常流畅。OLED驱动代码用的是常见的SSD1306中文显示方案把字模数组按固定格式放在代码里。如果你想显示汉字建议用小字体字模128x64的分辨率塞不了太多内容设计页面时要在信息量和字号之间取平衡。4. Proteus仿真搭建与联调4.1 仿真电路搭建思路Proteus仿真这部分我在资料包里提供了完整的仿真工程文件可以直接打开运行但我还是建议你自己动手搭一遍因为仿真搭建过程中对电路的理解会比直接跑现成的深很多。新建Proteus工程后从元件库里搜索添加以下元件STM32F103C8T6在Proteus中可以直接搜索到、DHT11、光敏电阻用LDR或直接用可变电阻RV1模拟、MQ-2Proteus元件库没有MQ-2模型用RV2滑动变阻器代替通过调节阻值模拟烟雾浓度变化、OLEDProteus老版本没有SSD1306模型新版有如果没有就改用LM016L即LCD1602代替、8Ω蜂鸣器BUZZER、S8050三极管、电阻电容若干。注意MCU主频设置Proteus仿真时如果代码用的8MHz外部晶振配置但Proteus中的STM32模型有时对HSE仿真支持不完美容易导致延时函数时间不准表现出来就是DHT11读不出来。我的做法是仿真工程的代码版本使用HSI内部时钟8MHz绕开外部晶振仿真问题。这是仿真和实物差异最大的地方我在资料里放了两个不同时钟配置的工程版本不必混用。4.2 仿真联调流程与技巧仿真联调的第一步是编译生成hex文件。在Keil中把Output选项卡里的“Create HEX File”打勾编译后在OBJ目录下生成.hex文件。然后在Proteus中双击STM32F103C8T6芯片在Program File一栏选择这个hex文件时钟频率设为8MHz点击运行。如果一切正常OLED或LCD1602上会显示温湿度数据。在仿真里DHT11模型会自动输出环境温湿度你可以双击DHT11弹窗设置温度和湿度值看显示是否变化。湿度或温度超过报警阈值时仿真里的蜂鸣器图标会以红色/绿色变化来模拟发声。烟雾通道的模拟方式是调节RV2滑动变阻器的百分比这会改变PA1引脚的电压从而改变ADC采样值。你可以把RV2调到90%以上模拟高浓度烟雾看蜂鸣器是否触发报警。光敏通道同理RV1的阻值调节模拟光照变化。这里我重点提醒一个调试技巧用Proteus的虚拟示波器和逻辑分析仪。你可以把DHT11的数据引脚接到虚拟逻辑分析仪上能看到完整的起始信号、响应信号、数据位波形这对理解DHT11时序特别有帮助比在实物上拿示波器测方便得多。ADC输入引脚也可以接虚拟电压表实时观察传感器电压和ADC采样值的对应关系。4.3 仿真和实物的差异提前打好预防针仿真能验证逻辑但仿真和实物有差异这一点一定要心里有数。首先是DHT11的时序差异。实物DHT11的时序要求比较严格起始信号的低电平时间、数据位的采样点都对延时的精确度有要求。仿真里的DHT11模型则宽容很多只要基本时序对就能出数据。所以你在仿真上能跑通不代表实物也一定能一次跑通。反过来也有情况有些在实物上需要反复调整延时的地方仿真里根本看不出来。其次是ADC采样。仿真里的电压源是理想电源没有噪声而实物的电源纹波、元件精度、引线阻抗都会造成ADC值波动。这就是为什么我在项目里强调软件滤波它在实物调试中不是可选项是必选项。第三是晶振和时钟配置。这个前面提过Proteus的STM32模型对HSE外部晶振仿真有时候不稳定所以我仿真版本用HSI。但实物上我建议用HSE外部8MHz晶振因为内部HSI的精度在常温下还行但温漂比外部晶振大而且如果你后期要用到USB、定时器精确延时等场景HSE是标配。最大的差异是传感器行为模型。Proteus里DHT11的湿度读数范围、响应速度都是理想化的MQ-2更是直接用变阻器替代。实物MQ-2有预热过程有响应时间有温漂这些是仿真模型无法体现的。仿真验证的是代码逻辑和电路连接的正确性实物的传感器标定工作必须靠真实验证。5. 常见问题与调试经验速查我整理了一个问题速查表涵盖我从第一批测试者反馈和自己调试经历中收集到的典型问题按“现象-原因-解法”的方式列出来方便对照排查。问题现象可能原因排查与解决办法DHT11一直读不到数据返回错误数据线上没接4.7K上拉电阻GPIO模式未切换延时函数精度不够引脚号不对先量引脚电平空闲时应为高电平确认代码里GPIO配置为开漏或推挽输出读取时切换为输入用逻辑分析仪看时序波形逐个核对引脚定义OLED白屏I2C地址不对SDA/SCL接反上拉电阻缺失供电不够用软件扫描0x3C和0x3D两个地址检查接线确认上拉电阻已接用万用表量OLED的VCC引脚电压是否正常ADC采集值跳变严重电源纹波大采样时间太短未加滤波电容受到蜂鸣器/继电器干扰加强去耦电容增大ADC采样周期到55.5周期以上软件加大滤波力度检查蜂鸣器是否共用电源线蜂鸣器不响三极管管脚接反限流电阻太大GPIO模式配置错误用万用表量三极管基极电压按键触发时应为高电平确认1K电阻存在确认GPIO为推挽输出50MHz烧录失败提示Cannot connect to targetBOOT0不在低电平SWD线太长芯片供电异常ST-Link驱动问题确认BOOT0接10K下拉到地SWD线尽量短必要时降低SWD速度量3.3V引脚电压重装ST-Link驱动Proteus仿真运行缓慢或卡死晶振频率配置太高仿真时钟设置错误程序死循环把Keil工程时钟配置改为HSI 8MHzProteus芯片时钟也设为8MHz检查代码中是否有未加超时的死等循环按键按下没反应消抖逻辑不完善GPIO内部上拉没开硬件上用了外部上拉但代码没配置确认GPIO配置为上拉输入打印按键扫描值如果使用外部中断检查中断标志位是否清除5.1 DHT11读取问题的深度排查DHT11的问题是出现频率最高的我再单独展开说。如果你的DHT11读不到数据按照下面的顺序排查第一步用万用表量DHT11的VCC和GND电压应在3.3-5V之间我建议3.3V。第二步量DATA引脚静态电压DHT11不通信时应被上拉到高电平3.3V附近如果量到0V或电压很低大概率是上拉电阻没接或焊接问题。第三步检查代码初始化逻辑DHT11读取过程中GPIO要经历“输出模式”、“释放总线”、“输入模式”的状态切换时序要严格按照datasheet来。第四步延时函数精度这个之前反复强调了在STM32F103上72MHz主频下delay_us由SysTick实现实测误差在1-2us以内是可以接受的。还有个容易忽略的点DHT11的采样周期是1秒两次读取之间至少要间隔1秒以上。如果你在主循环里连续调用读取函数第二次、第三次就可能返回错误。我在代码里加了一个时间戳判断如果距离上次读取不足1秒就直接使用上一次的缓存数据不发起新的读取这样既符合传感器时序要求又不阻塞主循环。5.2 MQ-2标定与报警阈值设置的实战建议很多拿到项目的人会问烟雾报警阈值到底设多少合适答案是不能照搬我的代码必须现场标定。我的做法是这样的在正常环境下系统上电预热3分钟后连续采样100次取平均值作为“正常基线”。然后在距离传感器10cm左右的位置用打火机短暂放一下气注意安全或者用烟头靠近记录此时的ADC值。报警阈值取正常基线和触发值之间的某个中间点这样既有相对高的灵敏度又不会因为基线小幅波动而误报。还可以做一个动态基线修正系统每10分钟记录一次ADC值如果连续一段时间没有报警就缓慢更新基线这样可以抵消传感器本身的温漂和老化。这个功能我没放进开源代码里算是留给大家的扩展作业实现并不难就是在定时器中断里做滑动平均加低通滤波。5.3 电源噪声与ADC采样的处理心得我在实物调试中遇到过最头疼的问题就是ADC值跳动。现象是光照传感器和烟雾传感器共用一个3.3V电源当蜂鸣器响起时ADC值会瞬间跳变几十甚至上百个LSB。原因很清楚蜂鸣器工作时的电流脉冲导致3.3V电源跌落虽然AMS1117稳压芯片有一定抑制能力但高频瞬态还是会影响ADC的参考电压。我的处理方案是综合治理第一蜂鸣器单独走电源线从5V经独立的AMS1117供电或者至少不让蜂鸣器电流经过模拟部分的电源走线第二模拟部分加RC低通滤波1K电阻加100nF电容构成截止频率约1.6kHz的滤波器第三软件端加强中值滤波。这三板斧下去ADC跳动问题基本消除。如果你做实物时发现ADC值还是跳可以用示波器看3.3V的电源纹波纹波超过50mV就该从硬件入手找问题了。6. 开源资料结构与二次开发建议6.1 开源资料包目录说明资料包我按下面的结构整理拿到手不会一头雾水代码工程文件夹含HSE外部晶振版实物代码、HSI内部时钟版仿真代码两个版本原理图文件夹含PDF版本原理图和嘉立创EDA工程文件Proteus仿真文件夹直接打开可运行的仿真工程数据手册文件夹DHT11、MQ-2、SSD1306、STM32F103C8T6等核心芯片的数据手册使用说明文档环境搭建步骤、如何烧录、如何修改阈值、常见问题索引代码工程里我把每个模块的函数都加了详细的注释特别是DHT11和ADC这两块关键代码段旁边解释了为什么这样写。原理图工程用的是嘉立创EDA标准格式可以直接转成PCB打样两层板设计元器件都选的是容易买到的常规封装。6.2 在开源项目基础上扩展的方向这套项目做完、跑通之后如果你想再往前走一步我有几个方向建议。方向一联网化加一个ESP8266模块通过串口把温湿度、烟雾浓度数据上传到云平台手机端实时查看。这是现在毕设最容易拿加分的方向实现难度也不大ESP8266用AT指令固件代码里加一个串口发送函数就行。方向二多节点组网在一个大空间里部署多个监测节点用RS485总线或者LoRa模块组网每个节点一个地址主机统一轮询管理。这涉及通信协议设计能锻炼的东西就多了。方向三低功耗化如果需要离线长期运行把系统改成电池供电STM32进入停机模式定时唤醒采集一次数据完事继续睡。用STM32L4系列可以做到微安级待机电流这也是目前物联网终端的主流设计模式。方向四功能强化把DHT11换成SHT30或BME280精度和稳定性会上一个台阶加一个风扇和加热器作为执行机构做成闭环温湿度控制系统或者加一个SD卡模块把历史数据记录下来方便后期分析。6.3 给大家的一些个人建议这套项目我陆陆续续改过好几个版本最近整理的时候有个很深的体会一个项目能不能跑通很多时候不是看代码写得多花哨而是看基础电路有没有做扎实。DHT11的上拉电阻、I2C的上拉电阻、去耦电容、蜂鸣器的续流二极管——这些一个都不能省。现在的开源资料越来越多大家下载一份代码就能跑但跑通之后一定要回头想想每一个元件在电路里到底在干什么。把最小系统、常用传感器接口、通信协议这些基本功练扎实了后面再做LoRa网关也好、视觉小车也好、嵌入Linux也罢都是在这些地基上盖房子而已。最后说一句如果你在复现这套系统的时候遇到了代码层面和硬件层面的问题先对照上面的排查表走一遍绝大多数问题都是那几类。真遇到帖子里没覆盖的情况自己用逻辑分析仪看波形、用万用表量电平这个独立排查的过程本身就是做嵌入式项目最值钱的经验积累。祝大家都能一次点亮顺利跑通。
返回列表