【智能家居】6、语音控制及网络控制代码实现
一、语音控制
1、指令结构体编写
这个结构体定义了一个命令输入的模型。在这个模型中,包含以下几个部分:
- cmdName:一个长度为128的字符串,用于存储命令名称。
- dvicesName:一个长度为128的字符串,用于存储设备名称。
- cmd:一个长度为32的字符串,用于存储具体的命令。
- Init:一个函数指针,该函数接受三个参数:指向
InputCmd
结构体实例的指针(可以读取所有字段)、IP地址和端口号,并返回一个整数值。 - getCmd:一个函数指针,该函数接受一个参指向
InputCmd
结构体实例的指针(可以读取所有字段)并返回一个整数值。 - log:一个长度为1024的字符数组,用于存储日志信息。
- fd:一个整数,文件描述符。
- next:一个指向结构体本身的指针,用于操控链表。
imputCmd.h
#include <stdio.h>
#include <wiringPi.h>
#include <wiringSerial.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>struct InputCmd{char cmdName[128];char devicesName[128];char cmd[32];int (*Init)(struct InputCmd *cmd,char *ipAdress,char *port);int (*getCmd)(struct InputCmd *cdm);char *log[1024];int fd;char port[12];char ipAddress[32];int s_fd;struct InputCmd *next;
};
2、实例化对象
(1)结构体变量初始化
一个结构体变量初始化的例子,声明并初始化了一个`InputCmd`类型的变量`voice`,并将每个字段分别赋值。
- cmdName字段被赋值为字符串"voice"。
- devicesName字段被赋值为字符串"/dev/ttyAMA0"。
- cmd字段被赋值为空字符串。
- init字段被赋值为`voice_init`函数的地址。
- getCmd字段被赋值为`voice_getCmd`函数的地址。
- log字段被赋值为空字符串。
(2)对应字段函数编写
初始化串口,获取文件描述符
fd=serialOpen(voice->devicesName,9600)
它将尝试以9600波特率打开名为 voice->devicesName
的串行端口,并将返回的文件描述符(File Descriptor)赋值给变量 fd
。这里的 voice->devicesName
是指向一个字符串的指针,该字符串包含要打开的串行端口的名称或路径。例如,在Linux系统上,这可能是类似于 "/dev/ttyS0" 或 "/dev/ttyUSB0" 的设备文件路径。
9600
是波特率,它决定了数据传输的速度,表示每秒传输9600个数据位。如果 serialOpen
函数成功打开串行端口,它将返回一个非负整数。如果打开失败,函数通常会返回 -1
。
读取指令
从voicer->fd
指向的串行端口读取数据,并将这些数据存储在voicer->command
缓冲区中。
插入链表等待被调用
Voice.c
#include "inputCmd.h"int voice_init(struct InputCmd *voice,char *ipAdress,char *port){int fd;if((fd=serialOpen(voice->devicesName,9600))==-1){exit(-1);}voice->fd=fd;return fd;
}int voice_getCmd(struct InputCmd *voice){int nread=0;nread=read(voice->fd,voice->cmd,sizeof(voice->cmd));if(nread==0){printf("usart for voice read over time\n");}elsereturn nread;
}struct InputCmd voice={.cmdName="voice",.devicesName="/dev/ttyAMA0",.cmd={'\0'},.Init=voice_init,.getCmd=voice_getCmd,.log={'\0'}
};struct InputCmd* addVoiceToInputCmdLink(struct InputCmd *phead){if(phead==NULL){return &voice;}else{voice.next=phead;phead=&voice;}
}
3、将插入链表函数加入inputCmd.h等待被调用
4、main函数编写
插入链表等待被调用
mainPro.c
#include <stdio.h>
#include <string.h>#include "controlDevices.h"
#include "inputCmd.h"struct Devices *findDevicesName(char *name,struct Devices *phead){struct Devices *tmp=phead;if(phead==NULL){return NULL;}else{while(tmp!=NULL){if(strcmp(tmp->devicesName,name)==0){return tmp;}tmp=tmp->next;}return NULL;}
}int main(){if(wiringPiSetup()==-1){return -1;}struct Devices *pdevicesHead=NULL;struct InputCmd *pinputCmdHead=NULL;pdevicesHead=addbathroomLightToDevicesLink(pdevicesHead);pdevicesHead=addupstairLightToDevicesLink(pdevicesHead);pdevicesHead=addlivingroomLightToDevicesLink(pdevicesHead);pdevicesHead=addrestaurantLightToDevicesLink(pdevicesHead);pdevicesHead=addFireToDevicesLink(pdevicesHead);pinputCmdHead=addVoiceToInputCmdLink(pinputCmdHead);char name[128]={'\0'};struct Devices *tmp=NULL;while(1){printf("INPUT:\n");scanf("%s",name);tmp=findDevicesName(name,pdevicesHead);if(tmp!=NULL){tmp->devicesInit(tmp->pinNum);tmp->open(tmp->pinNum); tmp->readStatus(tmp->pinNum);}}return 0;
}
二、网络控制
1、结构体变量初始化
2、对应字段函数编写
(1)socket_Init
1、创建一个服务器端的套接字并初始化服务器地址结构
- 定义两个socket描述符变量:
s_fd
为服务端socket描述符,c_fd
为客户端socket描述符。 - 定义两个
sockaddr_in
结构体变量:s_addr
存储服务器端网络地址信息,c_addr
存储客户端网络地址信息。 - 使用
memset()
函数清零这两个结构体变量,确保它们的所有成员初始化为0。 - 创建服务器端socket
调用 socket()
函数创建一个基于IPv4协议的流式(TCP)socket。如果返回值 s_fd
为-1,则表示socket创建失败,程序通过 perror("socket")
输出错误信息,并使用 exit(-1)
终止程序执行。
- 初始化服务器地址结构体:
s_addr.sin_family = AF_INET
:设置地址族为Internet(IPv4)。
s_addr.sin_port = htons(atoi(socketInit->port)):
将字符串形式的端口号转换为整型数字,然后使用 htons()
函数将端口号从主机字节序转换为网络字节序。
inet_aton(socketInit->ipaddress, &s_addr.sin_addr)
: 将字符串形式的IP地址转换为二进制格式,并存入到s_addr.sin_addr
中。这样就完成了服务器地址的配置,接下来可以调用bind()函数绑定这个地址和端口到刚创建的socket上。(需要包含头文件#include <arpa/inet.h>)
2、将创建的socket与特定的IP地址和端口号绑定
s_fd
是之前通过socket()
函数创建的socket描述符。(struct sockaddr *)&s_addr
指向已经初始化好的服务器地址结构体s_addr
。由于bind()
函数的第二个参数要求指向一个通用套接字地址结构(struct sockaddr *
),所以我们需要类型转换。
如果 bind()
调用成功,那么该socket就会监听指定的IP地址和端口上的连接请求。如果失败,则会返回一个错误码,通常需要通过 perror()
或检查 errno
来获取错误信息并进行相应的处理。
3、 将socket设置为监听模式
s_fd
是之前创建并绑定到特定IP地址和端口的socket描述符。- 第二个参数(这里是10)表示backlog,即在服务器开始拒绝连接请求前,可以排队等待处理的最大连接数。当这个数目达到后,新的连接请求将会被拒绝,直到服务器完成对已有连接的处理。
将已经初始化并设置为监听状态的socket描述符 s_fd
赋值给结构体 socketInit
的成员变量 s_fd
(2) socket_getCmd
1、声明变量与初始化c_addr结构体
int c_fd;
:声明一个整型变量 c_fd
,用于存储接受到的客户端socket描述符。
int n_read = 0;
:声明一个整型变量 n_read
,用于记录从客户端socket读取数据的数量。
struct sockaddr_in c_addr;
:定义一个结构体变量 c_addr
,用于存储客户端的网络地址信息。
memset(&c_addr, 0, sizeof(struct sockaddr_in));
:清零 c_addr
结构体,确保所有成员初始化为0。
int len = sizeof(struct sockaddr_in);
:声明并初始化一个整型变量 len
,表示要获取的客户端地址结构体的大小。
2、等待并接受来自客户端的连接请求
c_fd = accept(socketGet.s_fd, (struct sockaddr *)&c_addr, &len);
:使用 accept()
函数等待并接受来自客户端的连接请求。
- 第一个参数是服务端监听的socket描述符(即之前创建并调用
listen()
的s_fd
)。 - 第二个参数是一个指向
sockaddr_in
结构体的指针,用于接收已连接客户端的地址信息。 - 第三个参数是一个指向整数的指针,用于接收实际填充到地址结构体中的字节数。
3、从已连接的客户端socket (c_fd
) 读取数据
n_read = read(c_fd, socketGet->command, sizeof(socket_command));
:使用 read()
函数从已连接的客户端socket (c_fd
) 读取数据,并将数据存入 socketGet
结构体中 command
成员指定的缓冲区。第二个参数是缓冲区的起始地址,第三个参数是期望读取的最大字节数。
对于 read()
函数的返回值进行判断:
- 如果
n_read == -1
,说明读取过程中发生错误,通过perror("read")
输出错误信息。 - 如果
n_read > 0
,则打印出读取到的数据长度。 - 如果
n_read == 0
,通常意味着客户端已经关闭了连接,此时输出 "client quit!",然后可能执行相应的退出循环操作(这里没有显示完整的上下文,所以无法确定是否有break语句所在的循环)。
最后返回 n_read
,代表本次从客户端读取数据的实际字节数。
(3)插入链表等待被调用
socket.c
#include "inputCmd.h"int socket_init(struct InputCmd *socketInit,char *ipAdress,char *port){int s_fd,c_fd;//s_fd:服务(service)端socket描述符;c_fd:客户(client)端socket描述符struct sockaddr_in s_addr;//s_addr:存储服务器端网络地址信息struct sockaddr_in c_addr;//c_addr:存储客户端网络地址信息memset(&s_addr,0,sizeof(struct sockaddr_in));//初始化结构体memset(&c_addr,0,sizeof(struct sockaddr_in));//sockets_fd=socket(AF_INET,SOCK_STREAM,0);if(s_fd==-1){perror("socket");exit(-1);}s_addr.sin_family=AF_INET;s_addr.sin_port=htons(atoi(socketInit->port));inet_aton(socketInit->ipAddress,&s_addr.sin_addr);//bindbind(s_fd,(struct sockaddr *)&s_addr,sizeof(struct sockaddr_in));//listenlisten(s_fd,10);socketInit->s_fd=s_fd;return s_fd;
}int socket_getCmd(struct InputCmd *Socket){int c_fd;int n_read=0;struct sockaddr_in c_addr;memset(&c_addr,0,sizeof(struct sockaddr_in));int len=sizeof(struct sockaddr_in);c_fd=accept(Socket->s_fd,(struct sockaddr *)&c_addr,&len);n_read=read(c_fd,Socket->cmd,sizeof(Socket->cmd));if(n_read==-1){perror("read");}else if(n_read>0){printf("\n");printf("get:%d\n",n_read);}else{printf("client quit!\n");}return n_read;
}struct InputCmd Socket={.cmdName="socket",.cmd={'\0'},.Init=socket_init,.getCmd=socket_getCmd,.log={'\0'},.port="8080",.ipAddress="172.20.10.9"
};struct InputCmd* addSocketToInputCmdLink(struct InputCmd *phead){if(phead==NULL){return &Socket;}else{Socket.next=phead;phead=&Socket;}
}
3、将插入链表函数加入inputCmd.h等待被调用
#include <stdio.h>
#include <wiringPi.h>
#include <wiringSerial.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>struct InputCmd{char cmdName[128];char devicesName[128];char cmd[32];int (*Init)(struct InputCmd *cmd,char *ipAdress,char *port);int (*getCmd)(struct InputCmd *cdm);char *log[1024];int fd;char port[12];char ipAddress[32];int s_fd;struct InputCmd *next;
};struct InputCmd* addVoiceToInputCmdLink(struct InputCmd *phead);
struct InputCmd* addSocketToInputCmdLink(struct InputCmd *phead);
4、main函数编写
mainPro.c
#include <stdio.h>
#include <string.h>#include "controlDevices.h"
#include "inputCmd.h"struct Devices *findDevicesName(char *name,struct Devices *phead){struct Devices *tmp=phead;if(phead==NULL){return NULL;}else{while(tmp!=NULL){if(strcmp(tmp->devicesName,name)==0){return tmp;}tmp=tmp->next;}return NULL;}
}int main(){if(wiringPiSetup()==-1){return -1;}struct Devices *pdevicesHead=NULL;struct InputCmd *pinputCmdHead=NULL;pdevicesHead=addbathroomLightToDevicesLink(pdevicesHead);pdevicesHead=addupstairLightToDevicesLink(pdevicesHead);pdevicesHead=addlivingroomLightToDevicesLink(pdevicesHead);pdevicesHead=addrestaurantLightToDevicesLink(pdevicesHead);pdevicesHead=addFireToDevicesLink(pdevicesHead);pinputCmdHead=addVoiceToInputCmdLink(pinputCmdHead);pinputCmdHead=addSocketToInputCmdLink(pinputCmdHead);char name[128]={'\0'};struct Devices *tmp=NULL;while(1){printf("INPUT:\n");scanf("%s",name);tmp=findDevicesName(name,pdevicesHead);if(tmp!=NULL){tmp->devicesInit(tmp->pinNum);tmp->open(tmp->pinNum); tmp->readStatus(tmp->pinNum);}}return 0;
}
三、测试
将工程放入树莓派中,编译通过,无错误无警告
四、当前阶段源代码
链接:https://pan.baidu.com/s/1vh8smf725jrxSUlDOHFOfg
提取码:sail
相关文章:

