当前位置:   article > 正文

【智能家居】6、语音控制及网络控制代码实现_c语言语音控制

c语言语音控制

需要毕业论文私信有偿获取

一、语音控制

1、指令结构体编写

68c492d2d9ee4d83ac17a14c916301d9.png

这个结构体定义了一个命令输入的模型。在这个模型中,包含以下几个部分:

  • cmdName:一个长度为128的字符串,用于存储命令名称。
  • dvicesName:一个长度为128的字符串,用于存储设备名称。
  • cmd:一个长度为32的字符串,用于存储具体的命令。
  • Init:一个函数指针,该函数接受三个参数:指向InputCmd结构体实例的指针(可以读取所有字段)、IP地址和端口号,并返回一个整数值。
  • getCmd:一个函数指针,该函数接受一个参指向InputCmd结构体实例的指针(可以读取所有字段)并返回一个整数值。
  • log:一个长度为1024的字符数组,用于存储日志信息。
  • fd:一个整数,文件描述符。
  • next:一个指向结构体本身的指针,用于操控链表。

imputCmd.h

  1. #include <stdio.h>
  2. #include <wiringPi.h>
  3. #include <wiringSerial.h>
  4. #include <unistd.h>
  5. #include <stdlib.h>
  6. #include <sys/types.h>
  7. #include <sys/socket.h>
  8. #include <netinet/in.h>
  9. #include <arpa/inet.h>
  10. #include <string.h>
  11. struct InputCmd{
  12. char cmdName[128];
  13. char devicesName[128];
  14. char cmd[32];
  15. int (*Init)(struct InputCmd *cmd,char *ipAdress,char *port);
  16. int (*getCmd)(struct InputCmd *cdm);
  17. char *log[1024];
  18. int fd;
  19. char port[12];
  20. char ipAddress[32];
  21. int s_fd;
  22. struct InputCmd *next;
  23. };

2、实例化对象

(1)结构体变量初始化

29e01620ea5442e0a4f5997fffec7fb6.png

一个结构体变量初始化的例子,声明并初始化了一个`InputCmd`类型的变量`voice`,并将每个字段分别赋值。

  • cmdName字段被赋值为字符串"voice"。
  • devicesName字段被赋值为字符串"/dev/ttyAMA0"。
  • cmd字段被赋值为空字符串。
  • init字段被赋值为`voice_init`函数的地址。
  • getCmd字段被赋值为`voice_getCmd`函数的地址。
  • log字段被赋值为空字符串。

(2)对应字段函数编写

初始化串口,获取文件描述符

8e9b857ed03440b78b31614cfa617611.png

fd=serialOpen(voice->devicesName,9600)它将尝试以9600波特率打开名为 voice->devicesName 的串行端口,并将返回的文件描述符(File Descriptor)赋值给变量 fd。这里的 voice->devicesName 是指向一个字符串的指针,该字符串包含要打开的串行端口的名称或路径。例如,在Linux系统上,这可能是类似于 "/dev/ttyS0" 或 "/dev/ttyUSB0" 的设备文件路径。

9600 是波特率,它决定了数据传输的速度,表示每秒传输9600个数据位。如果 serialOpen 函数成功打开串行端口,它将返回一个非负整数。如果打开失败,函数通常会返回 -1

读取指令

bf95102f942244dbba2980f55b00478c.png

voicer->fd指向的串行端口读取数据,并将这些数据存储在voicer->command缓冲区中。

插入链表等待被调用

6af420ee2ff84b8e9a5bbcf347217816.png

Voice.c

  1. #include "inputCmd.h"
  2. int voice_init(struct InputCmd *voice,char *ipAdress,char *port){
  3. int fd;
  4. if((fd=serialOpen(voice->devicesName,9600))==-1){
  5. exit(-1);
  6. }
  7. voice->fd=fd;
  8. return fd;
  9. }
  10. int voice_getCmd(struct InputCmd *voice){
  11. int nread=0;
  12. nread=read(voice->fd,voice->cmd,sizeof(voice->cmd));
  13. if(nread==0){
  14. printf("usart for voice read over time\n");
  15. }else
  16. return nread;
  17. }
  18. struct InputCmd voice={
  19. .cmdName="voice",
  20. .devicesName="/dev/ttyAMA0",
  21. .cmd={'\0'},
  22. .Init=voice_init,
  23. .getCmd=voice_getCmd,
  24. .log={'\0'}
  25. };
  26. struct InputCmd* addVoiceToInputCmdLink(struct InputCmd *phead){
  27. if(phead==NULL){
  28. return &voice;
  29. }else{
  30. voice.next=phead;
  31. phead=&voice;
  32. }
  33. }

