wm8978 音频解码 及 hlk_V2.0 语音识别
·
WM8978是什么?
跳过专业的说法,其实它就是一个可以将文件解码成音频的模块,我们之前学习的SD卡读取和文件系统,也就是说,我们可以读取到任何文件,如果读到的是音频文件,发送给它,它就能帮我们解码成音频,然后使用它自带的喇叭就可以进行播放了。
原理图

移植过程:
将关于内存管理的文件、移植到文件系统中、进行空间开辟、文件类型注册等

在工程中新建一个文件夹存放音乐解码文件

将对应文件添加到工程中、并添加.h文件(其中fattester.c文件不用添加)

延时函数名称不对自行修改、如果在audioplay.c中dir_sdi找不到自行在ff.h中进行声明、声明之前先把ff.c源文件中的static进行注释


然后在主函数进行头文件声明和函数调用

并在key.h中添加音乐头文件

在main.c中添加初始化
WM8978_Init(); //初始化WM8978
WM8978_HPvol_Set(0, 0); //耳机音量设置
WM8978_SPKvol_Set(0); //喇叭音量设置
WM8978_ADDA_Cfg(1, 0); //开启DAC
WM8978_Input_Cfg(0, 0, 0); //关闭输入通道
WM8978_Output_Cfg(1, 0); //开启DAC输出
WM8978_I2S_Cfg(2, 0); //飞利浦标准,16位数据长度
I2S2_Init(I2S_Standard_Phillips, I2S_Mode_MasterTx, I2S_CPOL_Low, I2S_DataFormat_16bextended); //飞利浦标准,主机发送,时钟低电平有效,16位扩展帧长度
I2S2_SampleRate_Set(44100); //设置采样率
I2S2_TX_DMA_Init(NULL, NULL, WAV_I2S_TX_DMA_BUFSIZE/2); //配置TX DMA
status_dev.volume = 63; //初始保存音量 0~63
WM8978_SPKvol_Set(status_dev.volume);
在主函数中调用音乐播放函数进行音乐播放
Audio_MusicPlay();//循环播放 按键切换歌曲
hlk v2.0 语音识别模块

工作原理:串口通信,通过串口接收语音识别传来的三个字节的的数据来判断语音的功能,
主要为中间字节

