点击上方“嵌入式从0到1”,选择“置顶/星标公众号”
干货福利,第一时间送达!
我们继续在上文口令模式的Demo示例程序基础上,实现本文的目标。
上文链接如下:
语音识别LD3320模块控制LED和舵机
只留五句PrintCom串口输出,对应五个命令:
JSON字符串 | 含义 |
---|---|
{"VoiceCommandCode":0} | 唤醒词 |
{"VoiceCommandCode":1} | 开灯 |
{"VoiceCommandCode":2} | 关灯 |
{"VoiceCommandCode":3} | 开门 |
{"VoiceCommandCode":4} | 关门 |
cJSON相关知识参考阅读:
Keil环境下STM32工程加入cJSON
用cJSON解析心知天气返回的数据包
程序编译没有错误之后,将编译结果下载至LD3320模块中验证程序是否正确。
测试四个口令,查看串口输出的字符串是否符合预期。
由上可以看出,四个指令跟咱们预先设定的值是一致的,将LD3320模块与STM32的串口相连,然后STM32对接收到的串口数据进行解析,进而做不同的动作即可,至此LD3320端的开发完毕。
STC单片机更新程序的方法参考网文:
STC单片机开发环境建立及更新LD3320模块程序
LD3320模块与STM32F103的串口4相连,具体原理图如下图所示:
因为LD3320模块使用的波特率为9600,所以串口4也要初始化为波特率9600,串口初始化调用的代码如下:
uart4_init(9600);
USART4_RX_STA=0;
memset(USART4_RX_BUF, 0, sizeof(USART4_RX_BUF));
串口初始化代码中添加了TIM4的初始化代码,设置的定时器时间为10ms,串口4的初始化详细代码如下:
//初始化串口4
//bound:波特率
void uart4_init(u32 bound){
//GPIO端口设置
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_UART4, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE); //使能USART4,GPIOC时钟
USART_DeInit(UART4); //复位串口4
//USART4_TX PC.10
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10; //PC10
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出
GPIO_Init(GPIOC, &GPIO_InitStructure); //初始化PC10
//USART4_RX PC.11
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入
GPIO_Init(GPIOC, &GPIO_InitStructure); //初始化PC11
//USART 初始化设置
USART_InitStructure.USART_BaudRate = bound;//一般设置为9600;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;//字长为8位数据格式
USART_InitStructure.USART_StopBits = USART_StopBits_1;//一个停止位
USART_InitStructure.USART_Parity = USART_Parity_No;//无奇偶校验位
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//无硬件数据流控制
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; //收发模式
USART_Init(UART4, &USART_InitStructure); //初始化串口
#if EN_USART4_RX //如果使能了接收
//Usart4 NVIC 配置
NVIC_InitStructure.NVIC_IRQChannel = UART4_IRQn; //中断号
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=1 ;//抢占优先级3
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; //子优先级3
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道使能
NVIC_Init(&NVIC_InitStructure); //根据指定的参数初始化VIC寄存器
USART_ITConfig(UART4, USART_IT_RXNE, ENABLE);//开启中断
#endif
USART_Cmd(UART4, ENABLE); //使能串口
TIM4_Int_Init(99,7199); //10ms中断
USART4_RX_STA=0; //清零
TIM_Cmd(TIM4,DISABLE); //关闭定时器4
}
void UART4_IRQHandler(void)
{
u8 res;
if(USART_GetITStatus(UART4, USART_IT_RXNE) != RESET)//接收到数据
{
res =USART_ReceiveData(UART4);
if((USART4_RX_STA&(1<<15))==0)//接收完的一批数据,还没有被处理,则不再接收其他数据
{
if(USART4_RX_STA<USART4_REC_LEN) //还可以接收数据
{
TIM_SetCounter(TIM4,0); //计数器清空 //计数器清空
if(USART4_RX_STA==0) //使能定时器4的中断
{
TIM_Cmd(TIM4,ENABLE); //使能定时器4
}
USART4_RX_BUF[USART4_RX_STA++]=res; //记录接收到的值
}
else
{
USART4_RX_STA|=1<<15; //强制标记接收完成
}
}
}
}
从接收到第一个字符开始启动定时器,当收到一个新字符的时候,计数器清空,直到定时器中断产生时,即计时到10ms时间之后,如果不再收到新的串口数据,证明一个完整的数据包接收完毕,在TIM4的中断函数中,对串口4是否接收完成数据的变量USART4_RX_STA进行标记,代表数据接收完毕。
//定时器4中断服务程序
void TIM4_IRQHandler(void)
{
if (TIM_GetITStatus(TIM4, TIM_IT_Update) != RESET)//是更新中断
{
USART4_RX_STA|=1<<15; //标记接收完成
TIM_ClearITPendingBit(TIM4, TIM_IT_Update ); //清除TIM4更新中断标志
TIM_Cmd(TIM4, DISABLE); //关闭TIM4
}
}
//LD3320
if(USART4_RX_STA&0x8000)
{
uart4Len=USART4_RX_STA&0x3f; //得到此次接收到的数据长度
receive_json = cJSON_Parse(USART4_RX_BUF); //创建JSON解析对象,返回JSON格式是否正确
if (!receive_json)
{
printf("JSON格式错误:%s \r\n", cJSON_GetErrorPtr()); //输出json格式错误信息
}
else
{
item_obj = receive_json->child;
while(item_obj)
{
char * string = item_obj->string;
if(!strcmp(string,"VoiceCommandCode"))
{
if(item_obj->valueint==0)
{
printf("收到一级口令 小哈 ... \r\n");
}
else if(item_obj->valueint==1)
{
printf("“开灯”命令识别成功 \r\n");
RelayControl(1);
}
else if(item_obj->valueint==2)
{
printf("“关灯”命令识别成功\r\n");
RelayControl(0);
}
else if(item_obj->valueint==3)
{
printf("“开门”命令识别成功\r\n");
}
else if(item_obj->valueint==4)
{
printf("“关门”命令识别成功\r\n");
}
}
item_obj = item_obj->next;
}
}
cJSON_Delete(receive_json);
USART4_RX_STA=0;
memset(USART4_RX_BUF, 0, sizeof(USART4_RX_BUF)); //清空数组
}
本文实现的方法和使用LD3320直接控制设备的方法相比,利用串口使STM32和LD3320模块进行数据通信的优势是:传统设备,只需要预留一个串口,就可以为传统设备添加语音控制功能。主控制板无需大的改动即可升级完毕,而且这种方式更灵活,也可以将项目转移到自己熟悉的领域(假如不熟悉STC单片机,熟悉STM32的话),降低了开发难度。
留言区置顶留言获取本文相关代码。