ccccccc@ 发表于 2024-10-18 11:48

《STM32H7S78-DK 开发套件二周目评测:简单声音采集之驱动MAX4466高精度声音传感器》

本帖最后由 ccccccc@ 于 2024-10-18 11:52 编辑

<div>MAX4466是一款高精度声音传感器,能够将声音信号转化为相应的模拟电压输出。STM32H7系列微控制器具备高性能的ADC(模数转换器)功能,可以精确地采集模拟信号并进行数字化处理。</div>

<div>
<div style="text-align: center;"></div>

<p>&nbsp;</p>
</div>

<div>&nbsp;</div>

<div>使用STM32H7S78-DK开发板,通过ADC(模数转换器)采集MAX4466高精度声音传感器的模拟信号,最终实现一个简单的音量检测功能。</div>

<div>有下面个步骤:</div>

<div>- 从MAX4466传感器采集音频信号。</div>

<div>- 对采集的数据进行处理,获得稳定的音量信息。</div>

<p>&nbsp;</p>

<ol>
        <li>硬件连接:<br />
        引脚连接:
        <div style="text-align: center;"></div>
        <br />
        如上图所示,可以将MAX4466传感器的输出引脚连接到STM32的ADC输入引脚(即PC0,ADC12_IN10),设置该GPIO的ADC功能属性。<br />
        &nbsp;</li>
        <li>使用CubeMX进行配置:<br />
        在CubeMX中,进行如下设置:<br />
        选择ADC模块:选择ADC1,设置为12位分辨率,适合音频信号处理。<br />
        设置采样时间:设置为3.5个ADC时钟周期,确保稳定采样。<br />
        设置转换模式:选择单次转换模式(Single Conversion),适合简单应用。<br />
        时钟设置: 确保ADC时钟频率与采样时间相匹配,避免采样延迟。<br />
        引脚设置:配置PC0为ADC输入模式。</li>
        <li>生成代码并导入Keil:<br />
        &nbsp;在CubeMX中生成代码,并导入Keil进行后续的代码开发。</li>
        <li>在Keil中,检查&nbsp; 初始化ADC并读取值的代码
        <pre>
<code class="language-cpp">#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(&amp;hadc1); // 初始化ADC
   }

   uint32_t Read_ADC_Value(void) {
       HAL_ADC_Start(&amp;hadc1); // 启动ADC转换
       HAL_ADC_PollForConversion(&amp;hadc1, HAL_MAX_DELAY); // 等待转换完成
       return HAL_ADC_GetValue(&amp;hadc1); // 返回ADC值
   }</code></pre>
        </li>
        <li>数据处理:在main代码中进行添加下面的代码进行采集信息的数据处理
        <ol>
                <li>滤波处理: 使用简单的移动平均滤波器平滑采样值,减少波动。
                <pre>
<code class="language-cpp">float moving_average(float new_value) {
static float avg = 0;
static int count = 0;
count++;
avg += (new_value - avg) / count; // 计算平均值
return avg;
}</code></pre>
                </li>
                <li>偏移量校正:在初始化时获取基准值,以确保测量的准确性。
                <pre>
<code class="language-cpp">static int32_t offset = 0;
void Calculate_Offset(void) {
for (int i = 0; i &lt; 100; i++) {
HAL_ADC_Start(&amp;hadc1);
HAL_ADC_PollForConversion(&amp;hadc1, HAL_MAX_DELAY);
offset += HAL_ADC_GetValue(&amp;hadc1); // 累加ADC值
}
offset /= 100; // 计算平均偏移量
}
uint32_t Get_Corrected_ADC_Value(void) {
uint32_t adc_value = Read_ADC_Value(); // 读取ADC值
return adc_value - offset; // 返回校正后的值
}</code></pre>

                <p>&nbsp;</p>
                </li>
        </ol>
        </li>
        <li>UART配置:<br />
        通过UART输出采样结果,方便观察和调试。当然也可以使用LED进行对应的显示。在CUBEMAX进行对应的配置;</li>
</ol>

<p>&nbsp;</p>

<div style="text-align: center;"></div>

<p>&nbsp;</p>

<div style="text-align: center;">&nbsp;</div>

<ul>
        <li>
        <pre>
<code class="language-cpp">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(&amp;huart1); // 初始化UART
}
void UART_Send_Data(uint32_t data) {
char buffer;
sprintf(buffer, "ADC Value: %lu\n", data); // 格式化输出
HAL_UART_Transmit(&amp;huart1, (uint8_t*)buffer, strlen(buffer), HAL_MAX_DELAY); // 发送数据
}</code></pre>

        <p>7.主程序:</p>
        </li>
</ul>

<div>在主循环中读取ADC值,并通过UART输出。
<pre>
<code class="language-cpp">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值
}
}</code></pre>

<p>&nbsp;</p>
</div>

<div>8.关于噪声处理:</div>

<div>滤波策略:可以通过选择适当的滤波窗口,达到避免数据波动的效果。并且考虑使用中位数滤波或加权平均滤波,以处理异常值和噪声。</div>

<div>&nbsp;</div>

<div>9.当然还可以进一步进行性能优化:</div>

<div>使用DMA: 对于快速连续采样的需求,可以考虑使用DMA(直接存储器访问)进行数据采集,减轻CPU负担。
<pre>
<code class="language-cpp">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(&amp;hdma_adc1); // 初始化DMA
__HAL_LINKDMA(&amp;hadc1, DMA_Handle, hdma_adc1); // 连接DMA与ADC
}</code></pre>

<p>&nbsp;</p>
</div>

<p>&nbsp;</p>

<p><!--importdoc--></p>

<p>&nbsp;</p>

Jacktang 发表于 2024-10-20 09:13

<p>通过选择适当的滤波窗口,避免数据波动,用中位数滤波,加权平均滤波,处理异常值和噪声,这个厉害。</p>

cc1989summer 发表于 2024-10-29 00:31

<p></p>


<p>楼主,STM32H7S78-DK本身就带数字麦克风,理论上可以通过该麦克风实现音量检测……:victory:</p>

ccccccc@ 发表于 2024-10-30 15:50

cc1989summer 发表于 2024-10-29 00:31
楼主,STM32H7S78-DK本身就带数字麦克风,理论上可以通过该麦克风实现音量检测……

<p>我开始也是看他有数字麦克风,才想测评弄这个,但是我只找到一个麦克风接口,有点疑惑。所以就干脆直接买了一个麦克风</p>

cc1989summer 发表于 2024-10-30 21:46

ccccccc@ 发表于 2024-10-30 15:50
我开始也是看他有数字麦克风,才想测评弄这个,但是我只找到一个麦克风接口,有点疑惑。所以就干脆直接买 ...

<p>哥们,翻到开发板背面,靠近USB1上面,有个芯片U1:MP23DB01,就是数字麦克风</p>

ccccccc@ 发表于 2024-11-1 09:42

cc1989summer 发表于 2024-10-30 21:46
哥们,翻到开发板背面,靠近USB1上面,有个芯片U1:MP23DB01,就是数字麦克风

<p>o.o!!!我看手册是写有麦克风,但是又看示意图写的是一个麦克风接口。原来是这样!</p>
页: [1]
查看完整版本: 《STM32H7S78-DK 开发套件二周目评测:简单声音采集之驱动MAX4466高精度声音传感器》