注册 登录
电子工程世界-论坛 返回首页 EEWORLD首页 频道 EE大学堂 下载中心 Datasheet 专题
ccccccc@的个人空间 https://home.eeworld.com.cn/space-uid-947001.html [收藏] [复制] [分享] [RSS]
日志

《STM32H7S78-DK 开发套件二周目评测:简单声音采集之频率检测与显示》

已有 424 次阅读2024-10-18 14:23 |个人分类:STM32H7S78-DK

在实现adc基础上,实现对音频信号频率的检测。读取模拟信号并通过 FFT(快速傅里叶变换)分析频率成分。同时,在串口输出检测到的频率,并通过 LED 显示结果。

一、硬件连接

  1. 引脚连接
    • 将 MAX4466 传感器的输出引脚连接到 STM32 的 ADC 输入引脚(PC0,即 ADC1_IN10)。
    • LED选取PO5。在高电平时候点亮。

       

二、使用 CubeMX 进行配置

在 CubeMX 中进行如下设置:

2.1 ADC 模块配置

  • 时钟设置:配置 ADC 时钟为 84MHz,选择 ADC 的时钟分频器为 1,以达到较高的采样精度。
  • 采样时间:设置 ADC 的采样时间为 15.5 个 ADC 时钟周期,以提高采样精度。
  • 通道设置:将 ADC 通道设置为 ADC1_IN10(PC0),确保能够读取传感器输出。

2.2 TIM 模块配置

  • 定时器配置:配置 TIM2 为定时器,用于生成定时中断。
    • 设置预分频器为 7999,自动重装载值为 999,以设定频率采样率(例如 1kHz)。

2.3 GPIO 设置

将 PO5 配置为推挽输出模式,用于控制 LED。

生成代码并导入 Keil,在 CubeMX 中生成代码,并导入 Keil 进行后续的代码开发。

四、代码实现

4.1 初始化模块

在 Keil 中,初始化 ADC、定时器和 LED 控制的代码如下:
#include "arm_math.h"
#include "stm32h7xx_hal.h"
#define FFT_SIZE 1024 // FFT 输入数组的大小
float32_t input[FFT_SIZE];
float32_t output[FFT_SIZE];
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 实例
}

 

4.2 FFT 处理

使用 CMSIS DSP 库实现 FFT 分析信号频率:
void Perform_FFT(void) {
 arm_cfft_f32(&fft_instance, input, 0, 1); // 执行 FFT
 arm_cmplx_mag_f32(input, output, FFT_SIZE); // 计算幅度
}

 

4.3 频率检测与 LED 显示

计算频率并控制 LED 的开关状态的代码如下:
void Display_Frequency(void) {
 float max_value = output[0];
 uint32_t max_index = 0;
 for (uint32_t i = 1; i < FFT_SIZE / 2; i++) {
 if (output[i] > max_value) {
 max_value = output[i];
 max_index = i;
 }
}

 

// 控制 LED 的开关状态
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
 }
}

 

4.4 主程序

在主循环中进行 ADC 采集、FFT 处理和 LED 控制的代码如下:
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[sample_index] = (float32_t)adc_value; // 存储到 FFT 输入数组
 sample_index++;
// 如果达到 FFT_SIZE 大小,则进行 FFT 计算
 if (sample_index >= FFT_SIZE) {
  sample_index = 0; // 重置索引

  Perform_FFT();
  Display_Frequency();
  }
 }
}

本文来自论坛,点击查看完整帖子内容。

评论 (0 个评论)

facelist doodle 涂鸦板

您需要登录后才可以评论 登录 | 注册

热门文章