前阵子做室内空气质量检测,买了几款成品检测仪,要么是显示数值不太透明,要么是数据拿不出来做二次分析。后来索性决定自己用STM32做一套环境质量监测系统,把温湿度、空气质量、光照这些核心参数全部采集起来,在本地OLED屏上实时显示,同时通过串口把数据输出给上位机,整套方案还做到了原理图开源、代码开源、仿真可跑。如果你正在入门STM32,或者想做一款小体积、低成本、可复现程度高的环境数据采集终端,这篇文章应该能帮你少走不少弯路。
项目里我用的是STM32F103C8T6这颗经典芯片,配合DHT11读取温湿度、MQ135检测空气质量、BH1750采集光照强度,外加一块0.96寸I2C接口的OLED屏幕作为本地显示终端。整套系统的代码量不大,按功能模块拆解后每一块都很清晰,适合拿来练手,也适合在原有框架上继续扩展比如PM2.5传感器、继电器控制、WiFi上传等。仿真部分用的是Proteus,传感器均能找到对应的仿真模型,哪怕手上暂时没有硬件,也可以先把逻辑和代码调通。
1. 系统架构与方案选型
1.1 为什么选择STM32F103C8T6作为主控
市面上做环境监测的MCU选择非常多,51单片机、Arduino、ESP32、STM32都是常见选项。但在这个项目里我最终还是选了STM32F103C8T6,核心原因有几个。首先是资源够用且不浪费,这颗芯片基于ARM Cortex-M3内核,主频72MHz,Flash为64KB,SRAM为20KB,跑一个轻量级的环境数据采集逻辑绰绰有余。它内置多个定时器、ADC、USART、I2C、SPI等外设,恰好覆盖本项目需要的模拟量采集(MQ135输出为模拟电压)、数字温湿度读取(单总线协议)、I2C显示(OLED)、串口通信(上位机交互)。
其次是生态成熟度,STM32F103系列的材料和学习资源非常丰富,不管是HAL库还是标准外设库,都能支撑一个完整的项目。即便你是第一次接触STM32,遇到问题时的检索成本会低很多。第三点是价格和供货稳定,作为一颗出货量极大的芯片,C8T6的最小系统板价格很友好,用来做原型验证或者课程设计都非常合适。
对比来看,51单片机虽然上手简单,但片上外设数量少,后续想扩展PWM调速、ADC多通道采集或者DMA传输时会觉得处处受限。ESP32虽然自带WiFi和蓝牙,但对纯本地环境监测来说有点大材小用,而且它的功耗控制、模拟采集精度在入门场景下反而不如STM32直观。所以在“硬件成本低、代码易理解、扩展空间足”这三个目标之间,STM32F103C8T6是一个平衡点非常合适的选择。
1.2 环境参数维度与传感器选型思路
环境质量是一个综合概念,普通人最关心的几个指标无非是温度、湿度、空气质量以及光照。这四个参数覆盖了“舒不舒适”“空气干不干净”“光线亮不亮”三个核心场景,而且它们的传感器方案都相当成熟,非常适合作为系统第一版的功能基线。
- 温湿度测量:选了DHT11。它是一颗数字温湿度传感器,采用单总线协议,只需要一根数据线就能完成通信。测量范围是温度0到50摄氏度、湿度20%到90%RH,精度分别是正负2摄氏度和正负5%RH。对室内环境监测来说,这个精度完全够用了。如果你对精度有更高要求,后续可以直接换成DHT22或SHT30,软件层只需要改驱动函数。
- 空气质量检测:选了MQ135。它是半导体气体传感器,对氨气、硫化物、苯系蒸汽、烟雾等有一定敏感度,输出信号可以是模拟量,也可以经过比较器电路输出数字量。本项目中我直接读取它的模拟电压输出,通过ADC转换成浓度相关的数值,再映射到“优/良/差”等级。
- 光照强度:选了BH1750。这是一颗I2C接口的数字环境光传感器,测量范围1到65535 lux,内部自带16位ADC和光敏二极管,使用非常方便。它可以直接读到物理光照值,不需要自己做线性标定。
- 显示终端:0.96寸OLED,SSD1306驱动芯片,I2C接口。显示密度高、功耗低、调试时反馈直观,代码驱动也比较成熟。
传感器的选型逻辑其实很明确:优先选数字接口或标准模拟输出的,减少后端信号调理电路的复杂度。DHT11和BH1750都是数字输出,开发时几乎不需要外围电路;MQ135输出模拟电压,只需要一个ADC通道即可读取,配上一路参考电压做阈值判断就可以了。
1.3 系统整体工作流程
整套系统上电后先做外设初始化,包括时钟配置、GPIO方向设定、ADC通道初始化、I2C初始化、串口初始化,以及OLED屏幕的显示初始化。随后主循环按顺序执行以下逻辑:读取DHT11温湿度数据、读取BH1750光照数据、通过ADC读取MQ135电压值,计算空气等级,把所有这些数据打包后同时送OLED和串口输出。
比较关键的设计点是我把传感器读取和显示刷新做了分时处理。DHT11读取一次需要等待约20ms,MQ135的ADC采样很快,BH1750一次转换需要约16ms。如果串行地从头到尾跑一遍,整个周期大约在80ms左右,人眼在OLED上看不出刷新问题。但串口上位机如果同时用9600波特率接收,会出现轻微的数据堆积现象。后来我把主循环设计成状态机模式,每个传感器读取放在对应的时间片里,整体调度周期稳定在100ms,上位机每500ms接收一次完整数据帧,整个系统运行顺畅很多。
2. 硬件原理图设计深度解析
2.1 最小系统电路设计
STM32最小系统是整块板子的地基,包含电源电路、复位电路、时钟电路和启动模式选择四大部分,原理图设计时每一块都有需要注意的细节。
电源部分我采用的是USB 5V输入,经过AMS1117-3.3稳压芯片降到3.3V给MCU和传感器供电。AMS1117是LDO线性稳压器,纹波小、电路简单,适合这种小电流传感器系统。输入和输出端各加一个10uF钽电容和一个0.1uF陶瓷电容,用于滤除低频纹波和高频噪声。特别要提醒的是,电容要尽量靠近稳压芯片的引脚放置,走线先经过电容再到芯片电源脚,否则滤波效果会打折扣。
复位电路是经典的上电复位结构:NRST引脚接一个10K上拉电阻到3.3V,同时接一个0.1uF电容到GND。按下复位按键时,NRST被拉低,MCU执行复位。有些入门设计中会把按键省掉,用ST-Link也能复位,但板子上放一个独立复位键在调试时会方便很多,尤其是程序跑飞或者进入异常状态时。
时钟电路用了8MHz无源晶振加两个20pF负载电容。STM32F103内部有HSI 8MHz RC振荡器,理论上不接外部晶振也能跑,但内部RC精度有限,而且后续如果要做USB通信,就必须使用外部晶振保证48MHz时钟准确。所以最小系统板上晶振电路是必备的。两个负载电容的值根据晶振规格书选择,一般在10pF到22pF之间,实测20pF最稳定。
启动模式选择通过BOOT0引脚实现,BOOT0串联10K电阻接GND,保证默认从用户Flash启动。BOOT1引脚直接悬空或者也下拉到GND,因为FLASH启动模式下BOOT1状态无影响。
2.2 传感器接口电路设计
DHT11的接口电路非常简单,DATA引脚接MCU的一个普通GPIO(我用的PA1),数据线上加一个4.7K上拉电阻到3.3V。因为DHT11采用单总线协议,空闲时数据线保持高电平,MCU发送起始信号后释放总线,DHT11拉低响应,整个时序过程都是开漏结构,必须有上拉电阻才能正常工作。如果你用的模块板上已经自带上拉电阻,原理图中可以不用重复添加,但要在BOM上标注清楚。
BH1750模块是标准的I2C接口,SDA和SCL分别接PB7和PB6,同样需要上拉电阻。I2C协议要求总线空闲时SDA和SCL都为高电平,STM32的I2C外设配置为开漏输出后,必须通过外部上拉电阻提供高电平驱动能力。我用的是4.7K上拉接到3.3V。如果你用的模块板上有集成上拉,外部可以省略,但建议预留焊盘,方便调试时根据实际波形调整电阻值。
MQ135模块的输出有模拟量(AO)和数字量(DO)两种引脚。本项目中我只使用AO引脚,接一个电压跟随器后送入STM32的ADC输入引脚PA0。为什么要加电压跟随器?因为半导体气体传感器的加热电阻和敏感电阻阻值较大,输出阻抗不低,直接接入ADC可能导致采样值偏低或不稳定。用一个轨到轨运放搭建电压跟随器,可以在不影响信号幅值的前提下大幅降低输出阻抗,保证ADC采样的准确性。市售模块上通常已经集成了比较器电路,AO输出的驱动能力够用,也可以不用额外跟随器,直接接PA0加一个0.1uF滤波电容即可。
2.3 OLED显示与串口通信电路
OLED模块我选用的是0.96寸、SSD1306控制器、I2C接口版本。模块的VCC接3.3V,GND接GND,SDA和SCL与BH1750共用同一条I2C总线。因为两个设备的I2C地址不同,BH1750的地址是0x23(ADDR引脚接低),OLED的地址是0x3C,总线仲裁没有问题。共用总线的好处是少占用两个GPIO,布线也更简洁。不过共享总线上多个设备时,I2C速率需要根据最慢设备来设定,BH1750支持400kHz,SSD1306手册标称最大400kHz,实测跑400kHz没问题,但为了稳妥我统一配置成200kHz。
串口部分用的是USART1,TX为PA9,RX为PA10。由于STM32的IO电平是3.3V,和PC的RS-232电平不兼容,所以需要经过USB转TTL芯片(如CH340或CP2102)与电脑通信。原理图中我把USART1的收发引脚直接通过排针引出,外部接CH340模块。这样板子本身更简洁,也方便灵活换用不同品牌的USB转串口模块。调试时注意共地,USB转TTL模块和主控板必须在同一个GND电平上,否则通信会出现乱码。
2.4 蜂鸣器报警与预留扩展接口
为了让环境数据超限时能本地提示,我加了一个有源蜂鸣器,接在PB5引脚,通过NPN三极管驱动。为什么不能直接用GPIO驱动蜂鸣器?因为STM32的GPIO输出电流能力有限,标准模式下最大约20mA,而有源蜂鸣器正常工作电流往往在30mA以上,直接驱动可能导致GPIO口烧坏或电压跌落。我用的是SS8050三极管搭建的开关电路,GPIO输出高电平时三极管导通,蜂鸣器发声;GPIO输出低电平时截止。原理图上蜂鸣器两端反并联一个1N4148二极管,用于吸收关断瞬间感性负载产生的反向电动势,防止击穿三极管。
扩展接口方面,我预留了两组5V和3.3V电源排针,以及一组包含PB3、PB4、PA4、PA5的通用GPIO排针。这些接口可以方便地接入继电器模块、ESP8266 WiFi模块、PWM风扇等外设。实际测试中,我在PB3上挂过一个继电器,通过修改报警逻辑,实现了空气质量超标时自动启动排风风扇的效果,整个扩展过程不需要改动原有原理图架构。
3. 软件代码实现解析
3.1 工程结构与模块划分
代码工程采用标准HAL库架构,按外设模块做了清晰的文件夹划分。核心文件包括:
- main.c:系统初始化、主循环调度
- dht11.c/dht11.h:DHT11单总线时序驱动、温湿度数据解析
- bh1750.c/bh1750.h:BH1750的I2C寄存器配置、光照读取
- adc_mq.c/adc_mq.h:ADC初始化、MQ135电压采集与等级映射
- oled.c/oled.h:SSD1306初始化、字符与图形显示
- usart1.c/usart1.h:串口初始化、数据帧打包发送
- systick_delay.c/systick_delay.h:基于SysTick的毫秒和微秒延时
模块化设计有几个明显好处。每个传感器只有一个明确的程序接口,比如DHT11_Read_TempHumidity(float *temp, float *hum),主函数只关心调用这个函数后能不能拿到数值,不关心底层时序细节。后续如果要替换传感器或者更改通信协议,只需要改动对应的驱动文件,不需要波及主循环逻辑。对于刚接触嵌入式开发的读者来说,这种“一处功能一个文件”的组织方式也比较容易对照理解。
3.2 DHT11单总线时序驱动要点
DHT11的驱动是整个项目中时序最敏感的部分,也是新手最容易踩坑的地方。单总线协议要求MCU必须精确控制微秒级别的电平变化,时序错误会导致传感器不应答或者数据全部为0。
标准读取流程是这样的:MCU先把数据线拉低至少18ms,然后释放并延时20到40us,此时DHT11检测到起始信号,会拉低总线80us作为响应,然后再拉高80us准备发送数据。随后DHT11开始发送40位数据,每一位都由低电平50us和高电平的持续时间来区分:高电平持续26到28us代表逻辑0,持续70us代表逻辑1。
所以在驱动代码中,我会先拉低PA1并延时20ms,然后拉高并延时30us左右,再切换IO为输入模式等待传感器响应。读取每一位时,先等待电平变低,再等待电平拉高,然后测量高电平持续的时间,超过40us判为逻辑1,否则判为逻辑0。为了避免阻塞时间过长造成系统卡死,我为每一次等待都加了超时判断,比如等待低电平最多持续200us,超过就跳出并返回错误码。
延时函数我用的SysTick实现了微秒级延时,实测精度够用。这里有一个重要的注意事项:开启编译器优化等级为O2时,部分空循环延时会因为代码优化的原因被大幅压缩,导致时序失败。所以我强烈建议用SysTick或定时器实现延时函数,而不是用简单的for循环空转。这个坑我踩过一次,当时一开优化等级,DHT11数据就全错了,排查了很久才发现是空循环延时被优化掉了。
3.3 BH1750光照读取的寄存器配置
BH1750的I2C操作相对友好,它支持两种地址模式,地址由ADDR引脚决定。ADDR接低电平时地址为0x23,接高电平时为0x5C。我的原理图中ADDR直接接地,所以器件地址是0x23。
芯片上电后默认处于断电模式,需要先发送连续高分辨率测量模式的指令(0x10),然后等待约180ms(手册标称最大120ms,我留了余量),再连续读取两个字节数据。高字节在前,低字节在后,合成一个16位整数后除以1.2即得到以lux为单位的光照值。这里除以1.2是因为在H分辨率模式下,1个LSB对应1.2lux。如果用的是低分辨率模式,则1个LSB对应的是4lux,换算系数不同。
需要注意的细节是BH1750对START和STOP条件的时序要求比一般I2C设备苛刻一些,特别是从发送测量指令到读取数据之间,不能插入其他I2C总线的通信。在工程实现中,我读取光照时会对I2C总线加锁,等两个字节的数据取回来后再释放总线,避免OLED刷新正好打在这个时间段里造成数据错乱。
3.4 ADC采集与空气质量等级映射
MQ135输出的模拟电压范围大约是0到4V,这个范围超出了STM32的3.3V参考电压上限,所以我在原理图设计时对传感器模块的供电使用了5V,并且通过电阻分压后再送ADC。具体实现有两种方案:一是在模块输出端串联10K电阻再接GND的10K电阻做1/2分压,二是用运放搭建减法电路。考虑到成本和简洁性,我选择了电阻分压方案。但需要提醒的是,电阻分压会降低传感器的分辨率,3.3V量程分配到0到4V的输入范围上,每个ADC单位代表的电压值变大,精度自然下降。
配置ADC1的通道0,采样时间选择239.5个周期,这样对高阻抗信号源更友好。我连续采样8次后取平均,可以有效降低噪声干扰。采集到的原始值通过公式计算出实际电压,再映射到空气等级:
- 电压低于0.3V,对应“优”
- 电压在0.3V到1.0V之间,对应“良”
- 电压在1.0V到2.0V之间,对应“轻度污染”
- 电压超过2.0V,对应“重度污染”
这个阈值是根据MQ135在清洁空气中的典型输出电压和污染环境下的响应特性粗略划分的。如果你用的是不同批次或不同品牌的模块,阈值可能需要根据实测数据微调。在做原型验证时,我一般会在正常房间内记录一组数据作为基线,然后靠近酒精、烟雾或者香薰测试一组数据,用两组数据的差值来修正判级边界。
3.5 OLED显示与串口数据帧协议
OLED显示逻辑相对直观,SSD1306初始化后,我把屏幕划分为三个区域:顶部显示“Temp: xx.x C”和“Humi: xx.x%”,中间显示光照强度“Lux: xxxx”,底部大字体显示空气等级。因为SSD1306不带字库,中文字符需要自己取模,所以我统一使用ASCII字符集,等级用英文缩写(EXCELLENT, GOOD, LIGHT, HEAVY)表示,避免取模的麻烦。实际效果清晰可读,界面信息一屏览尽。
串口协议我定义成了一个简单但完备的JSON行格式:
{"T":25.3,"H":58.2,"L":320,"A":1}其中T代表温度、H代表湿度、L代表光照强度、A代表空气等级编号。每条数据以换行符结尾。这个格式虽然比纯二进制数据多一点字节开销,但调试时可以直接在串口助手里阅读,也能被Python、Node-RED等上位机直接解析。实测9600波特率下,发送一行约60字节的数据耗时不到70ms,完全满足500ms一次的上报频率。
4. Proteus仿真设计与联调实践
4.1 仿真工程的搭建方法
Proteus 8以上的版本自带STM32F103C8T6模型,器件库里可以直接搜索并放置。搭建工程时,除了放置MCU,还需要从库中调出DHT11模型、BH1750模型、MQ135模型、OLED模型以及虚拟终端。特别注意,Proteus的DHT11模型与实物行为一致,单总线时序必须严格按照手册要求操作才能读到数据;BH1750模型支持I2C,仿真时能正确响应读取命令;MQ135模型则通过一个可调电位器模拟气体浓度变化,方便观察ADC电压变化。
连线方式和原理图保持一致:PB6和PB7接入SDA和SCL上拉后接OLED和BH1750,PA1接DHT11,PA0接MQ135模块的输出节点。虚拟终端连接在PA9和PA10上,用于查看串口输出的数据。连线完成后,将编译好的HEX文件加载到MCU模型上,开始运行仿真。
第一次跑仿真时最容易出现的问题是MCU没有时钟源。Proteus中STM32模型的时钟频率需要手动设置,默认可能是4MHz或12MHz,如果代码里配置的SystemCoreClock是72MHz而仿真器没有同步修改,延时函数就全乱了。在仿真项目的“Design > Configure Power Rail”弹出的对话框里,把处理器时钟频率设为72MHz,同时确认外部晶振参数,才能保证和实际硬件运行节奏一致。
4.2 仿真中如何模拟传感器数据变化
Proteus里的MQ135模型使用一个模拟电位器来改变输出电压。运行仿真后,可以通过点击电位器并滑动旋钮来调整电压。如果你希望实现自动变化的阶梯波形,可以在信号源中选择“DSP”类别的“SINE”或者“DC”信号源,接在MQ135输出节点上作为替代。实际测试中,我用一个低频正弦信号源接在PA0节点,使电压在0.3V到2.5V之间缓慢变化,观察到OLED上的空气等级随时间从“优”变到“重度污染”,ADC采集和等级映射逻辑均正确响应。
BH1750在仿真中通过一个光强度调节旋钮来改变照度值。把旋钮从低到高旋转,OLED屏幕上的光照数据随之线性增长,验证了I2C通信链路的正确性。DHT11的温度和湿度则分别在模型属性里设置具体数值,修改后点击运行,OLED上立即显示出新的温湿度。这比在真实硬件上反复改变环境条件要方便太多,特别适合用来验证代码逻辑是否存在明显bug。
4.3 仿真与硬件验证的差异点
Proteus仿真能帮你验证核心逻辑和大部分时序问题,但它和真实硬件仍有几个明显差异,需要提前预判。第一,仿真的I2C通信时序和真实器件比更理想化,信号不存在毛刺或上升沿缓慢导致的问题,所以在仿真中跑通的I2C代码,烧到实机上可能偶发误码,建议使用ST-Link配合逻辑分析仪实际观察一次波形。第二,MQ135的真实响应速度非常慢,半导体传感器从接触到气体到输出稳定电压往往需要数十秒甚至数分钟,而仿真中的电位器电压是即时变化的,所以仿真适合验证判级逻辑,不适合模拟真实的气体响应曲线。第三,DHT11的时序在仿真中相对宽容,即使在延时函数上有一点误差也能读到数据,但实机上时序要求苛刻得多,所以我在3.2节提到的微秒延时实现问题,一定要在实机阶段重点验证。
5. 常见问题与调试经验实录
5.1 DHT11一直返回0或超时
这个问题的概率极高,我在群里帮不少朋友排查过。首要检查的是GPIO模式和上拉电阻。DHT11通信过程中,GPIO需要在输出和输入模式之间切换,如果用HAL库配置成GPIO_MODE_OUTPUT_OPEN_DRAIN,同时外部加4.7K上拉电阻,可以省略模式切换的麻烦,开漏输出天然支持输出低电平和输入读电平的双向操作。如果配置成推挽模式,数据线就永远被强行拉高或拉低,单总线时序无法正常工作。
其次是延时精度问题。实测用SysTick实现的us延时在72MHz主频下可以做到正负2us误差,再用空循环做延时的话误差可能到10us以上。DHT11对0和1的电平持续时间划分是40us,40us到70us的窗口期只有30us,延时误差过大会导致全部位识别为同一逻辑值,最终结果就是数据校验失败返回0。
5.2 OLED白屏或显示乱码
白屏通常说明I2C地址配置错误或者上拉电阻缺失。用I2C扫描程序确认一下总线上的设备地址,OLED一般是0x3C或0x3D,0x3D出现在ADDR引脚接高电平时。如果扫描结果只有0x23(BH1750)而没有OLED的地址,基本可以确定OLED模块供电或者SDA、SCL接线有误。
显示乱码则大概率是初始化序列的对比度或显示方向配置问题。SSD1306初始化序列中有一条0xA8命令设置多路复用比率,0x1F对应128x32屏幕,0x3F对应128x64屏幕。你用的0.96寸OLED大多是128x64,如果初始化代码是按32行配置的,会出现只有上半屏有内容或字形被拉扁的现象。另外显示方向可以通过0xC8命令(上下翻转)和0xA1命令(左右翻转)调整,要根据模块的硬件走线灵活配置,否则屏幕上的图像可能是镜像或倒置的。
5.3 ADC采样值跳变严重
MQ135的输出信号本身带有较强噪声,特别是模块靠近电源变压器或者开关稳压器时。我在原理图中已经加了0.1uF的滤波电容,但实测下来还远远不够,最后在软件上做了更激进的处理:连续采样8次,去掉一个最大值和一个最小值,再对剩余6次取平均。配合ADC的硬件过采样,最终数据稳定性有了明显提升。
另外要检查ADC参考电压是否干净。STM32F103的内部VREF和VDDA是同一个网络,如果板子上3.3V电源纹波大,参考电压抖动直接反映到采样结果中。建议在VDDA引脚上额外加一个10uF电容和1uH磁珠组成的LC滤波电路,实测这个办法能有效减少电源纹波对ADC采样精度的干扰。
5.4 串口收到的数据乱码
乱码九成是波特率不匹配。ST-Link板载的虚拟串口一般支持常用波特率,而CH340模块也兼容广泛,但有些国产USB转串口芯片在9600波特率下配合有源晶振精度不够的MCU时,会产生微小误差累积。查看MCU的时钟树配置,确保USART1的时钟源选择正确,如果用的是HSE 8MHz经过PLL倍频到72MHz,那USART波特率计算不会有问题。再用示波器或逻辑分析仪测量TX引脚的电平宽度,确认每一位信号的实际时间是否和9600波特率理论值相符。
还有一个容易忽略的点是接线顺序。很多USB转TTL模块上的TXD和RXD标注是从模块自身角度看的,TXD应该接MCU的RX,RXD应该接MCU的TX。如果按“同名相接”很容易造成串口收不到任何数据。这个错误不涉及硬件损坏,但非常浪费排查时间。
5.5 仿真运行时处理器不执行
Proteus仿真工程加载HEX文件后,屏幕没有反应,虚拟终端也没有输出。先检查单片机模型是否设置了正确的晶振频率,再检查是否添加了启动代码。STM32F103在Proteus模型里需要勾选“Clock Divider”设置为HSE/1,并确保8MHz晶振挂在OSC_IN和OSC_OUT引脚。如果模型里没有外部晶振选项,也可以把时钟源改成内部HSI 8MHz,代码侧同时把SystemClock配置改为HSI方案。仿真里对时钟的配置容错比实机低很多,很多实机上HAL会自动处理的细节在仿真环境都需要手动确认。
说实话,我在这个项目上踩过的坑比预想的多,尤其是DHT11单总线时序和ADC参考电压这两个环节,一度都想放弃改用全I2C传感器方案省心了。但坚持调通了之后,整个系统的稳定性和可维护性都让我很满意。目前这套系统已经在我们项目组办公室连续运行了将近两个月,数据每天通过串口采集到一个Python脚本里,自动绘制成温湿度和光照变化曲线。如果你也想做一套类似的环境监测终端,我建议先照这个设计跑通原型,然后把MQ135换成分辨率更高、选择性更好的SGP30或SGP40,再按自己的需求加上报警联动和数据上传,这套框架完全可以撑得住后续的二次开发。