【智能家居】6、语音控制及网络控制代码实现
一、语音控制 1、指令结构体编写 这个结构体定义了一个命令输入的模型。在这个模型中,包含以下几个部分: cmdName:一个长度为128的字符串,用于存储命令名称。dvicesName:一个长度为128的字符串,用于存储设…...

Windows断开映射磁盘提示“此网络连接不存在”,并且该磁盘直在资源管理器中
1、打开注册表编辑器 快捷键winR 打开“运行”, 输入 regedit 2、 删除下列注册表中和无法移除的磁盘相关的选项 \HKEY_CURRENT_USER\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\MountPoints2\ 3、打开“任务管理器”,重新启动“Windows资源…...

Java项目要不要部署在Docker里?
部署Java项目有很多种方式,传统的方式是直接在物理机或虚拟机上部署应用,但为什么现在容器化部署变得越来越流行, 个人觉得原因有以下几个: 1、 环境一致性:使用Docker可以确保开发、测试和生产环境的一致性ÿ…...

Linux 入门基础知识(一)—— Linux的基本使用
Linux 入门基础知识 一、Linux的基本使用和配置1.1、终端1.2、消耗内存1.3、运行级别1.6、登录前欢迎语1.5、登录后欢迎语1.6、shell1.7、ps aux1.8、设置主机名1.9、whoami和who am i1.10、命令提示符 二、Linux执行命令的过程详解和命令类型2.1、命令执行2.2、hash缓存表2.3、…...

