若要完成串口之间的通信,需要再树莓派上完成配置文件的修改,利用测试代码验证串口收发功能是否正常,详情可以参考博文:树莓派——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 ;
}
//线程的ID
pthread_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返回的文件描述符赋值给fd
int 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
添加关键词和识别码