前言:这部分是对于语音模块的输入识别,根据模块的不同,但是基本的识别逻辑大同小异。无非是对于识别的结果通过串口发送给单板进行接收处理,当然识别成功后发出的结果通过处理,都会有相对应执行程序,语音模块发出的字符数据可以自行指定。当然可以是数字,也可以是一串字符。
语音模块需要用到串口编程,因此抽象出的结构体如下:
struct InputCommander voiceCol ={
.comName = "voice",
.devName = "/dev/ttyS5",
.command = {'\0'},
.fd = 0,
.init = voiceColInit,
.getCommand = voiceColGetCom,
.log = {'\0'},
.next = NULL
};
对于wiringpi库的串口编程,需要用到串口对应的设备节点文件,因此在结构体中申明。
对于链表需要在对应的设备输入链表中添加,具体函数详见附加页。
字符串成员当中需要用到的函数是init函数,就是对串口的初始化操作如下:
int voiceColInit(struct InputCommander* voiceCol, char *ipAdress, char* port)
{
int fd;
if((fd = serialOpen(voiceCol->devName, 9600)) < 0){
perror("Serial:why");
}else{
printf("SerialOpen success\n");
voiceCol->fd = fd;
}
return fd;
}
对于指令的获取,采用read()函数进行循环读取:
int voiceColGetCom(struct InputCommander* voiceCol)
{
int n_read = 0;
char str_data;
char* p = voiceCol->command;
while(read(voiceCol->fd, &str_data, 1) == 1)
{
if(str_data == '\n') break;
*p = str_data;
p++;
n_read++;
}
return n_read;
}
对于语音模块,我也会单独开一个线程,线程的开辟不作解释了,执行函数如下:
void* voiceHandler(void* datas)
{
int nread;
int i = 0;
int err = 0;
int n_read = 0;
voiceStr = findInputName("voice",pheadCom);
if(voiceStr == NULL){
printf("03:voice par not found\n");
pthread_exit(NULL);
}
else
{
printf("03:voice par found success\n");
if((voiceStr->init(voiceStr, NULL, NULL)) < 0){
pthread_exit(NULL);
}else{
printf("03:Init Voice Handler success\n");
}
}
while(1){
while(serialDataAvail(voiceStr->fd) >= 1)
{
pthread_mutex_lock(&mutex);
memset(voiceStr->command, '\0', sizeof(voiceStr->command));
n_read = voiceStr->getCommand(voiceStr);
if(nread > 0)
{
voicLitCrl(voiceStr->command);
}
pthread_mutex_unlock(&mutex);
sleep(1);
}
}
}
由于我的语音模块采用指令模式,需要进行一次唤醒后,再次进行识别成功后则执行相应的控制操作。因此我会对这一部分进行“上锁”,防止识别过程中出现资源的争夺。voicLitCrl() 函数跟socket编程当中的socketLitCol()函数的处理是相似的,后续放到补充部分讲解。
注意:串口编程对于不同的平台,不同的接收策略会有不同的结果,因此当发现接收到的数据出错时,最好先进行单线程,或者不使用线程进行调试,配合串口助手,进行调试。
总结:语音模块的操作主要还是串口,对于串口的调试可以配合串口助手,先保证语音识别可行,打印出接收到的数据是确定的,随后进行比较处理即可。