纯静态微信小程序水果商城
首页代码 <view class"container"><!-- 轮播图 --><view class"swiper-container"><swiper class"screen-swiper" indicator-dots"true" circular"true" autoplay"true" interval"300…...

操作系统-线程的实现方式和多线程模型(用户级线程 内核级线程 多线程模型的情况)和线程的状态,转换,组织,控制
文章目录 线程的实现方式和多线程模型总览线程的实现方式用户级线程内核级线程多线程模型一对一多对一多对多 小结 线程的状态,转换,组织,控制总览 线程的状态与转换线程的组织与控制 线程的实现方式和多线程模型 总览 线程的实现方式 用户级线程 程序自己通过自己设计的线程…...

计算机网络 应用层
文章目录 应用层域名系统 DNS域名系统概述互联网的域名结构域名服务器 文件传送协议FTP 概述FTP 的基本工作原理简单文件传送协议 TFTP 远程终端协议 TELNET万维网 WWW统一资源定位符 URL超文本传送协议 HTTP万维网的信息检索系统 电子邮件电子邮件概述简单邮件传送协议 SMTP邮…...

拥有你的微调大模型,零代码定制+算力免费送
2023年,ChatGPT的横空出世掀起了人工智能领域的新一轮革命。 很快大模型的潮水就越过广袤的太平洋,席卷国内科技圈和投资圈,几乎所有科技公司都在押注大模型。根据工信部赛迪研究院数据,预计2023年我国语言大模型市场规模将达到1…...