串口初始化及中断代码:
/*************************
函数名称:Usart3_Init(u32 baud)
函数功能:Usart3初始化函数
返回值:无
形参:u32 baud
作者:me
版本:1.0
U3 TX - PD8 U3 RX - PD9 APB1
*************************/
void Usart3_Init(u32 baud)
{
//打开串口/IO时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3, ENABLE);
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, ENABLE);
//初始化IO口 复用模式
//初始化IO口 复用模式
GPIO_InitTypeDef GPIO_InitStruct;
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_8 | GPIO_Pin_9;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStruct.GPIO_Speed = GPIO_Low_Speed;
GPIO_Init(GPIOD, &GPIO_InitStruct);
GPIO_PinAFConfig(GPIOD,GPIO_PinSource8,GPIO_AF_USART3);//PD8服用到USART3
GPIO_PinAFConfig(GPIOD,GPIO_PinSource9,GPIO_AF_USART3);//PD9服用到USART3
//初始化USART3控制器
USART_InitTypeDef USART_InitStruct;
USART_InitStruct.USART_BaudRate = baud;
USART_InitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None;// 无硬件流控制
USART_InitStruct.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
USART_InitStruct.USART_Parity = USART_Parity_No; //无校验
USART_InitStruct.USART_StopBits = USART_StopBits_1; //一位停止位
USART_InitStruct.USART_WordLength = USART_WordLength_8b; //8位数据位
USART_Init(USART3, &USART_InitStruct);
//中断使能
USART_ITConfig(USART3,USART_IT_RXNE,ENABLE);//接收中断,接收数据断,接受到一个字节触发
USART_ITConfig(USART3,USART_IT_IDLE,ENABLE);//空闲中断,接收结束后经过1个帧还没有数据的时候为1
//NVIC
NVIC_InitTypeDef NVIC_InitStruct;
NVIC_InitStruct.NVIC_IRQChannel = USART3_IRQn;//要配置的中断通道
NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 3;//抢占优先级(值越小优先级越高)
NVIC_InitStruct.NVIC_IRQChannelSubPriority = 0;//次级优先级(值越小优先级越高)
NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;//使能,失能中断
NVIC_Init( &NVIC_InitStruct);
//U3 使能
USART_Cmd(USART3,ENABLE);
}
U3 u3;
/*************************
函数名称:USART3_IRQHandler(void)
函数功能:USART3接收中断服务函数
返回值:无
形参:无
作者:me
版本:1.0
函数说明:这里结构体由于是全局的变量,则初始值为0
*************************/
void USART3_IRQHandler(void)
{
if(USART_GetITStatus(USART3, USART_IT_RXNE))//如果接收到了数据 0中断未触发 1触发
{
USART_ClearITPendingBit(USART3,USART_IT_RXNE);//清除接收中断标志位
u3.buff[u3.len++] = USART_ReceiveData(USART3);
}
if(USART_GetITStatus(USART3, USART_IT_IDLE))//进入空闲中断
{
USART3->SR;//清标志位
USART3->DR;//清标志位
printf("%s", u3.buff); // 打印接收到的数据
u3.len = 0;
u3.flag = 1;
for(u8 i=0;i<3;i++)
{
printf("0x%02x ", u3.buff[i]);
}
printf("\r\n");
}
}
USART3SPRE.H
#ifndef _USART3SPRE_H
#define _USART3SPRE_H
#include "main.h"
typedef struct{
u8 buff[10];//保存接收的字符串
u16 len;//记录接收数据长度的大小
u8 flag;//记录数据是否完成 0:未接收到新数据 1:接收数据完成
}U3;
extern U3 u3;
void Usart3_Init(u32 baud);
void Voice_Control(void);
#endif
功能函数的实现
/*************************
函数名称:Voice_Control(void)
函数功能:语言控制函数
返回值:无
形参:无
作者:me
版本:1.0
*************************/
void Voice_Control(void)
{
//判断U3是否接收数据完成
if(u3.flag == 1)
{
u3.flag = 0;
switch(u3.buff[1])
{
case 0x35:
//唤醒词 小凌小凌 需要做什么
cst.current_page = 0; // 切换到电机页面显示
Touch_Range(0,0,240,320);
//播放语音反馈
Audio_PlaySong((u8 *)"0:/voice/迎.wav");
break;
case 0x01:
//打开风扇 需要做什么
cst.motor_state = 1;
cst.current_page = 2; // 切换到电机页面显示
TIM_SetCompare3(TIM3,1000);
Touch_Range(0,0,240,320);
//语言反馈
Audio_PlaySong((u8 *)"0:/voice/开风扇.wav");
break;
case 0x02:
//关闭风扇
cst.motor_state = 0;
cst.current_page = 2; // 切换到电机页面显示
TIM_SetCompare3(TIM3,0);
Touch_Range(0,0,240,320);
//语言反馈
Audio_PlaySong((u8 *)"0:/voice/关风扇.wav");
break;
case 0x10:
//开灯
cst.led_state = 1;
cst.current_page = 1; // 切换到LED页面显示
LED1_ON; LED2_ON; LED3_ON;
Rgb_Control(0xff,0xff,0xff);
Rgb_Control(0xff,0xff,0xff);
Rgb_Control(0xff,0xff,0xff);
Rgb_Control(0xff,0xff,0xff);
Touch_Range(0,0,240,320);
//语言反馈
Audio_PlaySong((u8 *)"0:/voice/开灯.wav");
break;
case 0x11:
//关灯
cst.led_state = 0;
cst.current_page = 1; // 切换到LED页面显示
LED1_OFF; LED2_OFF; LED3_OFF;
Rgb_Control(0x00,0x00,0x00);
Rgb_Control(0x00,0x00,0x00);
Rgb_Control(0x00,0x00,0x00);
Rgb_Control(0x00,0x00,0x00);
Touch_Range(0,0,240,320);
//语言反馈
Audio_PlaySong((u8 *)"0:/voice/关灯.wav");
break;
case 0x07:
//打开空调 开舵机
cst.servo_state = 1;
cst.current_page = 3; // 切换到舵机页面显示
Servo_motor_Control(30);
Touch_Range(0,0,240,320);
//语言反馈
Audio_PlaySong((u8 *)"0:/voice/开舵机.wav");
break;
case 0x08:
//关闭空调 关闭舵机
cst.servo_state = 0;
cst.current_page = 3; // 切换到舵机页面显示
Servo_motor_Control(120);
Touch_Range(0,0,240,320);
//语言反馈
Audio_PlaySong((u8 *)"0:/voice/关舵机.wav");
break;
}
}
}
更多推荐
所有评论(0)