智能家居1 -- 实现语音模块

项目整体框架: 

监听线程×4:

1. 语音监听线程:用于监听语音指令, 当有语音指令过来后, 通过消息队列的方式给消息处理线程发送指令

2. 网络监听线程:用于监听网络指令,当有网络指令过来后, 通过消息队列的方式给消息处理线程发送指令

3. 火灾检测线程:当存在煤气泄漏或者火灾闲情时, 发送警报指令给消息处理线程

4. 消息监听线程: 用于处理以上3个线程发过来的指令,并根据指令要求配置GPIO引脚状态,OLED屏显示、语音播报,还有人脸识别开门

统一的监听模块接口 -- control:

上述四个线程采用统一个对外接口接口,同时添加到监听链表中

统一的监听模块接口如下:

struct control
{
char control_name[128]; //监听模块名称
int (*init)(void); //初始化函数
void (*final)(void);//结束释放函数
void *(*get)(void *arg);//监听函数,如语音监听
void *(*set)(void *arg); //设置函数,如语音播报
struct control *next;
};

//定义类似如下函数向这个统一的接口中添加

struct control *add_device_to_ctrl_list(struct control *phead, struct control *device);

统一的设备类接口

被控制的设备类也统一配置接口,同时添加到设备链表中。

统一的设备类接口如下:


 

struct gdevice
{
char dev_name[128]; //设备名称
int key; //key值,用于匹配控制指令的值
int gpio_pin; //控制的gpio引脚
int gpio_mode; //输入输出模式
int gpio_status; //高低电平状态
int check_face_status; //是否进行人脸检测状态
int voice_set_status; //是否语音语音播报
struct gdevice *next;
};

主要代码: 


-------------------------------------------

Makefile

CC  :=  aarch64-linux-gnu-gcc
# SRC -- 存放所有的 .c 文件
SRC :=  $(shell find src -name "*.c")
# INC --  存放所有的 头文件 (包括自己写的 和 第三方)
INC := ./inc \./3rd/usr/local/include \./3rd/usr/include \./3rd/usr/include/python3.10 \./3rd/usr/include/aarch64-linux-gnu/python3.10 \./3rd/usr/include/aarch64-linux-gnu#  把需要包含的 .c 文件,替换为.o 文件
OBJ := $(subst src/,obj/,$(SRC:.c=.o))#  创建目标 , 并且指定存放位置
TARGET  =  obj/smarthome#   -I./inc  -- 存放头文件路径
CFLAGS := $(foreach item,$(INC),-I$(item))# -I 指定的 第三方 库文件路径
LIBS_PATH := ./3rd/usr/local/lib \./3rd/lib/aarch64-linux-gnu \./3rd/usr/lib/aarch64-linux-gnu \./3rd/usr/lib/python3.10 \# -L ./3rd/usr/local/LIBS
LDFLAGS := $(foreach item,$(LIBS_PATH),-L$(item))#  指定我们要链接的库
LIBS := -lwiringPi -lpython3.10 -pthread -lexpat -lz -lcrypt #  生成obj文件夹,里面包含源文件对应的.o文件
obj/%.o:src/%.cmkdir -p obj$(CC) -o $@ -c $< $(CFLAGS)#  一来obj 下面的.o文件 编译
$(TARGET) : $(OBJ)$(CC) -o $@ $^ $(CFLAGS) $(LDFLAGS)    $(LIBS)compile : $(TARGET)clean: rm $(TARGET) obj &(OBJ) -rfdebug:echo $(CC) echo $(SRC)echo $(INC)echo $(OBJ)echo $(TARGET)echo $(CFLAGS)echo $(LDFLAGS)echo $(LIBS).PHONY: clean compile debug 


============================

main.c 

#include <stdio.h>
#include <pthread.h>
#include <stdlib.h>#include "control.h"
#include "mq_queue.h"
#include "voice_interface.h"
#include "global.h"// msg_queue_createint main() {pthread_t thread_id;struct control *control_phead = NULL;struct control *pointer = NULL;ctrl_info_t *ctrl_info = NULL;ctrl_info = (ctrl_info_t *)malloc(sizeof(ctrl_info_t));ctrl_info->ctrl_phead = NULL;ctrl_info->mqd = -1;int node_num = 0; // 统计节点数// 创建消息队列ctrl_info->mqd = msg_queue_create();if(-1 == ctrl_info->mqd)// 创建消息队列失败{printf("%s|%s|%d, mqd= %d\n",__FILE__,__func__,__LINE__,ctrl_info->mqd);return -1;}ctrl_info->ctrl_phead = add_voice_to_ctrl_list(ctrl_info->ctrl_phead);//ctrl_info->ctrl_phead = add_socket_to_ctrl_list(ctrl_info->ctrl_phead);//ctrl_info->ctrl_phead = add_fire_to_ctrl_list(ctrl_info->ctrl_phead);pointer = ctrl_info->ctrl_phead;while(NULL!=pointer) // 对所有控制结构体初始化,并且统计节点数{if(NULL != pointer->init){pointer->init();}pointer = pointer->next;node_num++; // 统计节点数}// 根据节点的总数 --> 创建对应数目的线程pthread_t *tid = (pthread_t *)malloc(sizeof(int) *node_num);pointer = ctrl_info->ctrl_phead;for(int i=0;i<node_num;++i){if(NULL != pointer->get)pthread_create(&tid[i],NULL,(void *)pointer->get,(void *)ctrl_info); // 传入这个结构体参数,方便同时调用多组线程里面的API}for(int i=0;i<node_num;++i){pthread_join(tid[i],NULL);}for(int i=0;i<node_num;++i){if(NULL != pointer->final)pointer->final(); // 接打开的使用接口关闭pointer = pointer->next;}msq_queue_final(ctrl_info->mqd);}

