IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 嵌入式 -> 基于stm32f4的数字化语音存储及回放(软件部分) -> 正文阅读

[嵌入式]基于stm32f4的数字化语音存储及回放(软件部分)

基于stm32f4的数字化语音存储及回放(软件部分)

1.程序部分整体思路

  1. 在主函数中放置模式选择,通过按键来实现

  2. 主函数定期会跳出去执行中断

  3. 在定时器中断中放置不同模式下的执行函数,通过调整定时器的频率来改变adc采样的频率

  4. 中断里read模式下adc获得值存放在flash

  5. Play模式下flash指定区域获得数值,通过dac放出

  6. Stop模式下获得现在的adc值,并通过dac放出,未有保存操作

  7. 可使用自制串口上位机通过蓝牙模块或无线模块控制(可以用)

2.以下为主要程序部分,分别为main.c | led.c| adc.c | timer.c |dac.c| flash.c部分

本次主要是对adc采样进行调参

main.c

#include "sys.h"
#include "delay.h"
#include "usart.h"
#include "led.h"
#include "key.h"
#include "adc.h"
#include "timer.h"
#include "dac.h"


u8 mode;
extern __IO uint16_t ADC_ConvertedValue;
int main(void){
	LED_Init();                                     //LED端口初始化
	KEY_Init();
	ADC_1_Init();
	Dac1_Init();
	delay_init(168);    	 							//延时函数初始化	  
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);	 //设置NVIC中断分组2:2位抢占优先级,2位响应优先级 	
	TIM3_Int_Init(4200,1);								//为了提高音质,把采样频率提到了10k
	mode = wait;
	while(1){				
		if(KEY0 == 0){
			delay_ms(10);
			if(KEY0 == 0)
				mode = re;
		}
		if(KEY1 == 0){
			delay_ms(10);
			if(KEY1 == 0)
				mode = play;
		}
		if(KEY2==0){
			delay_ms(10);
			if(KEY2==0)
				mode=clear;
		}
		if(WK_UP==1)
		{
			TIM3_Int_Init(6300,1);
		}
	}
}

led.c

#include "led.h" 
//初始化PF9和PF10为输出口.并使能这两个口的时钟		    
//LED IO初始化
void LED_Init(void)
{    	 
    GPIO_InitTypeDef  GPIO_InitStructure;

    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOF, ENABLE);//使能GPIOF时钟

  //GPIOF9,F10初始化设置
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10| GPIO_Pin_9;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;//普通输出模式
    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;//推挽输出
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;//100MHz
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;//上拉
    GPIO_Init(GPIOF, &GPIO_InitStructure);//初始化
	
	GPIO_SetBits(GPIOF,GPIO_Pin_10| GPIO_Pin_9);//GPIOF9,F10设置高,灯灭

}

adc.c

#include "ADC.h"

