《STM32H7S78-DK 开发套件二周目评测:简单声音采集之驱动MAX4466高精度声音传感器》
[复制链接]
本帖最后由 ccccccc@ 于 2024-10-18 11:52 编辑
MAX4466是一款高精度声音传感器,能够将声音信号转化为相应的模拟电压输出。STM32H7系列微控制器具备高性能的ADC(模数转换器)功能,可以精确地采集模拟信号并进行数字化处理。
使用STM32H7S78-DK开发板,通过ADC(模数转换器)采集MAX4466高精度声音传感器的模拟信号,最终实现一个简单的音量检测功能。
有下面个步骤:
- 从MAX4466传感器采集音频信号。
- 对采集的数据进行处理,获得稳定的音量信息。
- 硬件连接:
引脚连接:
如上图所示,可以将MAX4466传感器的输出引脚连接到STM32的ADC输入引脚(即PC0,ADC12_IN10),设置该GPIO的ADC功能属性。
- 使用CubeMX进行配置:
在CubeMX中,进行如下设置:
选择ADC模块:选择ADC1,设置为12位分辨率,适合音频信号处理。
设置采样时间:设置为3.5个ADC时钟周期,确保稳定采样。
设置转换模式:选择单次转换模式(Single Conversion),适合简单应用。
时钟设置: 确保ADC时钟频率与采样时间相匹配,避免采样延迟。
引脚设置:配置PC0为ADC输入模式。
- 生成代码并导入Keil:
在CubeMX中生成代码,并导入Keil进行后续的代码开发。
- 在Keil中,检查 初始化ADC并读取值的代码
#include "stm32h7xx_hal.h"
ADC_HandleTypeDef hadc1;
void ADC_Init(void) {
// 使能ADC时钟
__HAL_RCC_ADC12_CLK_ENABLE();
// ADC配置
hadc1.Instance = ADC1;
hadc1.Init.Resolution = ADC_RESOLUTION_12B; // 12位分辨率
hadc1.Init.ScanConvMode = ADC_SCAN_DISABLE; // 禁用扫描模式
hadc1.Init.ContinuousConvMode = DISABLE; // 禁用连续转换
hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START; // 软件触发
hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT; // 数据右对齐
hadc1.Init.NbrOfConversion = 1; // 单次转换
HAL_ADC_Init(&hadc1); // 初始化ADC
}
uint32_t Read_ADC_Value(void) {
HAL_ADC_Start(&hadc1); // 启动ADC转换
HAL_ADC_PollForConversion(&hadc1, HAL_MAX_DELAY); // 等待转换完成
return HAL_ADC_GetValue(&hadc1); // 返回ADC值
}
- 数据处理:在main代码中进行添加下面的代码进行采集信息的数据处理
- 滤波处理: 使用简单的移动平均滤波器平滑采样值,减少波动。
float moving_average(float new_value) {
static float avg = 0;
static int count = 0;
count++;
avg += (new_value - avg) / count; // 计算平均值
return avg;
}
- 偏移量校正:在初始化时获取基准值,以确保测量的准确性。
static int32_t offset = 0;
void Calculate_Offset(void) {
for (int i = 0; i < 100; i++) {
HAL_ADC_Start(&hadc1);
HAL_ADC_PollForConversion(&hadc1, HAL_MAX_DELAY);
offset += HAL_ADC_GetValue(&hadc1); // 累加ADC值
}
offset /= 100; // 计算平均偏移量
}
uint32_t Get_Corrected_ADC_Value(void) {
uint32_t adc_value = Read_ADC_Value(); // 读取ADC值
return adc_value - offset; // 返回校正后的值
}
- UART配置:
通过UART输出采样结果,方便观察和调试。当然也可以使用LED进行对应的显示。在CUBEMAX进行对应的配置;
-
UART_HandleTypeDef huart1;
void UART_Init(void) {
// 使能USART1时钟
__HAL_RCC_USART1_CLK_ENABLE();
// USART配置
huart1.Instance = USART1;
huart1.Init.BaudRate = 115200; // 波特率
huart1.Init.WordLength = USART_WORDLENGTH_8B; // 字长
huart1.Init.StopBits = USART_STOPBITS_1; // 停止位
huart1.Init.Parity = USART_PARITY_NONE; // 无奇偶校验
huart1.Init.Mode = USART_MODE_TX_RX; // 发送接收模式
HAL_UART_Init(&huart1); // 初始化UART
}
void UART_Send_Data(uint32_t data) {
char buffer[20];
sprintf(buffer, "ADC Value: %lu\n", data); // 格式化输出
HAL_UART_Transmit(&huart1, (uint8_t*)buffer, strlen(buffer), HAL_MAX_DELAY); // 发送数据
}
7.主程序:
在主循环中读取ADC值,并通过UART输出。
int main(void) {
HAL_Init(); // 初始化HAL库
ADC_Init(); // 初始化ADC
UART_Init(); // 初始化UART
Calculate_Offset(); // 计算偏移量
while (1) {
uint32_t corrected_value = Get_Corrected_ADC_Value(); // 获取校正后的ADC值
float smoothed_value = moving_average(corrected_value); // 平滑处理
UART_Send_Data(corrected_value); // 发送ADC值
}
}
8.关于噪声处理:
滤波策略:可以通过选择适当的滤波窗口,达到避免数据波动的效果。并且考虑使用中位数滤波或加权平均滤波,以处理异常值和噪声。
9.当然还可以进一步进行性能优化:
使用DMA: 对于快速连续采样的需求,可以考虑使用DMA(直接存储器访问)进行数据采集,减轻CPU负担。
DMA_HandleTypeDef hdma_adc1;
void DMA_Init(void) {
__HAL_RCC_DMA2_CLK_ENABLE(); // 使能DMA时钟
hdma_adc1.Instance = DMA2_Stream0;
hdma_adc1.Init.Channel = DMA_CHANNEL_0; // 选择通道
hdma_adc1.Init.Direction = DMA_PERIPH_TO_MEMORY; // 从外设到内存
hdma_adc1.Init.PeriphInc = DMA_PINC_DISABLE; // 禁用外设地址递增
hdma_adc1.Init.MemInc = DMA_MINC_ENABLE; // 启用内存地址递增
hdma_adc1.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD; // 外设数据对齐
hdma_adc1.Init.MemDataAlignment = DMA_MDATAALIGN_WORD; // 内存数据对齐
hdma_adc1.Init.Mode = DMA_CIRCULAR; // 循环模式
hdma_adc1.Init.Priority = DMA_PRIORITY_HIGH; // 高优先级
HAL_DMA_Init(&hdma_adc1); // 初始化DMA
__HAL_LINKDMA(&hadc1, DMA_Handle, hdma_adc1); // 连接DMA与ADC
}
|