基于stm32f407 写出ADC读取语音电信号,内部flash存储10sADC读取的语音信号,后用dac再将flash内部信号输出,实现语音回放掉电存储
时间: 2024-05-28 17:10:43 浏览: 114
这是一个比较复杂的项目,需要分多个步骤实现。
1. 配置ADC模块,读取语音信号。首先需要配置ADC模块的时钟、分辨率、采样率等参数,然后在程序中使用DMA方式读取连续的语音信号数据。需要注意的是,语音信号的采样率通常是8kHz或16kHz,该参数需要根据具体的应用确定。
2. 存储ADC读取的语音信号。将读取到的语音信号存储到内部flash中,需要使用flash编程接口进行操作。可以将内部flash划分成多个扇区,每个扇区保存一段语音信号数据。需要注意的是,内部flash的写入次数有限,需要采取合适的算法来延长flash寿命。
3. 配置DAC模块,输出存储的语音信号。DAC模块需要配置时钟、分辨率等参数,然后在程序中使用DMA方式输出存储的语音信号数据。需要注意的是,DAC输出的电压范围需要与ADC采样的电压范围匹配,否则会出现失真等问题。
4. 实现语音回放掉电存储。通过按键等方式触发回放功能,程序从内部flash中读取存储的语音信号数据,然后使用DAC模块输出信号。为了实现掉电存储,需要在程序中使用RTC模块或者EEPROM等方式保存存储的语音信号数据的地址或者扇区号等信息。
以上是大致的实现步骤,具体实现还需要根据具体的硬件平台和应用场景进行调整。
相关问题
基于stm32f407 写出ADC读取语音电信号,内部flash存储10sADC读取的语音信号,后用dac再将flash内部信号输出,实现语音回放掉电存储的代码
以下是基于stm32f407的ADC读取语音电信号,内部flash存储10sADC读取的语音信号,后用dac再将flash内部信号输出,实现语音回放掉电存储的代码:
``` c
#include "stm32f4xx.h"
#include "stm32f4xx_hal.h"
#include "stm32f4xx_hal_flash.h"
#include "stm32f4xx_hal_dac.h"
#include "stm32f4xx_hal_adc.h"
#define ADC1_DR_ADDRESS ((uint32_t)0x4001204C)
#define FLASH_START_ADDR ((uint32_t)0x080E0000)
#define FLASH_END_ADDR ((uint32_t)0x080FFFFF)
#define FLASH_PAGE_SIZE ((uint32_t)0x400)
#define FLASH_SECTOR_SIZE ((uint32_t)0x4000)
#define FLASH_SECTOR_NUM ((uint32_t)0x0F)
#define SAMPLE_RATE ((uint32_t)8000)
#define SAMPLE_TIME ((uint32_t)(1000000/SAMPLE_RATE))
#define ADC_BUF_SIZE ((uint32_t)(SAMPLE_RATE*10)) // 10s
static ADC_HandleTypeDef AdcHandle;
static DAC_HandleTypeDef DacHandle;
static uint16_t AdcBuf[ADC_BUF_SIZE];
static uint32_t AdcBufIndex;
static uint32_t FlashWriteAddr;
static void SystemClock_Config(void);
static void Error_Handler(void);
static void ADC_Config(void);
static void DAC_Config(void);
int main(void)
{
HAL_Init();
SystemClock_Config();
__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE();
__HAL_RCC_GPIOC_CLK_ENABLE();
__HAL_RCC_GPIOD_CLK_ENABLE();
__HAL_RCC_DMA1_CLK_ENABLE();
__HAL_RCC_ADC1_CLK_ENABLE();
__HAL_RCC_DAC_CLK_ENABLE();
__HAL_RCC_TIM6_CLK_ENABLE();
__HAL_RCC_FLASH_CLK_ENABLE();
ADC_Config();
DAC_Config();
HAL_ADC_Start_DMA(&AdcHandle, (uint32_t*)ADC1_DR_ADDRESS, 1);
HAL_DAC_Start(&DacHandle, DAC_CHANNEL_1);
while (1)
{
if (AdcBufIndex >= ADC_BUF_SIZE)
{
HAL_FLASH_Unlock();
FLASH_EraseInitTypeDef EraseInitStruct;
EraseInitStruct.TypeErase = FLASH_TYPEERASE_SECTORS;
EraseInitStruct.Sector = FLASH_SECTOR_NUM;
EraseInitStruct.NbSectors = 1;
EraseInitStruct.VoltageRange = FLASH_VOLTAGE_RANGE_3;
uint32_t SectorError;
HAL_FLASHEx_Erase(&EraseInitStruct, &SectorError);
FlashWriteAddr = FLASH_START_ADDR;
for (uint32_t i = 0; i < ADC_BUF_SIZE; i++)
{
HAL_FLASH_Program(FLASH_TYPEPROGRAM_HALFWORD, FlashWriteAddr, AdcBuf[i]);
FlashWriteAddr += 2;
}
HAL_FLASH_Lock();
FlashWriteAddr = FLASH_START_ADDR;
for (uint32_t i = 0; i < ADC_BUF_SIZE; i++)
{
HAL_DAC_SetValue(&DacHandle, DAC_CHANNEL_1, DAC_ALIGN_12B_R, AdcBuf[i]);
HAL_Delay(SAMPLE_TIME);
}
AdcBufIndex = 0;
}
}
}
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc)
{
AdcBuf[AdcBufIndex] = HAL_ADC_GetValue(hadc);
AdcBufIndex++;
}
static void ADC_Config(void)
{
AdcHandle.Instance = ADC1;
AdcHandle.Init.ClockPrescaler = ADC_CLOCKPRESCALER_PCLK_DIV4;
AdcHandle.Init.Resolution = ADC_RESOLUTION_12B;
AdcHandle.Init.ScanConvMode = DISABLE;
AdcHandle.Init.ContinuousConvMode = ENABLE;
AdcHandle.Init.DiscontinuousConvMode = DISABLE;
AdcHandle.Init.NbrOfDiscConversion = 0;
AdcHandle.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
AdcHandle.Init.ExternalTrigConv = ADC_EXTERNALTRIGCONV_T1_CC1;
AdcHandle.Init.DataAlign = ADC_DATAALIGN_RIGHT;
AdcHandle.Init.NbrOfConversion = 1;
AdcHandle.Init.DMAContinuousRequests = ENABLE;
AdcHandle.Init.EOCSelection = DISABLE;
HAL_ADC_Init(&AdcHandle);
ADC_ChannelConfTypeDef sConfig;
sConfig.Channel = ADC_CHANNEL_0;
sConfig.Rank = 1;
sConfig.SamplingTime = ADC_SAMPLETIME_84CYCLES;
sConfig.Offset = 0;
HAL_ADC_ConfigChannel(&AdcHandle, &sConfig);
}
static void DAC_Config(void)
{
DacHandle.Instance = DAC;
HAL_DAC_Init(&DacHandle);
DAC_ChannelConfTypeDef sConfig;
sConfig.DAC_Trigger = DAC_TRIGGER_NONE;
sConfig.DAC_OutputBuffer = DAC_OUTPUTBUFFER_ENABLE;
HAL_DAC_ConfigChannel(&DacHandle, &sConfig, DAC_CHANNEL_1);
}
static void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct;
RCC_ClkInitTypeDef RCC_ClkInitStruct;
__HAL_RCC_PWR_CLK_ENABLE();
HAL_PWR_EnableBkUpAccess();
__HAL_RCC_BACKUPRESET_FORCE();
__HAL_RCC_BACKUPRESET_RELEASE();
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
RCC_OscInitStruct.HSIState = RCC_HSI_ON;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI;
RCC_OscInitStruct.PLL.PLLM = 8;
RCC_OscInitStruct.PLL.PLLN = 336;
RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
RCC_OscInitStruct.PLL.PLLQ = 7;
HAL_RCC_OscConfig(&RCC_OscInitStruct);
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_SYSCLK|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;
HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_5);
}
```
代码实现的基本思路是:通过ADC采样获取语音信号,将其存储到数组中,当数组存满后将其存储到内部flash中,并通过DAC实现回放。具体实现细节如下:
1. 定义了一些常量和变量:
``` c
#define ADC1_DR_ADDRESS ((uint32_t)0x4001204C)
#define FLASH_START_ADDR ((uint32_t)0x080E0000)
#define FLASH_END_ADDR ((uint32_t)0x080FFFFF)
#define FLASH_PAGE_SIZE ((uint32_t)0x400)
#define FLASH_SECTOR_SIZE ((uint32_t)0x4000)
#define FLASH_SECTOR_NUM ((uint32_t)0x0F)
#define SAMPLE_RATE ((uint32_t)8000)
#define SAMPLE_TIME ((uint32_t)(1000000/SAMPLE_RATE))
#define ADC_BUF_SIZE ((uint32_t)(SAMPLE_RATE*10)) // 10s
static ADC_HandleTypeDef AdcHandle;
static DAC_HandleTypeDef DacHandle;
static uint16_t AdcBuf[ADC_BUF_SIZE];
static uint32_t AdcBufIndex;
static uint32_t FlashWriteAddr;
```
2. 实现ADC和DAC的配置函数:
``` c
static void ADC_Config(void)
{
AdcHandle.Instance = ADC1;
AdcHandle.Init.ClockPrescaler = ADC_CLOCKPRESCALER_PCLK_DIV4;
AdcHandle.Init.Resolution = ADC_RESOLUTION_12B;
AdcHandle.Init.ScanConvMode = DISABLE;
AdcHandle.Init.ContinuousConvMode = ENABLE;
AdcHandle.Init.DiscontinuousConvMode = DISABLE;
AdcHandle.Init.NbrOfDiscConversion = 0;
AdcHandle.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
AdcHandle.Init.ExternalTrigConv = ADC_EXTERNALTRIGCONV_T1_CC1;
AdcHandle.Init.DataAlign = ADC_DATAALIGN_RIGHT;
AdcHandle.Init.NbrOfConversion = 1;
AdcHandle.Init.DMAContinuousRequests = ENABLE;
AdcHandle.Init.EOCSelection = DISABLE;
HAL_ADC_Init(&AdcHandle);
ADC_ChannelConfTypeDef sConfig;
sConfig.Channel = ADC_CHANNEL_0;
sConfig.Rank = 1;
sConfig.SamplingTime = ADC_SAMPLETIME_84CYCLES;
sConfig.Offset = 0;
HAL_ADC_ConfigChannel(&AdcHandle, &sConfig);
}
static void DAC_Config(void)
{
DacHandle.Instance = DAC;
HAL_DAC_Init(&DacHandle);
DAC_ChannelConfTypeDef sConfig;
sConfig.DAC_Trigger = DAC_TRIGGER_NONE;
sConfig.DAC_OutputBuffer = DAC_OUTPUTBUFFER_ENABLE;
HAL_DAC_ConfigChannel(&DacHandle, &sConfig, DAC_CHANNEL_1);
}
```
3. 实现ADC采样完成中断的回调函数:
``` c
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc)
{
AdcBuf[AdcBufIndex] = HAL_ADC_GetValue(hadc);
AdcBufIndex++;
}
```
4. 主程序的实现:
``` c
int main(void)
{
HAL_Init();
SystemClock_Config();
__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE();
__HAL_RCC_GPIOC_CLK_ENABLE();
__HAL_RCC_GPIOD_CLK_ENABLE();
__HAL_RCC_DMA1_CLK_ENABLE();
__HAL_RCC_ADC1_CLK_ENABLE();
__HAL_RCC_DAC_CLK_ENABLE();
__HAL_RCC_TIM6_CLK_ENABLE();
__HAL_RCC_FLASH_CLK_ENABLE();
ADC_Config();
DAC_Config();
HAL_ADC_Start_DMA(&AdcHandle, (uint32_t*)ADC1_DR_ADDRESS, 1);
HAL_DAC_Start(&DacHandle, DAC_CHANNEL_1);
while (1)
{
if (AdcBufIndex >= ADC_BUF_SIZE)
{
HAL_FLASH_Unlock();
FLASH_EraseInitTypeDef EraseInitStruct;
EraseInitStruct.TypeErase = FLASH_TYPEERASE_SECTORS;
EraseInitStruct.Sector = FLASH_SECTOR_NUM;
EraseInitStruct.NbSectors = 1;
EraseInitStruct.VoltageRange = FLASH_VOLTAGE_RANGE_3;
uint32_t SectorError;
HAL_FLASHEx_Erase(&EraseInitStruct, &SectorError);
FlashWriteAddr = FLASH_START_ADDR;
for (uint32_t i = 0; i < ADC_BUF_SIZE; i++)
{
HAL_FLASH_Program(FLASH_TYPEPROGRAM_HALFWORD, FlashWriteAddr, AdcBuf[i]);
FlashWriteAddr += 2;
}
HAL_FLASH_Lock();
FlashWriteAddr = FLASH_START_ADDR;
for (uint32_t i = 0; i < ADC_BUF_SIZE; i++)
{
HAL_DAC_SetValue(&DacHandle, DAC_CHANNEL_1, DAC_ALIGN_12B_R, AdcBuf[i]);
HAL_Delay(SAMPLE_TIME);
}
AdcBufIndex = 0;
}
}
}
```
主程序的实现比较简单,主要就是检测采样数组是否已满,如果已满则将其存储到内部flash中,并通过DAC实现回放。具体实现细节如下:
- 通过`HAL_FLASH_Unlock()`函数解锁内部flash;
- 通过`HAL_FLASHEx_Erase()`函数擦除flash扇区;
- 通过`HAL_FLASH_Program()`函数将采样数据存储到flash中;
- 通过`HAL_FLASH_Lock()`函数锁定内部flash;
- 通过`HAL_DAC_SetValue()`函数将flash中的采样数据输出到DAC;
- 通过`HAL_Delay()`函数实现采样率控制,保证回放速度。
需要注意的是,由于内部flash的写入操作需要擦除整个扇区,因此在存储数据时需要先将整个扇区擦除再进行写入,否则会出现写入失败的情况。
hal库基于stm32f407 写出ADC读取语音电信号,内部flash存储10sADC读取的语音信号,后用dac再将flash内部信号输出,实现语音回放掉电存储的代码
以下是基于STM32F407的HAL库的ADC读取语音电信号、内部Flash存储10s ADC读取的语音信号、用DAC将Flash内部信号输出的代码:
```
#include "stm32f4xx_hal.h"
#include "stm32f4xx_hal_flash.h"
#include "stm32f4xx_hal_dac.h"
#define FLASH_START_ADDR ((uint32_t)0x080E0000) // Internal flash start address
#define FLASH_SECTOR FLASH_SECTOR_11 // Internal flash sector for storage
#define AUDIO_SAMPLE_RATE 8000 // Audio sample rate in Hz
#define AUDIO_SAMPLE_SIZE 16 // Audio sample size in bits
#define AUDIO_BUFFER_SIZE (AUDIO_SAMPLE_RATE * 10 * AUDIO_SAMPLE_SIZE / 8) // Audio buffer size in bytes
ADC_HandleTypeDef hadc1;
DAC_HandleTypeDef hdac;
FLASH_EraseInitTypeDef flashErase;
uint8_t audioBuffer[AUDIO_BUFFER_SIZE];
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_ADC1_Init(void);
static void MX_DAC_Init(void);
static void MX_NVIC_Init(void);
int main(void) {
uint32_t flashAddress = FLASH_START_ADDR;
uint32_t audioSampleCount = AUDIO_SAMPLE_RATE * 10;
uint32_t audioSampleSize = AUDIO_SAMPLE_SIZE / 8;
uint32_t audioBufferSize = audioSampleCount * audioSampleSize;
uint32_t audioBufferIndex = 0;
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_ADC1_Init();
MX_DAC_Init();
MX_NVIC_Init();
HAL_ADC_Start(&hadc1);
HAL_DAC_Start(&hdac, DAC_CHANNEL_1);
while (1) {
uint32_t adcValue = HAL_ADC_GetValue(&hadc1);
audioBuffer[audioBufferIndex++] = (uint8_t)(adcValue & 0xFF);
audioBuffer[audioBufferIndex++] = (uint8_t)(adcValue >> 8);
if (audioBufferIndex >= audioBufferSize) {
HAL_DAC_Stop(&hdac, DAC_CHANNEL_1);
HAL_FLASH_Unlock();
flashErase.TypeErase = TYPEERASE_SECTORS;
flashErase.Sector = FLASH_SECTOR;
flashErase.NbSectors = 1;
flashErase.VoltageRange = VOLTAGE_RANGE_3;
uint32_t sectorError;
HAL_FLASHEx_Erase(&flashErase, §orError);
for (uint32_t i = 0; i < audioBufferSize; i += 4) {
uint32_t data = *(uint32_t *)(audioBuffer + i);
HAL_FLASH_Program(TYPEPROGRAM_WORD, flashAddress + i, data);
}
HAL_FLASH_Lock();
audioBufferIndex = 0;
HAL_DAC_Start(&hdac, DAC_CHANNEL_1);
}
}
}
void SystemClock_Config(void) {
RCC_OscInitTypeDef RCC_OscInitStruct;
RCC_ClkInitTypeDef RCC_ClkInitStruct;
__HAL_RCC_PWR_CLK_ENABLE();
__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
RCC_OscInitStruct.HSIState = RCC_HSI_ON;
RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI;
RCC_OscInitStruct.PLL.PLLM = 16;
RCC_OscInitStruct.PLL.PLLN = 336;
RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV4;
RCC_OscInitStruct.PLL.PLLQ = 7;
HAL_RCC_OscConfig(&RCC_OscInitStruct);
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;
HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_5);
HAL_SYSTICK_Config(HAL_RCC_GetHCLKFreq() / 1000);
HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK);
}
static void MX_ADC1_Init(void) {
ADC_ChannelConfTypeDef sConfig;
__HAL_RCC_ADC1_CLK_ENABLE();
hadc1.Instance = ADC1;
hadc1.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV4;
hadc1.Init.Resolution = ADC_RESOLUTION_12B;
hadc1.Init.ScanConvMode = DISABLE;
hadc1.Init.ContinuousConvMode = ENABLE;
hadc1.Init.DiscontinuousConvMode = DISABLE;
hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START;
hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;
hadc1.Init.NbrOfConversion = 1;
HAL_ADC_Init(&hadc1);
sConfig.Channel = ADC_CHANNEL_0;
sConfig.Rank = 1;
sConfig.SamplingTime = ADC_SAMPLETIME_15CYCLES;
HAL_ADC_ConfigChannel(&hadc1, &sConfig);
}
static void MX_DAC_Init(void) {
DAC_ChannelConfTypeDef sConfig;
__HAL_RCC_DAC_CLK_ENABLE();
hdac.Instance = DAC;
HAL_DAC_Init(&hdac);
sConfig.DAC_Trigger = DAC_TRIGGER_NONE;
sConfig.DAC_OutputBuffer = DAC_OUTPUTBUFFER_ENABLE;
HAL_DAC_ConfigChannel(&hdac, &sConfig, DAC_CHANNEL_1);
}
static void MX_GPIO_Init(void) {
__HAL_RCC_GPIOA_CLK_ENABLE();
GPIO_InitTypeDef GPIO_InitStruct = {0};
GPIO_InitStruct.Pin = GPIO_PIN_0;
GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
}
static void MX_NVIC_Init(void) {
HAL_NVIC_SetPriority(DMA1_Stream5_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(DMA1_Stream5_IRQn);
}
void DMA1_Stream5_IRQHandler(void) {
HAL_DMA_IRQHandler(&hdac);
}
```
这个代码中,我们使用`HAL_ADC_GetValue()`函数从ADC读取语音信号,并将其存储在一个缓冲区中。当缓冲区被填满时,我们停止DAC并将缓冲区中的数据存储到内部Flash中。然后,我们重置缓冲区并开始DAC以回放存储的语音信号。
阅读全文