3、将插入链表函数加入inputCmd.h等待被调用

3d0f0ebbda874ef6a720deebe5f284c8.png

4、main函数编写

插入链表等待被调用

f342be3c504c4787a505108fec915cf0.png

mainPro.c

  1. #include <stdio.h>
  2. #include <string.h>
  3. #include "controlDevices.h"
  4. #include "inputCmd.h"
  5. struct Devices *findDevicesName(char *name,struct Devices *phead){
  6. struct Devices *tmp=phead;
  7. if(phead==NULL){
  8. return NULL;
  9. }else{
  10. while(tmp!=NULL){
  11. if(strcmp(tmp->devicesName,name)==0){
  12. return tmp;
  13. }
  14. tmp=tmp->next;
  15. }
  16. return NULL;
  17. }
  18. }
  19. int main(){
  20. if(wiringPiSetup()==-1){
  21. return -1;
  22. }
  23. struct Devices *pdevicesHead=NULL;
  24. struct InputCmd *pinputCmdHead=NULL;
  25. pdevicesHead=addbathroomLightToDevicesLink(pdevicesHead);
  26. pdevicesHead=addupstairLightToDevicesLink(pdevicesHead);
  27. pdevicesHead=addlivingroomLightToDevicesLink(pdevicesHead);
  28. pdevicesHead=addrestaurantLightToDevicesLink(pdevicesHead);
  29. pdevicesHead=addFireToDevicesLink(pdevicesHead);
  30. pinputCmdHead=addVoiceToInputCmdLink(pinputCmdHead);
  31. char name[128]={'\0'};
  32. struct Devices *tmp=NULL;
  33. while(1){
  34. printf("INPUT:\n");
  35. scanf("%s",name);
  36. tmp=findDevicesName(name,pdevicesHead);
  37. if(tmp!=NULL){
  38. tmp->devicesInit(tmp->pinNum);
  39. tmp->open(tmp->pinNum);
  40. tmp->readStatus(tmp->pinNum);
  41. }
  42. }
  43. return 0
  44. }

二、网络控制

1、结构体变量初始化

2dda3e6c52a94d928daa170980a39d80.png

2、对应字段函数编写

(1)socket_Init

1、创建一个服务器端的套接字并初始化服务器地址结构

9a82c105fee94404b26946eb0cc6263d.png

  • 定义两个socket描述符变量:s_fd 为服务端socket描述符,c_fd 为客户端socket描述符。
  • 定义两个sockaddr_in 结构体变量:s_addr 存储服务器端网络地址信息,c_addr 存储客户端网络地址信息。
  • 使用 memset() 函数清零这两个结构体变量,确保它们的所有成员初始化为0。
  • 创建服务器端socket

59282a7a09f54960a0787b5473c10f60.png

调用 socket() 函数创建一个基于IPv4协议的流式(TCP)socket。如果返回值 s_fd 为-1,则表示socket创建失败,程序通过 perror("socket") 输出错误信息,并使用 exit(-1) 终止程序执行。

  • 初始化服务器地址结构体:

49e9e0625e354569beee6ba2876e0ab9.png

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地址和端口号绑定

a87a05b4a9e843cea01b514bdf4c5efe.png

  • s_fd 是之前通过 socket() 函数创建的socket描述符。
  • (struct sockaddr *)&s_addr 指向已经初始化好的服务器地址结构体 s_addr。由于 bind() 函数的第二个参数要求指向一个通用套接字地址结构(struct sockaddr *),所以我们需要类型转换。

如果 bind() 调用成功,那么该socket就会监听指定的IP地址和端口上的连接请求。如果失败,则会返回一个错误码,通常需要通过 perror() 或检查 errno 来获取错误信息并进行相应的处理。

3、 将socket设置为监听模式

