基于STM32F103C8T6的分贝与PM2.5蓝牙监测方案
2026/9/17 22:20:31 网站建设 项目流程

简介:这是一份面向电子信息、自动化与物联网方向学生及嵌入式开发初学者的STM32智能环境噪音监测系统毕业设计文档,围绕环境噪音污染监测这一实际需求展开,解决传统噪音检测设备成本高、功能单一、不便随身查看的问题。全文从研究背景与意义、系统分析与可行性论证,到系统总体设计及硬件实现逐步推进,核心采用低成本且稳定的STM32单片机对声音信号采样处理后换算分贝值,并扩展粉尘浓度监测,模拟工地扬尘噪声监测设备的应用形态,检测结果通过液晶屏本地显示,同时借助蓝牙模块把噪音分贝值与PM2.5浓度值传送到安卓手机端,便于随时查看。资源包共1个doc文件,约1.06MB,为完整论文文档,包含中英文摘要、绪论、系统分析、总体设计与硬件实现、目录结构等模块,可直接参考方案框架、硬件选型思路与论文写作结构。目前已有373人浏览学习,适合需要快速搭建环境监测类嵌入式课题或撰写类似毕业设计的读者借鉴。

1. 从工地扬尘监测箱到桌面分贝仪:这套 STM32 方案到底解决什么问题

工地门口的扬尘噪声监测箱动辄上万,但真正拆开看,核心链路无非是"声音采集 → 模数转换 → 分贝换算 → 显示上传"。很多人做基于 STM32 的毕业设计时卡在同一个地方:分贝值算出来是电压不是声压级,PM2.5 读数飘得没法看,蓝牙发出去的数据手机端全是乱码。这套方案的价值在于用 STM32F103C8T6 把两条传感器链路(LM386 声音采集、GP2Y1010AU0F 粉尘采集)和一条通信链路(MLT-BT05 蓝牙)串成一个能实际跑的闭环,成本不到百元,逻辑电路简单到能手工搭出来。

它适合三类人:做嵌入式毕业设计需要完整软硬件链路的同学,想复现扬尘噪声监测原理的工程师,以及手头有最小系统板和传感器想练串口、ADC、蓝牙通信的人。往下看之前先明确一件事:这套东西不是声级计,它的分贝值是相对值,标定方式决定了它准不准。

2. 硬件链路设计:STM32F103C8T6 与两路传感器的选型与接线

2.1 为什么主控选 STM32F103C8T6 而不是 51 或 ESP32

主控选型决定了后面所有代码的写法。STM32F103C8T6 是 Cortex-M3 内核,72MHz 主频,64KB Flash、20KB SRAM,自带 2 个 12 位 ADC(原文用的是外置 ADC0832,后面会讲这个矛盾点)、3 个 USART。相比 STC89C52 这类 8 位机,它跑 FFT 做频谱分析时不会卡死;相比 ESP32,它的资料和标准库生态对新手更友好,Keil 下新建工程、装芯片包、烧录的路径已经被无数教程踩平了。

常见做法是用标准库而不是 HAL 库,原工程的 Main 函数里全是GPIO_Configuration_12864LCD()TIM4_Configuration()这种标准库风格调用,说明它是按标准库模板搭的。如果你从零建工程,注意两个坑:一是 Keil5 里要手动装 STM32F1 的 Device Family Pack,否则新建工程选不到芯片;二是 F103C8T6 的 PB3、PB4、PA15 默认被 JTAG 占用,拿它们做普通 GPIO 必须先禁用 JTAG 重映射。

// 关闭JTAG,保留SWD,释放PB3/PB4/PA15做普通IO RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE); GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE);

这段放在 GPIO 初始化最前面。参数说明:GPIO_Remap_SWJ_JTAGDisable只关 JTAG 保留 SWD,还能继续用 ST-Link 下载调试;如果写GPIO_Remap_SWJ_Disable会把 SWD 一起关掉,下载口就废了,得靠 BOOT0 拉高进系统存储器才能救回来。

2.2 声音采集链路:LM386 放大 + ADC 采样的信号走向

LM386 是一颗音频功率放大器,不是传感器。真正的拾音元件是它前面的驻极体麦克风(MIC),MIC 把声压转成微弱电压,LM386 把它放大到 0~3.3V 范围,再送进 ADC 采样。

