智能桌面天气预报系统(终)
常持正念方圆梦;不忘初心总是春。
前言
这是关于这个智能天气预报系统的最后一篇分享啦。本系统源码下载链接见文末
本系统人机对话功能采用了两个硬件模块:(1)语音识别模块:采用LD3320语音识别芯片;(2)语音合成模块:采用SYN6288语音合成芯片。
语音识别模块
本系统语音识别模块采用的语音芯片是LD3320。该芯片已经集成了语音识别的处理器,不需要外接其他的辅助芯片如Flash、 RAM 等,直接嵌入在现有的产品中就可以实现语音识别的功能。
语音识别的过程为:
(1)先预存要识别的关键词,如:
//-------------------------搜索天气-----------------------------------
#define STR00 "xiao tian" // 小天
#define STR01 "sou suo fu zhou tian qi" // 搜索福州天气
#define STR02 "sou suo shang hai tian qi" // 搜索上海天气
#define STR03 "sou suo shen zhen tian qi" // 搜索深圳天气
#define STR04 "sou suo bei jing tian qi" // 搜索北京天气
#define STR05 "sou suo guang zhou tian qi" // 搜索广州天气
#define STR06 "sou suo nan ning tian qi" // 搜索南宁天气
#define STR07 "sou suo xia men tian qi" // 搜索厦门天气
#define STR08 "sou suo quan zhou tian qi" // 搜索泉州天气
#define STR09 "sou suo pu tian tian qi" // 搜索莆田天气
#define STR10 "sou suo nan ping tian qi" // 搜索南平天气
可以预存50条关键词(关键句),小编已经把关键词写死在程序里了,这显然就不能灵活的面对各种场景。其实可以通过代码编写一个学习功能,即识别之前首先进行学习一些即将要识别的关键词,然后在进行识别演示,这样就可以应对比较多的场景。
但是,这样还是不够智能,毕竟只能识别已经预存的关键词(关键句),要是没有预存就没办法识别了。所以真正的语音识别应该是在软件算法上下功夫,关于语音识别已然成为热门的一大研究专题,这属于人工智能的范畴。
人工智能相关资源
(2)开始识别,如:
static void Task_ASR(void)
{
switch(nAsrStatus)
{
case LD_ASR_RUNING:
case LD_ASR_ERROR:
break;
case LD_ASR_NONE:
nAsrStatus=LD_ASR_RUNING;
if (RunASR()==0) // 启动一次ASR识别流程:ASR初始化,ASR添加关键词语,启动ASR运算
{
nAsrStatus = LD_ASR_ERROR;
}
break;
case LD_ASR_FOUNDOK:
nAsrRes = LD_GetResult( ); // 一次ASR识别流程结束,去取ASR识别结果
ASRSuccess_Handle(nAsrRes);
nAsrStatus = LD_ASR_NONE;
break;
case LD_ASR_FOUNDZERO:
default:
nAsrStatus = LD_ASR_NONE;
break;
}
}
nAsrStatus是用来表示语音识别的状态,不是LD3320芯片内部的状态寄存器。nAsrStatus有几种情况。我们比较关注的是LD_ASR_FOUNDOK状态。LD_ASR_FOUNDOK状态为识别成功,识别成功后将调用“ASRSuccess_Handle”函数进行识别后的操作。
(3)识别成功则执行相应操作,如
void ASRSuccess_Handle(uint8 asr_code)
{
printf("\r\n识别码:%d\n",asr_code);
if(0 == asr_code)
{
printf("我在,需要我的帮助吗?\n");
TTSPlay(0, "[t3][2]我在,[2]需要[2]我的[3]帮助吗");
RunFlag = TRUE;
}
else if(RunFlag)
{
RunFlag = FALSE;
/* 识别码0-10为搜索天气识别码 */
if(asr_code>=0&&asr_code<=10)
{
switch(asr_code)
{
case CODE01:
printf("“福州”命令识别成功\r\n");
TTSPlay(0, "[t3][2]小天正在为您搜索福州天气");
memcpy(g_city,"fujianfuzhou",sizeof(g_place));
break;
case CODE02:
printf("“上海”命令识别成功\r\n");
TTSPlay(0, "[t3][2]小天正在为您搜索上海天气");
memcpy(g_city,"shanghai",sizeof(g_place));
break;
case CODE03:
printf("“深圳”命令识别成功\r\n");
TTSPlay(0, "[t3][2]小天正在为您搜索深圳天气");
memcpy(g_city,"shenzhen",sizeof(g_place));
break;
case CODE04:
printf("“北京”命令识别成功\r\n");
TTSPlay(0, "[t3][2]小天正在为您搜索北京天气");
memcpy(g_city,"beijing",sizeof(g_place));
break;
case CODE05:
printf("“广州”命令识别成功\r\n");
TTSPlay(0, "[t3][2]小天正在为您搜索广州天气");
memcpy(g_city,"guangzhou",sizeof(g_place));
break;
case CODE06:
printf("“南宁”命令识别成功\r\n");
TTSPlay(0, "[t3][2]小天正在为您搜索南宁天气");
memcpy(g_city,"nanning",sizeof(g_place));
break;
case CODE07:
printf("“厦门”命令识别成功\r\n");
TTSPlay(0, "[t3][2]小天正在为您搜索厦门天气");
memcpy(g_city,"xiamen",sizeof(g_place));
break;
case CODE08:
printf("“泉州”命令识别成功\r\n");
TTSPlay(0, "[t3][2]小天正在为您搜索泉州天气");
memcpy(g_city,"quanzhou",sizeof(g_place));
break;
case CODE09:
printf("“莆田”命令识别成功\r\n");
TTSPlay(0, "[t3][2]小天正在为您搜索莆田天气");
memcpy(g_city,"putian",sizeof(g_place));
break;
case CODE10:
printf("“南平”命令识别成功\r\n");
TTSPlay(0, "[t3][2]小天正在为您搜索南平天气");
memcpy(g_city,"nanping",sizeof(g_place));
break;
}
memset(&weather_data, 0, sizeof(weather_data));
GET_NowWeather();
GET_DailyWeather();
GetWeatherTimer = TIMER1_HOUR;
DisplayWeather(weather_data);
DisplayWeatherIcon(weather_data);
}
else
{
switch(asr_code)
{
case CODE11:
printf("“语音播报天气”命令识别成功\r\n");
printf("%s\n",g_WeatherText);
// TTSPlay(0, (uint8_t*)g_WeatherText);
break;
case CODE12:
printf("“今天的气温是多少”命令识别成功\r\n");
break;
default:
TTSPlay(0, "语音识别失败,请对准麦克风说话!");
break;
}
}
}
}
设计识别码0为一级指令码,当一级指令码识别成功后,才能进行二级指令地识别。语音识别成功后,会调用“TTSPlay”函数播报所设定的语音,这样每一次地识别与播报就可以达到了一种人机互动的效果。
语音合成模块
本系统的语音合成模块采用SYN6288语音合成芯片,支持文本直接转化为语音。其与单片机的通信方式为串口通信。向该模块发送以下格式的数据包:
5字节帧头+文本+1字节校验,文本字节数小于等于200字节
即可合成语音。代码如:
void TTSPlay(uint8_t Music,uint8_t *Text)
{
/****************需要发送的文本**********************************/
uint8_t DataPacket[50]; //
uint8_t Text_Len;
uint8_t ecc = 0; //定义校验字节
uint8_t i=0;
Text_Len =strlen((const char*)Text); //需要发送文本的长度
/*****************帧固定配置信息**************************************/
DataPacket[0] = 0xFD ; //构造帧头FD
DataPacket[1] = 0x00 ; //构造数据区长度的高字节
DataPacket[2] = Text_Len + 3; //构造数据区长度的低字节
DataPacket[3] = 0x01 ; //构造命令字:合成播放命令
DataPacket[4] = 0x01 | Music<<4 ; //构造命令参数:背景音乐设定
/*******************校验码计算***************************************/
for(i = 0; i<5; i++) //依次发送构造好的5个帧头字节
{
ecc=ecc^(DataPacket[i]); //对发送的字节进行异或校验
}
for(i= 0; i<Text_Len; i++) //依次发送待合成的文本数据
{
ecc=ecc^(Text[i]); //对发送的字节进行异或校验
}
/*******************发送帧信息***************************************/
memcpy(&DataPacket[5], Text, Text_Len);
DataPacket[5+Text_Len]=ecc;
UART4_SendStr((char*)DataPacket,5+Text_Len+1);
}
调用方式如:
TTSPlay(0, "[t3][2]小天正在为您搜索福州天气");