ARTICLE DETAIL

资讯详情

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

STM32环境监测系统开源项目:DHT11+MQ-135+OLED完整教程

STM32环境监测系统开源项目:DHT11+MQ-135+OLED完整教程 一直有朋友在后台问我有没有一套适合课设或者嵌入式入门复现的STM32开源项目最好代码、原理图、仿真一步到位这套环境质量监测系统就是为这个需求做的。项目基于STM32F103C8T6集成了DHT11温湿度传感器、MQ-135空气质量传感器外加一块0.96寸OLED屏幕和蜂鸣器报警能在本地完成温度、湿度、空气质量三合一监测。更重要的是源码、原理图、Proteus仿真工程全部整理好开源从画板子到烧固件一条链路走通不需要你在几个论坛之间来回拼凑资料。这个工作量对我来说不算大但对刚接触STM32的人来说最大的痛点是“不知道从哪下手”。所以我打算用一篇完整的文章把整个项目的设计思路、原理图要点、固件写法、仿真和调试经验一次讲清楚。你在复现过程中遇到问题时也可以对照这篇内容快速定位。如果你正在准备课设、电赛或者只是想找个真实项目练手这套东西会比啃芯片手册直观得多。1. 先说需求这套系统测什么、为什么这么选1.1 环境监测不只是“测个温湿度”很多人一提到环境监测第一反应就是温湿度。实际上室内环境质量的维度远不止这两个甲醛、CO2、PM2.5、VOC可挥发性有机物都属于影响人体舒适度和健康的指标。但考虑到底层项目、成本控制和复现难度我不可能一次性把高精度电化学传感器全堆上去所以这套系统选定了三个最关键的参数温度、湿度、空气污染程度。温度湿度用DHT11数字传感器解决空气质量用MQ-135气体传感器解决。MQ-135对苯、甲苯、氨气、烟雾、甲醛等气体都有响应虽然做不到精确的浓度数值输出但用来做“优/良/轻度污染/重度污染”这样的等级判断完全够用。这个定位思路很重要嵌入式项目不一定每个指标都要做到实验室级别先把系统跑通、把监测链路完整走一遍再去考虑精度和标定才符合学习规律。空气污染等级通过STM32的ADC采集MQ-135的模拟电压来判断采集到的电压经过滤波后映射成空气质量等级等级过高时触发蜂鸣器报警。OLED屏幕上可以看到实时温度和湿度配合空气质量等级一起显示。整个项目逻辑清晰难度适中放在课设里很合适也不会因为太过简单而被老师质疑工作量。1.2 传感器选型对比与取舍在选择传感器的时候我对比过几组方案这里直接给结论。温湿度测量这条路最常用的三个选择是DHT11、DHT22AM2302和SHT30。DHT11便宜单总线协议时序要求不算特别苛刻但精度一般湿度误差正负5%RH温度误差正负2℃有时候会被吐槽“不准”。DHT22精度高不少价格大概贵一倍多采样间隔也更长协议和DHT11一致代码移植起来很容易只有延时参数和返回的数据格式有细微差别。SHT30走I2C精度和稳定性都不错但驱动代码比DHT11复杂一些。参数DHT11DHT22SHT30温度精度±2℃±0.5℃±0.3℃湿度精度±5%RH±2%RH±2%RH接口类型单总线单总线I2C采样周期1s以上2s以上可配置价格段最低中等中等偏上代码难度低低中我这套项目默认用DHT11把采样周期控制在1秒以上。如果你手头有DHT22可以把驱动里的数据类型和延时调一调其余逻辑不用动。空气质量传感器这边我对比了MQ-135和SGP30。MQ-135是模拟输出价格极低适合先做定性监测SGP30是数字I2C接口能输出eCO2和TVOC数值但价格高不少而且市面上存在假货风险新手买到坏芯片后容易把问题错怪到代码上。所以在基础版里我用MQ-135模块后续如果你打算做更精细的研究可以换SGP30但整体代码架构需要加一层抽象接口。1.3 系统框图与引脚规划整个系统的数据流是这样一个链路传感器采集物理量转换成电信号STM32读取后做数据处理一部分送OLED显示一部分和阈值比较后驱动蜂鸣器报警同时通过串口打印到调试助手。引脚分配我做得比较保守尽量避开复用的默认外设引脚。DHT11挂在PB12这个引脚没有默认的特殊外设功能冲突当作普通GPIO用就行。MQ-135模块的AO输出接PA0这是ADC1通道0也是大家最熟悉的一个ADC引脚。OLED用的软件I2CSCL接PB6、SDA接PB7虽然这两根引脚也是硬件I2C1的默认引脚但我这里用GPIO模拟方便以后移植到其他型号的芯片上。蜂鸣器接PB8LED指示灯接PB1USART1调试串口用PA9和PA10。之所以不上硬件I2C是因为STM32F103的硬件I2C模块在社区里口碑比较微妙问题大多出现在中断和DMA配合上。软件I2C虽然会多占用一点CPU时间但对于这种小系统完全无感而且出问题后好排查。2. 原理图设计电源、信号接入与画图细节2.1 电源部分的设计底线环境监测系统大概率是要长时间通电的所以电源设计的稳定性比“能跑起来”重要得多。整个系统的供电来自USB的5V进入板子后分成两条路。一路直接给MQ-135的加热丝供电另一路经过AMS1117-3.3稳压到3.3V给STM32、DHT11、OLED、蜂鸣器、LED供电。很多新手画原理图会忽略去耦电容觉得“反正芯片能跑”。但实际上STM32在驱动OLED刷新、ADC采样、蜂鸣器开启的瞬间电流会有明显波动。如果3.3V引脚附近不放去耦电容轻则ADC采样值跳动重则芯片异常复位。我的习惯是每个电源引脚旁边放一个100nF的陶瓷电容靠近引脚放置再在电源入口放一个10uF的电解电容或钽电容做储能。不要小看这几个电容它能让系统的电磁兼容性能上一个台阶。另一个细节是LED限流电阻的计算。我把LED接在PB1和GND之间中间串联一个1k电阻。3.3V减去LED正向压降约2V电流就是(3.3-2)/1000大约是1.3mA。对于普通贴片LED来说这个亮度足够做状态指示电流也低不会给稳压器造成额外的负担。2.2 DHT11接入一根线上拉里藏着时序协议DHT11是单总线数字传感器只通过一根数据线通信。空闲状态下这根线必须被上拉电阻拉高到3.3V否则总线处于悬空状态主从设备都无法正确识别电平。这个上拉电阻的阻值选10k比较常见。有些模块板载了上拉电阻如果你用的是模块形式可以直接连如果买的是单独的DHT11元件必须在数据线和VCC之间自己放一个10k电阻。少了这个电阻你会看到通信偶尔失败而且失败频率毫无规律用示波器看波形才能发现电平爬升太慢。DHT11的供电范围是3.3V到5V接入3.3V完全没问题。要注意的是数据线电平幅度跟随供电电压如果DHT11用5V供电而STM32是3.3V数据线的低电平是0V、高电平是5VGPIO引脚耐受性虽然标注兼容5V但最好还是统一用3.3V供电不给单片机引脚留下任何潜在风险。原理图上还需要标注DHT11的四个引脚顺序。从正面看四根引脚从左到右分别是VCC、DATA、NC、GND。NC引脚是悬空脚很多人在画封装时容易搞错把那个NC焊盘接到别的地方去最后怎么调试都不对。2.3 MQ-135模拟量采集分压计算与ADC保护MQ-135传感器模块有两种形式裸探头和集成模块。裸探头需要自己搭负载电阻和分压电路。传感器内部有一个加热丝和一个二氧化锡半导体敏感层当空气中存在特定还原性气体时敏感层电导率升高在负载电阻RL上分得的电压随之升高。采集这个电压就相当于采集了气体浓度的相对变化。如果你用集成模块模块上有AO输出和DO输出DO端有电位器可以调节触发阈值。大多数集成模块的AO是直接输出的但不同模块在5V供电下AO输出范围可能超过3.3V直接进STM32的ADC有风险。我建议在原理图上留一个分压电阻的位置假设AO最大输出约5V用10k对地分压后再接一个10k串联电阻到PA0这样即使模块输出异常进ADC的电压也不会超过2.5V相当于给单片机加了一道保险。如果你买的模块支持3.3V供电那AO输出基本在0到3.3V以内可以直接连但串一个几百欧的保护电阻仍然是好习惯。负载电阻RL的取值直接影响灵敏度。常规做法是10k到20k之间我的项目里用的10k。RL越小传感器在洁净空气中的输出电压越低动态范围越大RL越大低浓度时的变化越明显但高浓度时容易饱和。实际调试时你可以通过串口打印的ADC原始值来判断当前量程是否合理。2.4 OLED、蜂鸣器与调试串口怎么接OLED屏我选的是0.96寸I2C接口的SSD1306模块四个引脚分别是VCC、GND、SCL、SDA。注意很多OLED模块背面标了VCC和GND但没有标明工作电压。SSD1306本身支持3.3V供电所以直接接到系统的3.3V上没问题。SCL和SDA需要接上拉电阻不过我实测绝大多数OLED模块板载已经焊了上拉所以你只要连接四根线就行。蜂鸣器这里有个区分细节有源蜂鸣器和无源蜂鸣器的驱动方式完全不同。有源蜂鸣器内部自带震荡源通电就响给高电平即可驱动无源蜂鸣器需要外部提供一定频率的方波才能发声通常用PWM或者定时器翻转GPIO来产生。我在项目里默认用的是有源蜂鸣器低电平触发这样代码里只要拉低引脚就会响简单直接。你的系统里如果用无源蜂鸣器就需要写一个PWM输出或者用延时翻转的方式产生2.7kHz左右的方波。不管哪种蜂鸣器都不建议直接用GPIO驱动。GPIO的灌电流和拉电流能力有限蜂鸣器工作电流可能到三四十毫安直接把IO拉低容易导致电压跌落。我在原理图上用了一颗NPN三极管S8050做开关GPIO输出高电平时三极管导通蜂鸣器接通GND低电平时截止。这个电路成本不到一毛钱但对GPIO的保护很有价值。调试串口则用的是USART1PA9做TXPA10做RX。如果你用的是USB转TTL模块注意要把TXD接PA10、RXD接PA9还要共地。这个串口在调试阶段几乎是必需品你能通过它看到DHT11原始数据和ADC采样值不用反复猜测传感器状态。2.5 原理图可读性的几个习惯原理图不光是给自己看的开源出去之后别人也要能看懂。我在整理这个项目图纸时有一些习惯性的规矩这里一并分享出来。第一电源和地符号要统一3.3V和GND的符号不要混用网络标号。第二每个IC附近放一个元件位号和参数标注比如AMS1117旁边标注输出电压和封装形式。第三多页原理图不要忘记设置页码我之前就因为多页图纸的PAGE NUMBER都设成了1打印和生成PDF时页面顺序一片混乱这个错误虽然不起眼但在开源评审时非常减分。第四图形符号的方向应当符合信号流向左进右出这样别人读图时思路会非常顺。第五画完后导出一份BOM清单把元件的封装、型号、数量整理好方便自己和别人打板买料。3. 固件实现驱动、滤波和主循环的组织逻辑3.1 Keil5工程结构与下载配置软件的骨架直接决定了后续调试的效率所以我先把工程划分一下。我用的是Keil MDK5加STM32标准外设库虽然HAL库现在已经很普及但标准外设库的代码量更少直接操作寄存器风格的API更适合理解底层行为。工程下的目录我按功能拆成了四个部分System系统时钟、延时函数DriverDHT11、OLED、蜂鸣器、ADC等底层驱动App主逻辑、显示任务、报警任务Usermain.c、中断服务在Keil的Options for Target里有两个地方比较容易漏。一个是C/C选项卡里的Define宏标准外设库需要定义STM32F10X_MD如果是HD系列的芯片还得定义成STM32F10X_HD。另一个是芯片型号的选择Debug选项卡中选择ST-Link Debugger然后在Flash Download里勾选Reset and Run。如果你漏掉了Reset and Run程序烧录完之后不会自动运行还以为是代码出了问题其实只是没有复位。延时函数我用的是SysTick定时器把它配置成1us中断来源再封装出delay_us和delay_ms。DHT11的时序要求微秒级延时如果只用循环空转很容易因为编译器优化等级不同而出现时间偏差。3.2 DHT11驱动最容易栽跟头的单总线时序DHT11的通信时序看起来不复杂但实际写驱动时会在几个地方翻车我把完整流程拆开讲。主机开始通信时先把数据线拉低至少18ms然后拉高20到30us之后释放总线并切换成输入模式。这18ms是启动信号DHT11收到这个低电平后才会从待机模式切换到工作模式。拉低时间过短会导致传感器不响应我见过有人写成2ms结果无论怎么读都返回0。从机响应后会把总线拉低约80us表示“我已经准备好发数据了”接着释放总线并拉高80us然后开始发送40bit数据。每一bit都是以50us低电平开头后面跟一个高电平。高电平持续时间在26到28us左右这是“0”高电平时间在70us左右这是“1”。我读取一个字节的代码写成这样注意里面的延时判断逻辑uint8_t DHT11_ReadByte(void) { uint8_t i; uint8_t data 0; for (i 0; i 8; i) { while (DHT11_PIN_READ() 0); // 等待50us低电平结束 delay_us(30); if (DHT11_PIN_READ()) { data | (0x80 i); // 高电平宽说明是1 } else { data ~(0x80 i); // 高电平窄说明是0 } while (DHT11_PIN_READ() 1); // 等待高电平结束 } return data; }这里的delay_us(30)是关键。数据位的低电平是50us高电平如果只有26us左右就代表0如果等到高电平时长超过40us再读不管是0还是1都会被读成1因为0的高电平已经结束了。所以必须是在低电平结束后偏早的时机去采样这样才能区分出0和1。实际调试中如果读出来的数据全是0xFF或者数据在跳变基本就是这里的延时偏了。读取完40bit数据后需要校验。DHT11返回的5个字节是湿度整数、湿度小数、温度整数、温度小数、校验和。校验和等于前四个字节之和的低8位。如果校验不对我直接丢弃这次数据不更新显示等待第二次读取。环境监测系统不追求实时性丢一帧数据完全无感但绝对不能让错误数据上屏。一定要记住两次读取的间隔至少1秒以上。DHT11上电后第一次读取可能不稳定而且它的最大采样周期是1Hz如果读得太频繁传感器会进入忙状态返回的数据可能全是0。我在主循环里用一个1秒的软件定时器来控制读取节奏。3.3 MQ-135ADC采样、滤波和等级映射MQ-135的AO输出接到PA0STM32F103配置ADC1的通道012位分辨率转换范围从0到4095对应0到3.3V电压。ADC软件我最开始写的是单次转换模式读一次就返回。但单次ADC值在传感器上会有不小的噪音尤其是气体浓度变化的时候数值经常上下跳几百个字。这个噪音来自传感器本身的化学动态过程和空间电磁干扰不能只靠硬件滤掉软件上也要做平滑处理。我用的是滑动平均滤波连续采样8次去掉最大值和最小值剩下的6个值求平均。这样做的好处是既能把尖峰脉冲剔除又能保证响应速度不至于太慢。MQ-135对气体浓度变化的响应本来就有几秒的延迟所以滤波带来的额外延迟完全在可接受范围内。uint16_t MQ135_ReadAverage(void) { uint16_t buf[8]; uint8_t i, j; uint16_t sum 0; uint16_t min, max; for (i 0; i 8; i) { buf[i] Read_ADC1_Channel0(); delay_ms(2); } min buf[0]; max buf[0]; for (j 0; j 8; j) { if (buf[j] min) min buf[j]; if (buf[j] max) max buf[j]; sum buf[j]; } sum sum - min - max; return sum / 6; }空气质量等级映射我定义成四档。ADC值小于1000为“优”1000到1800为“良”1800到2600为“轻度污染”大于2600为“重度污染”。这个阈值不是拍脑袋定的而是根据MQ-135在洁净空气、点燃蚊香、靠近酒精等场景下实测得到的。你的环境里底噪可能和我不同所以代码里我把阈值定义成宏方便随时调整。等级判断还有一个容易忽视的点阈值回差。如果直接用单一阈值当ADC值在阈值附近波动时等级会在两个档位之间反复横跳屏幕上的字跟着闪观感很差。我加了一层滞回比较比如从“优”变“良”要ADC值超过1050但要从“良”回到“优”必须降到950以下。这样中间留出100个字的缓冲带界面的稳定性明显就好了。3.4 OLED显示软件I2C和UI设计SSD1306的驱动在这类项目里已经非常成熟我建议直接移植现成的驱动不要自己从头写初始化序列。但有一点要做个性化处理UI布局。我的屏幕分成三个区域。顶部两块区域分别显示当前温度和湿度包括数值和单位字号用16x8的ASCII字体。中间区域显示空气质量等级和对应的进度条等级用文字表示进度条用水平长条根据ADC值占满的比例来绘制。底部一行显示当前系统状态比如“NORMAL”表示正常“ALARM”表示当前处于报警状态。软件I2C的代码核心就是GPIO的翻转SCL和SDA按照I2C协议产生起始信号、停止信号和字节。写字节的时候要记得SDA在SCL低电平期间变化在SCL高电平期间保持稳定。我遇到过有人把SDA变化放在SCL高电平期间结果OLED完全没反应。OLED的通信速率不用追求极限200kHz到400kHz足够用了。我的软件I2C没有做严格的时序优化在STM32F103这种72MHz主频下刷一屏数据最多几十毫秒完全够用。如果你发现系统在刷新显示时偶发卡顿可以把汉字字模的数组放到const区域而不是RAM里就能省下不少内存。void OLED_DisplayAll(void) { OLED_Clear(); OLED_ShowString(0, 0, Temp:, 16); OLED_ShowNum(56, 0, temp_int, 2, 16); OLED_ShowChar(88, 0, C, 16); OLED_ShowString(0, 2, Humi:, 16); OLED_ShowNum(56, 2, humi_int, 2, 16); OLED_ShowChar(88, 2, %, 16); OLED_ShowString(0, 4, Air:, 16); OLED_ShowString(48, 4, levelStr[air_level], 16); OLED_DrawProgressBar(0, 6, 128, 8, adc_percent); }这里每一行y坐标用页或者像素来计算0.96寸OLED是128x64分辨率一页是8个像素高。16号字体占两页所以y坐标为0、2、4、6时刚好能排满四行内容。3.5 主循环状态机报警逻辑的设计细节主循环里我没有用复杂的RTOS就是简单的轮询加标志位。SysTick每1ms加一次计数在1秒到达时置一个读取标志。DHT11读一次数据更新温湿度显示。ADC读取则是每50ms循环一次因为空气质量变化相对缓慢不需要在1秒周期里重复读太多。报警逻辑我是这样设计的温湿度只做超限报警默认温度超过35℃或湿度超过80%时报警空气质量等级达到“重度污染”时报警。报警触发后蜂鸣器以500ms为周期鸣响同时LED灯闪烁这样可以明显区分正常工作状态和报警状态。报警后要加一个“撤销”机制。如果触发条件消失了蜂鸣器应该自动关闭不能一直叫下去。我这里的逻辑是当前报警条件满足且上一次不满足置报警标志报警标志状态下如果连续3次采样都恢复到正常范围就清除报警标志。这样不会因为单次ADC波动就误报也不会因为一次正常值就草率解除报警。主循环的代码结构非常直观while (1) { if (flag_1s) { flag_1s 0; DHT11_ReadData(humi, temp); } adc_value MQ135_ReadAverage(); air_level MQ135_GetLevel(adc_value); if (temp TEMP_ALARM_TH || humi HUMI_ALARM_TH || air_level LEVEL_ALARM) { alarm_count; if (alarm_count 3) { BEEP_ON(); LED_ON(); } } else { alarm_count 0; BEEP_OFF(); LED_OFF(); } OLED_DisplayAll(); printf(temp%d humi%d adc%d level%d\r\n, temp, humi, adc_value, air_level); delay_ms(50); }这种结构的好处是逻辑完全线性每个周期做的事情一眼就能看完整。一段时间跑下来系统的行为可以预期不会有任务调度上的隐藏bug。如果你后面想加入按键菜单或者联网功能再往这个结构里扩展新的模块即可。4. Proteus仿真、实物调试与校准经验4.1 Proteus仿真工程的搭建要点Proteus 8可以仿真STM32F103系列芯片我建的工程里主要用到了STM32F103C8T6、DHT11、一个电位器POT-HG、OLED屏以及虚拟终端Virtual Terminal。仿真工程搭建的时候重点在以下几步把STM32的HEX文件加载到芯片里。在Proteus里双击芯片在Program File项选择Keil编译输出目录下的HEX文件然后设置好CKS8MHz的晶振频率否则延时函数会全部错位。DHT11模型在Proteus的传感器库中可以找到放置后接在PB12填充模块符号数据线引脚上也需要一个上拉电阻。MQ-135在Proteus里没有对应的现成模型我的做法是用一个电位器来模拟传感器输出。电位器的中间抽头接在PA0上调节电位器就能改变ADC输入的电压从而验证我的滤波算法和等级判断。这种方式在仿真阶段很实用你不需要模拟传感器内部的化学过程只需要验证MCU这一侧的逻辑是否正确。OLED在Proteus里如果找不到完全一样的SSD1306模型可以用库里的“P8X8CharacterDisplay”或类似的通用I2C显示屏替代或者干脆在仿真阶段把OLED显示代码注释掉通过Virtual Terminal打印的数据来验证温湿度和ADC采样。实际上我调试时大部分逻辑判断都是靠串口打印完成的显示部分的UI效果留给实物阶段去检查。虚拟终端接USART1的TX和RX引脚波特率设成115200或者和你的printf串口初始化的波特率一致。仿真运行时DHT11模型的读数和真实传感器存在偏差这一点要特别留意。4.2 从仿真到实物五个容易翻车的点仿真跑通不代表实物一定能跑通下面这五个问题几乎每个做实物的人都会碰上一次我先踩过坑写在这里帮你绕开。第一个是供电问题。USB供电给整个系统时如果蜂鸣器报警瞬间电压跌落OLED会闪屏严重的会导致STM32复位。我排查这个问题时先量了3.3V在报警瞬间的波形发现跌落明显。解决方法是把蜂鸣器的电源从5V取而不是和MCU共用3.3V同时把三极管的地和MCU的地在一点汇合。OLED在报警时也不要同时做全屏刷新尽量只在数据变化时局部更新。第二个是DHT11的数据读取间隔。实物调试时我把读取周期从1秒改成了200ms结果数据频繁出错。这是因为DHT11上电后需要至少1秒才能完成一次完整采样读取频率高于传感器的输出频率时会读到无效数据。这个不是代码bug是器件本身的工作特性。第三个是OLED的I2C地址。市面上绝大多数0.96寸OLED模块是0x78或者0x3C但有一部分会不一样。初始化失败时先用I2C扫描程序把地址扫出来不要盲目相信网上的配置。我的驱动里把地址宏单独定义改起来很方便。第四个是蜂鸣器有源无源的区别。我在前面的章节提过这里再强调一次仿真里用的是一个逻辑电平就能驱动的蜂鸣器模型实物可能不一样。如果你发现焊好的蜂鸣器不响先查一下外壳上有没有标注或者直接拿万用表测一下两端电压有源和无源的驱动方法差别很大。第五个是ADC采样的参考电压。STM32F103的VREF默认和VDDA绑在一起如果你的3.3V电压有波动ADC结果就会跟着波动。我调试时发现不同USB口供电下MQ-135的底噪能差好几百个ADC字。后来我用万用表校准了3.3V的电压然后根据实际电压修正了ADC值到真实电压的换算系数数据才稳定下来。4.3 实测数据、校准方法与阈值参考实物跑起来后我在一个正常的室内环境里记录的参考数据大概是这样的室温26℃左右DHT11读出来是25到27℃之间波动湿度55%左右MQ-135的ADC底噪值在950到1200之间波动。把酒精棉球靠近传感器时ADC值会在几秒内攀升到2500以上有明显的响应过程拿走的几分钟后又会慢慢回落到原来的水平。这个响应速度给了我很重要的启示环境质量监测系统不需要对瞬时值做过于激进的报警更适合用滑动窗口的平均值来判断。如果你需要更稳定的输出可以把采样窗口从8次扩展到16次牺牲一点响应速度换取更好的平滑效果。校准方面做不了专业的气体标定但至少要做到两件事。第一基准校准。在通风良好的环境里开机预热半小时读取出ADC底噪值作为基准BASE_VALUE。第二相对等级映射。把ADC值超过基准值的比例映射到空气质量等级。我在代码里用的阈值其实就是基于这个思路把BASE_VALUE约等于1000作为“优”的上限超过基准值1.8倍以上算“灯光污染”超过2.6倍以上算“重度污染”。这个比例关系比绝对阈值更通用因为不同供电电压下ADC底噪会有差异但相对倍率基本是稳定的。如果你手头有参考用的空气检测仪可以对比着校准。让两个设备同时放在同一个环境里观察我的等级判断和参考仪器的趋势是否一致如果不一致就调整阈值。校准的过程一定要记录数据不要凭感觉改参数。我通常在调试助手里面把时间戳、温度、湿度、ADC原值、空气等级一起打印出来回到电脑上整理成表格这样改参数时能清楚看到每个阈值的影响。还有一点MQ-135上电预热时间比较长刚上电的前几分钟输出并不稳定加热丝还没有达到正常工作温度。所以我的代码里加了一个初始化提示开机前5秒屏幕显示“WARM UP”ADC数据虽然照常采集但不参与报警判断。这个细节让系统在长时间运行时的误报率明显下降成本几乎是零。这个项目的完整资料我按“拿到就能用”的标准整理了一遍Keil工程、原理图源文件、仿真文件、BOM清单和README都放在一起。如果后面有同学按这套流程做出来了我建议你们别急着收工把原始ADC数据和传感器标定过程记录下来写成调试笔记。环境监测这类项目代码跑通只是开始传感器漂移、温度补偿和阈值合理性才是真正决定它在实际场景里能不能用的关键。我的仓库里除了这套系统的基础工程还会不定期更新一些二次开发的参考方案有问题欢迎带着调试日志来讨论。
返回列表