【ARM-Linux篇】项目:智能家居

一、项目概述

•项目功能

通过语音控制客厅灯、卧室灯、风扇、人脸识别开门等,可以进行火灾险情监测,可以并且实现Sockect发送指令远程控制各类家电等
•项目描述

全志H616通过串口连接各模块硬件,检测语音的识别结果,分析语音识别的结果来对家电设备进行控制。摄像头拍摄到人脸之后通过阿里云平台人脸识别方案对比阿里云人脸数据库来进行人脸识别开锁。该项目采用设计模式中的简单工厂模式,让设备端和控制端都采用链表管理,提高了项目代码的稳定性和拓展性。

二、系统框图

三、硬件搭建

语音模块及人脸识别方案配置参考: 语音模块配置      人脸识别方案

四、软件框架

整个项目开启4个监听线程, 分别是:
1. 语音监听线程:用于监听语音指令, 当有语音指令过来后, 通过消息队列的方式给消息处理线程发送指令
2. 网络监听线程:用于监听网络指令,当有网络指令过来后, 通过消息队列的方式给消息处理线程发送指令
3. 火灾检测线程:当存在煤气泄漏或者火灾闲情时, 发送警报指令给消息处理线程
4. 消息监听线程: 用于处理以上3个线程发过来的指令,并根据指令要求配置GPIO引脚状态,OLED屏显示、语音播报,还有人脸识别开门
上述四个线程采用统一个对外接口接口,同时添加到监听链表中。 

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

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;
};
struct gdevice *add_device_to_gdevice_list(struct gdevice *phead, struct gdevice *device);
struct gdevice *find_gdevice_by_key(struct gdevice *pdev, unsigned char key);
int set_gpio_gdevice_status(struct gdevice *pdev);

 五、项目代码

本项目代码量较大,仅展示部分源代码,项目开源地址:https://gitee.com/GeekerGao/smart-home

(一)

监听模块接口加入链表

control.c

#include <stdio.h>
#include "control.h"struct control *add_interface_to_control_list(struct control *phead,struct control *control_interface)
{//头插法添加节点if(NULL == phead){   phead = control_interface; }else{control_interface->next = phead;phead = control_interface;   }return phead;
};

control.h

#ifndef __CONTROL_H__
#define __CONTROL_H__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_interface_to_control_list(struct control *phead,struct control *control_interface);#endif

消息队列的接口 

msg_queue.c

#include <stdio.h>
#include "msg_queue.h"// 定义消息队列的名称
#define QUEQUE_NAME "/test_queue"
// 创建一个新的消息队列
mqd_t msg_queue_create(void)
{// 初始化mqd_t变量mqd为-1,表示未成功打开消息队列mqd_t mqd = -1;// 定义并初始化消息队列的属性结构体struct mq_attr attr;// 设置消息队列属性:默认为阻塞模式attr.mq_flags = 0;           // 消息队列最大消息数量为10attr.mq_maxmsg = 10;         // 每条消息的最大字节数为256attr.mq_msgsize = 256;       // 当前消息队列中消息数量初始化为0attr.mq_curmsgs = 0;         // 使用mq_open函数创建消息队列,如果不存在则根据属性创建(O_CREAT),并设置读写权限(O_RDWR)// 第三个参数是权限位,0666表示所有用户都有读写权限,实际权限还需参考umask值// 第四个参数是指向消息队列属性的指针mqd = mq_open(QUEQUE_NAME, O_CREAT | O_RDWR, 0666, &attr);    // 打印消息队列描述符,用于调试printf("%s | %s | %d:mqd = %d\n", __FILE__,__func__,__LINE__,mqd);// 返回创建的消息队列描述符return mqd; 
}
// 清理并关闭消息队列
void msg_queue_fianl(mqd_t mqd)
{// 如果消息队列描述符有效,则关闭消息队列if(-1 != mqd)mq_close(mqd);// 删除消息队列mq_unlink(QUEQUE_NAME);    // 保险起见,再次将mqd设为-1mqd = -1;   
}
// 向消息队列发送消息
int send_message(mqd_t mqd,void *msg,int msg_len)
{int byte_send = -1;// 使用mq_send函数发送消息到消息队列,第四个参数0为消息的优先级,默认情况下优先级不影响消息的发送顺序byte_send = mq_send(mqd, (char *)msg, msg_len, 0);   // 返回发送的字节数,成功时应等于msg_len,失败时返回-1return byte_send;
}

 msg_queue.h