__IO uint16_t ADC_ConvertedValue;
void ADC_1_Init(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;
	DMA_InitTypeDef DMA_InitStructure;
	ADC_InitTypeDef ADC_InitStructure;
	//时钟使能
	ADC_CommonInitTypeDef ADC_CommonInitStructure;
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2|RCC_AHB1Periph_GPIOA,ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1,ENABLE);
	//*io口
	GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AN;
	GPIO_InitStructure.GPIO_Pin=GPIO_Pin_5;
	GPIO_InitStructure.GPIO_PuPd=GPIO_PuPd_NOPULL;
	GPIO_Init(GPIOA,&GPIO_InitStructure);
	//DMA
	DMA_DeInit(DMA2_Stream0);  
	DMA_InitStructure.DMA_Channel=DMA_Channel_0;//对应的ADC1通道
	DMA_InitStructure.DMA_BufferSize=1;//传输数据宽度
	DMA_InitStructure.DMA_PeripheralBaseAddr=(uint32_t)ADC1_DR_ADDRESS;//外设地址
	DMA_InitStructure.DMA_Memory0BaseAddr=(uint32_t)&ADC_ConvertedValue;//内存地址
	DMA_InitStructure.DMA_DIR=DMA_DIR_PeripheralToMemory;//外设到内存模式
	DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;//外设非增量模式
	DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Disable;//内存非增量模式
	DMA_InitStructure.DMA_PeripheralDataSize =DMA_PeripheralDataSize_HalfWord;  //外设数据宽度16位
	DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;//内存数据宽度
	DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;//循环模式
	DMA_InitStructure.DMA_Priority = DMA_Priority_High;//高等级
	DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;//缓冲不开       
	DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull;
	DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;//存储器突发单次传输
	DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;//内存突发单次传输
	DMA_Init(DMA2_Stream0,&DMA_InitStructure);
	//ADC初始化

	//DMA_Init(DMA2_Stream0, &DMA_InitStructure);
	// 使能DMA流
	DMA_Cmd(DMA2_Stream0, ENABLE);
	ADC_CommonInitStructure.ADC_DMAAccessMode=ADC_DMAAccessMode_Disabled;//关闭DMA访问通道
	ADC_CommonInitStructure.ADC_Mode=ADC_Mode_Independent;//独立模式
	ADC_CommonInitStructure.ADC_Prescaler=ADC_Prescaler_Div2;//预分频4
	ADC_CommonInitStructure.ADC_TwoSamplingDelay=ADC_TwoSamplingDelay_5Cycles;//采样间隔20
	ADC_CommonInit(&ADC_CommonInitStructure);

	ADC_StructInit(&ADC_InitStructure);//初始化ADC(默认值)
	
	ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;// ADC 分辨率
	ADC_InitStructure.ADC_ScanConvMode = DISABLE; // 禁止扫描模式,多通道采集才需要
	ADC_InitStructure.ADC_ContinuousConvMode = ENABLE; // 连续转换	
	ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;//禁止外部边沿触发
	ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T1_CC1;//外部触发通道,本例子使用软件触发,此值随便赋值即可
	ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;//数据右对齐	
	ADC_InitStructure.ADC_NbrOfConversion = 1;//转换通道 1个                                    
	ADC_Init(ADC1, &ADC_InitStructure);
	
	ADC_RegularChannelConfig(ADC1, ADC_Channel_5, 1, ADC_SampleTime_480Cycles);// 配置 ADC 通道转换顺序为1,第一个转换,采样时间为3个时钟周期
	
	ADC_DMARequestAfterLastTransferCmd(ADC1, ENABLE);// 使能DMA请求 after last transfer (Single-ADC mode)
	
	ADC_DMACmd(ADC1, ENABLE);// 使能ADC DMA

	ADC_Cmd(ADC1, ENABLE);// 使能ADC  
	
	ADC_SoftwareStartConv(ADC1);//开始adc转换,软件触发
}

timer.c

#include "timer.h"
#include "led.h"
#include "dac.h"
#include "adc.h"
#include "key.h"
#include "flash.h"
#include "delay.h"

#define TEXT_LENTH sizeof(adc)	 		//数组长度	
#define size TEXT_LENTH/4+((TEXT_LENTH%4)?1:0)//要写入的32位数据的个数 
extern u8 mode;
extern	__IO uint16_t ADC_ConvertedValue;
int x=0,y=0;
//uint16_t adc[6][10000];//54000个数据
//u8 datatemp[6][10000];//读出数据暂存数组	

//通用定时器3中断初始化
//arr:自动重装值。
//psc:时钟预分频数
//定时器溢出时间计算方法:Tout=((arr+1)*(psc+1))/Ft us.
//Ft=定时器工作频率,单位:Mhz
//这里使用的是定时器3!
void TIM3_Int_Init(u16 arr,u16 psc)
{
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitSture;
	NVIC_InitTypeDef NVIC_InitStructure;
	
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE); //定时器使能
	
	TIM_TimeBaseInitSture.TIM_Period=arr;
	TIM_TimeBaseInitSture.TIM_Prescaler=psc;
	TIM_TimeBaseInitSture.TIM_CounterMode=TIM_CounterMode_Up;
	TIM_TimeBaseInitSture.TIM_ClockDivision=TIM_CKD_DIV1;
	TIM_TimeBaseInit(TIM3,&TIM_TimeBaseInitSture);
	
	TIM_ITConfig(TIM3,TIM_IT_Update,ENABLE);
	
	NVIC_InitStructure.NVIC_IRQChannel=TIM3_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0x03;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority=0x00;
	NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;
	NVIC_Init(&NVIC_InitStructure);

	TIM_Cmd(TIM3,ENABLE);
}

