初级会员

- 积分
- 78
- 金钱
- 78
- 注册时间
- 2012-10-20
- 在线时间
- 7 小时
|
发表于 2022-1-10 12:17:27
|
显示全部楼层
wavplay.cpp文件
- #include "wavplay.h"
- #include <stdlib.h>
- #include "HardwareSerial.h"
- #include "SPIFlash.h"
- extern SPIFlash flash;
- uint32_t WAV_ADDR[2] =
- {
- WAV_BASE + WAV1_OFFSET,
- WAV_BASE + WAV2_OFFSET
- };
- WAV_CTR_t wavctrl; //WAV控制结构体
- //WAV解析初始化
- //fname:文件路径+文件名
- //wavx:wav 信息存放结构体指针
- //返回值:0,成功;1,打开文件失败;2,非WAV文件;3,DATA区域未找到.
- uint8_t wav_decode_init(WAV_CTR_t *wavx , uint32_t addr)
- {
- // FIL*ftemp;
- uint8_t *buf;
- uint8_t res = 0;
- ChunkRIFF *riff;
- ChunkFMT *fmt;
- ChunkFACT *fact;
- ChunkDATA *data;
- buf = (uint8_t *)malloc(64);
- if(buf) //内存申请成功
- {
- flash.readBytes(addr, buf, 64);
- riff = (ChunkRIFF *)buf; //获取RIFF块
- if(riff->Format == 0X45564157) //是WAV文件
- {
- fmt = (ChunkFMT *)(buf + 12); //获取FMT块
- fact = (ChunkFACT *)(buf + 12 + 8 + fmt->ChunkSize); //读取FACT块
- if(fact->ChunkID == 0X74636166 || fact->ChunkID == 0X5453494C)wavx->datastart = 12 + 8 + fmt->ChunkSize + 8 + fact->ChunkSize; //具有fact/LIST块的时候(未测试)
- else wavx->datastart = 12 + 8 + fmt->ChunkSize;
- data = (ChunkDATA *)(buf + wavx->datastart); //读取DATA块
- if(data->ChunkID == 0X61746164) //解析成功!
- {
- wavx->audioformat = fmt->AudioFormat; //音频格式
- wavx->nchannels = fmt->NumOfChannels; //通道数
- wavx->samplerate = fmt->SampleRate; //采样率
- wavx->bitrate = fmt->ByteRate * 8; //得到位速
- wavx->blockalign = fmt->BlockAlign; //块对齐
- wavx->bps = fmt->BitsPerSample; //位数,16/24/32位
- wavx->datasize = data->ChunkSize; //数据块大小
- wavx->datastart = wavx->datastart + 8; //数据流开始的地方.
- wavx->addr = addr;
- wavx->data_offset = 0;
- Serial.printf("wavx->audioformat:%d\r\n", wavx->audioformat);
- Serial.printf("wavx->nchannels:%d\r\n", wavx->nchannels);
- Serial.printf("wavx->samplerate:%d\r\n", wavx->samplerate);
- Serial.printf("wavx->bitrate:%d\r\n", wavx->bitrate);
- Serial.printf("wavx->blockalign:%d\r\n", wavx->blockalign);
- Serial.printf("wavx->bps:%d\r\n", wavx->bps);
- Serial.printf("wavx->datasize:%d\r\n", wavx->datasize);
- Serial.printf("wavx->datastart:%d\r\n", wavx->datastart);
- Serial.printf("wavx->addr:%d\r\n", wavx->addr);
- }
- else res = 3; //data区域未找到.
- }
- else res = 2; //非wav文件
- }
- free(buf);
- return res;
- }
- void Speaker_Config()
- {
- #define WAV_SAMPLERATE 12000
- NVIC_InitTypeDef NVIC_InitStructure;
- GPIO_InitTypeDef GPIO_InitStructure;
- TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
- TIM_OCInitTypeDef TIM_OCInitStructure;
- RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM16, ENABLE);
- RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM14, ENABLE); //使能TIMx外设
- RCC_AHBPeriphClockCmd( RCC_AHBPeriph_GPIOB, ENABLE);
- //设置该引脚为复用输出功能,输出TIM4 CH1的PWM脉冲波形
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1; //TIM_CH1
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; //复用功能输出
- GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
- GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
- GPIO_Init(GPIOB, &GPIO_InitStructure); //初始化GPIO
- TIM_TimeBaseStructure.TIM_Period = 0xFF; //设置自动重装载周期值
- TIM_TimeBaseStructure.TIM_Prescaler = 0; //设置预分频值 不分频
- TIM_TimeBaseStructure.TIM_ClockDivision = 0; //设置时钟分割:TDTS = Tck_tim
- TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //TIM向上计数模式
- TIM_TimeBaseInit(TIM14, &TIM_TimeBaseStructure); //根据指定的参数初始化TIMx
- TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2; //CH1 PWM2模式
- TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //比较输出使能
- TIM_OCInitStructure.TIM_Pulse = 0x80; //设置待装入捕获比较寄存器的脉冲值
- TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low; //OC1 低电平有效
- TIM_OC1Init(TIM14, &TIM_OCInitStructure); //根据指定的参数初始化外设TIMx
- TIM_OC1PreloadConfig(TIM14, TIM_OCPreload_Enable); //CH1 预装载使能
- TIM_ARRPreloadConfig(TIM14, ENABLE); //使能TIMx在ARR上的预装载寄存器
- TIM_Cmd(TIM14, ENABLE); //使能TIMx
-
-
-
-
-
- TIM_TimeBaseStructure.TIM_Period = (uint16_t)(SystemCoreClock / WAV_SAMPLERATE - 1); //设定计数器自动重装值3273 中断频率=72M/3273=22Khz
- TIM_TimeBaseStructure.TIM_Prescaler = 0; //预分频器为0.
- TIM_TimeBaseStructure.TIM_ClockDivision = 0; //设置时钟分割:TDTS = Tck_tim
- TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //TIM向上计数模式
- TIM_TimeBaseInit(TIM16, &TIM_TimeBaseStructure); //根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位
- TIM_ITConfig(TIM16, TIM_IT_Update, DISABLE ); //使能或者失能指定的TIM中断
- TIM_Cmd(TIM16, ENABLE); //使能TIMx外设
- //NVIC中断配置
- NVIC_InitStructure.NVIC_IRQChannel = TIM16_IRQn; //组2,优先级次之
- NVIC_InitStructure.NVIC_IRQChannelPriority = 1;
- NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
- NVIC_Init(&NVIC_InitStructure);
- }
- //uint32_t Out_Data_Offset = 0;
- extern "C" void TIM16_IRQHandler(void)
- {
- uint32_t addr;
- if (TIM_GetITStatus(TIM16, TIM_IT_Update) != RESET) //检查指定的TIM中断发生与否:TIM 中断源
- {
- if(wavctrl.status == 0)
- {
- //停止
- TIM14->CCR1 = 0x80;
- wavctrl.data_offset = 0;
- TIM_ITConfig(TIM16, TIM_IT_Update, DISABLE ); //使能或者失能指定的TIM中断
- }
- else if(wavctrl.status == 1)
- {
- //播放
- if(wavctrl.data_offset < wavctrl.datasize)
- {
- addr = wavctrl.addr + wavctrl.datastart + wavctrl.data_offset;//Out_Data_Offset;
- uint8_t data = flash.readByte(addr);
- TIM14->CCR1 = data; //改变PWM DAC的值
- wavctrl.data_offset++;
- // Out_Data_Offset++;//地址数据要加2.这个可以跟转换出来的wav文件有关。
- }
- else
- {
- //播放完毕
- TIM14->CCR1 = 0x80;
- wavctrl.data_offset = 0;
- TIM_ITConfig(TIM16, TIM_IT_Update, DISABLE ); //使能或者失能指定的TIM中断
- }
- }
- else if(wavctrl.status == 2)
- {
- //暂停
- TIM_ITConfig(TIM16, TIM_IT_Update, DISABLE ); //使能或者失能指定的TIM中断
- }
- }
- TIM_ClearITPendingBit(TIM16, TIM_IT_Update ); //清除TIMx的中断待处理位:TIM 中断源
- }
- void WavPause()
- {
- wavctrl.status = 2;
- }
- void WavResume()
- {
- wavctrl.status = 1;
- TIM_ITConfig(TIM16, TIM_IT_Update, ENABLE ); //使能或者失能指定的TIM中断
- }
- void WavStop()
- {
- wavctrl.status = 0;
- }
- void WavPlay(uint8_t num )
- {
- wavctrl.status = 0;
- uint32_t wav_info_addr = 183*4096;
- uint32_t addr = wav_info_addr + num*4;
-
- uint32_t wav_addr = flash.readByte(addr);
- wav_addr = (wav_addr<<8) + flash.readByte(addr+1);
- wav_addr = (wav_addr<<8) + flash.readByte(addr+2);
- wav_addr = (wav_addr<<8) + flash.readByte(addr+3);
- Serial.printf("wav_addr=%d\r\n",wav_addr);
-
- uint8_t res = wav_decode_init(&wavctrl, wav_addr); //得到文件的信息
- Serial.printf("res=%d\r\n", res);;
- if(res == 0)
- {
- wavctrl.status = 1;
- TIM_ITConfig(TIM16, TIM_IT_Update, ENABLE ); //使能或者失能指定的TIM中断
- }
- }
复制代码
头文件wavplay.h
- #ifndef __WAVPLAY_H
- #define __WAVPLAY_H
- #include "stm32f0xx.h"
- #define WAV_BASE 184*4096
- #define WAV1_OFFSET 0
- #define WAV2_OFFSET 486398
- #define TIME_LEN 353266
- //RIFF块
- typedef __packed struct
- {
- uint32_t ChunkID; //chunk id;这里固定为"RIFF",即0X46464952
- uint32_t ChunkSize ; //集合大小;文件总大小-8
- uint32_t Format; //格式;WAVE,即0X45564157
- } ChunkRIFF ;
- //fmt块
- typedef __packed struct
- {
- uint32_t ChunkID; //chunk id;这里固定为"fmt ",即0X20746D66
- uint32_t ChunkSize ; //子集合大小(不包括ID和Size);这里为:20.
- uint16_t AudioFormat; //音频格式;0X01,表示线性PCM;0X11表示IMA ADPCM
- uint16_t NumOfChannels; //通道数量;1,表示单声道;2,表示双声道;
- uint32_t SampleRate; //采样率;0X1F40,表示8Khz
- uint32_t ByteRate; //字节速率;
- uint16_t BlockAlign; //块对齐(字节);
- uint16_t BitsPerSample; //单个采样数据大小;4位ADPCM,设置为4
- // uint16_t ByteExtraData; //附加的数据字节;2个; 线性PCM,没有这个参数
- } ChunkFMT;
- //fact块
- typedef __packed struct
- {
- uint32_t ChunkID; //chunk id;这里固定为"fact",即0X74636166;
- uint32_t ChunkSize ; //子集合大小(不包括ID和Size);这里为:4.
- uint32_t NumOfSamples; //采样的数量;
- } ChunkFACT;
- //LIST块
- typedef __packed struct
- {
- uint32_t ChunkID; //chunk id;这里固定为"LIST",即0X74636166;
- uint32_t ChunkSize ; //子集合大小(不包括ID和Size);这里为:4.
- } ChunkLIST;
- //data块
- typedef __packed struct
- {
- uint32_t ChunkID; //chunk id;这里固定为"data",即0X5453494C
- uint32_t ChunkSize ; //子集合大小(不包括ID和Size)
- } ChunkDATA;
- //wav头
- typedef __packed struct
- {
- ChunkRIFF riff; //riff块
- ChunkFMT fmt; //fmt块
- // ChunkFACT fact; //fact块 线性PCM,没有这个结构体
- ChunkDATA data; //data块
- } __WaveHeader;
- //wav 播放控制结构体
- typedef struct
- {
- uint16_t audioformat; //音频格式;0X01,表示线性PCM;0X11表示IMA ADPCM
- uint16_t nchannels; //通道数量;1,表示单声道;2,表示双声道;
- uint16_t blockalign; //块对齐(字节);
- uint32_t datasize; //WAV数据大小
- uint32_t totsec ; //整首歌时长,单位:秒
- uint32_t cursec ; //当前播放时长
- uint32_t bitrate; //比特率(位速)
- uint32_t samplerate; //采样率
- uint16_t bps; //位数,比如16bit,24bit,32bit
- uint32_t datastart; //数据帧开始的位置(在文件里面的偏移)
- uint32_t addr;
- uint32_t data_offset;
- uint32_t status;//0 停止,1 播放 2,暂停
- } WAV_CTR_t;
- uint8_t wav_decode_init(WAV_CTR_t* wavx , uint32_t addr);
- void Speaker_Config();
- void WavStop();
- void WavPause();
- void WavResume();
- void WavPlay(uint8_t num );
- extern uint32_t WAV_ADDR[];
- extern WAV_CTR_t wavctrl;
- #endif
复制代码
声音 12KHZ 8bit 单声道 wav文件。
这个项目好久了用c++写的代码,具体分析代码吧。当初测试是能工作的。 |
|