#ifndef __MSG_QUEUE_H__
#define __MSG_QUEUE_H__#include <mqueue.h>
#include <pthread.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>mqd_t msg_queue_create(void);
void msg_queue_fianl(mqd_t mqd);
int send_message(mqd_t mqd,void *msg,int msg_len);#endif

语音监听接口 

global.h

#ifndef __GLOBAL_H__
#define __GLOBAL_H__    
typedef struct {mqd_t mqd;struct control *ctrl_phead;
}ctrl_info_t;#endif

voice_interface.c

#include <stdio.h>
#include <pthread.h> // 线程库
#include "voice_interface.h" // 语音接口头文件
#include "uartTool.h" // 串口操作工具库
#include "msg_queue.h" // 消息队列操作库
#include "global.h" // 全局变量和宏定义头文件// 串口文件描述符,初始设为-1
static int serial_fd = -1;
// 初始化语音模块
static int voice_init(void)
{// 打开指定的串口设备,BAUD为波特率宏定义serial_fd = myserialOpen(SERIAL_DEV, BAUD);// 打印日志,显示串口文件描述符printf("%s|%s|%d:serial_fd = %d\n", __FILE__, __FUNCTION__, __LINE__, serial_fd);return serial_fd;
}
// 释放语音模块资源
static void voice_final(void)    
{if(-1 != serial_fd) // 如果串口已打开{// 关闭串口close(serial_fd);// 重置串口文件描述符为-1serial_fd = -1;}
}
// 线程函数,用于接收语音指令
static void *voice_get(void *arg)
{unsigned char buffer[6] = {0}; // 初始化缓冲区int len; // 接收长度mqd_t mqd 

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

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

相关文章

视频上面怎样编辑文字?4种视频编辑文字方法分享

视频已成为我们日常生活中不可或缺的一部分。无论是社交分享、商业宣传还是个人记录&#xff0c;视频都以其直观、生动的特点吸引着观众的眼球。然而&#xff0c;一个优质的视频&#xff0c;除了画面和音效&#xff0c;文字编辑也是提升观看体验的关键。那么&#xff0c;如何在…

Webpack: 并行构建

概述 受限于 Node.js 的单线程架构&#xff0c;原生 Webpack 对所有资源文件做的所有解析、转译、合并操作本质上都是在同一个线程内串行执行&#xff0c;CPU 利用率极低&#xff0c;因此&#xff0c;理所当然地&#xff0c;社区出现了一些以多进程方式运行 Webpack&#xff0…

Redis学习——Redisson 分布式锁集成及其简单使用

文章目录 引言1. Redisson概述1.1 Redisson的基本概念1.2 Redisson的主要功能1.3 Redisson的优点 2. 开发环境3. Redisson的安装与配置3.1 添加依赖3.2 配置Redisson 4. 使用Redisson4.1 可重入锁4.1.1 可重入锁的概念4.1.2 可重入锁的实现原理4.1.3 简单使用锁的获取和释放 4.…

在线疫苗预约小程序的设计

管理员账户功能包括&#xff1a;系统首页&#xff0c;个人中心&#xff0c;工作人员管理&#xff0c;管理员管理&#xff0c;用户管理&#xff0c;疫苗管理&#xff0c;论坛管理&#xff0c;公告管理 微信端账号功能包括&#xff1a;系统首页&#xff0c;公告&#xff0c;疫苗&…

【FreeRTOS】空闲任务

目录 空闲任务及其钩子函数介绍使用钩子函数的前提 实际操作任务如何退出&#xff1f;IDLE函数 空闲任务及其钩子函数 介绍 空闲任务(Idle任务)的作用之一&#xff1a;释放被删除的任务的内存。 除了上述目的之外&#xff0c;为什么必须要有空闲任务? 这是一个良好的程序&…

Linux基础 - DHCP 动态管理主机地址

目录 零. 简介 一. 部署 dhcpd 二. 提高安全性 零. 简介 DHCP&#xff08;Dynamic Host Configuration Protocol&#xff0c;动态主机配置协议&#xff09;是一种网络协议&#xff0c;用于动态地为主机分配 IP 地址、子网掩码、默认网关、DNS 服务器等网络配置信息。 其主要…

鸿蒙 HarmonyOs 动画效果 快速入门

一、理论 1.1 animation属性 名称参数类型必填描述durationnumber否设置动画时长&#xff0c;默认值&#xff1a;1000&#xff0c;单位&#xff1a;毫秒temponumber否动画播放速度。数值越大&#xff0c;速度越快&#xff0c;默认为1curvestring | Curve否 设置动画曲线。 默…

C语言--vs使用调试技巧

1.什么是bug? 1.产品说明书中规定要做的事情&#xff0c;而软件没有实现。 2.产品说明书中规定不要做的事情&#xff0c;而软件确实现了。 3.产品说明书中没有提到过的事情&#xff0c;而软件确实现了。 4.产品说明书中没有提到但是必须要做的事情&#xff0c;软件确没有实…

vue3中使用弹幕组件vue-danmaku

1、最开始使用的是vue3-marquee&#xff0c;后面发现一直有一个bug无法解决&#xff0c;就是鼠标hover到第一个弹幕上字体就会变粗&#xff0c;已经提了issue给作者&#xff0c;但是目前还未答复&#xff0c;所以就换了方案。 地址如下&#xff1a; https://github.com/megasa…

stable-diffusion-webui-colab搭建SadTalker由图生成视频人

在这里选择一个stable-diffusion-webui-colab ​​​​​​​​​GitHub - camenduru/stable-diffusion-webui-colab: stable diffusion webui colab 这里我选择是&#xff1a; https://colab.research.google.com/github/camenduru/stable-diffusion-webui-colab/blob/main…

【Python时序预测系列】基于LSTM实现多输入多输出单步预测(案例+源码)

这是我的第312篇原创文章。 一、引言 单站点多变量输入多变量输出单步预测问题----基于LSTM实现。 多输入就是输入多个特征变量 多输出就是同时预测出多个标签的结果 单步就是利用过去N天预测未来1天的结果 二、实现过程 2.1 读取数据集 dfpd.read_csv("data.csv&qu…

CSS-实例-div 水平居中 垂直靠上

1 需求 2 语法 3 示例 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>表格水平居中、垂直靠上示例…

AI 上车的一些随想

​最近一直在做AI大模型上车的战略企划工作&#xff0c;听了好多供应商的宣讲&#xff0c;自己也查阅了大量书籍、资料。信息输入呈现爆炸性增长&#xff0c;受限于专业知识水平&#xff0c;仅能在应用层面上有所思考。纯个人观点&#xff0c;仅供参考。 车自古以来都是移动工…

2024年06月CCF-GESP编程能力等级认证Scratch图形化编程四级真题解析

本文收录于《Scratch等级认证CCF-GESP图形化真题解析》专栏,专栏总目录:点这里,订阅后可阅读专栏内所有文章。 一、单选题(共 10 题,每题 2 分,共 30 分) 第1题 小杨父母带他到某培训机构给他报名参加 CCF 组织的 GESP 认证考试的第 1 级,那他可以选择的认证语言有几…

前端面试题(基础篇十四)

一、DOMContentLoaded 事件和 Load 事件的区别&#xff1f; 当初始的 HTML 文档被完全加载和解析完成之后&#xff0c;DOMContentLoaded 事件被触发&#xff0c;而无需等待样式表、图像和子框架的加载完成。 Load 事件是当所有资源加载完成后触发的。 二、简述一下你对 HTML 语…

机器学习 中数据是如何处理的?

数据处理是将数据从给定形式转换为更可用和更理想的形式的任务&#xff0c;即使其更有意义、信息更丰富。使用机器学习算法、数学建模和统计知识&#xff0c;整个过程可以自动化。这个完整过程的输出可以是任何所需的形式&#xff0c;如图形、视频、图表、表格、图像等等&#…

理想汽车提出3DRealCar:首个大规模3D真实汽车数据集

理想提出3DRealCar&#xff0c;这是第一个大规模 3D 实车数据集&#xff0c;包含 2500 辆在真实场景中拍摄的汽车。我们希望 3DRealCar 可以成为促进汽车相关任务的宝贵资源。 理想汽车提出3DRealCar&#xff1a;首个大规模3D真实汽车数据集! 我们精心策划的高质量3DRealCar数…

全球点赞第一起名大师颜廷利:是金子总会“花光”的

在物质世界的繁华背后&#xff0c;隐藏着一个深刻的真理&#xff1a;有形之物的分享会逐渐减少&#xff0c;而无形之物的传递却能不断增值。金钱、货币、银两这些商业领域的实体&#xff0c;往往激发出人类对更多财富的渴望和对资源枯竭的恐惧。这种恐惧源于资源的有限性&#…

【数据结构】(C语言):二叉搜索树

二叉搜索树&#xff1a; 树不是线性的&#xff0c;是层级结构。基本单位是节点&#xff0c;每个节点最多2个子节点。有序。每个节点&#xff0c;其左子节点都比它小&#xff0c;其右子节点都比它大。每个子树都是一个二叉搜索树。每个节点及其所有子节点形成子树。可以是空树。…