《STM32H7S78-DK 开发套件二周目评测:简单声音采集之频率检测与显示》
<h1><span style="font-family:宋体;"><span style="font-size:16px;">在实现adc基础上,实现对音频信号频率的检测。读取模拟信号并通过 FFT(快速傅里叶变换)分析频率成分。同时,在串口输出检测到的频率,并通过 LED 显示结果。</span></span></h1><h2><span style="font-family:宋体;">一、硬件连接</span></h2>
<ol>
<li><span style="font-family:宋体;"><strong>引脚连接</strong>:</span>
<ul>
<li><span style="font-family:宋体;">将 MAX4466 传感器的输出引脚连接到 STM32 的 ADC 输入引脚(PC0,即 ADC1_IN10)。</span></li>
<li><span style="font-family:宋体;">LED选取PO5。在高电平时候点亮。</span>
<div style="text-align: center;"><span style="font-family:宋体;"></span></div>
<p> </p>
</li>
</ul>
</li>
</ol>
<h2><span style="font-family:宋体;">二、使用 CubeMX 进行配置</span></h2>
<div><span style="font-family:宋体;">在 CubeMX 中进行如下设置:</span></div>
<h3><span style="font-family:宋体;">2.1 ADC 模块配置</span></h3>
<ul>
<li><span style="font-family:宋体;"><strong>时钟设置</strong>:配置 ADC 时钟为 84MHz,选择 ADC 的时钟分频器为 1,以达到较高的采样精度。</span></li>
<li><span style="font-family:宋体;"><strong>采样时间</strong>:设置 ADC 的采样时间为 15.5 个 ADC 时钟周期,以提高采样精度。</span></li>
<li><span style="font-family:宋体;"><strong>通道设置</strong>:将 ADC 通道设置为 ADC1_IN10(PC0),确保能够读取传感器输出。</span></li>
</ul>
<h3><span style="font-family:宋体;">2.2 TIM 模块配置</span></h3>
<ul>
<li><span style="font-family:宋体;"><strong>定时器配置</strong>:配置 TIM2 为定时器,用于生成定时中断。</span>
<ul>
<li><span style="font-family:宋体;">设置预分频器为 7999,自动重装载值为 999,以设定频率采样率(例如 1kHz)。</span></li>
</ul>
</li>
</ul>
<h3><span style="font-family:宋体;">2.3 GPIO 设置</span></h3>
<div><span style="font-family:宋体;">将 PO5 配置为推挽输出模式,用于控制 LED。</span></div>
<h2><span style="font-family:宋体;"><span style="font-size:16px;">生成代码并导入 Keil,在 CubeMX 中生成代码,并导入 Keil 进行后续的代码开发。</span></span></h2>
<h2><span style="font-family:宋体;">四、代码实现</span></h2>
<h3><span style="font-family:宋体;">4.1 初始化模块</span></h3>
<div><span style="font-family:宋体;">在 Keil 中,初始化 ADC、定时器和 LED 控制的代码如下:</span></div>
<div>
<pre>
<code class="language-cpp">#include "arm_math.h"
#include "stm32h7xx_hal.h"
#define FFT_SIZE 1024 // FFT 输入数组的大小
float32_t input;
float32_t output;
arm_cfft_instance_f32 fft_instance;
TIM_HandleTypeDef htim2;
ADC_HandleTypeDef hadc1;
void ADC_Init(void) {
ADC_ChannelConfTypeDef sConfig = {0};
__HAL_RCC_ADC12_CLK_ENABLE(); // 使能 ADC 时钟
hadc1.Instance = ADC1;
hadc1.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV2;
hadc1.Init.Resolution = ADC_RESOLUTION_12B;
hadc1.Init.ScanConvMode = DISABLE;
hadc1.Init.ContinuousConvMode = ENABLE;
hadc1.Init.DiscontinuousConvMode = DISABLE;
hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START;
HAL_ADC_Init(&hadc1);
sConfig.Channel = ADC_CHANNEL_10; // 选择通道 10
sConfig.Rank = 1;
sConfig.SamplingTime = ADC_SAMPLETIME_15CYCLES; // 设置采样时间
HAL_ADC_ConfigChannel(&hadc1, &sConfig);
}
uint32_t Read_ADC_Value(void) {
uint32_t adc_value = 0;
HAL_ADC_Start(&hadc1); // 启动 ADC
HAL_ADC_PollForConversion(&hadc1, HAL_MAX_DELAY); // 等待转换完成
adc_value = HAL_ADC_GetValue(&hadc1); // 获取 ADC 值
HAL_ADC_Stop(&hadc1); // 停止 ADC
return adc_value;
}
void TIM_Init(void) {
__HAL_RCC_TIM2_CLK_ENABLE(); // 使能 TIM2 时钟
htim2.Instance = TIM2;
htim2.Init.Prescaler = 7999; // 对应 1kHz
htim2.Init.Period = 999; // 对应 1ms
htim2.Init.CounterMode = TIM_COUNTERMODE_UP; // 向上计数
HAL_TIM_Base_Init(&htim2); // 初始化定时器
HAL_TIM_Base_Start_IT(&htim2); // 启动定时器中断
}
void FFT_Init(void) {
arm_cfft_init_f32(&fft_instance, FFT_SIZE); // 初始化 FFT 实例
}</code></pre>
<p> </p>
</div>
<h3><span style="font-family:宋体;">4.2 FFT 处理</span></h3>
<div><span style="font-family:宋体;">使用 CMSIS DSP 库实现 FFT 分析信号频率:</span></div>
<div>
<pre>
<code class="language-cpp">void Perform_FFT(void) {
arm_cfft_f32(&fft_instance, input, 0, 1); // 执行 FFT
arm_cmplx_mag_f32(input, output, FFT_SIZE); // 计算幅度
}</code></pre>
<p> </p>
</div>
<h3><span style="font-family:宋体;">4.3 频率检测与 LED 显示</span></h3>
<div><span style="font-family:宋体;">计算频率并控制 LED 的开关状态的代码如下:</span></div>
<div>
<pre>
<code class="language-cpp">void Display_Frequency(void) {
float max_value = output;
uint32_t max_index = 0;
for (uint32_t i = 1; i < FFT_SIZE / 2; i++) {
if (output > max_value) {
max_value = output;
max_index = i;
}
}</code></pre>
<p> </p>
</div>
<div><span style="font-family:宋体;">// 控制 LED 的开关状态</span></div>
<div>
<pre>
<code class="language-cpp">if (max_index > 10) {
HAL_GPIO_WritePin(GPIOO, GPIO_PIN_5, GPIO_PIN_SET); // 点亮 LED
} else {
HAL_GPIO_WritePin(GPIOO, GPIO_PIN_5, GPIO_PIN_RESET); // 熄灭 LED
}
}</code></pre>
<p> </p>
</div>
<h3><span style="font-family:宋体;">4.4 主程序</span></h3>
<div><span style="font-family:宋体;">在主循环中进行 ADC 采集、FFT 处理和 LED 控制的代码如下:</span></div>
<div>
<pre>
<code class="language-cpp">int main(void) {
HAL_Init();
SystemClock_Config();
ADC_Init();
TIM_Init();
FFT_Init();
while (1) {
UART_Send_Data(corrected_value);
}
}
// 定时器溢出回调
void HAL_TIM_PERIOD_ELAPSED_CALLBACK(TIM_HandleTypeDef *htim) {
if (htim->Instance == TIM2) {
// 每次定时器溢出时读取 ADC 值
uint32_t adc_value = Read_ADC_Value(); // 获取 ADC 值
static uint32_t sample_index = 0;
input = (float32_t)adc_value; // 存储到 FFT 输入数组
sample_index++;
// 如果达到 FFT_SIZE 大小,则进行 FFT 计算
if (sample_index >= FFT_SIZE) {
sample_index = 0; // 重置索引
Perform_FFT();
Display_Frequency();
}
}
}</code></pre>
</div>
<p>这个对检测的音频信号有没有要求呢,比如最低的频率大小</p>
<h1> </h1>
Jacktang 发表于 2024-10-20 08:50
这个对检测的音频信号有没有要求呢,比如最低的频率大小
<p>按照目前的采样率的话,理论上的最低频率大约为1hz,最高大约是500hz的样子</p>
页:
[1]