32c2803c1e9c48c7a21ec41a56e60f8e.png

  • s_fd 是之前创建并绑定到特定IP地址和端口的socket描述符。
  • 第二个参数(这里是10)表示backlog,即在服务器开始拒绝连接请求前,可以排队等待处理的最大连接数。当这个数目达到后,新的连接请求将会被拒绝,直到服务器完成对已有连接的处理。

9fafa7c9b3dc4c3e86bd08c91bdd10d7.png

 将已经初始化并设置为监听状态的socket描述符 s_fd 赋值给结构体 socketInit 的成员变量 s_fd

(2) socket_getCmd

1、声明变量与初始化c_addr结构体

022a2b6e211d4b5cb2c3ccecec7ef887.png

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、等待并接受来自客户端的连接请求

0f1dbcd658ca4478817ee0f3bf4193e6.png

c_fd = accept(socketGet.s_fd, (struct sockaddr *)&c_addr, &len);:使用 accept() 函数等待并接受来自客户端的连接请求。

  • 第一个参数是服务端监听的socket描述符(即之前创建并调用 listen()s_fd)。
  • 第二个参数是一个指向 sockaddr_in 结构体的指针,用于接收已连接客户端的地址信息。
  • 第三个参数是一个指向整数的指针,用于接收实际填充到地址结构体中的字节数。

3、从已连接的客户端socket (c_fd) 读取数据

a5e9c35cea9e4085a553458b45e5a167.png

n_read = read(c_fd, socketGet->command, sizeof(socket_command));:使用 read() 函数从已连接的客户端socket (c_fd) 读取数据,并将数据存入 socketGet 结构体中 command 成员指定的缓冲区。第二个参数是缓冲区的起始地址,第三个参数是期望读取的最大字节数。

960cb01d36e54d8992925e4751cc90c5.png

对于 read() 函数的返回值进行判断:

  • 如果 n_read == -1,说明读取过程中发生错误,通过 perror("read") 输出错误信息。
  • 如果 n_read > 0,则打印出读取到的数据长度。
  • 如果 n_read == 0,通常意味着客户端已经关闭了连接,此时输出 "client quit!",然后可能执行相应的退出循环操作(这里没有显示完整的上下文,所以无法确定是否有break语句所在的循环)。

b1f25cfd1ace43558c91ac452795adc0.png

最后返回 n_read,代表本次从客户端读取数据的实际字节数。

(3)插入链表等待被调用

eb769fcc28b54284bed90cd7350f2ea2.png

socket.c

  1. #include "inputCmd.h"
  2. int socket_init(struct InputCmd *socketInit,char *ipAdress,char *port){
  3. int s_fd,c_fd;//s_fd:服务(service)端socket描述符;c_fd:客户(client)端socket描述符
  4. struct sockaddr_in s_addr;//s_addr:存储服务器端网络地址信息
  5. struct sockaddr_in c_addr;//c_addr:存储客户端网络地址信息
  6. memset(&s_addr,0,sizeof(struct sockaddr_in));//初始化结构体
  7. memset(&c_addr,0,sizeof(struct sockaddr_in));
  8. //socket
  9. s_fd=socket(AF_INET,SOCK_STREAM,0);
  10. if(s_fd==-1){
  11. perror("socket");
  12. exit(-1);
  13. }
  14. s_addr.sin_family=AF_INET;
  15. s_addr.sin_port=htons(atoi(socketInit->port));
  16. inet_aton(socketInit->ipAddress,&s_addr.sin_addr);
  17. //bind
  18. bind(s_fd,(struct sockaddr *)&s_addr,sizeof(struct sockaddr_in));
  19. //listen
  20. listen(s_fd,10);
  21. socketInit->s_fd=s_fd;
  22. return s_fd;
  23. }
  24. int socket_getCmd(struct InputCmd *Socket){
  25. int c_fd;
  26. int n_read=0;
  27. struct sockaddr_in c_addr;
  28. memset(&c_addr,0,sizeof(struct sockaddr_in));
  29. int len=sizeof(struct sockaddr_in);
  30. c_fd=accept(Socket->s_fd,(struct sockaddr *)&c_addr,&len);
  31. n_read=read(c_fd,Socket->cmd,sizeof(Socket->cmd));
  32. if(n_read==-1){
  33. perror("read");
  34. }else if(n_read>0){
  35. printf("\n");
  36. printf("get:%d\n",n_read);
  37. }else{
  38. printf("client quit!\n");
  39. }
  40. return n_read;
  41. }
  42. struct InputCmd Socket={
  43. .cmdName="socket",
  44. .cmd={'\0'},
  45. .Init=socket_init,
  46. .getCmd=socket_getCmd,
  47. .log={'\0'},
  48. .port="8080",
  49. .ipAddress="172.20.10.9"
  50. };
  51. struct InputCmd* addSocketToInputCmdLink(struct InputCmd *phead){
  52. if(phead==NULL){
  53. return &Socket;
  54. }else{
  55. Socket.next=phead;
  56. phead=&Socket;
  57. }
  58. }