接线要点:MIC 输出经耦合电容进 LM386 的引脚 3(同相输入),引脚 2 接地,引脚 1 和 8 之间接 10μF 电容加一个 10kΩ 电位器可以调增益(增益范围 20~200 倍),引脚 5 输出。输出端必须加直流偏置,把信号抬到 VCC/2 附近,因为单片机的 ADC 只能采 0~3.3V 正电压,而放大后的音频是正负交变信号,不加偏置负半周直接被削平,分贝值会偏低。

模块引脚接到 STM32作用
LM386 声音模块OUTPA0 (ADC1_IN0)放大后的音频模拟量
LM386 声音模块VCC/GND3.3V/GND供电
GP2Y1010AU0FVOUTPA1 (ADC1_IN1)粉尘浓度模拟量
GP2Y1010AU0FLEDPA2红外 LED 驱动脉冲
MLT-BT05RXDPA9 (USART1_TX)单片机发、蓝牙收
MLT-BT05TXDPA10 (USART1_RX)蓝牙发、单片机收

这里有个原工程的接线矛盾要指出:原文写"声音传感器引脚 3 与单片机 P30 引脚相连",P30/P31 是 51 单片机的 P3.0/P3.1 命名,STM32 上是没有 P30 这个引脚的。这是从 51 方案改写时留下的痕迹。实际接 STM32 时按上表走,声音模拟量进 ADC 通道,而不是进串口。串口只留给蓝牙模块。

2.3 粉尘采集链路:GP2Y1010AU0F 的脉冲驱动与时序

GP2Y1010AU0F 是夏普的红外光学粉尘传感器,内部一颗红外 LED 和一颗光电晶体管斜对放置,空气流过时灰尘把 LED 的光散射到光电晶体管上,散射光越强说明灰尘越多,输出电压越高。它的特点是 LED 不能常亮——必须给脉冲驱动,否则 LED 发热、寿命骤减、读数漂移。

典型时序是:LED 引脚拉低 0.28ms 点亮 → 采样 VOUT → LED 拉高 0.968ms 熄灭,整个周期约 10ms,对应 100Hz 采样。代码一般是先拉低驱动、延时 280μs、读 ADC、再延时 40μs 后拉高。

// GP2Y1010AU0F 一次采样,周期≥10ms #define DUST_LED GPIO_Pin_2 #define DUST_LED_PORT GPIOA #define SAMPLE_DELAY_US 280 #define LED_OFF_DELAY_US 40

参数说明:SAMPLE_DELAY_US = 280是数据手册规定的最小点亮稳定时间;LED_OFF_DELAY_US = 40是采样后必须保持的延迟,两个加起来要比 320μs 大。ADC 读到的值再按浓度(μg/m³) = (Vout - 0.6) / 0.005换算,这个 0.6V 是洁净空气本底、0.005 是灵敏度,不同批次传感器本底电压会有偏差,实测时用无尘环境校一遍更准。

2.4 蓝牙与显示:MLT-BT05 串口透传和 12864 显示

MLT-BT05 走串口透传,上电后用 AT 指令配置。默认波特率常见 9600,指令格式是AT+NAME名字改设备名、AT+BAUD4改波特率(4 对应 9600)。注意 AT 指令模式下波特率必须和单片机串口一致,否则配完就失联,得重新上电进 AT 模式。

// USART1 初始化,对接蓝牙模块 USART_InitStructure.USART_BaudRate = 9600; USART_InitStructure.USART_WordLength = USART_WordLength_8b; USART_InitStructure.USART_StopBits = USART_StopBits_1; USART_InitStructure.USART_Parity = USART_Parity_No; USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;

参数说明:8 位数据、1 位停止、无校验是三线透传的标准配置,和蓝牙模块出厂设置对齐。12864 液晶这里用的是串行通信模式,PSB 引脚接低电平即进入串口模式,四线 CS、SID、CLK、RST 接对应 IO。串行模式比并行省 IO,但刷新慢,全屏刷一次要几十毫秒,所以主循环里加了delay_ms(10)控制刷新节奏,避免显示闪烁。

3. 分贝值怎么算出来的:从 ADC 采样到 A 声级显示

3.1 ADC 采样的两种方案选择:内置 ADC 还是外置 ADC0832

原工程目录里同时出现了"ADC0832 模数转换模块"和 STM32 内置 ADC 的处理,这是个需要讲清的地方。ADC0832 是 8 位 8 通道串行 ADC,51 平台常用;STM32F103C8T6 自带 12 位 ADC,精度比 ADC0832 高 16 倍,所以合理的做法是直接用内置 ADC,把 PA0/PA1 配成模拟输入。

