基于STM32的录音机设计

基于STM32的录音机设计

一、系统概述与核心功能

1. 系统定位

基于STM32的录音机以“音频采集-编码存储-回放控制-低功耗续航”为核心,实现声音信号的实时录制、WAV格式存储、播放控制及文件管理,支持麦克风输入、耳机/喇叭输出、SD卡扩展存储,适用于会议记录、语音备忘、音乐练习等场景,替代传统磁带/数字录音笔,提供高性价比嵌入式录音方案。

2. 核心功能模块

模块 功能描述
音频采集 麦克风模块(如MAX9814)采集声音,STM32通过ADC/I2S接口实现8-16kHz采样、16位量化
音频编码 软件编码为PCM/WAV格式(可选ADPCM压缩),添加WAV头(RIFF块、fmt块、data块)
存储管理 SD卡(FAT32格式)存储录音文件,支持文件创建/删除/重命名,FatFS文件系统管理
回放控制 播放/暂停/停止/快进/快退,音量调节(DAC输出/PWM调功放),支持循环播放
用户交互 OLED显示(录音时长、文件列表、电量),按键/旋转编码器操作,LED状态指示
低功耗设计 待机时关闭非必要模块(显示/编码),STM32进入STOP模式,续航≥8小时(2000mAh电池)

二、硬件设计方案

1. 核心硬件选型

模块 型号 关键参数 接口方式
主控MCU STM32F407ZGT6 168MHz Cortex-M4,1MB Flash,192KB RAM,I2S、DAC、SDIO、DMA,支持FPU/DSP 核心控制器
音频采集 MAX9814 驻极体麦克风+自动增益控制(AGC),输出模拟信号(0-3.3V),信噪比>60dB ADC1_IN0(PA0,12位ADC)
音频输出 STM32内部DAC+TPA6130A2 DAC1(PA4)输出模拟音频,TPA6130A2功放(3.3V/1.5W)驱动耳机/喇叭 DAC+ I2C(功放控制)
存储模块 Micro SD卡(TF卡) 8GB-32GB,Class 10(高速读写),FAT32格式 SDIO(SDIO_D0-D3+CLK+CMD)
显示模块 OLED 12864(I2C) 0.96寸,128×64像素,低功耗(<10mA),显示文件列表、录音时长、电量 I2C1(PB6=SCL,PB7=SDA)
用户输入 轻触按键×4+旋转编码器 按键(录音/播放/停止/菜单),编码器(音量调节/快进快退) GPIO(PC0-PC3按键,PA6-PA7编码器)
电源模块 3.7V锂电池+TP4056+AMS1117 3.7V/2000mAh锂电池,TP4056充电(5V Micro USB),AMS1117-3.3V/1.8V稳压输出 供电一体化(带过充保护)
辅助模块 有源蜂鸣器+LED 蜂鸣器(操作提示音),LED(红/绿双色,电源/录音状态) GPIO(PB0=蜂鸣器,PB1=LED)

2. 硬件电路设计要点

2.1 核心电路连接

2.2 抗干扰设计

三、软件设计与核心代码

1. 系统架构(FreeRTOS多任务调度)

采用FreeRTOS实时操作系统,划分5个核心任务(优先级从高到低):

  1. 音频采集任务(优先级4):通过ADC DMA采集麦克风信号,存储至环形缓冲区。
  2. 编码存储任务(优先级3):读取环形缓冲区数据,编码为WAV格式,写入SD卡(FatFS)。
  3. 回放控制任务(优先级3):解析WAV文件,通过DAC DMA输出音频,响应播放/暂停指令。
  4. 用户交互任务(优先级2):扫描按键/编码器,更新OLED显示,处理菜单操作(文件选择、删除)。
  5. 低功耗管理任务(优先级1):检测无操作超时(5分钟),关闭显示/功放,进入STOP模式。

2. 核心代码实现(基于HAL库)

2.1 音频采集与DMA传输(ADC)

#include "audio_capture.h"
#include "stm32f4xx_hal.h"

#define ADC_BUFFER_SIZE 1024  // 环形缓冲区大小(1024×2字节=2KB)
uint16_t adc_buffer[ADC_BUFFER_SIZE];
uint16_t dma_index = 0;  // DMA传输索引