//定时器3中断服务函数
void TIM3_IRQHandler(void){
	if(TIM_GetITStatus(TIM3,TIM_IT_Update)==SET){	//溢出中断
		switch (mode){
			case re:
				LED0 = 0;	
				LED1 = 1;
				STMFLASH_Write(ADDR_FLASH_SECTOR_4+x,(u32*)&ADC_ConvertedValue,1);//写入
				x+=4;
				//adc[x][y]=ADC_ConvertedValue/2;
				break;
					
			case play:
				LED0 = 1;	
				LED1 = 0;
				if((ADDR_FLASH_SECTOR_4+y)>=0x080FFFFF){	
					LED1=1;
					break;
				}
				DAC_SetChannel1Data(DAC_Align_12b_R,(u16)STMFLASH_ReadWord(ADDR_FLASH_SECTOR_4+y));//12位右对齐数据格式设置DAC值;
				y+=4;
				break;
			
			case clear:
				mode=wait;
				LED0 = 0;
				LED1 = 0;
				flash_clear();
				delay_ms(500);
				LED0 = 1;
				LED1 = 1;
				break;
			
			default :
				LED1 = 1;	
				LED0 = 1;
				x=y=0;
				break;
		}
		/*if(mode == re){
			y++;
			if(y>9999){
				y = 0;
				x++;
			}
			if(x > 5){
				mode = stop;
				x=0;
				STMFLASH_Write(FLASH_SAVE_ADDR,(u32*)&DAC_ConvertedValue,1);//写入
			}
		}*/
	}
	TIM_ClearITPendingBit(TIM3,TIM_IT_Update);  //清除中断标志位
}

dac.c

#include "dac.h"


//DAC通道1输出初始化
void Dac1_Init(void)
{  
	GPIO_InitTypeDef  GPIO_InitStructure;
	DAC_InitTypeDef DAC_InitType;

	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);//使能GPIOA时钟
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_DAC, ENABLE);//使能DAC时钟

	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;//GPIOA
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;//模拟输入
	GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_DOWN;//下拉
	GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化

	DAC_InitType.DAC_Trigger=DAC_Trigger_None;	//不使用触发功能 TEN1=0
	DAC_InitType.DAC_WaveGeneration=DAC_WaveGeneration_None;//不使用波形发生
	DAC_InitType.DAC_LFSRUnmask_TriangleAmplitude=DAC_LFSRUnmask_Bit0;//屏蔽、幅值设置
	DAC_InitType.DAC_OutputBuffer=DAC_OutputBuffer_Disable ;	//DAC1输出缓存关闭 BOFF1=1
	DAC_Init(DAC_Channel_1,&DAC_InitType);	 //初始化DAC通道1

	DAC_Cmd(DAC_Channel_1, ENABLE);  //使能DAC通道1

	DAC_SetChannel1Data(DAC_Align_8b_R,0);  //8位右对齐数据格式设置DAC值
}

//设置通道1输出电压
//vol:0~3300,代表0~3.3V
void Dac1_Set_Vol(u16 vol)
{
	double temp=vol;
	temp/=1000;
	temp=temp*4096/3.3;
	DAC_SetChannel1Data(DAC_Align_12b_R,temp);//12位右对齐数据格式设置DAC值
}

falsh.c

#include "flash.h"
#include "delay.h"
#include "usart.h"
#include "led.h"