如果你为了复现原设计坚持外置 ADC0832,它的时序是:CS 拉低使能 → 前两个时钟周期发起始位和通道配置(SGL=1 单端、ODD 选通道)→ 后两个时钟周期读高位在前 → 再读低位在后 → CS 拉高结束。原工程ADC0832_Read()函数里那串_nop_()就是在掐时序。但说句实在话,STM32 上外挂 ADC0832 属于负优化,除非是为了跟论文图完全一致。

用内置 ADC 的配置:

// PA0 模拟输入,ADC1 通道0,规则转换 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; // 模拟输入 GPIO_Init(GPIOA, &GPIO_InitStructure); ADC_InitStructure.ADC_ContinuousConvMode = ENABLE; // 连续转换 ADC_InitStructure.ADC_SampleTime = ADC_SampleTime_55Cycles5; ADC_InitStructure.ADC_NbrOfChannel = 1; ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_55Cycles5); ADC_Cmd(ADC1, ENABLE); ADC_ResetCalibration(ADC1); while(ADC_GetResetCalibrationStatus(ADC1)); ADC_StartCalibration(ADC1); // 上电必须先校准 while(ADC_GetCalibrationStatus(ADC1));

参数说明:ADC_SampleTime_55Cycles5是采样时间,音频信号频率不高,55.5 周期够用;ADC_StartCalibration必须调用,否则首次读出的值有偏差。电压换算V = ADC_Val * 3.3 / 4096,4096 是 12 位满量程。

3.2 有效值、分贝与 A 计权的计算链路

拿到 ADC 序列之后,不能直接取一个瞬时值当分贝。正确链路是:采一批点(比如 1024 个)→ 算有效值(RMS)→ 转声压级 → 加 A 计权。

有效值是交流分量的均方根,要先减掉直流偏置:

// 计算交流有效值,dc 为静态偏置对应的 ADC 值 float sum = 0; for (i = 0; i < N; i++) { float diff = buf[i] - dc; sum += diff * diff; } float rms = sqrtf(sum / N); float voltage = rms * 3.3f / 4096.0f; // 转回电压

声压级公式是dB = 20 * log10(V / Vref),Vref 是参考电压,对应你标定时选定的基准。这一步是整套系统最容易出错的地方——很多毕设直接dB = 20*log10(rms),量纲全错,算出来要么是负数要么爆表到几百。

A 计权是模拟人耳对不同频率敏感度的差异,3kHz 附近人耳最灵敏。实现方式有两种:一是对采样后的时域信号做 FFT 转频域,按 A 计权曲线对各频点加权后再合成;二是用简化的一阶/二阶滤波器组近似。毕设里常见做法是采样 1024 点、跑 FFT、按倍频程划分、加权求和。

3.3 标定:让读数和真实声级计对得上

相对值要变成能看的读数,必须标定。做法是拿一部手机装个声级计 APP(或者借一台真实声级计)当参考,在安静房间和稳定噪声源(比如放一段固定音量白噪)下各测几组,记下本系统读数和参考读数,做线性拟合,把斜率和截距写进代码。

参考声级计(dB)本系统原始读数换算后误差
4031241.2+1.2
6050559.6-0.4
8070380.1+0.1

这种做法只在有限区间内线性,超过量程两端误差会放大。想要更准就得逐频点做传递函数校正,那已经是声级计的范畴了,毕设级别到线性拟合够用。

4. 主循环、中断与蓝牙数据帧:让数据稳定传到手机

4.1 main 函数的初始化顺序为什么不能乱

原工程 Main 里初始化一长串,顺序是有讲究的:NVIC_PriorityGroupConfig必须最先,中断分组定下来之后才能配各外设中断;delay_init紧跟其后,因为后面所有延时都依赖系统滴答定时器;按键、LED、串口、LCD、定时器、传感器依次初始化,最后才进 while(1) 刷显示。

顺序错了的典型症状:把USART1_Config()放在delay_init()之前,串口中断触发时delay_ms用的 SysTick 还没配好,可能出现第一次数据丢失甚至卡死在延时里——这也是热搜里"stm32 延时函数 delay 卡死"最常见的成因之一。如果delay_ms卡在while(!(SysTick->CTRL & (1<<16))),先查 SysTick 有没有初始化、有没有被别的中断打断。

NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); delay_init(); Key_GPIO_Config(); USART1_Config(); // 蓝牙串口 USART3_Config(); // 调试串口(可选) TIM4_Configuration(); // 定时采样触发 Initial_LCD_ST7684(); InitGP2Y1010AU0F(); while (1) { DisplayWindow(); delay_ms(10); }

4.2 定时器触发采样和串口中断收数据的分工

主循环只干显示,采样交给定时器。TIM4 配成 100Hz 更新中断(周期 10ms),在中断里分别触发声音 ADC 和粉尘 ADC,采完把结果存全局变量,主循环读。这样采样节拍稳定,不会被 LCD 刷新的耗时拖偏。

串口用中断收,因为手机端发阈值下发是异步的。USART1 中断服务函数里读到一帧就存进缓冲区,主循环里解析。不用中断而用轮询,手机发数据时主循环正在刷屏,容易漏字节。

void USART1_IRQHandler(void) { if (USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) { uint8_t ch = USART_ReceiveData(USART1); rx_buf[rx_idx++] = ch; if (rx_idx >= RX_BUF_SIZE) rx_idx = 0; // 防溢出 USART_ClearITPendingBit(USART1, USART_IT_RXNE); } }

参数说明:RX_BUF_SIZE按最大帧长设,别开太小;rx_idx要做环形或长度保护,否则手机狂发会越界踩内存。

4.3 自定义数据帧协议与安卓端解析

直接printf发字符串,手机端解析容易出错,工程做法是自定义帧。推荐格式:帧头(0xAA 0x55) + 数据长度 + 分贝高位 + 分贝低位 + PM2.5 高位 + PM2.5 低位 + 校验和 + 帧尾(0x0D 0x0A)。校验和取前面所有字节异或,安卓收到后先对帧头、再验校验和,错了就丢帧重等。

安卓端用 Android Studio 做,蓝牙部分用BluetoothSocketInputStream按字节读,找帧头后拼完整帧再解析。注意安卓 6.0 以上要动态申请位置权限才能扫到蓝牙设备,12 以后还要 BLUETOOTH_SCAN、BLUETOOTH_CONNECT 权限,漏了权限就是搜不到设备或连上就断。

注意:串口透传的收发线必须交叉,单片机的 TX 接蓝牙的 RX,TX 接 TX 是不通的。这是新手接线最高频的错误。

5. 排错与精度提升:几个实测才暴露的坑

5.1 分贝读数为负或跳变:先查偏置和采样窗口

分贝读负值九成是直流偏置没减干净或采样窗口太短。偏置对应的 ADC 值(代码里的dc)要在无声音环境下多采几次取平均,别用理论值 2048 硬写。采样窗口 N 太小(比如 64 点),RMS 波动大,读数会来回跳;加到 1024 点稳定很多,代价是每帧要等更久。另外 ADC 输入加一级 RC 低通(10kΩ + 0.1μF)能滤掉高频干扰,读数立刻安静。

5.2 PM2.5 数值飘:驱动时序和预热

粉尘传感器飘有两个原因。一是 LED 驱动时序不对,点亮时间不够 280μs,散射光没稳定就采样,读数偏低且随机;二是传感器没预热。红外 LED 和光电晶体管上电后温度会缓慢变化,输出跟着漂,规范做法是上电后空转 1 分钟再取数,粉尘仓里最好加个小风扇让空气流动,否则灰尘不流通,读数长期偏低。

5.3 蓝牙连上但收不到数据:波特率与供电排查

按这个顺序查:① 单片机和蓝牙模块波特率是否一致,改过 BAUD 后有没有重新上电;② 蓝牙模块供电,MLT-BT05 峰值电流能到 40mA,从单片机 3.3V 取电要看 LDO 够不够,供电不足会连上就掉;③ 数据线交叉是否接对;④ 安卓端有没有开对应权限。用 USB-TTL 直连电脑串口助手看单片机有没有发数据,能快速定位是单片机端还是安卓端的问题。

5.4 用手机 APP 做参考验证与阈值回设

验证时手机装一个声级计类应用放在检测板旁边同步读数,做几组对比表格记录误差。安卓 APP 上那套"修改 PM2.5 报警阈值"功能,实现方式是手机下发一个设定帧,STM32 收到后写进全局变量并返回确认帧。阈值下发后要回读一次确认,不回读的话数据传丢了你都不知道,蜂鸣器该响不响。最后看一眼整体帧结构,从传感器到 LCD 到蓝牙三处数值必须一致,任何一处对不上,先查数据类型转换——float直接按字节发过去、安卓端按int解,这就是乱码的经典来源。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询