// ADC初始化(PA0,12位,DMA传输)
void ADC1_Init(void) {
  ADC_ChannelConfTypeDef sConfig = {0};
  hadc1.Instance = ADC1;
  hadc1.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV4;  // 84MHz/4=21MHz
  hadc1.Init.Resolution = ADC_RESOLUTION_12B;
  hadc1.Init.ScanConvMode = DISABLE;
  hadc1.Init.ContinuousConvMode = ENABLE;  // 连续转换
  hadc1.Init.DMAContinuousRequests = ENABLE;  // DMA连续请求
  hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;
  HAL_ADC_Init(&hadc1);
  
  sConfig.Channel = ADC_CHANNEL_0;  // PA0
  sConfig.Rank = 1;
  sConfig.SamplingTime = ADC_SAMPLETIME_480CYCLES;  // 480周期采样(16kHz采样率)
  HAL_ADC_ConfigChannel(&hadc1, &sConfig);
  
  // 启动DMA传输(循环模式)
  HAL_ADC_Start_DMA(&hadc1, (uint32_t*)adc_buffer, ADC_BUFFER_SIZE);
}

// DMA传输完成中断回调(半满/全满时触发)
void HAL_ADC_ConvHalfCpltCallback(ADC_HandleTypeDef* hadc) {
  // 处理前半缓冲区数据(录音/存储)
  process_audio_data(adc_buffer, ADC_BUFFER_SIZE/2);
}

void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc) {
  // 处理后半缓冲区数据
  process_audio_data(&adc_buffer[ADC_BUFFER_SIZE/2], ADC_BUFFER_SIZE/2);
}

2.2 WAV文件编码与存储(FatFS)

#include "ff.h"
#include "wav_encoder.h"

FIL wav_file;  // FATFS文件对象
uint32_t data_size = 0;  // 录音数据大小

// WAV头结构(44字节)
typedef struct {
  char riff[4];          // "RIFF"
  uint32_t file_size;    // 文件总大小-8
  char wave[4];          // "WAVE"
  char fmt[4];           // "fmt "
  uint32_t fmt_size;     // fmt块大小(16)
  uint16_t audio_format; // 音频格式(1=PCM)
  uint16_t channels;     // 声道数(1=单声道)
  uint32_t sample_rate;  // 采样率(16000)
  uint32_t byte_rate;    // 字节率=采样率×声道数×位数/8
  uint16_t block_align;  // 块对齐=声道数×位数/8
  uint16_t bits_per_sample; // 位深(16)
  char data[4];          // "data"
  uint32_t data_size;    // 数据块大小
} WAV_Header_t;

// 创建WAV文件并写入头
uint8_t create_wav_file(const char* filename) {
  WAV_Header_t header = {
    .riff = {'R','I','F','F'},
    .wave = {'W','A','V','E'},
    .fmt = {'f','m','t',' '},
    .fmt_size = 16,
    .audio_format = 1,
    .channels = 1,
    .sample_rate = 16000,
    .byte_rate = 16000*1*16/8,
    .block_align = 1*16/8,
    .bits_per_sample = 16,
    .data = {'d','a','t','a'}
  };
  
  FRESULT res = f_open(&wav_file, filename, FA_CREATE_NEW | FA_WRITE);
  if (res != FR_OK) return 1;
  
  // 写入WAV头(数据大小暂设为0,后续更新)
  header.data_size = 0;
  header.file_size = 36;  // 44-8=36(初始值)
  f_write(&wav_file, &header, sizeof(header), NULL);
  return 0;
}

// 写入音频数据(PCM)
void write_audio_data(uint16_t* data, uint32_t len) {
  UINT bw;
  f_write(&wav_file, data, len*2, &bw);  // 16位数据,2字节/点
  data_size += len*2;
}

// 关闭文件时更新WAV头
void close_wav_file(void) {
  WAV_Header_t header;
  f_lseek(&wav_file, 0);
  f_read(&wav_file, &header, sizeof(header), NULL);  // 读取原头
  header.data_size = data_size;
  header.file_size = 36 + data_size;
  f_lseek(&wav_file, 0);
  f_write(&wav_file, &header, sizeof(header), NULL);  // 更新头
  f_close(&wav_file);
}

2.3 音频回放(DAC DMA输出)

#include "audio_playback.h"

DAC_HandleTypeDef hdac;
TIM_HandleTypeDef htim6;  // DAC触发定时器(16kHz)

