基于 STM32 与机器学习的电机 / 风扇异常声音检测系统设计与实现
一、系统概述
在工业生产和日常生活中,电机与风扇是广泛应用的动力设备,其运行状态直接影响设备整体可靠性。传统的故障检测依赖人工巡检,存在效率低、主观性强、无法实时预警等问题。电机 / 风扇运行时的异常声音(如摩擦声、异响、振动噪声等)是设备故障的重要表征,因此设计一套基于嵌入式技术的实时异常声音检测系统具有重要实用价值。
本系统以 STM32F103C8T6 单片机为控制核心,通过 MAX9814 麦克风模块采集电机 / 风扇运行声音信号,结合时域特征提取与简单机器学习模型实现异常声音识别。同时,系统配备 SD 卡存储模块用于保存音频数据、OLED 显示模块用于实时展示运行状态,最终实现 “声音采集 - 特征分析 - 异常判断 - 状态显示 - 数据存储” 的完整功能闭环。
二、硬件部分设计
硬件设计是系统运行的基础,需满足声音信号高精度采集、数据实时处理与外设交互的需求。本节从核心芯片选型、功能模块选型及硬件接线三方面展开说明。
2.1 核心芯片选型
系统核心控制芯片选用STM32F103C8T6,属于意法半导体 STM32F1 系列 Cortex-M3 内核单片机,具体选型理由如下:
- 性能满足需求:主频最高 72MHz,内置 64KB Flash 和 20KB SRAM,可承载音频数据采集、特征计算与外设驱动程序。
- 外设资源丰富:包含 3 个 12 位 ADC(模数转换器)、2 个 I2C 接口、1 个 SPI 接口、多个 GPIO 口,可直接对接麦克风、OLED、SD 卡等模块。
- 性价比高:作为嵌入式开发常用芯片,资料丰富、价格低廉(单颗约 10-15 元),适合原型设计与批量应用。
2.2 功能模块选型
除核心芯片外,系统需搭配声音采集、数据存储、状态显示与人机交互模块,各模块选型及功能如下表所示:
| 模块名称 | 选型型号 | 核心功能 | 选型优势 |
|---|---|---|---|
| 声音采集模块 | MAX9814 | 采集电机 / 风扇运行声音并转换为电信号 | 内置低噪声放大器(增益可调)和自动增益控制(AGC),适合弱信号采集 |
| 数据存储模块 | Micro SD 卡模块 | 存储原始音频数据与异常检测结果 | 采用 SPI 通信,容量可选(1-32GB),数据易导出分析 |
| 显示模块 | 0.96 寸 OLED 屏 | 实时显示系统状态(正常 / 异常) | I2C 通信,功耗低(约 3mA)、显示清晰(128*64 分辨率) |
| 人机交互模块 | 独立按键 | 系统启动 / 停止、模式切换 | 结构简单,成本低,便于用户操作 |
2.3 硬件接线设计
各模块与 STM32F103C8T6 的接线需遵循 “信号匹配、接口对应” 原则,具体接线方案如下:
(1)MAX9814 麦克风模块接线
MAX9814 输出模拟信号,需接入 STM32 的 ADC 引脚进行模数转换,接线如下:
- MAX9814-VCC → STM32-3.3V(模块供电)
- MAX9814-GND → STM32-GND(共地,减少干扰)
- MAX9814-OUT → STM32-ADC1_IN0(PA0 引脚,模拟信号输入)
- MAX9814-GAIN → 悬空(默认增益 40dB,可通过电阻调节)
- MAX9814-AGC → 接 3.3V(开启自动增益控制)
(2)0.96 寸 OLED 屏(I2C 接口)接线
OLED 屏通过 I2C 接口与 STM32 通信,接线如下:
- OLED-VCC → STM32-3.3V
- OLED-GND → STM32-GND
- OLED-SDA → STM32-I2C1_SDA(PB7 引脚)
- OLED-SCL → STM32-I2C1_SCL(PB6 引脚)
(3)Micro SD 卡模块(SPI 接口)接线
SD 卡模块通过 SPI 接口与 STM32 通信,接线如下:
- SD-VCC → STM32-3.3V
- SD-GND → STM32-GND
- SD-MOSI → STM32-SPI1_MOSI(PA7 引脚)
- SD-MISO → STM32-SPI1_MISO(PA6 引脚)
- SD-SCK → STM32-SPI1_SCK(PA5 引脚)
- SD-CS → STM32-GPIO(PA4 引脚,片选信号)
(4)独立按键接线
按键采用 “上拉电阻” 方式(可利用 STM32 内部上拉),接线如下:
- 按键一端 → STM32-GPIO(PB0 引脚)
- 按键另一端 → STM32-GND
三、软件部分设计
软件设计是系统实现智能检测的核心,需完成 “数据采集 - 特征提取 - 异常判断 - 外设控制” 的逻辑流程。本节从软件整体流程图、关键子模块流程图及核心代码三方面展开说明。
3.1 软件整体流程图
系统软件采用模块化设计,整体流程如下:

