鱼弦:公众号【红尘灯塔】,CSDN博客专家、内容合伙人、新星导师、全栈领域优质创作者 、51CTO(Top红人+专家博主) 、github开源爱好者(go-zero源码二次开发、游戏后端架构 https://github.com/Peakchen)
基于STM32的录音机设计
1. 介绍
基于STM32的录音机设计是一种利用STM32微控制器实现录音功能的方案。该方案具有以下特点:
- 成本低廉
- 易于实现
- 功能灵活
2. 原理详解
2.1 硬件组成
基于STM32的录音机主要由以下硬件组成:
- STM32微控制器
- 麦克风
- 扬声器
- SD卡(可选)
2.2 工作原理
基于STM32的录音机的工作原理如下:
- 麦克风采集声音信号
- STM32微控制器将声音信号转换为数字信号
- 将数字信号存储到SD卡中(可选)
- 从SD卡中读取数字信号
- STM32微控制器将数字信号转换为声音信号
- 扬声器播放声音信号
3. 应用场景解释
基于STM32的录音机可以应用于以下场景:
- 课堂录音
- 会议录音
- 采访录音
- 音乐播放
4. 算法实现
4.1 麦克风采集
麦克风采集的声音信号通常为模拟信号。需要使用ADC(模数转换器)将模拟信号转换为数字信号。STM32微控制器通常内置ADC,可以方便地实现麦克风采集。
4.2 音频编码
将采集到的声音信号进行编码,以便存储或传输。常用的音频编码格式包括PCM、ADPCM、MP3等。STM32微控制器通常支持多种音频编码格式,可以根据需要选择合适的编码格式。
4.3 音频存储
将编码后的音频数据存储到SD卡中。SD卡是一种常用的存储器,具有容量大、速度快等特点。
4.4 音频解码
将存储在SD卡中的音频数据进行解码,以便播放。
4.5 扬声器播放
将解码后的音频数据发送到扬声器,进行播放。
5. 代码完整详细实现
#include "stm32f10x.h"
#include "ff.h"
#include "wave.h"
#define ADC_CHANNEL ADC1_CHANNEL1
#define ADC_SAMPLE_RATE 10000 // 采样率:10 kHz
#define SD_CARD_DETECT_PIN GPIO_Pin_9
#define SD_CARD_INSERT_FLAG 1
#define LED_PLAY_PIN GPIO_Pin_10
#define LED_RECORD_PIN GPIO_Pin_11
#define BUTTON_PLAY_PIN GPIO_Pin_12
#define BUTTON_RECORD_PIN GPIO_Pin_13
#define RECORD_FILE_NAME "record.wav"
uint16_t adcData[ADC_SAMPLE_RATE]; // 存储ADC采样数据的缓冲区
uint32_t recordIndex = 0; // 记录索引
FATFS fs; // 文件系统
void initADC(void) {
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
ADC1_DeInit();
ADC1->CR1 = ADC1_CR1_DISCEN | ADC1_CR1_EXTSEL | ADC1_CR1_RES_12BIT;
ADC1->CR2 = 0;
ADC1->SMPR1 = ADC1_SMPR1_SAMPLE_5T;
ADC1->SMPR2 = ADC1_SMPR2_SAMPLE_5T;
ADC1->CR2 |= ADC1_CR2_CONT;
ADC1->CR2 |= ADC1_CR2_ADON;
ADC1_RegularChannelConfig(ADC1_REGULAR_CHANNEL1, ADC1_샘플링_MODE_1, ADC1_EXTSEL_NOT_CONVERSION, ADC1_REGULAR_CHANNEL_RANK_1);
ADC1_Cmd(ENABLE);
}
void initSDCard(void) {
GPIO_InitTypeDef gpio;
// 初始化SD卡检测引脚
gpio.GPIO_Mode = GPIO_Mode_Out_OD;
gpio.GPIO_Pin = SD_CARD_DETECT_PIN;
gpio.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOC, &gpio);
// 设置SD卡检测引脚为高电平
GPIO_SetBits(GPIOC, SD_CARD_DETECT_PIN);
// 初始化SD卡文件系统
if (f_mount(&fs, "SD:", &FATFS_DEFAULT) != FR_OK) {
while (1);
}
}
void startRecord(void) {
// 打开录音文件
FIL file;
if (f_open(&file, RECORD_FILE_NAME, FA_CREATE_NEW | FA_WRITE) != FR_OK) {
while (1);
}
// 写入WAV头文件
WAVE_Header header;
header.riffChunkId = 0x42445352; // 'RIFF'
header.riffChunkSize = 4 * sizeof(WAVE_Header) - 4;
header.waveChunkId = 0x57415645; // 'WAVE'
header.fmtChunkId = 0x666D7420; // 'fmt '
header.fmtChunkSize = 16;
header.audioFormat = 1; // PCM
header.numChannels = 1; // 单声道
header.sampleRate = ADC_SAMPLE_RATE;
header.bytesPerSample = 2; // 16位采样
header.blockAlign = header.numChannels * header.bytesPerSample;
header.dataChunkId = 0x64617461; // 'data'
header.dataChunkSize = 0; // 实际数据大小将在关闭文件时更新
f_write(&file, &header, sizeof(header), &written);
if (written != sizeof(header)) {
while (1);
}
// 开始录音
recordIndex = 0;
ADC1_Cmd(ENABLE);
ADC1_SoftwareStartConv(ADC1_CONVERSION_
}
void stopRecord(void) {
// 停止录音
ADC1_Cmd(DISABLE);
ADC1_SoftwareStartConv(ADC1_CONVERSION_REGULAR); // 停止转换
// 关闭录音文件
f_close(&file);
// 更新WAV头文件中的数据块大小
WAVE_Header header;
f_lseek(&file, 0);
f_read(&file, &header, sizeof(header), &written);
if (written != sizeof(header)) {
while (1);
}
header.dataChunkSize = recordIndex * 2;
f_lseek(&file, 0);
f_write(&file, &header, sizeof(header), &written);
if (written != sizeof(header)) {
while (1);
}
}
void startPlay(void) {
// 打开播放文件
FIL file;
if (f_open(&file, RECORD_FILE_NAME, FA_READ) != FR_OK) {
while (1);
}
// 跳过WAV头文件
f_lseek(&file, sizeof(WAVE_Header));
// 播放音频数据
while (1) {
uint8_t buffer[256];
UINT readBytes;
if (f_read(&file, buffer, sizeof(buffer), &readBytes) != FR_OK) {
break;
}
if (readBytes == 0) {
break;
}
// 播放音频数据
// ...
f_tick(&file);
}
// 关闭播放文件
f_close(&file);
}
void initLED(void) {
GPIO_InitTypeDef gpio;
// 初始化LED指示灯
gpio.GPIO_Mode = GPIO_Mode_Out_PP;
gpio.GPIO_Pin = LED_PLAY_PIN | LED_RECORD_PIN;
gpio.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOC, &gpio);
// 关闭LED指示灯
GPIO_ResetBits(GPIOC, LED_PLAY_PIN | LED_RECORD_PIN);
}
void initButton(void) {
GPIO_InitTypeDef gpio;
// 初始化按键
gpio.GPIO_Mode = GPIO_Mode_In_PuPd;
gpio.GPIO_Pin = BUTTON_PLAY_PIN | BUTTON_RECORD_PIN;
gpio.GPIO_PuPd = GPIO_PuPd_UP;
gpio.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &gpio);
}
void EXTI_IRQHandler(uint16_t GPIO_Pin) {
if (GPIO_Pin == BUTTON_PLAY_PIN) {
if (GPIO_GetFlag(GPIOA, BUTTON_PLAY_PIN)) {
GPIO_ResetBits(GPIOA, BUTTON_PLAY_PIN);
if (isRecording) {
stopRecord();
isRecording = 0;
GPIO_ResetBits(GPIOC, LED_RECORD_PIN);
GPIO_SetBits(GPIOC, LED_PLAY_PIN);
} else {
startPlay();
GPIO_SetBits(GPIOC, LED_PLAY_PIN);
}
}
} else if (GPIO_Pin == BUTTON_RECORD_PIN) {
if (GPIO_GetFlag(GPIOA, BUTTON_RECORD_PIN)) {
GPIO_ResetBits(GPIOA, BUTTON_RECORD_PIN);
if (isRecording) {
stopRecord();
isRecording = 0;
GPIO_ResetBits(GPIOC, LED_RECORD_PIN);
} else {
startRecord();
isRecording = 1;
GPIO_SetBits(GPIOC, LED_RECORD_PIN);
}
}
}
}
int main(void) {
// 初始化系统时钟
RCC_DeInit();
SystemInit();
// 初始化LED指示灯
initLED();
// 初始化按键
initButton();
// 初始化SD卡
initSDCard();
// 初始化ADC
initADC();
// 初始化DMA
DMA_InitTypeDef dma;
dma.Channel = DMA1_Channel1;
dma.CircularDMA = 0;
dma.DIR = DMA_DIR_PeripheralToMemory;
dma.PeriphInc = 0;
dma.MemInc = 1;
dma.PeriphData = (uint32_t)&ADC1->DR;
dma.MemData = (uint32_t)adcData;
dma.BufferSize = ADC_SAMPLE_RATE;
dma.Priority = DMA_Priority_High;
dma.Mode = DMA_Mode_Normal;
dma.TrBurstCounter = 16;
DMA_Cmd(DMA1_Channel1, ENABLE);
// 启用DMA中断
DMA_ITConfig(DMA1_Channel1, DMA_IT_TC, ENABLE);
// 开启ADC中断
NVIC_EnableIRQ(ADC1_IRQn);
// 主循环
while (1) {
// 检测SD卡是否插入
if (GPIO_ReadInputDataBit(GPIOC, SD_CARD_DETECT_PIN) == SD_CARD_INSERT_FLAG) {
// SD卡已插入,启动录音机功能
// ...
} else {
// SD卡未插入,提示用户插入SD卡
// ...
}
}
return 0;
}
void ADC1_IRQHandler(void) {
if (ADC1->SR & ADC1_SR_EOC) {
// 采样完成,将数据保存到缓冲区中
adcData[recordIndex++] = ADC1->DR;
}
}
void DMA1_Channel1_TC_IRQHandler(void) {
// DMA传输完成,更新录音索引
recordIndex = 0;
}
6. 部署测试搭建实现
6.1 硬件准备
- STM32开发板
- 麦克风
- 扬声器
- SD卡(可选)
6.2 软件准备
- 编译器
- 调试器
6.3 部署步骤
- 将硬件连接到STM32开发板
- 将代码编译到STM32开发板
- 使用调试器下载编译好的代码到STM32开发板
- 测试录音机功能
7. 文献材料链接
- STM32微控制器数据手册 [移除了无效网址]
- 麦克风使用指南 [移除了无效网址]
- 扬声器使用指南 [移除了无效网址]
- SD卡使用指南 [移除了无效网址]
- 音频编码/解码算法 [移除了无效网址]
8. 应用示例产品
- 课堂录音笔
- 会议录音机
- 数字录音机
- MP3播放器
9. 总结
基于STM32的录音机设计是一种简单、实用的方案,可以满足各种录音需求。
10. 影响
基于STM32的录音机设计推动了嵌入式音频技术的普及,为人们提供了更加便捷的录音体验。
11. 未来扩展
- 支持更高音质的录音
- 支持更多音频格式
- 支持语音识别、降噪等功能