// DAC初始化(PA4,TIM6触发)
void DAC1_Init(void) {
  DAC_ChannelConfTypeDef sConfig = {0};
  hdac.Instance = DAC;
  HAL_DAC_Init(&hdac);
  
  sConfig.DAC_Trigger = DAC_TRIGGER_T6_TRGO;  // TIM6触发
  sConfig.DAC_OutputBuffer = DAC_OUTPUTBUFFER_ENABLE;
  HAL_DAC_ConfigChannel(&hdac, &sConfig, DAC_CHANNEL_1);
  
  // 启动DAC DMA(循环模式)
  HAL_DAC_Start_DMA(&hdac, DAC_CHANNEL_1, (uint32_t*)playback_buffer, PLAYBACK_BUFFER_SIZE, DAC_ALIGN_12B_R);
}

// 定时器6初始化(16kHz触发DAC)
void TIM6_Init(void) {
  htim6.Instance = TIM6;
  htim6.Init.Prescaler = 83;  // 84MHz/84=1MHz
  htim6.Init.Period = 62;     // 1MHz/62≈16kHz
  HAL_TIM_Base_Init(&htim6);
  HAL_TIM_Base_Start(&htim6);  // 启动定时器
}

// 播放WAV文件(解析头+读取数据)
void play_wav_file(const char* filename) {
  FIL file;
  WAV_Header_t header;
  UINT br;
  
  f_open(&file, filename, FA_READ);
  f_read(&file, &header, sizeof(header), &br);  // 读取WAV头
  
  // 检查格式(PCM、单声道、16位、16kHz)
  if (header.audio_format != 1 || header.channels != 1 || header.bits_per_sample != 16 || header.sample_rate != 16000) {
    f_close(&file);
    return;
  }
  
  // 读取数据块并播放(通过DAC DMA)
  uint16_t play_buffer[PLAYBACK_BUFFER_SIZE];
  while (f_read(&file, play_buffer, sizeof(play_buffer), &br) == FR_OK && br > 0) {
    // 等待DMA缓冲区空闲(简化处理,实际需用双缓冲)
    HAL_DAC_Start_DMA(&hdac, DAC_CHANNEL_1, (uint32_t*)play_buffer, PLAYBACK_BUFFER_SIZE, DAC_ALIGN_12B_R);
    while (HAL_DAC_GetState(&hdac) != HAL_DAC_STATE_READY);  // 等待传输完成
  }
  f_close(&file);
}

2.4 主程序框架(FreeRTOS任务调度)

#include "stm32f4xx_hal.h"
#include "FreeRTOS.h"
#include "task.h"
#include "audio_capture.h"
#include "audio_playback.h"
#include "ff.h"
#include "oled.h"

int main(void) {
  HAL_Init();
  SystemClock_Config();  // 168MHz
  MX_GPIO_Init();        // 按键、LED、编码器
  MX_ADC1_Init();        // 音频采集ADC
  MX_DAC1_Init();        // 音频输出DAC
  MX_SDIO_SD_Init();     // SD卡SDIO
  MX_FATFS_Init();       // FatFS初始化
  OLED_Init();           // OLED显示
  
  // FreeRTOS任务创建
  xTaskCreate(AudioCapture_Task, "Capture", 256, NULL, 4, NULL);  // 采集
  xTaskCreate(EncodeStore_Task, "Encode", 256, NULL, 3, NULL);    // 编码存储
  xTaskCreate(Playback_Task, "Playback", 256, NULL, 3, NULL);      // 回放
  xTaskCreate(UI_Task, "UI", 128, NULL, 2, NULL);                  // 用户交互
  xTaskCreate(LowPower_Task, "LowPower", 128, NULL, 1, NULL);      // 低功耗
  
  vTaskStartScheduler();  // 启动调度器
  while (1);
}

四、关键技术与优化

1. 音频质量优化

2. 存储效率优化

3. 低功耗设计

参考代码 基于STM32录音机设计 www.youwenfan.com/contentcst/133699.html

五、系统调试与扩展

1. 调试步骤

阶段 操作 工具
硬件调试 测量MIC输出(0-3.3V)、DAC输出(0-1.2V) 示波器、万用表
SD卡挂载 用FatFS测试程序创建/读写文件 串口打印文件列表
录音测试 录入语音,用Audacity分析WAV文件(采样率/位深) Audacity(音频分析软件)
回放测试 播放录音,检查是否有杂音/失真 耳机/喇叭+人耳听辨

2. 扩展功能

专注于matlab/simulink,电子电路,编程