3.2 关键子模块流程图
(1)声音采集子模块流程图

(2)异常检测子模块流程图

3.3 核心代码实现
系统软件基于 Keil MDK 开发,采用 C 语言编写,核心代码如下(仅展示关键模块,完整代码需包含外设驱动库):
(1)外设初始化代码
#include "stm32f10x.h"
#include "oled.h"
#include "sdcard.h"// 全局变量:音频数据缓冲区(1024个采样点)
uint16_t audio_buf[1024] = {0};
// 全局变量:特征值与检测结果
float audio_mean = 0.0f;
float audio_var = 0.0f;
uint16_t audio_peak = 0;
uint8_t is_abnormal = 0; // 0-正常,1-异常// ADC+定时器+DMA初始化(16kHz采样率)
void ADC_Timer_DMA_Init(void) {// 1. 初始化GPIO(PA0为模拟输入)GPIO_InitTypeDef GPIO_InitStruct;RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);GPIO_InitStruct.GPIO_Pin = GPIO_Pin_0;GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AIN; // 模拟输入GPIO_Init(GPIOA, &GPIO_InitStruct);// 2. 初始化ADC1ADC_InitTypeDef ADC_InitStruct;RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);ADC_InitStruct.ADC_Mode = ADC_Mode_Independent;ADC_InitStruct.ADC_ScanConvMode = DISABLE; // 单通道ADC_InitStruct.ADC_ContinuousConvMode = DISABLE; // 非连续模式(定时器触发)ADC_InitStruct.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T2_TRGO; // 定时器2触发ADC_InitStruct.ADC_DataAlign = ADC_DataAlign_Right; // 右对齐ADC_InitStruct.ADC_NbrOfChannel = 1;ADC_Init(ADC1, &ADC_InitStruct);ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_55Cycles5); // 采样时间55.5周期ADC_DMACmd(ADC1, ENABLE); // 使能ADC DMAADC_Cmd(ADC1, ENABLE);// 3. 初始化定时器2(生成16kHz触发信号)TIM_TimeBaseInitTypeDef TIM_InitStruct;RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);TIM_InitStruct.TIM_Period = 4499; // 自动重装载值:72MHz/(16kHz*(1+0)) -1 = 4499TIM_InitStruct.TIM_Prescaler = 0; // 预分频系数0TIM_InitStruct.TIM_CounterMode = TIM_CounterMode_Up;TIM_TimeBaseInit(TIM2, &TIM_InitStruct);TIM_SelectOutputTrigger(TIM2, TIM_TRGOSource_Update); // 触发信号为更新事件TIM_Cmd(TIM2, ENABLE);// 4. 初始化DMA1_Channel1(ADC1数据传输)DMA_InitTypeDef DMA_InitStruct;RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);DMA_InitStruct.DMA_PeripheralBaseAddr = (uint32_t)&ADC1->DR; // 外设地址(ADC数据寄存器)DMA_InitStruct.DMA_MemoryBaseAddr = (uint32_t)audio_buf; // 内存地址(缓冲区)DMA_InitStruct.DMA_DIR = DMA_DIR_PeripheralSRC; // 外设→内存DMA_InitStruct.DMA_BufferSize = 1024; // 缓冲区大小DMA_InitStruct.DMA_PeripheralInc = DMA_PeripheralInc_Disable; // 外设地址不递增DMA_InitStruct.DMA_MemoryInc = DMA_MemoryInc_Enable; // 内存地址递增DMA_InitStruct.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord; // 16位DMA_InitStruct.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;DMA_InitStruct.DMA_Mode = DMA_Mode_Circular; // 循环模式DMA_InitStruct.DMA_Priority = DMA_Priority_High;DMA_InitStruct.DMA_M2M = DMA_M2M_Disable;DMA_Init(DMA1_Channel1, &DMA_InitStruct);DMA_Cmd(DMA1_Channel1, ENABLE);
}// 按键初始化(PB0)
void Key_Init(void) {GPIO_InitTypeDef GPIO_InitStruct;RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);GPIO_InitStruct.GPIO_Pin = GPIO_Pin_0;GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPU; // 上拉输入GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOB, &GPIO_InitStruct);
}// 系统初始化(整合所有外设)
void System_Init(void) {ADC_Timer_DMA_Init();Key_Init();OLED_Init(); // OLED初始化(需包含oled.c驱动)SD_Init(); // SD卡初始化(需包含sdcard.c驱动)
}
(2)声音采集与特征提取代码
// 采集一帧音频数据(等待DMA缓冲区存满)
void Audio_Collect(void) {DMA_Cmd(DMA1_Channel1, ENABLE); // 启动DMA// 等待缓冲区存满(DMA1_Channel1->CNDTR为剩余数据量,等于0时存满)while (DMA_GetCurrDataCounter(DMA1_Channel1) != 0);DMA_Cmd(DMA1_Channel1, DISABLE); // 停止DMA
}// 提取音频时域特征(均值、方差、峰值)
void Audio_Feature_Extract(void) {uint32_t sum = 0;uint32_t sum_sq = 0;audio_peak = 0;// 遍历缓冲区计算总和、平方和、峰值for (uint16_t i = 0; i < 1024; i++) {sum += audio_buf[i];sum_sq += (uint32_t)audio_buf[i] * audio_buf[i];if (audio_buf[i] > audio_peak) {audio_peak = audio_buf[i];}}// 计算均值(1024为缓冲区大小)audio_mean = (float)sum / 1024.0f;// 计算方差:E[x²] - (E[x])²audio_var = (float)sum_sq / 1024.0f - audio_mean * audio_mean;
}
(3)异常检测与外设控制代码
// 异常检测(基于阈值,阈值通过正常样本训练得到)
void Audio_Abnormal_Detect(void) {// 示例阈值(需根据实际测试调整,单位:ADC采样值)const float MEAN_THRESHOLD = 2000.0f; // 均值阈值const float VAR_THRESHOLD = 100000.0f; // 方差阈值const uint16_t PEAK_THRESHOLD = 4000; // 峰值阈值// 任意一个特征超过阈值则判定为异常if (audio_mean > MEAN_THRESHOLD || audio_var > VAR_THRESHOLD || audio_peak > PEAK_THRESHOLD) {is_abnormal = 1;} else {is_abnormal = 0;}
}// OLED显示系统状态
void OLED_Display_Status(void) {OLED_Clear(); // 清屏OLED_ShowString(0, 0, "Motor/Fan Sound"); // 显示标题OLED_ShowString(0, 2, "Status:"); // 显示状态标签// 根据检测结果显示正常/异常if (is_abnormal == 0) {OLED_ShowString(64, 2, "Normal ");} else {OLED_ShowString(64, 2, "Abnormal!");}// 显示特征值(保留1位小数)OLED_ShowString(0, 4, "Mean:");OLED_ShowFloat(48, 4, audio_mean, 1);OLED_ShowString(0, 6, "Peak:");OLED_ShowNum(48, 6, audio_peak, 4);
}// 存储音频数据与检测结果到SD卡
void SD_Save_Data(void) {FIL file;FRESULT res;char buf[100];// 打开/创建文件(a+模式:追加写入)res = f_open(&file, "audio_data.txt", FA_OPEN_ALWAYS | FA_WRITE);if (res != FR_OK) return;// 移动文件指针到末尾f_lseek(&file, f_size(&file));// 写入检测结果与特征值if (is_abnormal == 0) {sprintf(buf, "Normal, Mean:%.1f, Var:%.1f, Peak:%d\r\n", audio_mean, audio_var, audio_peak);} else {sprintf(buf, "Abnormal, Mean:%.1f, Var:%.1f, Peak:%d\r\n", audio_mean, audio_var, audio_peak);}f_puts(buf, &file);// 关闭文件f_close(&file);
}
(4)主函数代码
int main(void) {uint8_t key_flag = 0; // 按键标志:0-停止,1-运行System_Init(); // 系统初始化OLED_ShowString(0, 3, "System Ready!");OLED_ShowString(0, 5, "Press Key to Start");while (1) {// 检测按键(PB0,按下时为低电平)if (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_0) == 0) {delay_ms(20); // 消抖if (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_0) == 0) {key_flag = !key_flag; // 切换运行/停止状态// 等待按键释放while (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_0) == 0);}}// 运行状态:采集-提取-检测-显示-存储if (key_flag == 1) {Audio_Collect(); // 1. 采集音频数据Audio_Feature_Extract(); // 2. 提取时域特征Audio_Abnormal_Detect(); // 3. 异常检测OLED_Display_Status(); // 4. 显示状态SD_Save_Data(); // 5. 存储数据delay_ms(100); // 延时,控制检测频率} else {// 停止状态:显示暂停信息OLED_Clear();OLED_ShowString(0, 3, "System Paused");OLED_ShowString(0, 5, "Press Key to Start");}}
}
四、系统测试与优化
4.1 测试环境搭建
- 测试对象:12V 直流风扇(正常运行与人为制造异常,如扇叶卡异物、轴承缺油)。
- 测试工具:示波器(观察 ADC 采样波形)、串口助手(打印特征值)、SD 卡读卡器(导出数据)。
- 测试步骤:
- 采集风扇正常运行时的音频数据,计算特征值均值、方差、峰值,确定阈值范围。
- 制造风扇异常(如贴一小块胶带在扇叶上),采集异常数据,验证系统是否能正确识别。
- 重复测试 10 次,统计系统异常检测准确率。
4.2 优化方向
- 硬件优化:增加电源滤波电容(100nF+10uF),减少电源噪声对麦克风采集的干扰;采用差分麦克风模块,进一步提高抗干扰能力。
- 软件优化:
- 引入 FFT(快速傅里叶变换)提取频域特征(如异常频率成分),结合时域特征提高检测准确率。
- 替换阈值判断为机器学习模型(如支持向量机 SVM、K 近邻 KNN),通过大量样本训练模型,适应不同类型电机 / 风扇的异常检测。
- 增加无线通信模块(如 ESP8266),实现异常信息远程报警(如发送短信、APP 推送)。
五、总结与展望
本系统基于 STM32F103C8T6 实现了电机 / 风扇异常声音的实时检测,硬件设计简洁可靠,软件流程清晰易懂,通过时域特征与阈值判断实现了基本的异常识别功能,可满足简单场景下的设备状态监测需求。
未来,系统可向 “高精度、智能化、网络化” 方向发展:一是引入更丰富的音频特征(频域、时频域)与复杂机器学习模型,提高异常检测的准确率和泛化能力;二是集成边缘计算功能,在本地实现模型训练与更新;三是接入工业物联网(IIoT)平台,实现多设备集中监控与故障预测,为工业设备的 predictive maintenance(预测性维护)提供技术支持。