实现语言控制模块-- voice_interface.c


#if 0
struct control
{
char control_name[128]; //监听模块名称
int (*init)(void); //初始化函数
void (*final)(void);//结束释放函数
void *(*get)(void *arg);//监听函数,如语音监听
void *(*set)(void *arg); //设置函数,如语音播报
struct control *next;
};
#endif#include <pthread.h>
#include <stdio.h>
#include "voice_interface.h"
#include "mq_queue.h"
#include "uartTool.h"
#include "global.h"static int serial_fd = -1; // static 这个 变量只在当前文件有效static int voice_init(void )
{serial_fd = myserialOpen(SERIAL_DEV,BAUD); // 初始化并且打开串口printf("%s|%s|%d   serial_fd = %d\n",__FILE__,__func__,__LINE__,serial_fd);return serial_fd;
}static void voice_final(void)
{if(-1 != serial_fd) // 打开串口成功{close(serial_fd); // 关闭我们打开的串口serial_fd = -1; // 复位}
}
// 接收语言指令
static void* voice_get(void *arg)// mqd 通过arg 传参获得
{int len = 0;mqd_t mqd = -1;ctrl_info_t * ctrl_info = NULL; if(NULL != arg)ctrl_info = (ctrl_info_t*)arg;unsigned char buffer[6] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; // 初始化 bufferif (-1 == serial_fd){//打开串口serial_fd = voice_init();// 尝试打开串口if (-1 == serial_fd){ //还是打开失败printf("%s | %s | %d:open serial failed\n", __FILE__, __func__, __LINE__); // 三个宏的含义: 文件名 - main.c,函数名 - pget_voice ,行号 -  138pthread_exit(0);   }                                                        // 串口打开失败 -->退出}mqd = ctrl_info->mqd; //为实现if((mqd_t)-1 == mqd){pthread_exit(0);  }pthread_detach(pthread_self());// 与父线程分离printf("%s thread start\n",__func__);while (1){len = serialGetstring(serial_fd, buffer); // 通过串口获得语言输入printf("%s|%s|%d,  0x%x,0x%x,0x%x,0x%x,0x%x,0x%x\n",__FILE__,__func__,__LINE__,buffer[0],buffer[1],buffer[2],buffer[3],buffer[4],buffer[5]);printf("%s|%s|%d:len = %d\n",__FILE__,__func__,__LINE__,len);if (len > 0)         // 判断是否 接到识别指令{if(buffer[0] == 0xAA && buffer[1] == 0x55 &&buffer[4]==0x55 && buffer[5]==0xAA){printf("%s|%s|%d, send: 0x%x,0x%x,0x%x,0x%x,0x%x,0x%x\n",__FILE__,__func__,__LINE__,buffer[0],buffer[1],buffer[2],buffer[3],buffer[4],buffer[5]);send_msg(mqd,buffer,len); // 注意获取len长度不能使用strlen() --> 0x00 会识别为截止位-->只能读取到三个字节(但不是我们实际的截止位(0x55 0xAA ))}memset(buffer,0,sizeof(buffer)); // 复位buffer}}pthread_exit(0);}static void* voice_set(void *arg)
{}struct  control voice_control ={.control_name = "voice",.init = voice_init,.final = voice_final,.get = voice_get,.set = voice_set,.next = NULL
};struct control *add_voice_to_ctrl_list(struct control *phead)
{//头插法实现 添加链表节点struct control *pnew = NULL;if(NULL == phead){phead = &voice_control; // 直接传入我们的 voice_control}else// 头结点非空 - 链表有数据{voice_control.next = phead; //把新的节点的next指向头结点voice_control = *phead; // 让心节点成为头结点}return phead;};

编译: 

// 注意我们的Makefile 里面指定了使用交叉编译工具链:  aarch64-linux-gnu-gcc

所以我们生成的文件在×86上是没法运行的,需要scp 传送到arm-64的系统上,

比如我们的orangepi02

编译命令: 

make complie

或者

make

传送


scp obj/smarthome  orangepi@192.168.1.11:/home/orangepi

切换到我们的香橙派上: 

执行

sudo -E ./smarthome

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/671052.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

存储故障后oracle报—ORA-01122/ORA-01207故障处理---惜分飞

客户存储异常,通过硬件恢复解决存储故障之后,oracle数据库无法正常启动(存储cache丢失),尝试recover数据库报ORA-00283 ORA-01122 ORA-01110 ORA-01207错误 以前处理过比较类似的存储故障case:又一起存储故障导致ORA-00333 ORA-00312恢复存储故障,强制拉库报ORA-600 kcbzib_kcr…

分析:Palo Alto在从SASE向SASO演进中定位不佳

摘要 我们通过上一篇文章&#xff08;Fortinet的愿景——超越SASE&#xff09;中应用于Fortinet的相同框架来回顾Palo Alto Network在网络和网络安全方面的前景。 SASE涉及数据传输的第一英里。不过&#xff0c;随着SASE的发展&#xff0c;投资者还需要考虑中间和最后一英里。…

工业物联网技术在生产流程中的应用及优势与挑战——青创智通

工业物联网解决方案-工业IOT-青创智通 随着科技的不断发展&#xff0c;物联网技术逐渐渗透到各个行业中&#xff0c;尤其是在工业领域&#xff0c;工业物联网的应用正在逐步重塑生产流程。本文将探讨工业物联网如何影响生产流程&#xff0c;并分析其带来的优势和挑战。 一、工…

人工智能概述与入门基础简述

人工智能&#xff08;AI&#xff09;是计算机科学的一个分支&#xff0c;它致力于创建能够执行通常需要人类智能的任务的机器。这篇科普文章将全面介绍人工智能的基本概念、发展历程、主要技术、实际应用以及如何入门这一领域。 一、人工智能的定义与发展历程 人工智能的概念…

[Java EE] 多线程(八):CAS问题与JUC包

&#x1f338;个人主页:https://blog.csdn.net/2301_80050796?spm1000.2115.3001.5343 &#x1f3f5;️热门专栏:&#x1f355; Collection与数据结构 (90平均质量分)https://blog.csdn.net/2301_80050796/category_12621348.html?spm1001.2014.3001.5482 &#x1f9c0;Java …

本机MySQL数据库服务启动了,但是cmd登录不上10061

注意&#xff1a;不建议安装MySQL8&#xff0c;建议直接使用phpstudy中自带的MySQL5.7 错误信息 ERROR 2003 (HY000): Cant connect to MySQL server on x.x.x.x (10061) 原因 可能是端口号错误。比如修改了my.ini中&#xff0c;或者phpstudy中数据库端口的配置&#xff0c;…

网络安全的重要性及人才需求

安全现在是大趋势&#xff0c;说是铁饭碗也不为过&#xff0c;就业前景好&#xff0c;方向多比传统计算机行业就业舒服点。但是大厂依然是985&#xff0c;211的天下&#xff0c;是双非能进大厂的&#xff0c;只是凤毛麟角。前提是你的能力可以让公司忽略你的学历。 以2023年为…

笔记86:关于【#ifndef + #define + #endif】的用法

当你在编写一个头文件&#xff08;例如 pid_controller.h&#xff09;时&#xff0c;你可能会在多个源文件中包含它&#xff0c;以便在这些源文件中使用该头文件定义的函数、类或其他声明。如果你在多个源文件中都包含了同一个头文件&#xff0c;那么当你将整个工程统一编译&am…

Unity类银河恶魔城学习记录 17-1,2 p166 Aliments fx p167 Blackhole additional vfx

Alex教程每一P的教程原代码加上我自己的理解初步理解写的注释&#xff0c;可供学习Alex教程的人参考 此代码仅为较上一P有所改变的代码 【Unity教程】从0编程制作类银河恶魔城游戏_哔哩哔哩_bilibili Entity.cs using System.Collections; using System.Collections.Generic; …

【爬虫】爬取A股数据写入数据库(一)

1. 对东方财富官网的分析 步骤&#xff1a; 通过刷新网页&#xff0c;点击等操作&#xff0c;我们发现https://datacenter-web.eastmoney.com/api/data/v1/get?请求后面带着一些参数即可以获取到相应数据。我们使用python来模拟这个请求即可。 我们以如下选择的页面为切入点…

open 函数到底做了什么

使用设备之前我们通常都需要调用 open 函数&#xff0c;这个函数一般用于设备专有数据的初始化&#xff0c;申请相关资源及进行设备的初始化等工作&#xff0c;对于简单的设备而言&#xff0c;open 函数可以不做具体的工作&#xff0c;你在应用层通过系统调用 open 打开设备…

基于深度学习检测恶意流量识别框架(80+特征/99%识别率)

基于深度学习检测恶意流量识别框架 目录 基于深度学习检测恶意流量识别框架简要示例a.检测攻击类别b.模型训练结果输出参数c.前端检测页面d.前端训练界面e.前端审计界面&#xff08;后续更新了&#xff09;f.前端自学习界面&#xff08;自学习模式转换&#xff09;f1.自学习模式…