ARTICLE DETAIL

资讯详情

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

STM32驱动红外PM2.5传感器:串口通信与数据解析实战

STM32驱动红外PM2.5传感器:串口通信与数据解析实战 1. 项目缘起与整体设计思路红外PM2.5传感器在空气质量监测领域算是性价比很高的一类方案尤其是那种带风扇主动进气的红外粉尘传感器几十块钱就能拿到输出方式通常是UART串口或者PWM脉宽。我这次做的项目就是用STM32去读取这类传感器的数据然后做本地显示和串口上报。选这个题目的原因很直接很多环境监测类的毕业设计、鱼缸控制、智能台灯项目都需要一个能测颗粒物的环节而红外方案比激光方案便宜、驱动简单对STM32的算力要求也低F103C8T6这种最小系统板就能跑得很稳。整体设计上我把项目拆成四块传感器供电与电平匹配、STM32串口接收、数据帧解析、以及数据输出。传感器这边市面上常见的红外PM2.5模块工作电压多在5V而STM32的IO是3.3V电平所以不能直接把传感器的TX接到STM32的RX上中间要处理电平。我试过两种方案一种是电阻分压一种是电平转换模块后面会详细说。STM32这边我用的是USART2接传感器USART1做调试打印这样调试的时候不会和传感器数据打架。数据解析部分红外传感器的串口协议一般是固定帧头加数据字节加校验和帧长和校验方式不同厂家略有差异需要先拿到手册确认。为什么不用PWM方式读因为PWM方式只能得到一个浓度对应的脉宽精度和抗干扰都不如串口而且串口方式能拿到更原始的数据方便后期做滤波和校准。另外串口方式对定时器的占用也少PWM捕获还得额外配置定时器输入捕获对新手来说容易在时钟树和中断优先级上踩坑。所以这个项目里我优先推荐串口方案PWM方案作为备选。适合谁来参考如果你正在做基于STM32的环境监测、智能家居、毕业设计或者单纯想学串口通信和传感器驱动这个项目都很合适。不需要你有很深的RTOS或者DMA基础会用Keil新建工程、会配置串口中断就能跟上。下面我按实际操作的顺序把每个环节拆开讲。2. 硬件连接与电平匹配的细节2.1 传感器引脚定义与供电选择红外PM2.5传感器一般有四个引脚VCC、GND、TX、RX。有的模块还多一个SET或者EN脚用来控制风扇启停或者进入校准模式。我手上这个模块是5V供电TX输出高电平也是5V。这里有个坑如果你直接把TX接到STM32的PA3USART2_RX短时间可能能读到数据但时间长了STM32的IO口会被5V倒灌轻则引脚损坏重则芯片发热。所以电平匹配必须做。供电方面我建议用STM32板子上的5V引脚给传感器供电但要注意电流。红外传感器内部有风扇或者加热丝启动瞬间电流可能到100mA以上如果STM32板子上的5V是从USB口过来的一般能撑住但如果同时带OLED、蜂鸣器就要算一下总电流。我实测这个模块稳定工作电流在60mA左右峰值不超过120mAUSB供电没问题。2.2 电平转换的两种做法与取舍第一种是电阻分压。传感器TX接一个10k电阻再串一个20k电阻到GND中间抽头接STM32的RX。这样5V经过分压后大约是3.3V。这个方案成本最低两个电阻就行。但缺点是分压后的信号边沿会变缓如果波特率高于9600波形可能畸变。我实测在9600波特率下没问题115200就不太稳。所以如果你要用高波特率建议用第二种方案。第二种是电平转换模块比如TXS0108E或者简单的MOS管电平转换电路。这种方案信号质量好支持高速率但要多花几块钱接线也多两根。我自己的做法是如果项目对成本敏感且波特率不超过9600用电阻分压如果要做产品或者波特率较高直接上电平转换模块。另外STM32的TX接到传感器RX时因为STM32输出3.3V高电平传感器那边一般能识别为高电平所以这一路可以不加转换但为了保险我一般也会加一个1k电阻限流。2.3 接线顺序与上电注意事项接线顺序很重要。我习惯先接GND再接VCC最后接TX和RX。为什么因为如果先接VCC传感器和STM32之间没有共地信号线可能会有电位差容易打坏IO。共地之后电位基准一致再接信号线就安全。上电顺序上先给STM32上电再给传感器上电或者同时上电。如果传感器先上电它的TX会输出5V高电平而STM32还没上电IO口处于高阻态这时候5V直接加到IO上虽然电流不大但长期这样也可能有问题。还有一个细节传感器的TX和RX不要接反。我见过有人把传感器的TX接到STM32的TX上结果两边都是输出谁也收不到数据还容易烧。记住口诀TX接RXRX接TX交叉连接。3. STM32串口接收与数据帧解析3.1 串口初始化与中断配置我用的是标准库因为很多教学和毕业设计还在用标准库资料多踩坑少。USART2的初始化步骤使能GPIOA和USART2时钟配置PA2为复用推挽输出TXPA3为浮空输入RX然后设置波特率9600、8位数据位、1位停止位、无校验。中断方面我开了接收中断RXNE每收到一个字节就进一次中断把数据存到缓冲区。这里有个关键点波特率必须和传感器一致。红外PM2.5传感器常见的波特率是9600也有4800的拿到手册先确认。如果波特率不对收到的全是乱码。我一般会在初始化之后先发一个测试指令如果传感器支持或者直接看接收到的数据有没有固定帧头来判断波特率是否正确。中断优先级方面如果项目里还有定时器中断、OLED刷新建议把串口接收中断设成较高优先级防止数据丢失。但也不要设成最高否则可能影响系统滴答定时器。我一般设成抢占优先级1子优先级0。3.2 数据帧格式与校验方式红外PM2.5传感器的串口输出一般是主动上报模式每隔1到2秒发一帧数据。帧格式常见的是帧头0x42 0x4D和某款激光传感器类似然后是数据长度、数据内容、校验和。但不同厂家不一样有的帧头是0xFF 0xAA有的是0xA5 0x5A。我手上这个模块的帧格式是帧头0xAA 0xBB然后是低字节、高字节、校验和共5个字节。校验和是前四个字节之和取低8位。解析的时候我建议用状态机的方式而不是一次性把缓冲区读完。状态机的好处是能处理断帧、粘帧的情况。具体做法定义几个状态比如等待帧头1、等待帧头2、接收数据、校验。每进一次中断根据当前状态决定下一步。这样即使数据流中间有干扰也能重新同步。3.3 数据滤波与浓度计算原始数据拿到之后不要直接显示。红外传感器的数据跳动比较大尤其是风扇刚启动的时候。我一般做两级滤波第一级是限幅滤波如果本次值和上次值差超过一定阈值比如50微克每立方米就认为这次是干扰丢弃第二级是滑动平均取最近5次的有效值做平均。这样显示出来的数据会平稳很多。浓度计算方面有的传感器直接输出浓度值有的输出的是原始AD值需要根据手册的公式换算。我手上这个模块输出的是浓度值单位是微克每立方米低字节在前高字节在后。计算方式就是低字节加上高字节乘以256。如果手册给的是电压和浓度的关系曲线那就需要先算电压再查表或者用公式算浓度。4. 完整实操流程与关键代码4.1 工程搭建与时钟配置新建工程的时候我习惯用Keil5芯片选STM32F103C8。时钟树配置成72MHz外部晶振8MHz。为什么强调时钟树因为串口波特率的计算依赖系统时钟如果时钟配错了波特率就会偏数据就乱。标准库里面SystemInit函数会帮你把时钟配好但如果你自己改了晶振频率就要手动改PLL倍频系数。串口初始化的代码大概是这样void USART2_Init(u32 bound) { GPIO_InitTypeDef GPIO_InitStructure; USART_InitTypeDef USART_InitStructure; NVIC_InitTypeDef NVIC_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE); GPIO_InitStructure.GPIO_Pin GPIO_Pin_2; GPIO_InitStructure.GPIO_Mode GPIO_Mode_AF_PP; GPIO_InitStructure.GPIO_Speed GPIO_Speed_50MHz; GPIO_Init(GPIOA, GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin GPIO_Pin_3; GPIO_InitStructure.GPIO_Mode GPIO_Mode_IN_FLOATING; GPIO_Init(GPIOA, GPIO_InitStructure); USART_InitStructure.USART_BaudRate bound; USART_InitStructure.USART_WordLength USART_WordLength_8b; USART_InitStructure.USART_StopBits USART_StopBits_1; USART_InitStructure.USART_Parity USART_Parity_No; USART_InitStructure.USART_HardwareFlowControl USART_HardwareFlowControl_None; USART_InitStructure.USART_Mode USART_Mode_Rx | USART_Mode_Tx; USART_Init(USART2, USART_InitStructure); USART_ITConfig(USART2, USART_IT_RXNE, ENABLE); NVIC_InitStructure.NVIC_IRQChannel USART2_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority 1; NVIC_InitStructure.NVIC_IRQChannelSubPriority 0; NVIC_InitStructure.NVIC_IRQChannelCmd ENABLE; NVIC_Init(NVIC_InitStructure); USART_Cmd(USART2, ENABLE); }这段代码里GPIOA的时钟和USART2的时钟都要开缺一不可。PA2配成复用推挽PA3配成浮空输入这是标准做法。中断优先级设成1和0避免和系统滴答冲突。4.2 中断服务函数与状态机实现中断服务函数里我只做一件事把接收到的字节存到环形缓冲区然后置一个标志位。解析放在主循环里做这样中断时间短不容易丢数据。状态机的实现大概是这样void USART2_IRQHandler(void) { if(USART_GetITStatus(USART2, USART_IT_RXNE) ! RESET) { u8 data USART_ReceiveData(USART2); ring_buf_write(data); USART_ClearITPendingBit(USART2, USART_IT_RXNE); } }主循环里从环形缓冲区读数据喂给状态机。状态机的状态定义typedef enum { STATE_HEAD1, STATE_HEAD2, STATE_DATA_L, STATE_DATA_H, STATE_CHECK } ParseState;每读一个字节根据当前状态判断。比如在STATE_HEAD1时如果字节是0xAA就转到STATE_HEAD2否则留在STATE_HEAD1。在STATE_CHECK时计算校验和如果正确就把数据存到全局变量否则丢弃重新回到STATE_HEAD1。4.3 数据输出与显示数据解析出来之后我一般做两件事一是通过USART1打印到串口助手方便调试二是显示到OLED或者LCD上。串口打印用printf重定向就行标准库里面重定向fputc到USART1。OLED显示的话用I2C或者SPI驱动显示浓度值和单位。这里有个小技巧如果浓度值跳动大可以在显示之前再做一次四舍五入比如显示整数。另外如果浓度超过阈值可以让LED闪烁或者蜂鸣器报警这个在智能家居项目里很实用。5. 常见问题与排查技巧实录5.1 收不到数据怎么办先检查硬件传感器供电是否正常TX和RX是否接反电平匹配是否做了。用万用表量一下传感器TX脚在空闲时的电压如果是5V说明传感器在工作如果是0V可能传感器没启动。然后检查STM32这边串口初始化是否正确波特率是否匹配中断是否使能。我遇到过有人忘了开USART2的时钟结果初始化函数里写再多也没用。还有一个容易忽略的点如果用了电阻分压电阻值选得太大比如100k信号边沿会非常缓STM32可能识别不到。我建议分压电阻用10k和20k或者4.7k和10k不要超过47k。5.2 数据乱码或跳变乱码一般是波特率不对或者时钟配置错了。先确认传感器的波特率再检查STM32的系统时钟。如果时钟是72MHz波特率9600误差应该在2%以内。如果用了内部晶振误差可能大一些建议用外部晶振。数据跳变的话先看是不是电源干扰。传感器和STM32共用电源时风扇启动瞬间会有电压波动可能导致数据异常。可以在传感器VCC和GND之间并一个100uF电解电容和一个0.1uF陶瓷电容能明显改善。另外软件滤波也要做前面说的限幅加滑动平均就很有效。5.3 校验和总是对不上校验和的计算方式一定要看手册。有的厂家是累加和取反有的是异或有的是累加取低8位。我手上这个模块是累加取低8位但手册上写的是“校验和0xAA0xBB低字节高字节”我一开始以为是取反结果一直对不上。后来用串口助手抓了几帧数据手动算了一下才发现是直接累加。所以拿到新模块先用串口助手抓原始数据手动验证校验和再写代码。5.4 中断优先级冲突如果项目里还有定时器中断、外部中断串口接收中断的优先级要合理安排。我遇到过串口中断被定时器中断打断导致数据丢失的情况。解决办法是把串口接收中断的抢占优先级设得比定时器高或者把解析放到主循环中断里只存数据。另外如果用了DMA接收可以进一步降低中断频率但DMA配置对新手来说稍复杂建议先把中断方式跑通再考虑DMA。5.5 传感器预热与校准红外PM2.5传感器上电后需要预热一般1到3分钟数据才稳定。刚上电时浓度值可能偏高或者偏低这是正常现象。如果项目要求高精度可以在预热完成后做一次校准比如在洁净空气中读一个基准值然后后续数据减去这个基准。但要注意红外传感器的一致性不如激光传感器校准只能针对单个模块换一个模块就要重新校准。6. 项目扩展与个人经验这个项目跑通之后可以扩展的方向很多。比如加一个SD卡模块把浓度数据存成CSV文件方便后期分析或者加一个ESP8266把数据上传到云平台做远程监测再或者加一个继电器当浓度超过阈值时自动启动空气净化器。我自己的鱼缸项目里就用这个方案监测空气质量联动风扇换气效果还不错。最后分享一个我在调试时的小技巧如果手头没有串口助手可以用STM32的USB虚拟串口功能把USART1的数据通过USB转发到电脑这样只需要一根USB线就能看数据不用额外接USB转TTL模块。配置USB虚拟串口稍微麻烦一点但网上教程很多照着做就行。另外Keil5的软件仿真也能看串口输出但实时性不如硬件调试传感器的时候还是建议用硬件串口。踩过的坑主要集中在校验和和电平匹配上这两个地方多花点时间后面就很顺了。传感器手册一定要看不要凭经验猜不同厂家的协议差异很大。
返回列表