//读取指定地址的半字(16位数据) 
//faddr:读地址 
//返回值:对应数据.
u32 STMFLASH_ReadWord(u32 faddr)
{
	return *(vu32*)faddr; 
}  
//获取某个地址所在的flash扇区
//addr:flash地址
//返回值:0~11,即addr所在的扇区
uint16_t STMFLASH_GetFlashSector(u32 addr)
{
	if(addr<ADDR_FLASH_SECTOR_1)return FLASH_Sector_0;
	else if(addr<ADDR_FLASH_SECTOR_2)return FLASH_Sector_1;
	else if(addr<ADDR_FLASH_SECTOR_3)return FLASH_Sector_2;
	else if(addr<ADDR_FLASH_SECTOR_4)return FLASH_Sector_3;
	else if(addr<ADDR_FLASH_SECTOR_5)return FLASH_Sector_4;
	else if(addr<ADDR_FLASH_SECTOR_6)return FLASH_Sector_5;
	else if(addr<ADDR_FLASH_SECTOR_7)return FLASH_Sector_6;
	else if(addr<ADDR_FLASH_SECTOR_8)return FLASH_Sector_7;
	else if(addr<ADDR_FLASH_SECTOR_9)return FLASH_Sector_8;
	else if(addr<ADDR_FLASH_SECTOR_10)return FLASH_Sector_9;
	else if(addr<ADDR_FLASH_SECTOR_11)return FLASH_Sector_10; 
	return FLASH_Sector_11;	
}
//从指定地址开始写入指定长度的数据
//特别注意:因为STM32F4的扇区实在太大,没办法本地保存扇区数据,所以本函数
//         写地址如果非0XFF,那么会先擦除整个扇区且不保存扇区数据.所以
//         写非0XFF的地址,将导致整个扇区数据丢失.建议写之前确保扇区里
//         没有重要数据,最好是整个扇区先擦除了,然后慢慢往后写. 
//该函数对OTP区域也有效!可以用来写OTP区!
//OTP区域地址范围:0X1FFF7800~0X1FFF7A0F
//WriteAddr:起始地址(此地址必须为4的倍数!!)
//pBuffer:数据指针
//NumToWrite:字(32位)数(就是要写入的32位数据的个数.) 
void STMFLASH_Write(u32 WriteAddr,u32 *pBuffer,u32 NumToWrite)	
{ 
  FLASH_Status status = FLASH_COMPLETE;
	//u32 addrx=0;
	u32 endaddr=0;	
  if(WriteAddr>=0x080FFFFF){ 
		LED0 = 1;
		return;
	}
	if(WriteAddr<STM32_FLASH_BASE||WriteAddr%4)return;	//非法地址
	FLASH_Unlock();									//解锁 
  FLASH_DataCacheCmd(DISABLE);//FLASH擦除期间,必须禁止数据缓存
 		
	//addrx=WriteAddr;				//写入的起始地址
	endaddr=WriteAddr+NumToWrite*4;	//写入的结束地址
	/*if(addrx<0X1FFF0000)			//只有主存储区,才需要执行擦除操作!!
	{
		while(addrx<endaddr)		//扫清一切障碍.(对非FFFFFFFF的地方,先擦除)
		{
			if(STMFLASH_ReadWord(addrx)!=0XFFFFFFFF)//有非0XFFFFFFFF的地方,要擦除这个扇区
			{   
				status=FLASH_EraseSector(STMFLASH_GetFlashSector(addrx),VoltageRange_3);//VCC=2.7~3.6V之间!!
				if(status!=FLASH_COMPLETE)break;	//发生错误了
			}else addrx+=4;
		} 
	}*/
	if(status==FLASH_COMPLETE)
	{
		while(WriteAddr<endaddr)//写数据
		{
			if(FLASH_ProgramWord(WriteAddr,*pBuffer)!=FLASH_COMPLETE)//写入数据
			{ 
				break;	//写入异常
			}
			WriteAddr+=4;
		} 
	}
  FLASH_DataCacheCmd(ENABLE);	//FLASH擦除结束,开启数据缓存
	FLASH_Lock();//上锁
} 

//从指定地址开始读出指定长度的数据
//ReadAddr:起始地址
//pBuffer:数据指针
//NumToRead:字(4位)数
void STMFLASH_Read(u32 ReadAddr,u32 *pBuffer,u32 NumToRead)   	
{
	if(ReadAddr>=ADDR_FLASH_SECTOR_5){ 
		LED1 = 1;
		return;
	}
	u32 i;
	for(i=0;i<NumToRead;i++)
	{
		pBuffer[i]=STMFLASH_ReadWord(ReadAddr);//读取4个字节.
		ReadAddr+=4;//偏移4个字节.	
	}
}

//flash清除函数
void flash_clear(){
	u32 addrx=0;
	FLASH_Status status = FLASH_COMPLETE;
	addrx=ADDR_FLASH_SECTOR_4;
	FLASH_Unlock();//解锁	
  FLASH_DataCacheCmd(DISABLE);//FLASH擦除期间,必须禁止数据缓存
	if(ADDR_FLASH_SECTOR_4<0x080FFFFF)//只有主存储区,才需要执行擦除操作!!
	{
		while(addrx<=0x080FFFFF)		//扫清一切障碍.(对非FFFFFFFF的地方,先擦除)
		{
			if(STMFLASH_ReadWord(addrx)!=0XFFFFFFFF)//有非0XFFFFFFFF的地方,要擦除这个扇区
			{   
				status=FLASH_EraseSector(STMFLASH_GetFlashSector(addrx),VoltageRange_3);//VCC=2.7~3.6V之间!!
				if(status!=FLASH_COMPLETE)break;	//发生错误了
			}else addrx+=4;
		} 
	}
	FLASH_DataCacheCmd(ENABLE);	//FLASH擦除结束,开启数据缓存
	FLASH_Lock();//上锁
}
  嵌入式 最新文章
基于高精度单片机开发红外测温仪方案
89C51单片机与DAC0832
基于51单片机宠物自动投料喂食器控制系统仿
《痞子衡嵌入式半月刊》 第 68 期
多思计组实验实验七 简单模型机实验
CSC7720
启明智显分享| ESP32学习笔记参考--PWM(脉冲
STM32初探
STM32 总结
【STM32】CubeMX例程四---定时器中断(附工
上一篇文章      下一篇文章      查看所有文章
加:2021-07-23 10:57:52  更:2021-07-23 10:59:44 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年12日历 -2024/12/27 10:11:16-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码
数据统计