基于stm32f407 写出ADC读取语音电信号,内部flash存储10sADC读取的语音信号,后用dac再将flash内部信号输出,实现语音回放掉电存储的代码
时间: 2024-05-09 17:14:20 浏览: 19
以下是基于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的写入操作需要擦除整个扇区,因此在存储数据时需要先将整个扇区擦除再进行写入,否则会出现写入失败的情况。
相关推荐
![zip](https://img-home.csdnimg.cn/images/20210720083736.png)
![zip](https://img-home.csdnimg.cn/images/20210720083736.png)
![](https://csdnimg.cn/download_wenku/file_type_ask_c1.png)
![](https://csdnimg.cn/download_wenku/file_type_ask_c1.png)
![](https://csdnimg.cn/download_wenku/file_type_ask_c1.png)
![](https://csdnimg.cn/download_wenku/file_type_ask_c1.png)
![](https://csdnimg.cn/download_wenku/file_type_ask_c1.png)
![](https://csdnimg.cn/download_wenku/file_type_ask_c1.png)
![](https://csdnimg.cn/download_wenku/file_type_ask_c1.png)
![](https://csdnimg.cn/download_wenku/file_type_ask_c1.png)
![](https://csdnimg.cn/download_wenku/file_type_ask_c1.png)
![](https://csdnimg.cn/download_wenku/file_type_ask_c1.png)
![zip](https://img-home.csdnimg.cn/images/20210720083736.png)