ARTICLE DETAIL

资讯详情

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

基于STM32的图书馆环境监测系统:从原理图到仿真实测

基于STM32的图书馆环境监测系统:从原理图到仿真实测 这阵子整理网盘的时候翻出前年做的一个练手项目——图书馆环境监测系统。当时正好赶上工作室接了校内图书馆的局部改造需求加上自己一直在折腾STM32就顺手用STM32F103C8T6搭了一套能测温度、湿度、光照和烟雾浓度的环境监测装置把原理图、源码和Proteus仿真一起打包开源了。做这个项目的初衷很简单图书馆自习区经常有人反映靠窗位置夏天太晒角落返潮有霉味机房附近异味重而馆方只能靠人工巡查效率和覆盖面都有限。我当时想的是能不能用一套低成本硬件加上清晰的上位机逻辑和报警机制把几个关键环境参数实时采集、显示、超限提醒顺便还能联动通风设备。对于正在学STM32的人来说这个项目正好把GPIO、ADC、I2C、定时器、中断、状态机这些核心外设全部串了一遍是一个典型的麻雀虽小五脏俱全的嵌入式综合练习。目前开源仓库里已经有不少人fork并做了改动比如有人加了ESP8266联网把数据推到MQTT有人把OLED界面重绘成曲线图还有人把DHT11换成了SHT30。不过大部分问题都集中在仿真怎么跑起来、原理图某些器件为什么要这么接、代码里那几个配置到底是干什么的。这篇文章不打算写成一份PDF式教程而是把我从立项、画图、写代码、调仿真、实测标定的全过程以及踩过的坑和取舍逻辑原原本本讲一遍。1. 项目动因图书馆场景对嵌入式系统提出的真实要求1.1 为什么选图书馆而不是智能家居刚开始我也想过直接套用常见的智能家居方案但那类项目的问题在于需求太泛最后做出来的东西常常只是一堆传感器数据滚动显示在屏幕上没什么实际约束力。图书馆不一样它有明确的物理空间边界、固定的巡查盲区、特定的环境隐患点这会让整个系统的设计目标变得非常聚焦。具体到图书馆场景我拆出了四个必须监测的参数温度夏季靠窗区域阳光直射温度可能比馆内平均温度高出5-8℃长时间高温对古籍、纸质书籍的保存不利。湿度地下室密集书库和洗手间附近的过道湿度经常超标湿度过高容易导致书籍发霉、纸张变脆。光照阳光直射会让书脊褪色但室内照明不足又影响阅读体验所以需要区分自然光强度和馆内照明。烟雾/可燃气体机房、配电间附近的烟雾隐患需要在明火或线路过热冒烟阶段就提前报警。这四个参数对应四种不同的采集方式恰好覆盖了数字单总线DHT11、I2CBH1750、ADC模拟量MQ-2烟雾传感器、数字电平判断火焰/烟雾二合一模块这几种嵌入式最常用的传感器接口类型。也就是说做完这个项目你基本就把单片机读传感器的常见姿势都练了一遍。1.2 主控和外设的选型逻辑主控选择上我用的是STM32F103C8T6也就是大家常说的蓝板核心板。选它的理由其实很现实第一价格便宜十几块钱一片烧了不心疼第二资料极其丰富任何一个外设遇到问题都能搜到案例第三这个项目需要的资源它刚好够用——72MHz主频、20KB RAM、64KB Flash、3个USART、2个I2C、2个SPI、10个ADC通道对一套环境监测系统来说性能完全溢出后续想加联网模块也不用换主控。传感器选择我参考了够用就好的原则传感器/模块型号接口测量范围精度为什么选它温湿度DHT11单总线20~90%RH0~50℃±5%RH±2℃便宜、常见、学时序正好光照BH1750I2C1~65535 lux±20%直接输出光照度数值不用自己算烟雾/可燃气体MQ-2ADC模拟量300~10000ppm粗略级反应速度快阈值可通过电位器调火焰检测红外火焰传感器数字电平0~1m可调开关量响应快作为烟雾传感器的补充显示和交互这边我用了一块0.96寸OLEDI2C接口SSD1306驱动三个按键菜单切换、加、减一个无源蜂鸣器一个继电器模块用来控制风扇。OLED选I2C版本纯粹是因为省引脚整个显示只占PB8和PB9两个IO口。蜂鸣器用了三极管驱动的无源蜂鸣器而不是开发板自带的那个有源蜂鸣器原因后面在电路部分细说。2. 硬件原理图设计每一根走线背后的工程考量2.1 电源与最小系统稳定是一切传感器数据的前提原理图设计的第一件事不是接传感器而是把电源和最小系统画扎实。这套系统里有个非常容易翻车的细节DHT11、BH1750、火焰传感器、OLED都可以在3.3V下工作但MQ-2烟雾传感器的加热丝部分必须用5V供电而它的模拟输出引脚接的是STM32的ADC这就涉及电平匹配问题。我的处理方式是整个系统用USB的5V供电5V直接给MQ-2的VCC和继电器线圈同时经过一颗AMS1117-3.3稳压芯片降压到3.3V给MCU和其余传感器用。MQ-2的AO输出引脚直接进STM32的PA1很多人担心3.3V单片机读5V传感器的模拟量会不会烧引脚实际上MQ-2的AO输出在洁净空气中大约只有0.1~0.3V浓度很高时也就3V左右它的分压电路决定了输出不会是满幅5V。不过为了稳妥我还是在AO与PA1之间串了一个1kΩ电阻并且在PA1对地并联了一个100nF电容做滤波这比直接飞线可靠得多。电源去耦这件事新手容易忽略但恰恰是ADC采样值稳定性的关键。我在原理图中给每个IC的电源引脚都就近放置了100nF的陶瓷电容在USB输入处放了10μF钽电容和100nF电容并联。实测下来如果不加这些电容MQ-2的ADC采样值会有明显的周期性波动大概是风扇或继电器动作瞬间的电流冲击耦合到了模拟参考电压上。最小系统部分STM32F103C8T6我用了常见的八脚配置BOOT0通过10kΩ电阻下拉到地确保从Flash启动NRST对地接一个100nF电容OSC_IN和OSC_OUT接8MHz晶振两个负载电容用20pFVDDA引脚串一个10Ω电阻后接3.3V并且对地接一个1μF电容——这个VDDA的滤波电容官方手册里特别强调要接它对ADC精度影响很大。2.2 传感器接口电路上拉、滤波与电平匹配传感器接口部分的原理图看起来就是几个排针但每个引脚的处理都有说法。DHT11的数据引脚是开漏输出必须外接上拉电阻才能保证通信时序正确。我用的是4.7kΩ上拉到3.3V。这个阻值其实是个经验值太小了会让总线上的低电平时间变长影响时序容限太大了则上升沿变缓单片机在窄脉冲采样时容易误判。4.7kΩ是DHT11数据手册和大部分参考设计共同推荐的实测在20cm杜邦线长度下很稳定。BH1750和OLED挂在同一条I2C总线上I2C同样需要上拉电阻。我选了4.7kΩ上拉到3.3V。这里有个小细节BH1750的地址引脚ADDR直接接地所以它的7位地址是0x23OLED的SSD1306地址默认是0x3C两者不冲突。同一总线上两个不同地址的I2C设备省了一组IO口。MQ-2的电路相对复杂一点模块上自带一个电位器用来调节比较器阈值同时有两个输出——AO是模拟输出DO是数字输出。我两个都接了AO接PA1做连续浓度采集DO接PA0做快速中断判断。这样系统可以在浓度超过DO阈值时立刻报警同时通过AO读取具体浓度值用户界面上的浓度进度条就是靠这个模拟量驱动的。火焰传感器模块输出的是数字开关量信号默认输出高电平检测到火焰时输出低电平。我在PA2引脚上配置了内部上拉因为模块输出的高电平其实是OC门集电极开路形式的外部需要上拉才能保证高电平是确定的3.3V。如果忘了使能内部上拉这个引脚在无火焰状态下会读到不确定的浮动电平偶尔会误报警。2.3 执行机构与报警电路驱动能力这件事报警和联动部分新手最容易犯的错是试图用单片机的IO口直接驱动继电器或蜂鸣器。STM32的GPIO在推挽模式下最大输出电流也就20mA左右而一个5V继电器线圈的吸合电流可能需要30~70mA蜂鸣器虽然电流小但反向电动势会倒灌。我的方案是蜂鸣器接在PB12引脚上通过一颗S8050三极管做开关驱动。PB12输出高电平时三极管导通蜂鸣器发声低电平时截止。蜂鸣器两端并联了一个1N4148二极管方向是负极接5V、正极接三极管集电极用来吸收关断瞬间的反向电动势——这个二极管不加的话蜂鸣器停止发声时会有一个负电压尖峰打在集电极上虽然不一定立刻损坏三极管但长期运行会缩短寿命而且可能干扰同一供电电源上的其他电路。继电器模块则直接用了市面上常见的一路5V低电平触发光耦隔离模块IN引脚接PC13。为什么要用光耦隔离模块而不是三极管直接驱动继电器因为继电器线圈在吸合和释放瞬间会产生较大的电流突变如果和MCU共地共电源这个突变会沿着地线窜回MCU表现为ADC采样值跳变、OLED偶发花屏。光耦隔离模块把控制侧和负载侧的电源彻底分开虽然成本多了一两块钱但系统的稳定性会上一个台阶。原理图里还有一个不起眼但很重要的设计OLED和传感器的电源引脚都单独引出一个100nF电容到地。这类模块在插拔瞬间会产生较大的电压毛刺有了电容缓冲插拔时MCU不容易复位。3. 代码架构与核心逻辑从轮询到下位机状态的完整实现3.1 分层文件组织与模块封装写这套代码的时候我给自己定的规矩是每个外设一个C文件和对应的H文件不把逻辑全堆在main.c里。最终的工程结构是这样的├── Core/ │ ├── main.c │ ├── stm32f1xx_it.c ├── Drivers/ │ ├── BSP/ │ │ ├── bsp_dht11.c/h │ │ ├── bsp_bh1750.c/h │ │ ├── bsp_oled.c/h │ │ ├── bsp_mq2.c/h │ │ └── bsp_flame.c/h │ ├── App/ │ │ ├── app_monitor.c/h │ │ └── app_menu.c/hmain.c里只做三件事初始化各外设、打印启动信息、进入while(1)主循环。具体的业务逻辑在app_monitor.c里它维护一个系统状态机每隔200ms做一次数据采集和刷新。这样做的最大好处是排错容易——如果OLED显示乱了直接查bsp_oled.c不影响其他模块如果采集数据异常单独测试对应的传感器模块就行。3.2 DHT11时序采样的关键细节DHT11是这套系统里唯一需要自己严格掐时序的外设也是最容易让新手崩溃的地方。它的通信协议是单总线主机拉低总线至少18ms然后释放DHT11会响应一个80μs的低电平然后进入40bit的数据传输阶段。每一位数据的时间长度不一样50μs的低电平之后如果跟着26~28μs的高电平则代表0如果跟着70μs的高电平则代表1最后还有一个50μs的结束低电平。我之前看到很多教程用简单的延时函数来读取这段时序实际上不太可靠因为DHT11的时序余量很小而且它要求主机在采样时总线忙等任何中断干扰都可能导致读到错误的电平宽度。我最后采用的方案是把DHT11的数据引脚挂在PA6上读取时先关闭该引脚的中断项目里PA6没开中断但保险起见还是加了__disable_irq这一行然后使用一个高精度的延时循环配合读取引脚电平uint8_t DHT11_ReadByte(void) { uint8_t i, data 0; for (i 0; i 8; i) { while (GPIO_ReadInputDataBit(DHT11_GPIO_PORT, DHT11_GPIO_PIN) RESET); // 等待低电平结束 DELAY_US(40); if (GPIO_ReadInputDataBit(DHT11_GPIO_PORT, DHT11_GPIO_PIN) SET) { data | (0x80 i); } while (GPIO_ReadInputDataBit(DHT11_GPIO_PORT, DHT11_GPIO_PIN) SET); // 等待高电平结束 } return data; }这段代码里最关键的是等待低电平结束这句话它让程序自动跳过前导信号在数据位传输到当前bit时才做采样。比固定延时然后读引脚的方式更抗干扰。实测下来在系统开启蜂鸣器报警、继电器吸合的电磁干扰环境下这个读取方式依然能稳定读到数据没有出现一位错乱或校验失败的情况。另外DHT11读取频率不能太高两次读取间隔至少要1s。我在代码里加了时间戳判断距离上一次采集不足800ms时直接返回上次结果避免了连续读取导致的时序冲突。数据校验用的是DHT11自带的8bit校验和机制读到的40bit中前四个字节是湿度和温度最后一个字节必须是前四字节之和的末8位校验不过就丢弃本次数据保留上一次有效值——这个机制在长时间运行中非常有用偶尔一次采集中断不会让屏幕上的温湿度突然变成0或乱码。3.3 多传感器融合简单但有效的环境判定规则环境监测系统真正有智商的部分在于怎么把多个传感器的数值综合成一个合理的判断。我的判定逻辑放在app_monitor.c里用一个全局结构体保存所有传感器的最新值和对应的标志位typedef struct { float temperature; float humidity; uint16_t light; uint16_t smokeValue; uint8_t flameFlag; uint8_t smokeAlarm; uint8_t tempAlarm; } EnvData_t;判定的核心规则是温度超过38℃或低于5℃触发温度报警蜂鸣器短鸣两声并在OLED上显示TEMP HIGH。湿度超过75%RH触发湿度报警同时自动开启继电器风扇提示通风。烟雾浓度持续超过阈值——注意是持续我在代码里用了一个计数器连续3次采集约600ms都超标才真正触发烟雾报警这能防止炒菜般短暂的烟雾尖峰引起误报。火焰传感器输出低电平时立即报警优先级最高无论其他参数是否正常OLED直接切换到FIRE!!警示页。光照值只做记录和显示不参与自动控制但会在OLED上通过一个进度条显示当前光照强度方便馆员判断是否需要拉开窗帘或调亮照明。规则设计上我刻意没有引入复杂的模糊控制或PID因为环境监测系统的核心价值是准确告知环境状态而不是自动把所有参数调节到最优。风扇联动只有在湿度和烟雾同时超标时才开启这是为了避免冬天湿度没到阈值但温度低的情况下风扇误启动让读者挨冻。3.4 显示与交互OLED驱动与按键状态机OLED部分用的是SSD1306驱动芯片的经典I2C写法先发控制字节0x00表示后续是命令、0x40表示后续是数据再发送具体的寄存器配置序列。初始化序列是从Adafruit的例程里精简出来的去掉了很多用不到的功能保留了显示开启、电荷泵开启、内存地址模式设置为页模式这几个必要步骤。UI设计上我做了三个页面第一页显示温湿度和环境状态图标用简单的中文字库点阵画了温湿光烟四个字第二页显示烟雾浓度和光照强度的数值进度条第三页是阈值设置页可以按键调整温度和湿度的报警阈值。三个页面通过菜单状态机切换状态定义如下MENU_MAIN默认显示页按确认键进入菜单列表MENU_TEMP_SET温度阈值设置页按加/减修改长按确认键保存并退出MENU_HUMI_SET湿度阈值设置页逻辑同上MENU_ABOUT版本信息页显示固件版本和开源仓库地址菜单状态机的实现用了一个switch-case结构按键扫描放在定时器中断里通过消抖逻辑连续两次扫描间隔20ms以上且电平稳定来确认按下事件这样主循环里读取到的永远是一个稳定的事件而不是电平状态。这个设计虽然简单但避免了按键抖动导致的一次按击被识别成多次操作的经典问题。4. 仿真搭建与踩坑实录Proteus仿真STM32的真实经历4.1 仿真环境的搭建固件烧录与器件库问题很多初学者以为Proteus仿真和实物开发一样直接把生成的HEX文件拖进单片机就行。实际上Proteus的STM32模型要求你先把固件加载到MCU再运行仿真。我的具体步骤是在Proteus中放置STM32F103C8T6元件双击打开属性对话框。在Program File一栏选择MDK工程编译出的HEX文件路径。晶振频率设置为8MHz程序执行方式选Debug运行而不是Run这样可以在仿真中观察GPIO电平变化。器件库里容易出问题的是DHT11Proteus自带的器件列表里其实没有完全匹配DHT11的模型但有个叫AM1001的温湿度传感器模型引脚定义和DHT11基本一致代码里稍作映射就能用。BH1750在Proteus里也没有现成模型我的处理方式是用一个I2C调试探针代替或者在仿真里干脆用滑动变阻器模拟光照的ADC电压把光照数值的ADC部分单独拉出来验证这样至少能确认ADC配置和数值计算公式是没问题的。如果你要把整个系统完整跑仿真我建议用Proteus 8.9以上版本早期的Proteus 8.0对STM32F103的I2C外设支持相当粗糙BH1750这种需要I2C时序读写的器件经常挂在总线通信上仿真结果和实物完全对不上。4.2 仿真与实物的差异哪些能信哪些必须实测这是我觉得整个过程里最有价值的认知收获仿真各有能信和不能信的地方。能信的是逻辑流程。比如菜单状态机切换、报警标志位置位、OLED页面的文字切换、按键消抖处理这些纯逻辑层面的东西在仿真里跑起来和实物是完全一致的。通过Proteus的虚拟终端和示波器还能很直观地看到I2C总线上每个字节的时序对不对这在实物上用逻辑分析仪才能做到对新手来说门槛低了很多。不能信的是模拟量的绝对精度和时序余量。Proteus的ADC模型是把输入的模拟电压线性映射到0~4095它不会模拟传感器的响应迟滞、温漂、供电纹波这些真实特性。MQ-2在仿真里给一个0~5V电压源读出来的是理想线性结果但实物里MQ-2预热阶段电压会漂移、不同浓度下响应时间也不同。同样DHT11在仿真里读取时序只要逻辑对就能出结果但实物上因为线缆电容、供电噪声和温度变化同样的代码可能偶尔读零。所以我建议的流程是先在仿真里确认代码逻辑正确再烧录到实物上把仿真阶段用不到的校准环节补齐。我这个项目的仿真文件主要用于展示系统架构和运行流程而不是用来精确模拟传感器数据的。4.3 一次灵异现象的排查ADC数值跳变的真相仿真阶段我遇到过一个特别典型的坑值得单独拿出来说。当时我在仿真里把MQ-2的AO引脚接到一个可调电压源模拟不同烟雾浓度发现PA1读到的ADC值在电压源显示1.2V时稳定在900左右这没问题但当我同时打开继电器模块仿真里是一个LED电阻模拟时ADC值突然跳到了1100而且跳得不规律。排查的过程先怀疑程序问题仔细检查了ADC配置代码初始化顺序、采样通道选择、采样时间设置都没问题。又怀疑是ADC参考电压不稳但仿真里VREF是理想3.3V。最后试着把继电器模块的地线在仿真原理图上单独拉了一根地线回路ADC值立刻恢复正常了。原因其实很简单在Proteus里如果多个模块的地符号都直接用GROUND这个元件它们之间是共地的。当继电器动作时电流冲击会在共享的地回路上产生微小的电压降而这个压降恰好叠加到了模拟信号源的参考地上导致ADC输入端的有效电压发生了偏移。换成实物其实也是同一个道理——所以我在实物布局时把继电器模块的电源和地单独走线在核心板附近一点接地就是反推这个仿真经验。仿真帮我提前暴露了一个在实物上很难定位的问题这算它的额外价值。5. 实测数据与参数标定让系统真正可用的最后一步5.1 温湿度校准DHT11的误差修正DHT11出厂标称精度是±2℃和±5%RH这个精度在精确气象站面前是上不了台面的但作为环境监测的提示系统完全够用。我在实测阶段做了一件事把DHT11和水银温度计、毛发自记湿度计放在同一个环境里连续记录48小时对比数据后发现DHT11的温度读数平均偏高0.8℃湿度读数平均偏低6%RH左右。这个偏差在DHT11的允许误差范围内但可以通过软件修正温度减去0.8℃湿度加上6%RH。修正后与标准仪器误差控制在±1℃和±4%RH以内。具体的校准偏移量每个批次可能略有不同我在代码里定义了两个可调参数#define TEMP_CAL_OFFSET (-0.8f) #define HUMI_CAL_OFFSET (6.0f)建议拿到传感器后先和室内温度计对比一两天根据自己的硬件修正这两个值。不同供应商的DHT11一致性差异较大直接抄我的偏移值不一定适用。5.2 烟雾传感器阈值整定避免误报的科学方法MQ-2传感器的输出特性是洁净空气中输出电压较低且相对稳定遇到烟雾或可燃气体时电压上升。但它的零点会随着环境温度和湿度漂移我实测同一块模块在湿度30%的空调房和湿度80%的雨天的零点电压能差出0.2V左右反映到ADC上就是几十个码值的偏移。阈值到底设多少合适我的做法是上电后让系统先运行10分钟预热MQ-2内部加热丝需要时间达到稳定工作温度然后程序自动读取100次ADC值取平均记为baseline。报警阈值设置为baseline 100ADC码值对应大约0.08V压差。这个偏移量是通过点燃一小片纸靠近传感器实测确定的——烟雾浓度刚引起人注意时ADC大概比baseline高出60~80码值明显呛人时高出200以上。阈值设在100既不至于在轻微烟味时误报也不会让浓烟产生时无法触发。同时我将ADC采样做了一阶低通滤波每次新采样值x_new更新smokeFiltered 0.8 * smokeFiltered 0.2 * x_new。这个滤波不是简单地平均而是让响应既平滑又有足够的反应速度。实测中连续吹一口电子烟约2秒后滤波后的数值大约在1秒内爬升到峰值的70%足够触发报警而环境中偶然的干扰尖峰则被抑制掉了。5.3 功耗与长时间运行稳定性系统在5V供电下实测整机电流约180mA其中MQ-2加热丝占了约150mA单片机加传感器约30mA。如果连续运行一个月大概会消耗130度电——对于图书馆这种24小时供电的场所不算什么但如果想用电池供电MQ-2的大电流就是必须解决的问题。我做了两个优化实验一是让MQ-2间歇工作每10分钟通电1分钟采集一次功耗降为原来的十分之一但代价是烟雾响应的实时性变差二是改成低功耗方案用STM32的STOP模式定时RTC唤醒采集一次后继续睡眠。这两个扩展方向我在仓库的README里都写了思路实测数据也列了后续想改项目的人可以直接参考。长时间运行稳定性方面我连续跑过一个月出现两个现象一是DHT11偶尔会间隔几天出现一次校验失败代码里的保留上次有效值机制让这种偶发错误无感二是OLED屏幕出现轻微残影这是OLED正常的老化现象不影响使用但如果屏幕固定显示同内容建议增加屏幕保护机制比如2分钟无操作后降低亮度。6. 开源资料的使用方法代码原理图仿真怎么快速跑起来6.1 工程目录结构与文件说明开源仓库的核心目录在项目主页就能看到我按硬件固件仿真文档四个维度做了划分LibraryEnvMonitor/ ├── Hardware/ │ ├── Schematic_LibraryEnvMonitor.pdf │ └── PCB_LibraryEnvMonitor/ ├── Firmware/ │ ├── MDK-ARM/ │ ├── Core/ │ └── Drivers/ ├── Simulation/ │ ├── LibraryEnvMonitor.pdsprj │ └── Libraries/ └── Docs/ ├── README.md ├── UserManual.pdf └── CalibrationGuide.md需要特别提醒的是Simulation/Libraries目录Proteus工程打开如果提示找不到器件十有八九是库文件路径没关联。打开Proteus后先在系统→系统设置→仿真器/调试器里确认版本再到库→库管理把Libraries文件夹添加进去然后重新打开工程。Proteus版本尽量不低于8.9低版本打开高版本工程会缺失部分器件模型。6.2 一步一步从代码下载到板子跑通如果你是第一次接触这类项目按照下面的顺序操作成功率最高先用Keil MDK打开Firmware/MDK-ARM目录下的工程文件按F7编译确认没有error。如果用的是Keil 5.25以下版本打开时可能会提示device pack版本过低去Keil官网装一下对应版本的STM32F1xx_DFP即可。编译成功后在Output目录生成HEX文件。我用的是STM32F103C8T6其他型号如果Flash或RAM容量不够直接换高配型号改一下芯片选择就行代码不需要动。烧录用ST-Link或串口ISP都行。ST-Link接线方式是SWDIO接PA13、SWCLK接PA14、GND接GND、3.3V接3.3V四根线就够。串口ISP需要BOOT0拉高再上电用FlyMcu选择HEX下载。下载代码后会看到OLED先显示开机Logo2秒后进入主界面显示温湿度数据。如果没有显示先测一下I2C地址是不是0x3C有时候OLED模块地址是0x3D改一下bsp_oled.c里宏定义就行。然后测试报警和联动用手捏住DHT11探头温度上升或者往MQ-2附近哈气烟雾浓度上升应该能看到OLED界面变化、蜂鸣器响、继电器吸合。不响不动作的话优先检查蜂鸣器管脚PB12和继电器管脚PC13的电平时序用Debug模式看代码有没有跑到报警分支。仿真验证打开Simulation目录下的工程加载HEX点运行。注意仿真里没有真正的DHT11模型我用的是替代器件如果修改了代码中DHT11的引脚定义仿真里也要同步改。6.3 扩展方向这个项目还能怎么改仓库里我已经预留了几个扩展点都是实测验证过的思路联网化在USART1上外接ESP8266模块将采集数据通过AT指令上报到MQTT服务器或B站大屏数据接口。我测试过用USART1的DMA空闲中断接收AT回调波特率115200数据帧格式是JSON约1.2KB一条稳定性没问题。多节点组网用485总线把多套监测系统串起来上位机用Modbus协议轮询。需要加一个MAX3485收发器STM32的USART2加方向控制引脚代码里把Modbus从站协议栈移植过来就能用。数据记录加一片W25Q64 Flash每5分钟记录一条带时间戳的数据用一个简单的环形缓冲区写入掉电不丢失。读者拿这些数据做数据分析或画趋势图都很方便。升级传感器把DHT11换成SHT30I2C接口精度提升一个量级代码只需要替换bsp_dht11.c模块其他逻辑不用动。BH1750也可以换成VEML7700环境光响应更平滑但寄存器配置需要重新调。我个人在实际操作中的体会是这个项目最难的部分不是任何一个单独的模块而是把多个模块组合在一起后怎么让它们稳定协作。比如继电器动作和ADC采样的地线干扰问题不长期跑根本发现不了代码里沿用校验失败保留上次数据的思路在任何一个传感器项目里都值得推广。你现在下载的这套代码至少已经被几十个人在自己板子上验证过了遇到问题先在Github Issues里搜一下大概率有人踩过同样的坑。如果真找不到解决办法欢迎开个issue把现象和原理图发上来我看到都会回。
返回列表