《Docker技术革命:从虚拟机到容器化,全面解析Docker的原理与应用-上篇》
文章目录 Docker为什么会出现总结 Docker的思想Docker历史总结 Docker能干嘛虚拟机技术虚拟机技术的缺点 容器化技术Docker和虚拟机技术的区别 Docker概念Docker的基本组成镜像(image)容器(container)仓科(repository)…...
C,C++,C# 的区别
C,C,C# 是三种不同的编程语言。它们有一些共同点,但也有很多区别。 C是一种过程式编程语言,被广泛用于系统级编程和嵌入式开发。它具有简单的语法和较小的标准库,适合于高效的低级编程和处理底层细节。 C是一种面向对…...

操作筛选器的 1 个应用实例:自动启用事务
前言 在数据库操作过程中,有一个概念是绕不开的,那就是事务。 事务能够确保一系列数据库操作要么全部成功提交,要么全部失败回滚,保证数据的一致性和完整性。 在 Asp.Net Core Web API 中,我们可以使用操作筛选器给…...

搭建基于Java的分布式爬虫系统
目录 前言 一、分布式爬虫系统的架构设计 二、系统搭建步骤 1. 创建爬虫项目 2. 导入相关依赖 3. 编写分布式爬虫系统的核心代码 3.1 节点管理器(Node Manager) 3.2 调度器(Scheduler) 3.3 下载器(Downloader…...

rancher证书过期问题处理
问题 起初,打开rancher ui页面打不开,telnet rancher的服务端口也不通。查看rancher 控制节点,日志显示,X509:certificate has expired or is not ye valid。证书已过期 解决 现在网上大部分的解决方案都是针对的2…...

Spring Boot 中文件上传
Spring Boot 中文件上传 一、MultipartFile二、单文件上传案例三、多文件上传案例四、Servlet 规范五、Servlet 规范实现文件上传 上传文件大家用的最多的就是 Apache Commons FileUpload,这个库使用非常广泛。Spring Boot3 版本中已经不能使用了。代替它的是 Sprin…...
2023年06月CCF-GESP编程能力等级认证Python编程一级真题解析
一、单选题(共15题,共30分) 第1题 以下不属于计算机输出设备的有()。 A:麦克风 B:音箱 C:打印机 D:显示器 答案:A 第2题 ChatGPT 是 OpenAI 研发的聊天机器人程序,它能通过理解和学习人类的语言来进行对话,还能根据聊天的上下文进行互动,完成很多工作。请你…...
unity 使用数字图片来代替数字0到9显示
using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.UI; public class Trackracecomplete : MonoBehaviour { /// /// 数字图片 /// [SerializeField] private Sprite[] sprites; private string _Time “23:57:49”; [Ser…...
单片机如何实现延时1ms或者1us
1us //适配主频为120MHz的单片机 void Delay_us(int16_t nus) {int32_t temp; SysTick->LOAD nus*15; //120MHzSysTick->VAL0X00;SysTick->CTRL0X01;do { tempSysTick->CTRL;}while((temp&0x01)&&(!(temp&(1<<16))));SysTick->CTRL0x0…...

全国网络安全行业职业技能大赛WP
word_sercet 文档被加密 查看图片的属性 在备注可以看到解压密码 解密成功 在选项里面把隐藏的文本显示出来 可以看到ffag easy_encode 得到一个bmp二维码 使用qr research 得到的密文直接放瑞士军刀 base32解码base64解码hex解码 dir_pcap 直接搜索flag 发现flag…...
【Python函数与模块】(7)模块的分类与好处
文章目录 一、模块分类二、模块的好处 一、模块分类 Python标准模块(内置模块,标准库) 第三方模块/库(pypi.org) 自定义模块 二、模块的好处 可维护性更强 方便代码重用...
如何安全地多开Facebook/Twitter/TK/Ins等账号?
随着社交媒体的普及,人们需要在不同平台上管理多个账号。然而,如何安全地多开这些账号却是一个需要关注的问题。本文将介绍如何安全地多开Facebook、twitter、YouTube、TikTok等平台账号的方法。 重要关联因素: 1. 隐私和安全:保…...
React Native在HarmonyOS 5.0阅读类应用开发中的实践
一、技术选型背景 随着HarmonyOS 5.0对Web兼容层的增强,React Native作为跨平台框架可通过重新编译ArkTS组件实现85%以上的代码复用率。阅读类应用具有UI复杂度低、数据流清晰的特点。 二、核心实现方案 1. 环境配置 (1)使用React Native…...
Java - Mysql数据类型对应
Mysql数据类型java数据类型备注整型INT/INTEGERint / java.lang.Integer–BIGINTlong/java.lang.Long–––浮点型FLOATfloat/java.lang.FloatDOUBLEdouble/java.lang.Double–DECIMAL/NUMERICjava.math.BigDecimal字符串型CHARjava.lang.String固定长度字符串VARCHARjava.lang…...
【决胜公务员考试】求职OMG——见面课测验1
2025最新版!!!6.8截至答题,大家注意呀! 博主码字不易点个关注吧,祝期末顺利~~ 1.单选题(2分) 下列说法错误的是:( B ) A.选调生属于公务员系统 B.公务员属于事业编 C.选调生有基层锻炼的要求 D…...
HTML前端开发:JavaScript 常用事件详解
作为前端开发的核心,JavaScript 事件是用户与网页交互的基础。以下是常见事件的详细说明和用法示例: 1. onclick - 点击事件 当元素被单击时触发(左键点击) button.onclick function() {alert("按钮被点击了!&…...

【论文阅读28】-CNN-BiLSTM-Attention-(2024)
本文把滑坡位移序列拆开、筛优质因子,再用 CNN-BiLSTM-Attention 来动态预测每个子序列,最后重构出总位移,预测效果超越传统模型。 文章目录 1 引言2 方法2.1 位移时间序列加性模型2.2 变分模态分解 (VMD) 具体步骤2.3.1 样本熵(S…...
rnn判断string中第一次出现a的下标
# coding:utf8 import torch import torch.nn as nn import numpy as np import random import json""" 基于pytorch的网络编写 实现一个RNN网络完成多分类任务 判断字符 a 第一次出现在字符串中的位置 """class TorchModel(nn.Module):def __in…...

华硕a豆14 Air香氛版,美学与科技的馨香融合
在快节奏的现代生活中,我们渴望一个能激发创想、愉悦感官的工作与生活伙伴,它不仅是冰冷的科技工具,更能触动我们内心深处的细腻情感。正是在这样的期许下,华硕a豆14 Air香氛版翩然而至,它以一种前所未有的方式&#x…...
Linux C语言网络编程详细入门教程:如何一步步实现TCP服务端与客户端通信
文章目录 Linux C语言网络编程详细入门教程:如何一步步实现TCP服务端与客户端通信前言一、网络通信基础概念二、服务端与客户端的完整流程图解三、每一步的详细讲解和代码示例1. 创建Socket(服务端和客户端都要)2. 绑定本地地址和端口&#x…...
【学习笔记】erase 删除顺序迭代器后迭代器失效的解决方案
目录 使用 erase 返回值继续迭代使用索引进行遍历 我们知道类似 vector 的顺序迭代器被删除后,迭代器会失效,因为顺序迭代器在内存中是连续存储的,元素删除后,后续元素会前移。 但一些场景中,我们又需要在执行删除操作…...
【SpringBoot自动化部署】
SpringBoot自动化部署方法 使用Jenkins进行持续集成与部署 Jenkins是最常用的自动化部署工具之一,能够实现代码拉取、构建、测试和部署的全流程自动化。 配置Jenkins任务时,需要添加Git仓库地址和凭证,设置构建触发器(如GitHub…...