智能家居 —— 串口通信(语音识别)线程控制

若要完成串口之间的通信,需要再树莓派上完成配置文件的修改,利用测试代码验证串口收发功能是否正常,详情可以参考博文:树莓派——wiringPi库详解的串口通信API章节

串口通信线程控制代码

语音控制线程:

  1. 找到语音控制结构体
  2. 完成语音控制初始化
  3. 在循环中调用getCommand函数获取串口发送过来的数据
  4. 拿到串口发送过来的数据后调用比较函数进行比较
  5. 比较函数中通过指令控制设备的开与关

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

添加关键词和识别码

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值