文章目录
- 串口通信线程控制代码
- mianPro.c
- inputCommand.h
- voiceControl.c
- 测试结果
- 语音控制部分
- 语言控制模块YS-LDV7
若要完成串口之间的通信,需要再树莓派上完成配置文件的修改,利用测试代码验证串口收发功能是否正常,详情可以参考博文:树莓派——wiringPi库详解的串口通信API章节
串口通信线程控制代码
语音控制线程:
- 找到语音控制结构体
- 完成语音控制初始化
- 在循环中调用getCommand函数获取串口发送过来的数据
- 拿到串口发送过来的数据后调用比较函数进行比较
- 比较函数中通过指令控制设备的开与关
mianPro.c
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include "controlDevice.h"
#include "inputCommand.h"#include <pthread.h>//线程之间的通信一般采用全局变量
struct Devices *pdeviceHead = NULL;//定义设备工厂初始链表头
struct InputCommander *pcommandHead = NULL;//定义指令工厂初始链表头struct Devices* findDeviceByName(char *name, struct Devices *phead){ struct Devices *tmp =phead; if(phead == NULL){ return NULL; }else{ while(tmp != NULL){ if(strcmp(tmp->deviceName,name)==0){ return tmp; } tmp = tmp->next; } return NULL; }
}struct InputCommander* findCommandByName(char *name, struct InputCommander *phead){ struct InputCommander *tmp =phead; if(phead == NULL){ return NULL; }else{ while(tmp != NULL){ if(strcmp(tmp->commandName,name)==0){ return tmp; } tmp = tmp->next; } return NULL; }
}//调用语音处理函数
void Command(struct InputCommander *CmdHandler){struct Devices *tmp =NULL;//- 控制某个引脚的电平前需要初始化,可以通过指令进行初始化if(strcmp("CSHALL",CmdHandler->command )==0){tmp = findDeviceByName("smokeAlarm",pdeviceHead);if(tmp!=NULL)tmp->Init(tmp->pinNum);tmp = findDeviceByName("buzzer",pdeviceHead);if(tmp!=NULL)tmp->Init(tmp->pinNum);tmp = findDeviceByName("livingroomLight",pdeviceHead);if(tmp!=NULL)tmp->Init(tmp->pinNum);tmp = findDeviceByName("restaurantLight",pdeviceHead);if(tmp!=NULL)tmp->Init(tmp->pinNum);tmp = findDeviceByName("bedroomLight",pdeviceHead);if(tmp!=NULL)tmp->Init(tmp->pinNum);tmp = findDeviceByName("bathroomLight",pdeviceHead);if(tmp!=NULL)tmp->Init(tmp->pinNum);printf("设备已全部初始化\n");}if(strcmp("OL1",CmdHandler->command) == 0){ tmp = findDeviceByName("livingroomLight",pdeviceHead); if(tmp != NULL){ tmp->open(tmp->pinNum); printf("已打开客厅灯\n"); } } if(strcmp("CL1",CmdHandler->command) == 0){ tmp = findDeviceByName("livingroomLight",pdeviceHead); if(tmp != NULL){ tmp->close(tmp->pinNum); printf("已关闭客厅灯\n"); } } if(strcmp("OL2",CmdHandler->command) == 0){ tmp = findDeviceByName("restaurantLight",pdeviceHead); if(tmp != NULL){ tmp->open(tmp->pinNum); printf("已打开餐厅灯\n"); }} if(strcmp("CL2",CmdHandler->command) == 0){ tmp = findDeviceByName("restaurantLight",pdeviceHead); if(tmp != NULL){ tmp->close(tmp->pinNum); printf("已关闭餐厅灯\n"); } } if(strcmp("OL3",CmdHandler->command) == 0){ tmp = findDeviceByName("bedroomLight",pdeviceHead); if(tmp != NULL){ tmp->open(tmp->pinNum); printf("已打开卧室灯\n"); } } if(strcmp("CL3",CmdHandler->command) == 0){ tmp = findDeviceByName("bedroomLight",pdeviceHead); if(tmp != NULL){ tmp->close(tmp->pinNum); printf("已关闭卧室灯\n"); }} if(strcmp("OL4",CmdHandler->command) == 0){ tmp = findDeviceByName("bathroomLight",pdeviceHead); if(tmp != NULL){ tmp->open(tmp->pinNum); printf("已打开浴室灯\n"); } } if(strcmp("CL4",CmdHandler->command) == 0){ tmp = findDeviceByName("bathroomLight",pdeviceHead); if(tmp != NULL){ tmp->close(tmp->pinNum); printf("已关闭浴室灯\n"); } }if(strcmp("OLALL",CmdHandler->command) == 0){ tmp = findDeviceByName("livingroomLight",pdeviceHead); if(tmp != NULL) tmp->open(tmp->pinNum); tmp = findDeviceByName("restaurantLight",pdeviceHead); if(tmp != NULL) tmp->open(tmp->pinNum); tmp = findDeviceByName("bedroomLight",pdeviceHead); if(tmp != NULL) tmp->open(tmp->pinNum); tmp = findDeviceByName("bathroomLight",pdeviceHead); if(tmp != NULL) tmp->open(tmp->pinNum); printf("已打开所有灯\n"); } if(strcmp("CLALL",CmdHandler->command) == 0){ tmp = findDeviceByName("livingroomLight",pdeviceHead); if(tmp != NULL) tmp->close(tmp->pinNum); tmp = findDeviceByName("restaurantLight",pdeviceHead); if(tmp != NULL) tmp->close(tmp->pinNum); tmp = findDeviceByName("bedroomLight",pdeviceHead); if(tmp != NULL) tmp->close(tmp->pinNum); tmp = findDeviceByName("bathroomLight",pdeviceHead); if(tmp != NULL) tmp->close(tmp->pinNum); printf("已关闭所有灯\n"); }
}void *voiceControlThread(void *arg){int nread;struct InputCommander *voiceHandler = NULL;voiceHandler = findCommandByName("voice", pcommandHead);if(voiceHandler == NULL){printf("find voiceHandler error\n");pthread_exit(NULL);}else{if(voiceHandler->Init(voiceHandler)<0){printf("voiceControl init error\n");pthread_exit(NULL);}else{printf("voiceControl init success\n"); }while(1){memset(voiceHandler->command,'\0',sizeof(voiceHandler->command)); nread = voiceHandler->getCommand(voiceHandler);if(nread <= 0){printf("No voiceCommand received\n");}else{printf("Get VoiceCommand -->%s\n",voiceHandler->command);//调用语音处理函数,参数是结构体指针,调试的时候可以先注释掉//Command(voiceHandler);}}}}int main()
{if (wiringPiSetup () == -1) { fprintf (stdout, "Unable to start wiringPi: %s\n", strerror (errno)) ; return 1 ; }//线程的IDpthread_t voice_thread;//设备工厂初始化 pdeviceHead = addBathroomLightToDeviceLink(pdeviceHead); pdeviceHead = addBedroomLightToDeviceLink(pdeviceHead);pdeviceHead = addRestaurantLightToDeviceLink(pdeviceHead);pdeviceHead = addLivingroomLightToDeviceLink(pdeviceHead);pdeviceHead = addSmokeAlarmToDeviceLink(pdeviceHead);pdeviceHead = addBuzzerToDeviceLink(pdeviceHead);//指令工厂初始化pcommandHead = addVoiceControlToInputCommandLink(pcommandHead);//创建声音控制线程pthread_create(&voice_thread, NULL, voiceControlThread, NULL); //等待线程结束pthread_join(voice_thread, NULL); return 0;
}
inputCommand.h
#include <wiringPi.h>
#include <stdio.h>
#include <stdlib.h>
#include <wiringSerial.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <arpa/inet.h>struct InputCommander{char commandName[128];char deviceName[128]; char command[32];int fd; //存放文件描述符(串口/网络),后续socket会有两个文件描述符,将accept返回的文件描述符赋值给fdint s_fd; //socket网络套接字char port[12]; //端口号char ipAdress[32]; //ip地址int (*Init)(struct InputCommander *voiceControl); int (*getCommand)(struct InputCommander *voiceControl);char log[1024];struct InputCommander *next;};struct InputCommander* addVoiceControlToInputCommandLink(struct InputCommander *phead);
voiceControl.c
#include "inputCommand.h" int voiceGetCommand(struct InputCommander *voice){int nread = 0;nread = read(voice->fd, voice->command, sizeof(voice->command));return nread;
}int voiceInit(struct InputCommander *voiceControl){int fd;fd = serialOpen(voiceControl->deviceName,9600);if(fd <0){fprintf (stderr, "Unable to open serial device: %s\n", strerror (errno)) ; return 1 ;}voiceControl->fd = fd;return fd;}struct InputCommander voiceControl = { .commandName = "voice", .deviceName="/dev/ttyAMA0",.command={'\0'},//字符串置空.Init=voiceInit,.getCommand=voiceGetCommand,.log = {'\0'},.next = NULL
};struct InputCommander* addVoiceControlToInputCommandLink(struct InputCommander *phead)
{if(phead == NULL){return &voiceControl;}else{voiceControl.next = phead;phead = &voiceControl;return phead;}
}
测试结果
- 十秒未发送数据会返回No voiceCommand received
- 成功接收串口发送数据
- 结构体对象:
- 创建对象其实就是定义变量,要理解需要的变量有哪些
- 这些变量既可以用来识别区分不同的对象
- 也可以用来存储信息,作为参数在多线程之间传递
- 完成功能的初始化
注意:
- 指针取成员用->
- 对象取成员用.
- 控制某个引脚的电平前需要初始化,可以通过指令进行初始化,见command函数
- 线程里面是不允许return,用pthread_exit(NULL)退出
- 在该项目中,定义一个指向voicecontrol文件的结构体指针(全局变量),目的为了存储用户输入的命令在command里面,便于在比较函数中进行使用
- 若要让主程序不退出,可以不使用while而是采用pthread_join去阻塞等待线程的退出
- wiringPi库的串口的读取会阻塞,每个一段时间会返回一个值,通过该值我们可以在main文件里面打印超时字段展示
- 踩坑:串口打开不要遗漏了开头的斜杠 /dev/ttyAMA0
语音控制部分
语言控制模块YS-LDV7
添加关键词和识别码
- 语音模块开发——YS-LDV7 语音识别模块