3、将插入链表函数加入inputCmd.h等待被调用

  1. #include <stdio.h>
  2. #include <wiringPi.h>
  3. #include <wiringSerial.h>
  4. #include <unistd.h>
  5. #include <stdlib.h>
  6. #include <sys/types.h>
  7. #include <sys/socket.h>
  8. #include <netinet/in.h>
  9. #include <arpa/inet.h>
  10. #include <string.h>
  11. struct InputCmd{
  12. char cmdName[128];
  13. char devicesName[128];
  14. char cmd[32];
  15. int (*Init)(struct InputCmd *cmd,char *ipAdress,char *port);
  16. int (*getCmd)(struct InputCmd *cdm);
  17. char *log[1024];
  18. int fd;
  19. char port[12];
  20. char ipAddress[32];
  21. int s_fd;
  22. struct InputCmd *next;
  23. };
  24. struct InputCmd* addVoiceToInputCmdLink(struct InputCmd *phead);
  25. struct InputCmd* addSocketToInputCmdLink(struct InputCmd *phead);

4、main函数编写

a8f2e5452987477eb6a52744c5fe2ff9.png

mainPro.c

  1. #include <stdio.h>
  2. #include <string.h>
  3. #include "controlDevices.h"
  4. #include "inputCmd.h"
  5. struct Devices *findDevicesName(char *name,struct Devices *phead){
  6. struct Devices *tmp=phead;
  7. if(phead==NULL){
  8. return NULL;
  9. }else{
  10. while(tmp!=NULL){
  11. if(strcmp(tmp->devicesName,name)==0){
  12. return tmp;
  13. }
  14. tmp=tmp->next;
  15. }
  16. return NULL;
  17. }
  18. }
  19. int main(){
  20. if(wiringPiSetup()==-1){
  21. return -1;
  22. }
  23. struct Devices *pdevicesHead=NULL;
  24. struct InputCmd *pinputCmdHead=NULL;
  25. pdevicesHead=addbathroomLightToDevicesLink(pdevicesHead);
  26. pdevicesHead=addupstairLightToDevicesLink(pdevicesHead);
  27. pdevicesHead=addlivingroomLightToDevicesLink(pdevicesHead);
  28. pdevicesHead=addrestaurantLightToDevicesLink(pdevicesHead);
  29. pdevicesHead=addFireToDevicesLink(pdevicesHead);
  30. pinputCmdHead=addVoiceToInputCmdLink(pinputCmdHead);
  31. pinputCmdHead=addSocketToInputCmdLink(pinputCmdHead);
  32. char name[128]={'\0'};
  33. struct Devices *tmp=NULL;
  34. while(1){
  35. printf("INPUT:\n");
  36. scanf("%s",name);
  37. tmp=findDevicesName(name,pdevicesHead);
  38. if(tmp!=NULL){
  39. tmp->devicesInit(tmp->pinNum);
  40. tmp->open(tmp->pinNum);
  41. tmp->readStatus(tmp->pinNum);
  42. }
  43. }
  44. return 0;
  45. }

三、测试

将工程放入树莓派中,编译通过,无错误无警告

7b285dd651ad40bd8ad9070974e7e25b.png

四、当前阶段源代码

链接:https://pan.baidu.com/s/1vh8smf725jrxSUlDOHFOfg
提取码:sail

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/不正经/article/detail/457513
推荐阅读
相关标签
  

闽ICP备14008679号