当前位置: 首页 > news >正文

网站开发费用怎么账务处理网站建设多少钱专业

网站开发费用怎么账务处理,网站建设多少钱专业,孝感市门户,上海百度竞价最效果展示 演示视频链接#xff1a;基于树莓派实现的智能家居_哔哩哔哩_bilibilihttps://www.bilibili.com/video/BV1Tr421n7BM/?spm_id_from333.999.0.0 #xff08;PS#xff1a;房屋模型的搭建是靠纸板箱和淘宝买的家居模型#xff0c;户型参考了留学时短租的公寓~基于树莓派实现的智能家居_哔哩哔哩_bilibilihttps://www.bilibili.com/video/BV1Tr421n7BM/?spm_id_from333.999.0.0 PS房屋模型的搭建是靠纸板箱和淘宝买的家居模型户型参考了留学时短租的公寓~  前言 到目前为止对于linux的嵌入式软件开发从底层到上层都有了一定的认识。这个项目的初衷就是整合知识并以工厂模式的架构开发项目。 功能实现 实现了socket服务器远程控制卧室餐厅厕所客厅4盏灯的开启和关闭实现了语音控制卧室餐厅厕所客厅4盏灯的开启和关闭实现了当温度超过阈值的时候进行火灾报警并且可以语音关闭警报实现了进门前结合语音OLED和摄像头的人脸识别实现了实时的远程视频监控实现OLED屏幕的实时温湿度显示 开发环境 实现思路 开发板树莓派3B开发语言C编程工具Source Insight 3 工厂设计 对于这个项目的实现采用上节学到的工厂模式来设计从而提升整体代码的稳定性和可拓展性。 软件设计模式 --- 类对象和工厂模式的引入-CSDN博客 阅读功能需求后结合工厂模式的思路可以先设计两个工厂指令工厂 和 设备工厂 指令工厂存储需要使用到的指令设备工厂存储需要使用到的设备 工厂模式的主要的考量有两点 1. 工厂的类 struct device //设备工厂 {char device_name[64]; //设备名称int status;int (*init)(); //初始化函数int (*open)(); //打开设备的函数int (*close)(); //关闭设备的函数int (*read_status)(); //查看设备状态的函数struct device *next; };struct cmd //指令工厂 {char cmd_name[64]; //指令名称//char cmd_log[1024]; //指令日志int (*init)(int port, char *IP, char *UART, int BAUD); //初始化函数int (*accept)(int fd); //接受函数int (*cmd_handler)(struct device *phead, int fd); //处理指令的函数struct cmd *next; }; 2. 工厂的对象 实现思路QA Q如何实现socket服务器的远程控制 A使用之前学习的socket知识创建一个服务端一个客户端服务端负责创建套接字并绑定然后阻塞监听客户端负责建立连接后发送指令。指令在服务端通过指令工厂中socket对象的cmd_handler函数进行分析并作出相关动作。最后在main函数中使用一个线程不断阻塞等待新客户端的加入使用另一个线程不断阻塞接受客户端传来的指令并分析。 参考我之前的博文 相关的API讲解 Linux socket网络编程概述 和 相关API讲解_linux 网络编程-CSDN博客 具体如何使用API的实战父子进程版 基于Linux并结合socket网络编程的ftp服务器的实现-CSDN博客 具体如何使用API的实战多线程版 使用香橙派并基于Linux实现最终版智能垃圾桶项目 --- 上_linux 打印扔垃圾桶-CSDN博客 Q如何实现语音控制的操作 A使用之前学习的SU-03T在其官网对指令进行编辑和烧录然后通过串口来和树莓派进行通信。同样通过指令工厂中语音控制对象的cmd_handler函数来进行分析并作出相关动作。最后在main函数开启一个线程不断通过串口阻塞读取语音模块的指令并分析。 参考我之前的博文 如何设置官网指令并烧录通过电平变化来控制语音模块的实例 语音小车---6 最终整合_unioneupdatetool-CSDN博客 关于在多线程环境下通过串口通信来控制语音模块的实例 使用香橙派并基于Linux实现最终版智能垃圾桶项目 --- 下_香橙派 项目-CSDN博客 Q如何实现火灾报警 A使用之前学习的温湿度传感器DHT11和蜂鸣器通过阅读DHT11的手册在设备工厂中实现其激活和读取状态的函数在指令工厂中调用刚刚实现的函数结合手册实现温湿度的获取。最后在main函数中开启一个线程不断判断当前的温度来决定是否驱动蜂鸣器。 参考我之前的博文 DHT11的介绍和如何通过手册驱动DHT11的实例 温湿度传感器 DHT11_dht11温湿度传感器 库从哪里下载-CSDN博客 别人实现的通过树莓派驱动DHT11的例程 树莓派驱动DH11温湿度传感器_如何使用zynq驱动dh11-CSDN博客 Q如何实现OLED屏幕显示 参考我之前的博文 关于树莓派驱动OLED屏幕 使用树莓派 结合Python Adafruit驱动OLED屏幕 显示实时视频-CSDN博客 Q如何实现人脸识别 A使用一枚之前用过的USB摄像头HBV-W202012HD V33接入树莓派在设备工厂为其实现拍照等功能。然后接入阿里云的人脸识别方案当收到对应的人脸识别语音指令时在指令工厂的语音模块对象下的cmd_handler函数中添加人脸识别的代码并根据结果通过串口回传给语音模块播报结果。 参考我之前的博文 香橙派中驱动摄像头并调用阿里云物品识别的实例 使用香橙派并基于Linux实现最终版智能垃圾桶项目 --- 下_香橙派 项目-CSDN博客 树莓派中驱动摄像头并调用阿里云人脸识别的实例 基于阿里云平台 通过树莓派实现 11人脸识别-CSDN博客 硬件接线 整体的接线情况如下 注意如果外设和单片机采用了不同供电且外设和单片机存在信息交互那么就必须共地  预备工作 在有了大概的思路和硬件接线完毕完成后要进行两个重要的预备工作 摄像头的接入和mpjg-streamer的自动后台运行 由于这个项目在运行时只要涉及人脸识别就需要用到摄像头拍照并且需要实现实时的监控画面所以先将USB摄像头接入并让mpjg-streamer在每次树莓派开机的时候自动运行就很有必要了。 实现其实很简单可以参考我的这篇博文 树莓派接入USB摄像头并使用fswebcam和mjpg-streamer进行测试_在树莓派ros2中安装usb摄像头驱动-CSDN博客 语音模块SU-03T的指令编辑和烧写 这一步虽然叫预备工作但是在实际开发中随着项目的完善肯定要多次修改和烧写但是为了逻辑清晰所以将这一步归为预备工作仅展示最后的效果。 同时再次提醒只要涉及到SU-03T的串口输入输出就要下载固件而不是SDK 关于网站和具体细节请移步至上面的相关链接 引脚配置 命令设置 自定义配置 实现效果 1. 开机播报“海豹助手帮你实现智能居住体验 1. 当说出“你好小豹”可以唤醒模块模块回复“海豹在”或“有什么可以帮到你” 2. 当超过10s没有指令或说出“退下”时模块会进入休眠模式并回复“有需要再叫我” 3. 当说出“打开/关闭 客厅/卧室/餐厅/厕所 灯”时模块回复“收到”并根据当前灯的状态打开/关闭 相应的灯或回复“灯本来就开/关着哦” 4. 当说出“打开/关闭 所有灯”时模块回复“收到”并打开/关闭所有灯 5. 当说出“关闭警报”时模块回复“已关闭但为了您的安全请随时说出‘ 恢复警报 ’来恢复报警功能”并关闭警报 6.  当说出“恢复警报”时模块回复“火灾警报已经恢复工作”并恢复警报 7.  当说出“人脸识别”时开始人脸识别并根据识别结果回复“识别成功”或“识别失败” 代码开发 在刚刚提到代码编写的主要工具是“Source Insight”所以主要的代码编写就在windows下写完发送到树莓派测试 ①代码预创建 首先创建一个名为“smart_home”文件夹用于保存项目所有相关文件并在其中创建一个“si”文件夹用于保存source insight工程 在“smart_home”下创建会使用的.c和.h文件 以下是最终版的结果实际开发过程中这一步先创建可能会需要的文件后面随着实现慢慢的添加和修改 一共23个代码文件 打开source insight创建一个新工程并将代码全部包含进来并同步 具体步骤见上篇博文 最终效果 此时就可以开始正式编程了 ②代码编写 2.1 指令工厂cmd_fac.h和设备工厂dvice_fac.h的编写 这一步主要是根据上一节工厂模式的思路来实现具体有哪些函数根据代码的编写再反过来修改 cmd_fac.h #ifndef __CMDFAC_H__#define __CMDFAC_H__#include wiringPi.h #include sys/types.h #include sys/socket.h #include netinet/in.h #include arpa/inet.h #include unistd.h #include stdlib.h #include fcntl.h#include device_fac.h #include find_link.h #include mjm_uart_tool.h #include face_cmp.hstruct cmd {char cmd_name[64]; //指令名称//char cmd_log[1024]; //指令日志int (*init)(int port, char *IP, char *UART, int BAUD); //初始化函数int (*accept)(int fd); //接受函数int (*cmd_handler)(struct device *phead, int fd);struct cmd *next; };struct cmd* putSocketInLink(struct cmd *head); struct cmd* putVoiceInLink(struct cmd *head); struct cmd* putFireInLink(struct cmd *head);#endif device_fac.h #ifndef __DEVICEFAC_H__#define __DEVICEFAC_H__#include wiringPi.h #include stddef.h #include unistd.h #include stdio.h #include stdlib.hstruct device {char device_name[64]; //设备名称int status;int (*init)(); //初始化函数int (*open)(); //打开设备的函数int (*close)(); //关闭设备的函数int (*read_status)(); //查看设备状态的函数struct device *next; };struct device* putLight_bedroomInLink(struct device *head); struct device* putLight_diningroomInLink(struct device *head); struct device* putLight_livingroomInLink(struct device *head); struct device* putLight_washroomInLink(struct device *head); struct device* putDhtInLink(struct device *head); struct device* putBeeperInLink(struct device *head); struct device* putCameraInLink(struct device *head);#endif 2.2 串口通讯mjm_uart_tool.c/.h的编写 串口的代码使用我之前基于wiringPi库自己实现的函数详见 树莓派的的串口通信协议-CSDN博客 但是关于“serialSendstring”函数和“serialGetstring”函数需要进行一些修改其原因就是SU-03T语音模块在规定串口输入的时候有固定要求的帧头帧尾格式 //注意这个通过串口发送字符串的函数其中的read函数的第三个参数不能使用strlen //因为发送给语音模块的数据有固定的帧头帧尾都是16进制数不包含结束符 //所以如果使用了strlen的话就无法成功的发送 //所以为这个函数加一个len参数 void serialSendstring (const int fd, const unsigned char *s, int len) //void serialSendstring (const int fd, const char *s) {int ret;ret write (fd, s, len);//ret write (fd, s, strlen(s));if (ret 0)printf(Serial Puts Error\n); }int serialGetstring (const int fd, unsigned char *buffer) //int serialGetstring (const int fd, char *buffer) {int n_read;n_read read(fd, buffer,32);return n_read; } 主要修改有两点 “serialSendstring”函数增加一个参数len用于指示发送数据的具体长度两个函数的第二个参数都加上“unsigned”因为不加的话数据长度可能会超出普通char的范围127 mjm_uart_tool.c #include stdio.h #include stdlib.h #include stdint.h #include stdarg.h #include string.h #include termios.h #include unistd.h #include fcntl.h #include sys/ioctl.h #include sys/types.h #include sys/stat.h #include wiringSerial.hint myserialOpen (const char *device, const int baud) {struct termios options ;speed_t myBaud ;int status, fd ;switch (baud){case 9600: myBaud B9600 ; break ;case 115200: myBaud B115200 ; break ;}if ((fd open (device, O_RDWR | O_NOCTTY | O_NDELAY | O_NONBLOCK)) -1)return -1 ;fcntl (fd, F_SETFL, O_RDWR) ;// Get and modify current options:tcgetattr (fd, options) ;cfmakeraw (options) ;cfsetispeed (options, myBaud) ;cfsetospeed (options, myBaud) ;options.c_cflag | (CLOCAL | CREAD) ;options.c_cflag ~PARENB ;options.c_cflag ~CSTOPB ;options.c_cflag ~CSIZE ;options.c_cflag | CS8 ;options.c_lflag ~(ICANON | ECHO | ECHOE | ISIG) ;options.c_oflag ~OPOST ;options.c_cc [VMIN] 0 ;options.c_cc [VTIME] 100 ; // Ten seconds (100 deciseconds)tcsetattr (fd, TCSANOW, options) ;ioctl (fd, TIOCMGET, status);status | TIOCM_DTR ;status | TIOCM_RTS ;ioctl (fd, TIOCMSET, status);usleep (10000) ; // 10mSreturn fd ; }//注意这个通过串口发送字符串的函数其中的read函数的第三个参数不能使用strlen //因为发送给语音模块的数据有固定的帧头帧尾都是16进制数不包含结束符 //所以如果使用了strlen的话就无法成功的发送 //所以为这个函数加一个len参数 void serialSendstring (const int fd, const unsigned char *s, int len) //void serialSendstring (const int fd, const char *s) {int ret;ret write (fd, s, len);//ret write (fd, s, strlen(s));if (ret 0)printf(Serial Puts Error\n); }int serialGetstring (const int fd, unsigned char *buffer) //int serialGetstring (const int fd, char *buffer) {int n_read;n_read read(fd, buffer,32);return n_read; }int serialDataAvail (const int fd) {int result ;if (ioctl (fd, FIONREAD, result) -1)return -1 ;return result ; }mjm_uart_tool.h #ifndef __UART_H__#define __UART_H__int myserialOpen (const char *device, const int baud); void serialSendstring (const int fd, const unsigned char *s, int len); int serialGetstring (const int fd, unsigned char *buffer); int serialDataAvail (const int fd);#endif2.3 在工厂链表中查找对象的代码find_link.c/.h的编写 这部分的代码实现的功能就是封装“在工厂链表中查找特定对象”的函数其实现思路就是根据对象的名字来在链表中进行遍历 find_link.c #include find_link.hstruct device* findDEVICEinLink(char *name, struct device *phead) { struct device *p phead; while(p ! NULL){ if(strcmp(p-device_name,name)0){ return p; } p p-next; } return NULL; }struct cmd* findCMDinLink(char *name, struct cmd *phead) { struct cmd *p phead; while(p ! NULL){ if(strcmp(p-cmd_name,name)0){ return p; } p p-next; } return NULL; } find_link.h #ifndef __FINDLINK_H__#define __FINDLINK_H__#include stddef.h #include stdio.h #include string.h #include device_fac.h #include cmd_fac.hstruct device* findDEVICEinLink(char *name, struct device *phead); struct cmd* findCMDinLink(char *name, struct cmd *phead);#endif 2.4 OLED显示代码oled_show.c/.h python代码的编写 这部分的代码在之前给出的链接里已经大致实现其核心思路就是先用python调用Adafruit_Python_SSD1306库实现清屏显示温湿度和显示图片的代码再用C语言调用python封装这三个函数最后获得可以清屏显示温湿度和显示图片的C函数 oled_camera.py def init(): # Raspberry Pi pin configuration:RST 24# Note the following are only used with SPI:DC 23SPI_PORT 0SPI_DEVICE 0# 128x64 display with hardware I2C:disp Adafruit_SSD1306.SSD1306_128_64(rstRST)# Initialize library.disp.begin()# Clear display.disp.clear()disp.display()def display(): # Raspberry Pi pin configuration:RST 24# Note the following are only used with SPI:DC 23SPI_PORT 0SPI_DEVICE 0# 128x32 display with hardware I2C:disp Adafruit_SSD1306.SSD1306_128_64(rstRST)# Initialize library.disp.begin()img Image.open(/home/pi/mjm_code/smart_home/face.png)img_resized img.resize((128, 64),Image.LANCZOS)image img_resized.convert(1)# Display image.disp.image(image)disp.display()def tmphumi(tmp, humi):# Raspberry Pi pin configuration:RST 24# Note the following are only used with SPI:DC 23SPI_PORT 0SPI_DEVICE 0# 128x32 display with hardware I2C:disp Adafruit_SSD1306.SSD1306_128_64(rstRST)# Initialize library.disp.begin()# Create blank image for drawing.# Make sure to create image with mode 1 for 1-bit color.width disp.widthheight disp.heightimage Image.new(1, (width, height))# Get drawing object to draw on image.draw ImageDraw.Draw(image)# Load default font.font ImageFont.load_default()str1 ftmperature: {tmp} Cstr2 fhumidity: {humi} %# Write two lines of text.draw.text((20,20), str1, fontfont, fill255)draw.text((20,40), str2, fontfont, fill255)disp.image(image)disp.display()#测试用 if __name__ __main__: init()#display()tmphumi(25,50) oled_show.c #include stdio.h #include stddef.h #include stdlib.h #include string.h #include Python.h#include oled_show.hvoid oled_init(void) {Py_Initialize();PyObject *sys PyImport_ImportModule(sys);PyObject *path PyObject_GetAttrString(sys, path);PyList_Append(path, PyUnicode_FromString(.)); }void oled_final(void) {Py_Finalize(); }void oled_show_init(void) //清屏 {PyObject *pModule PyImport_ImportModule(oled_camera); if (!pModule){PyErr_Print();printf(Error: failed to load module\n);goto FAILED_MODULE; }PyObject *pFunc PyObject_GetAttrString(pModule, init); if (!pFunc){PyErr_Print();printf(Error: failed to load function\n);goto FAILED_FUNC;}PyObject *pValue PyObject_CallObject(pFunc, NULL);if (!pValue){PyErr_Print();printf(Error: function call failed\n);goto FAILED_VALUE;}FAILED_RESULT:Py_DECREF(pValue); FAILED_VALUE:Py_DECREF(pFunc); FAILED_FUNC:Py_DECREF(pModule); FAILED_MODULE: }void oled_show(void) //显示图片 {PyObject *pModule PyImport_ImportModule(oled_camera); if (!pModule){PyErr_Print();printf(Error: failed to load module\n);goto FAILED_MODULE; }PyObject *pFunc PyObject_GetAttrString(pModule, display); if (!pFunc){PyErr_Print();printf(Error: failed to load function\n);goto FAILED_FUNC;}PyObject *pValue PyObject_CallObject(pFunc, NULL);if (!pValue){PyErr_Print();printf(Error: function call failed\n);goto FAILED_VALUE;}FAILED_RESULT:Py_DECREF(pValue); FAILED_VALUE:Py_DECREF(pFunc); FAILED_FUNC:Py_DECREF(pModule); FAILED_MODULE: }void oled_tmphumi(int tmp, int humi) //显示温湿度 {PyObject *pModule PyImport_ImportModule(oled_camera); //加载python文件if (!pModule){PyErr_Print();printf(Error: failed to load module\n);goto FAILED_MODULE; //goto的意思就是如果运行到这里就直接跳转到FAILED_MODULE}PyObject *pFunc PyObject_GetAttrString(pModule, tmphumi); //加载python文件中的对应函数if (!pFunc){PyErr_Print();printf(Error: failed to load function\n);goto FAILED_FUNC;}//创建一个字符串作为参数PyObject *pArgs Py_BuildValue((i,i),tmp,humi); //(i,i)代表有两个int的元组PyObject *pValue PyObject_CallObject(pFunc, pArgs);if (!pValue){PyErr_Print();printf(Error: function call failed\n);goto FAILED_VALUE;}FAILED_RESULT:Py_DECREF(pValue); FAILED_VALUE:Py_DECREF(pFunc); FAILED_FUNC:Py_DECREF(pModule); FAILED_MODULE:} oled_show.h #ifndef __oled__H #define __oled__Hvoid oled_init(void); void oled_final(void); void oled_show_init(void); //清屏 void oled_show(void); //显示图片 void oled_tmphumi(int tmp, int humi); //显示温湿度#endif2.5 人脸识别代码face_cmp.c/.h python代码的编写 这部分的代码在之前给出的链接里已经大致实现其核心思路就是先用python调用阿里云的1:1人脸识别再用C语言调用python最后获得可以进行人脸识别的C函数 face.py # -*- coding: utf-8 -*- # 引入依赖?# 最低SDK版本要求facebody20191230的SDK版本需大于等于4.0.8 # 可以在此仓库地址中引用最新版本SDKhttps://pypi.org/project/alibabacloud-facebody20191230/ # pip install alibabacloud_facebody20191230import os import io from urllib.request import urlopen from alibabacloud_facebody20191230.client import Client from alibabacloud_facebody20191230.models import CompareFaceAdvanceRequest from alibabacloud_tea_openapi.models import Config from alibabacloud_tea_util.models import RuntimeOptionsdef face_detect():config Config(# 创建AccessKey ID和AccessKey Secret请参考https://help.aliyun.com/document_detail/175144.html? # 如果您用的是RAM用户的AccessKey还需要为RAM用户授予权限AliyunVIAPIFullAccess请参考https://help.aliyun.com/document_detail/145025.html? # 从环境变量读取配置的AccessKey ID和AccessKey Secret。运行代码示例前必须先配置环境变量? access_key_idos.environ.get(ALIBABA_CLOUD_ACCESS_KEY_ID),access_key_secretos.environ.get(ALIBABA_CLOUD_ACCESS_KEY_SECRET),# 访问的域? endpointfacebody.cn-shanghai.aliyuncs.com,# 访问的域名对应的regionregion_idcn-shanghai)runtime_option RuntimeOptions()compare_face_request CompareFaceAdvanceRequest()#场景一文件在本地streamA open(r/home/pi/mjm_code/smart_home/mjm.png, rb) #预存的照? compare_face_request.image_urlaobject streamAstreamB open(r/home/pi/mjm_code/smart_home/face.png, rb) #待测试的照片compare_face_request.image_urlbobject streamBtry:# 初始化Clientclient Client(config)response client.compare_face_advance(compare_face_request, runtime_option)# 获取整体结果#print(response.body)# 单独打印置信? confidence response.body.to_map()[Data][Confidence] #to_map()函数很重要不要忘记score int(confidence)#print(score)return scoreexcept Exception as error:# 获取整体报错信息print(error)# 获取单个字段print(error.code)# tips: 可通过error.__dict__查看属性名?# 关闭? streamA.close()streamB.close()if __name__ __main__:face_detect() face_cmp.c #include stdio.h #include stddef.h #include stdlib.h #include string.h #include Python.h#include face_cmp.hvoid face_init(void) {Py_Initialize();PyObject *sys PyImport_ImportModule(sys);PyObject *path PyObject_GetAttrString(sys, path);PyList_Append(path, PyUnicode_FromString(.)); }void face_final(void) {Py_Finalize(); }int face_score(void) //python下face_detect函数返回的是已经经过提取和取证过的置信度score是个int型 {PyObject *pModule PyImport_ImportModule(face); //加载python文件if (!pModule){PyErr_Print();printf(Error: failed to load module\n);goto FAILED_MODULE; //goto的意思就是如果运行到这里就直接跳转到FAILED_MODULE}PyObject *pFunc PyObject_GetAttrString(pModule, face_detect); //加载python文件中的对应函数if (!pFunc){PyErr_Print();printf(Error: failed to load function\n);goto FAILED_FUNC;}PyObject *pValue PyObject_CallObject(pFunc, NULL);if (!pValue){PyErr_Print();printf(Error: function call failed\n);goto FAILED_VALUE;}int result 0;if (!PyArg_Parse(pValue, i, result)) //ace_detect函数返回的是已经经过提取和取证过的置信度score是个int型用‘i’表示{PyErr_Print();printf(Error: parse failed);goto FAILED_RESULT;}/* 如果函数返回的是字符串上面的PyArg_Parse则需要用‘s’来表示且下面注释的代码非常重要因为字符串名代表了其首地址所以不能直接复制而是需要使用strncpy函数category (char *)malloc(sizeof(char) * (strlen(result) 1) ); //开辟一个新的字符串常量。1是为了留出空间给\0memset(category, 0, (strlen(result) 1)); //初始化字符串strncpy(category, result, (strlen(result) 1)); //将result的结果复制给新的字符串*/FAILED_RESULT:Py_DECREF(pValue); FAILED_VALUE:Py_DECREF(pFunc); FAILED_FUNC:Py_DECREF(pModule); FAILED_MODULE:return result; } face_cmp.h #ifndef __face__H #define __face__Hvoid face_init(void); void face_final(void); int face_score(void);#endif2.6 4盏灯的代码light_xxx.c的编写 作为设备工厂的对象灯代码的编写就是选择性的实现设备工厂的类并且4盏灯的代码除了wiringPi对应的引脚和名字不同之外几乎没有任何差别。 light_XXXX.c #include device_fac.h#define lightXXXX X //根据硬件接线来int light_XXXX_init() {pinMode (lightXXXX, OUTPUT); digitalWrite (lightXXXX, HIGH) ; }int light_XXXX_open() {digitalWrite (lightXXXX, LOW) ; }int light_XXXX_close() {digitalWrite (lightXXXX, HIGH) ; }int light_XXXX_status() {return digitalRead(lightXXXX); }struct device light_XXXX {.device_name light_XXXX,.init light_XXXX_init,.open light_XXXX_open,.close light_XXXX_close,.read_status light_XXXX_read_status, };struct device* putLight_XXXXInLink(struct device *head) { struct device *p head; if(p NULL){ head light_XXXX; }else{ light_XXXX.next head; head light_XXXX; } return head; } 2.7 温湿度传感器dht11.c的编写 作为设备工厂的对象dht11代码的编写就是选择性的实现设备工厂的类 dht11.c #include device_fac.h#define dht 4int dht_start() {pinMode(dht, OUTPUT); //起始拉高电平digitalWrite(dht, 1); delay(1000); pinMode(dht, OUTPUT); //拉低超过18msdigitalWrite(dht, 0);delay(21);digitalWrite(dht, 1); //拉高电平等响应pinMode(dht, INPUT);delayMicroseconds(28); }int dht_read_status() {return digitalRead(dht); }struct device dht11 {.device_name dht,.open dht_start,.read_status dht_read_status, };struct device* putDhtInLink(struct device *head) { struct device *p head; if(p NULL){ head dht11; }else{ dht11.next head; head dht11; } return head; }2.8 蜂鸣器beeper.c的编写 作为设备工厂的对象蜂鸣器代码的编写就是选择性的实现设备工厂的类蜂鸣器的实现和4盏灯极其类似直接看代码 beeper.c #include device_fac.h#define io 5int beep_init() {pinMode (io, OUTPUT); digitalWrite (io, HIGH) ; }int beep_open() {digitalWrite (io, LOW) ; //蜂鸣器响 }int beep_close() {digitalWrite (io, HIGH) ; //蜂鸣器不响 }struct device beeper {.device_name beeper,.init beep_init,.open beep_open,.close beep_close, };struct device* putBeeperInLink(struct device *head) { struct device *p head; if(p NULL){ head beeper; }else{ beeper.next head; head beeper; } return head; } 2.9 摄像头camera.c的编写 作为设备工厂的对象摄像头代码的编写就是选择性的实现设备工厂的类 camera.c #include device_fac.hint camera_takePic() //返回1成功拍到照片返回0拍照失败 {system(wget http://192.168.2.56:8080/?actionsnapshot -O /home/pi/mjm_code/smart_home/face.png); //拍照delay(10);//给一点时间让照片拍出来if(0 access(/home/pi/mjm_code/smart_home/face.png, F_OK)){ //如果照片成功拍到了return 1;}else{return 0;} }int camera_removePic() {return remove(/home/pi/mjm_code/smart_home/face.png); }struct device camera {.device_name camera,.open camera_takePic,.close camera_removePic, };struct device* putCameraInLink(struct device *head) { struct device *p head; if(p NULL){ head camera; }else{ camera.next head; head camera; } return head; } 2.10 socket控制socket_ctl.c的编写 作为指令工厂的对象socket控制就是选择性的实现指令工厂的类 socket_ctl.c #include cmd_fac.hchar *HELP welcome to smart home! Here are some cmd instructions:\n\oll\---open livingroom light\n\cll\---close livingroom light\n\odl\---open diningroom light\n\cdl\---close diningroom light\n\obl\---open bedroom light\n\cbl\---close bedroom light\n\owl\---open washroom light\n\cwl\---close washroom light\n\quit\---disconnect\ntype \help\ to review all the command\n; int conn_sockfd;int answer_success(int fd) {int ret 0;ret write(fd,operation success,18);if(ret -1){perror(write1);return -1;}else{return 0;} }int answer_fail(int fd) {int ret 0;ret write(fd,already open/close,19);if(ret -1){perror(write2);return -1;}else{return 0;} }int handler(int fd, char readbuf[128], struct device *phead) {struct device *device_pfind NULL;int ret; int i 0; char str[128]; //将读到的数据备份在这里 strcpy(str,readbuf); //由于字符串的首地址是字符串的名字所以此时相当于传入的地址所有对字符串的操作都会影响它所以需要进行备份先备份再对备份的数据进行数据处理就不会影响原数据了if(strcmp((char *)str,obl)0){ //收到打开卧室灯的指令device_pfind findDEVICEinLink(light_bedroom,phead);if(device_pfind-read_status()){//如果卧室灯关着device_pfind-open();answer_success(fd);}else{//如果卧室灯开着answer_fail(fd);}}else if(strcmp((char *)str,cbl)0){ //收到关闭卧室灯的指令device_pfind findDEVICEinLink(light_bedroom,phead);if(!device_pfind-read_status()){//如果卧室灯开着device_pfind-close();answer_success(fd);}else{//如果卧室灯关着answer_fail(fd);}}else if(strcmp((char *)str,odl)0){ //收到打开厨房灯的指令device_pfind findDEVICEinLink(light_diningroom,phead);if(device_pfind-read_status()){//如果厨房灯关着device_pfind-open();answer_success(fd);}else{//如果厨房灯开着answer_fail(fd);}}else if(strcmp((char *)str,cdl)0){ //收到关闭厨房灯的指令device_pfind findDEVICEinLink(light_diningroom,phead);if(!device_pfind-read_status()){//如果厨房灯开着device_pfind-close();answer_success(fd);}else{//如果厨房灯关着answer_fail(fd);}}else if(strcmp((char *)str,oll)0){ //收到打开客厅灯的指令device_pfind findDEVICEinLink(light_livingroom,phead);if(device_pfind-read_status()){//如果客厅灯关着device_pfind-open();answer_success(fd);}else{//如果客厅灯开着answer_fail(fd);}}else if(strcmp((char *)str,cll)0){ //收到关闭客厅灯的指令device_pfind findDEVICEinLink(light_livingroom,phead);if(!device_pfind-read_status()){//如果客厅灯开着device_pfind-close();answer_success(fd);}else{//如果客厅灯关着answer_fail(fd);}}else if(strcmp((char *)str,owl)0){ //收到打开厕所灯的指令device_pfind findDEVICEinLink(light_washroom,phead);if(device_pfind-read_status()){//如果厕所灯关着device_pfind-open();answer_success(fd);}else{//如果厕所灯开着answer_fail(fd);}}else if(strcmp((char *)str,cwl)0){ //收到关闭厕所灯的指令device_pfind findDEVICEinLink(light_washroom,phead);if(!device_pfind-read_status()){//如果厕所灯开着device_pfind-close();answer_success(fd);}else{//如果厕所灯关着answer_fail(fd);}}else if(strcmp((char *)str,quit)0){ret write(fd,Bye,4);if(ret -1){perror(write5);return -1;}else{return 0;}}else if(strcmp((char *)str,help)0){ret write(fd,HELP,512);if(ret -1){perror(write4);return -1;}else{return 0;}}else{return -1;}}int socket_init(int port, char *IP, char *UART, int BAUD) {int sockfd;int ret 0;int len sizeof(struct sockaddr_in);struct sockaddr_in my_addr;sockfd socket(AF_INET,SOCK_STREAM,0); if(sockfd -1){ perror(socket); return -1; }else{ printf(socket success, sockfd %d\n,sockfd);}//bind my_addr.sin_family AF_INET; my_addr.sin_port htons(port);//host to net (2 bytes) //此处原本是atoi(port)但考虑到port本来就是int所以不用使用atoiinet_aton(IP,my_addr.sin_addr); //char* format - net format ret bind(sockfd, (struct sockaddr *)my_addr, len);if(ret -1){ perror(bind); return -1; }else{ printf(bind success\n); }//listen ret listen(sockfd,10); if(ret -1){ perror(listen); return -1; }else{ printf(listening...\n); }return sockfd; }int socket_accept(int sockfd) //return 1代表连接成功return 0代表连接错误 {int ret 0;int len sizeof(struct sockaddr_in);struct sockaddr_in client_addr;//accept conn_sockfd accept(sockfd,(struct sockaddr *)client_addr,len);if(conn_sockfd -1){ perror(accept); return -1; }else{ printf(accept success, client IP %s\n,inet_ntoa(client_addr.sin_addr)); fflush(stdout);ret write(conn_sockfd,HELP,512);if(ret -1){perror(write3);return -2;}else{return 1; //return 给main里的conn_flag}}}//socket实现的handler函数下面这个没有使用第二个参数fd //这是因为我发现把conn_sockfd传进来会导致recv函数不认识这个标识符 //但我不太清楚为什么会这样因为我用这种方法传递其他fd就不会报错 int socket_receiveANDhandle(struct device *phead, int fd) {int ret;char readbuf[128];memset(readbuf,0,sizeof(readbuf)); ret recv(conn_sockfd, readbuf, sizeof(readbuf), 0); if(ret 0){ //如果recv函数返回0表示连接已经断开 printf(client has quit\n); fflush(stdout); close(conn_sockfd); return -1; }else if(ret -1){ perror(recv); return 0; //这个值会return 给 main中的conn_flag。此时打印一遍错误信息就会结束如果不把conn_flag置0在一个客户端退出另一个客户端还未接入时就会不停的打印错误信息 //pthread_exit(NULL); //此处不能退出因为因为这样如果有一个客户端接入并退出后这个线程就会退出为了保证一个客户端退出后另一个客户端还可以接入并正常工作此处仅显示错误信息而不退出 }ret handler(conn_sockfd, readbuf, phead);if(ret -1){printf(socket_cmd_handler error!\n);}printf(\nclient: %s\n,readbuf);fflush(stdout);return 1; //这句很重要正常情况下要保持conn_flag为1 }struct cmd sockt {.cmd_name socket,.init socket_init,.accept socket_accept,.cmd_handler socket_receiveANDhandle, };struct cmd* putSocketInLink(struct cmd *head) {struct cmd *p head; if(p NULL){ head sockt; }else{ sockt.next head; head sockt; } return head; } 2.11 火灾控制fire_ctl.c的编写 作为指令工厂的对象火灾控制就是选择性的实现指令工厂的类 fire_ctl.c #include cmd_fac.hint readDataFromDHT(struct device *phead, int fd) //此处的第二个参数fd用来指示返回的是温度还是湿度 {unsigned char crc, i;unsigned long data 0;struct device *device_pfind NULL;device_pfind findDEVICEinLink(dht,phead);device_pfind-open();if (!device_pfind-read_status()){ //主机接收到从机发送的响应信号低电平while(!device_pfind-read_status()); //主机接收到从机发送的响应信号高电平for (i 0; i 32; i){while(device_pfind-read_status()); //数据位开始的54us低电平while(!device_pfind-read_status()); //数据位开始的高电平就开始delayMicroseconds(50); //等50us此时电平高为1低为0(data) * 2; //进位if (device_pfind-read_status()){(data);}}for (i 0; i 8; i){while(device_pfind-read_status()); while(!device_pfind-read_status()); delayMicroseconds(50); crc * 2; if (device_pfind-read_status()){crc;}}//return 1;}else{//return 0;}if(fd 0){return ((data 8) 0xff); //将温度的整数位返回}else if(fd 1){return ((data 24) 0xff); //将湿度的整数位返回}//温度小数位data 0xff//湿度小数位(data 16) 0xff}struct cmd fire {.cmd_name fire,.cmd_handler readDataFromDHT, };struct cmd* putFireInLink(struct cmd *head) {struct cmd *p head; if(p NULL){ head fire; }else{ fire.next head; head fire; } return head; } 2.12 语音控制voice_ctl.c的编写 作为指令工厂的对象语音控制就是选择性的实现指令工厂的类 voice_ctl.c #include cmd_fac.h#define threhold 70int v_answer(int fd, int cmd) {unsigned char buffer[6] {0xAA, 0X55, 0X00, 0X00, 0X55, 0XAA};int ret 0;if(cmd 1){ //回复 成功打开buffer[2] 0X02;buffer[3] 0X01;}else if(cmd 2){ //回复 成功关闭buffer[2] 0X04;buffer[3] 0X03;}else if(cmd 3){ //回复 灯本来就开着哦buffer[2] 0X03;buffer[3] 0X02;}else if(cmd 4){ //回复 灯本来就关着哦buffer[2] 0X05;buffer[3] 0X04;}else if(cmd 5){ //回复 识别成功buffer[2] 0X06;buffer[3] 0X05;}else if(cmd 6){ //回复 识别失败buffer[2] 0X07;buffer[3] 0X06;}serialSendstring (fd, buffer, 6); }int voice_init(int port, char *IP, char *UART, int BAUD) {int serial_fd;serial_fd myserialOpen (UART, BAUD);if(serial_fd 0){perror(serial:);return -1;}else{return serial_fd;} }int voice_accept(int serialfd) {int ret;ret serialDataAvail (serialfd);if(ret ! -1){return ret;}else{perror(serial_DataAvail:);return -1;} }int voice_receiveANDhandle(struct device *phead, int fd) {struct device *device_pfind NULL;char readbuf[32] {\0};int re;int score;//人脸识别结果int val 0;int flags fcntl(fd, F_GETFL, 0);fcntl(fd, F_SETFL, flags | O_NONBLOCK);int len serialGetstring (fd,readbuf) ;if(len 0){perror(serialGetstring:);}if(strcmp(readbuf,opli) 0){ //收到打开客厅灯的指令device_pfind findDEVICEinLink(light_livingroom,phead);if(device_pfind-read_status()){//如果客厅灯关着device_pfind-open();v_answer(fd,1);}else{//如果客厅灯开着v_answer(fd,3);}}else if(strcmp(readbuf,clli) 0){ //收到关闭客厅灯的指令device_pfind findDEVICEinLink(light_livingroom,phead);if(!device_pfind-read_status()){//如果客厅灯开着device_pfind-close();v_answer(fd,2);}else{//如果客厅灯关着v_answer(fd,4);}}else if(strcmp(readbuf,opbe) 0){ //收到打开卧室灯的指令device_pfind findDEVICEinLink(light_bedroom,phead);if(device_pfind-read_status()){//如果卧室灯关着device_pfind-open();v_answer(fd,1);}else{//如果卧室灯开着v_answer(fd,3);}}else if(strcmp(readbuf,clbe) 0){ //收到关闭卧室灯的指令device_pfind findDEVICEinLink(light_bedroom,phead);if(!device_pfind-read_status()){//如果卧室灯开着device_pfind-close();v_answer(fd,2);}else{//如果卧室灯关着v_answer(fd,4);}}else if(strcmp(readbuf,opdi) 0){ //收到打开厨房灯的指令device_pfind findDEVICEinLink(light_diningroom,phead);if(device_pfind-read_status()){//如果厨房灯关着device_pfind-open();v_answer(fd,1);}else{//如果厨房灯开着v_answer(fd,3);}}else if(strcmp(readbuf,cldi) 0){ //收到关闭厨房灯的指令device_pfind findDEVICEinLink(light_diningroom,phead);if(!device_pfind-read_status()){//如果厨房灯开着device_pfind-close();v_answer(fd,2);}else{//如果厨房灯关着v_answer(fd,4);}}else if(strcmp(readbuf,opwa) 0){ //收到打开厕所灯的指令device_pfind findDEVICEinLink(light_washroom,phead);if(device_pfind-read_status()){//如果厕所灯关着device_pfind-open();v_answer(fd,1);}else{//如果厕所灯开着v_answer(fd,3);}}else if(strcmp(readbuf,clwa) 0){ //收到关闭厕所灯的指令device_pfind findDEVICEinLink(light_washroom,phead);if(!device_pfind-read_status()){//如果厕所灯开着device_pfind-close();v_answer(fd,2);}else{//如果厕所灯关着v_answer(fd,4);}}else if(strcmp(readbuf,opal) 0){ //收到打开所有灯的指令device_pfind findDEVICEinLink(light_washroom,phead);device_pfind-open();device_pfind findDEVICEinLink(light_diningroom,phead);device_pfind-open();device_pfind findDEVICEinLink(light_bedroom,phead);device_pfind-open();device_pfind findDEVICEinLink(light_livingroom,phead);device_pfind-open();}else if(strcmp(readbuf,clal) 0){ //收到关闭所有灯的指令device_pfind findDEVICEinLink(light_washroom,phead);device_pfind-close();device_pfind findDEVICEinLink(light_diningroom,phead);device_pfind-close();device_pfind findDEVICEinLink(light_bedroom,phead);device_pfind-close();device_pfind findDEVICEinLink(light_livingroom,phead);device_pfind-close();}else if(strcmp(readbuf,gbjb) 0){ //收到关闭警报指令return 3;}else if(strcmp(readbuf,hfjb) 0){ //收到恢复警报指令return 2;}else if(strcmp(readbuf,rlsb) 0){ //收到人脸识别指令device_pfind findDEVICEinLink(camera,phead);re device_pfind-open(); //拍照if(re 1){ //拍照成功oled_show_init(); //OLED清屏oled_show(); //显示拍出的照片score face_score(); //进行人脸识别获取置信度分数printf(score %d\n,score);fflush(stdout);if(score threhold){//识别成功v_answer(fd,5);val 4;}else{//识别失败v_answer(fd,6);val 5;}re device_pfind-close(); //删除照片if(re ! 0){printf(pic remove fail!\n);fflush(stdout);}}else{ //拍照失败v_answer(fd,6);val 5;}score 0;return val; //return 4说明 成功return 5说明失败 }}struct cmd voice {.cmd_name voice,.init voice_init,.accept voice_accept,.cmd_handler voice_receiveANDhandle, };struct cmd* putVoiceInLink(struct cmd *head) {struct cmd *p head; if(p NULL){ head voice; }else{ voice.next head; head voice; } return head; } 2.13 main函数的编写: main函数的核心思路就是利用以上所有代码提供的函数接口来完成项目的总体逻辑 main函数共有4个线程 socket等待连接的线程socket连接成功后接受数据的线程语音控制人脸识别线程火灾报警线程 main.c #include stdio.h #include string.h #include stdlib.h #include pthread.h#include device_fac.h #include cmd_fac.h #include find_link.h #include face_cmp.h #include oled_show.h#define port 8888 //端口号 #define IP 192.168.2.56 //IP地址 #define UART /dev/ttyAMA0 //串口驱动文件 #define BAUD 115200 //波特率 #define FIRE_TMP 30 //火灾报警温度struct device *device_phead NULL; struct cmd *cmd_phead NULL; int sockfd; int serialfd; //int conn_sockfd; int conn_flag 0; int ret; //char readbuf[128]; int voice_return_flag; int tmp; int humi;pthread_mutex_t mutex;void *thread1(void *arg) //socket等待连接的线程 {struct cmd *cmd_pfind_th1 NULL;while(1){cmd_pfind_th1 findCMDinLink(socket,cmd_phead);if(cmd_pfind_th1!NULL){//acceptconn_flag cmd_pfind_th1-accept(sockfd); //conn_flag保证了接收连接成功后才可以开始接收数据if(conn_flag ! 1 ){printf(s_accept error!\n);fflush(stdout);}}else{printf(thread1:cant find socket in link!\n);fflush(stdout);}}pthread_exit(NULL); }void *thread2(void *arg) //socket连接成功后接受数据的线程 { struct cmd *cmd_pfind_th2 NULL;while(1){while(conn_flag 1){cmd_pfind_th2 findCMDinLink(socket,cmd_phead);if(cmd_pfind_th2!NULL){conn_flag cmd_pfind_th2-cmd_handler(device_phead,0);//receive msg form client and handle cmdif(conn_flag -1){break;//说明客户端已退出退出内层while,等待下一个客户端接入}}else{printf(thread2:cant find socket in link!\n);fflush(stdout);}}}pthread_exit(NULL); }void *thread3(void *arg) //语音控制人脸识别线程 {struct cmd *cmd_pfind_th3 NULL;while(1){cmd_pfind_th3 findCMDinLink(voice,cmd_phead);if(cmd_pfind_th3!NULL){while(cmd_pfind_th3-accept(serialfd)){ //当串口接收到信息时即当语音模块发送信息时pthread_mutex_lock(mutex); //上锁voice_return_flag cmd_pfind_th3-cmd_handler(device_phead,serialfd);//voice的cmd_handler函数的返回值//返回2接收到“恢复警报”指令//返回3接收到“关闭警报”指令//返回4接收到“人脸识别”指令且识别成功//返回5接收到“人脸识别”指令且识别失败pthread_mutex_unlock(mutex); //解锁}}else{printf(thread3:cant find voice in link!\n);fflush(stdout);}}pthread_exit(NULL); }void *thread4(void *arg) //火灾报警线程 {struct cmd *cmd_pfind_th4 NULL;struct device *device_pfind_th4 NULL;while(1){//delay(1000);//不用delay因为线程间本来就是竞争关系加上一共有多个线程哪怕不delay也不会很快速的运行cmd_pfind_th4 findCMDinLink(fire,cmd_phead);if(cmd_pfind_th4!NULL){tmp cmd_pfind_th4-cmd_handler(device_phead,0);//检测温度humi cmd_pfind_th4-cmd_handler(device_phead,1);//检测湿度printf(current temperature:%d\n,tmp); //不断打印当前的温度同时充当心跳包fflush(stdout); pthread_mutex_lock(mutex); //上锁oled_show_init(); //清屏int tmp1 tmp; //保留tmp的值至于为什么要保留存疑如果不保留之后报警就会失效oled_tmphumi(tmp1,humi); //显示在OLED上pthread_mutex_unlock(mutex); //解锁if(tmp FIRE_TMP voice_return_flag!3){//如果温度大于XX度且用户希望警报打开device_pfind_th4 findDEVICEinLink(beeper,device_phead);//此处不需要再判断device_pfind是否为空因为main函数在初始化的时候判断过了device_pfind_th4-open(); }else{ //否则就关闭警报device_pfind_th4 findDEVICEinLink(beeper,device_phead);//此处不需要再判断device_pfind是否为空因为main函数在初始化的时候判断过了device_pfind_th4-close();}}else{printf(thread4:cant find fire in link!\n);fflush(stdout);}}pthread_exit(NULL); }int main() {pthread_t t1_id;pthread_t t2_id;pthread_t t3_id;pthread_t t4_id;struct device *device_pfind NULL;struct cmd *cmd_pfind NULL;wiringPiSetup(); //初始化wiringPi库//指令工厂初始化cmd_phead putSocketInLink(cmd_phead);cmd_phead putVoiceInLink(cmd_phead);cmd_phead putFireInLink(cmd_phead);//设备工厂初始化device_phead putLight_bedroomInLink(device_phead);device_phead putLight_diningroomInLink(device_phead);device_phead putLight_livingroomInLink(device_phead);device_phead putLight_washroomInLink(device_phead);device_phead putDhtInLink(device_phead);device_phead putBeeperInLink(device_phead);device_phead putCameraInLink(device_phead);device_pfind findDEVICEinLink(light_livingroom,device_phead);if(device_pfind ! NULL){device_pfind-init();}else{printf(main:cant find livingroom in link!\n);}device_pfind findDEVICEinLink(light_diningroom,device_phead);if(device_pfind ! NULL){device_pfind-init();}else{printf(main:cant find diningroom in link!\n);}device_pfind findDEVICEinLink(light_bedroom,device_phead);if(device_pfind ! NULL){device_pfind-init();}else{printf(main:cant find bedroom in link!\n);}device_pfind findDEVICEinLink(light_washroom,device_phead);if(device_pfind ! NULL){device_pfind-init();}else{printf(main:cant find washroom in link!\n);}device_pfind findDEVICEinLink(beeper,device_phead);if(device_pfind ! NULL){device_pfind-init();}else{printf(main:cant find beeper in link!\n);}//对于dht,唯一需要的初始化就是在通电后延时1秒越过不稳定状态delay(1000); //camera不需要初始化//socket初始化cmd_pfind findCMDinLink(socket,cmd_phead);if(cmd_pfind ! NULL){sockfd cmd_pfind-init(port,IP,NULL,0);if(sockfd -1){printf(socket init fail!\n);}}else{printf(main:cant find socket in link!\n);}//语音模块初始化cmd_pfind findCMDinLink(voice,cmd_phead);if(cmd_pfind ! NULL){serialfd cmd_pfind-init(0,NULL,UART,BAUD);if(serialfd -1){printf(main:voice init fail!\n);}}else{printf(main:cant find voice in link!\n);}//人脸识别初始化face_init();//OLED初始化oled_init();//互斥锁初始化ret pthread_mutex_init(mutex, NULL);if(ret ! 0){printf(mutex create error\n);}//socket控制线程ret pthread_create(t1_id,NULL,thread1,NULL);if(ret ! 0){printf(thread1 create error\n);}ret pthread_create(t2_id,NULL,thread2,NULL);if(ret ! 0){printf(thread2 create error\n);}//语音控制人脸识别线程ret pthread_create(t3_id,NULL,thread3,NULL);if(ret ! 0){printf(thread3 create error\n);}//火灾报警线程ret pthread_create(t4_id,NULL,thread4,NULL);if(ret ! 0){printf(thread4 create error\n);}pthread_join(t1_id,NULL);pthread_join(t2_id,NULL);pthread_join(t3_id,NULL);pthread_join(t4_id,NULL);//释放python解释器face_final();oled_final();return 0; }以上所有代码均属于服务端 以下代码属于客户端 2.14 socke客户端 client.c的编写 客户端的编写大量参考之前写的socket客户端详见上面的相关链接 client.c #include sys/types.h #include sys/socket.h #include stdio.h #include unistd.h #include netinet/in.h #include arpa/inet.h #include linux/in.h #include string.h #include sys/wait.h #include stdlib.h #include sys/stat.h #include errno.h #include fcntl.h#define port 8888 #define IP 192.168.2.56int main() {int sockfd;int ret;int n_read;int n_write;char readbuf[512];char msg[128];int fd; //fifochar fifo_readbuf[20] {0};char *fifo_msg quit;pid_t fork_return;/*if(argc ! 3){printf(param error!\n);return 1;}*/struct sockaddr_in server_addr;memset(server_addr,0,sizeof(struct sockaddr_in));//socketsockfd socket(AF_INET,SOCK_STREAM,0);if(sockfd -1){perror(socket);return 1;}else{printf(socket success, sockfd %d\n,sockfd);}//connectserver_addr.sin_family AF_INET;server_addr.sin_port htons(port);//host to net (2 bytes)inet_aton(IP,server_addr.sin_addr); ret connect(sockfd, (struct sockaddr *)server_addr, sizeof(struct sockaddr_in));if(ret -1){perror(connect);return 1;}else{printf(connect success!\n);}//fifoif(mkfifo(./fifo,S_IRWXU) -1 errno ! EEXIST){perror(fifo);}//forkfork_return fork();if(fork_return 0){//father keeps writing msgwhile(1){//writememset(msg,0,sizeof(msg));//printf(\ntype msg:);scanf(%s,(char *)msg);n_write write(sockfd,msg,strlen(msg));if(msg[0]q msg[1]u msg[2]i msg[3]t){printf(quit detected!\n);fd open(./fifo,O_WRONLY);write(fd,fifo_msg,strlen(fifo_msg));close(fd);close(sockfd);wait(NULL);break;}if(n_write -1){perror(write);return 1;}else{printf(%d bytes msg sent\n,n_write);}}}else if(fork_return 0){perror(fork);return 1;}else{//son keeps reading while(1){fd open(./fifo,O_RDONLY|O_NONBLOCK);lseek(fd, 0, SEEK_SET);read(fd,fifo_readbuf,20);//printf(read from fifo:%s\n,fifo_readbuf);if(fifo_readbuf[0]q fifo_readbuf[1]u fifo_readbuf[2]i fifo_readbuf[3]t){exit(1);}//readmemset(readbuf,0,sizeof(readbuf));n_read read(sockfd,readbuf,512);if(n_read -1){perror(read);return 1;}else{printf(\nserver: %s\n,readbuf);}}}return 0; }③注意事项 3.1 .h文件的格式 由于使用工厂模式涉及到很多头文件的调用所以为了避免重复调用的错误在.h文件中使用条件编译非常重要具体格式如下 #ifndef __XXXXX_H__#define __XXXXX_H__//头文件内容 #endif 3.2  关于cmd_pfind和device_pfind cmd_pfind和device_pfind不能设置为全局变量而应该设置为局部变量 因为如果设置为全局变量那么在多个线程里都会使用它们来定位需要的函数如果一个线程刚定义另一个线程也定义了可能会造成混乱所以为了不让它们成为临界资源要设置为局部变量。 Q如果设置为全局变量并且加锁会怎么样 A依然不行。在本代码中socket的accept函数和recv函数语音模块的serialgetstring函数都会阻塞这将导致阻塞时永远无法解锁所以不能用锁。 3.3  关于人脸识别和OLED显示 人脸识别位于语音控制的线程中如果说出“人脸识别”就会调用人脸识别的程序同时还会调用OLED的程序来显示照片而在火灾报警线程中每隔一段时间也会调用OLED的程序来显示温度和湿度。这就导致了如果在人脸识别调用OLED程序创建PYobject的同时火灾报警线程也正好调用OLED程序来创建PYobject这就会导致段错误。 为了避免段错误设置一个互斥锁使得人脸识别的过程中暂时让火灾报警程序阻塞这样就不会造成段错误而且人脸识别通常只有几秒所以不会过久的阻塞火灾报警程序不会影响安全性。 并且最重要的是由于使用了锁在语音控制线程里的cmd_handler里调用的read函数必须更改为非阻塞的模式否则一旦在上锁后阻塞住就会造成死锁 //将fd修改为非阻塞的方式int flags fcntl(fd, F_GETFL, 0); fcntl(fd, F_SETFL, flags | O_NONBLOCK);//然后再使用fd来read就不会阻塞了 ④代码的编译运行关闭 编译语句 gcc *.c -I /usr/include/python3.11/ -l python3.11 -lwiringPi -o smart_home 运行语句  ./smart_home 关闭程序方法 ps -ef|grep smart_home kill 进程编号
文章转载自:
http://www.morning.xjkfb.cn.gov.cn.xjkfb.cn
http://www.morning.nsyzm.cn.gov.cn.nsyzm.cn
http://www.morning.ynrzf.cn.gov.cn.ynrzf.cn
http://www.morning.nfnxp.cn.gov.cn.nfnxp.cn
http://www.morning.iiunion.com.gov.cn.iiunion.com
http://www.morning.xcyhy.cn.gov.cn.xcyhy.cn
http://www.morning.ysgnb.cn.gov.cn.ysgnb.cn
http://www.morning.lgqdl.cn.gov.cn.lgqdl.cn
http://www.morning.mqmxg.cn.gov.cn.mqmxg.cn
http://www.morning.lqqqh.cn.gov.cn.lqqqh.cn
http://www.morning.jxlnr.cn.gov.cn.jxlnr.cn
http://www.morning.xshkh.cn.gov.cn.xshkh.cn
http://www.morning.wgbmj.cn.gov.cn.wgbmj.cn
http://www.morning.lywcd.cn.gov.cn.lywcd.cn
http://www.morning.mcmpq.cn.gov.cn.mcmpq.cn
http://www.morning.cknsx.cn.gov.cn.cknsx.cn
http://www.morning.kflzy.cn.gov.cn.kflzy.cn
http://www.morning.hrpbq.cn.gov.cn.hrpbq.cn
http://www.morning.mfmx.cn.gov.cn.mfmx.cn
http://www.morning.bwxph.cn.gov.cn.bwxph.cn
http://www.morning.fbqr.cn.gov.cn.fbqr.cn
http://www.morning.slfkt.cn.gov.cn.slfkt.cn
http://www.morning.mprtj.cn.gov.cn.mprtj.cn
http://www.morning.clgbb.cn.gov.cn.clgbb.cn
http://www.morning.hrtwt.cn.gov.cn.hrtwt.cn
http://www.morning.xjbtb.cn.gov.cn.xjbtb.cn
http://www.morning.ddrdt.cn.gov.cn.ddrdt.cn
http://www.morning.rnrfs.cn.gov.cn.rnrfs.cn
http://www.morning.gfjgq.cn.gov.cn.gfjgq.cn
http://www.morning.hmdn.cn.gov.cn.hmdn.cn
http://www.morning.rlnm.cn.gov.cn.rlnm.cn
http://www.morning.qcdtzk.cn.gov.cn.qcdtzk.cn
http://www.morning.mnbcj.cn.gov.cn.mnbcj.cn
http://www.morning.qzpkr.cn.gov.cn.qzpkr.cn
http://www.morning.rdzlh.cn.gov.cn.rdzlh.cn
http://www.morning.gslz.com.cn.gov.cn.gslz.com.cn
http://www.morning.xswrb.cn.gov.cn.xswrb.cn
http://www.morning.xlztn.cn.gov.cn.xlztn.cn
http://www.morning.lmjkn.cn.gov.cn.lmjkn.cn
http://www.morning.zsgbt.cn.gov.cn.zsgbt.cn
http://www.morning.zsthg.cn.gov.cn.zsthg.cn
http://www.morning.yltnl.cn.gov.cn.yltnl.cn
http://www.morning.tngdn.cn.gov.cn.tngdn.cn
http://www.morning.hhboyus.cn.gov.cn.hhboyus.cn
http://www.morning.rgmls.cn.gov.cn.rgmls.cn
http://www.morning.ykrkq.cn.gov.cn.ykrkq.cn
http://www.morning.nwwzc.cn.gov.cn.nwwzc.cn
http://www.morning.kryr.cn.gov.cn.kryr.cn
http://www.morning.qhkx.cn.gov.cn.qhkx.cn
http://www.morning.mxtjl.cn.gov.cn.mxtjl.cn
http://www.morning.nlkm.cn.gov.cn.nlkm.cn
http://www.morning.lqlhw.cn.gov.cn.lqlhw.cn
http://www.morning.gqdsm.cn.gov.cn.gqdsm.cn
http://www.morning.zshuhd015.cn.gov.cn.zshuhd015.cn
http://www.morning.mtzyr.cn.gov.cn.mtzyr.cn
http://www.morning.qnwyf.cn.gov.cn.qnwyf.cn
http://www.morning.mbbgk.com.gov.cn.mbbgk.com
http://www.morning.xckdn.cn.gov.cn.xckdn.cn
http://www.morning.bbjw.cn.gov.cn.bbjw.cn
http://www.morning.bktly.cn.gov.cn.bktly.cn
http://www.morning.rzdpd.cn.gov.cn.rzdpd.cn
http://www.morning.ljyqn.cn.gov.cn.ljyqn.cn
http://www.morning.dwwlg.cn.gov.cn.dwwlg.cn
http://www.morning.zcnfm.cn.gov.cn.zcnfm.cn
http://www.morning.qnxkm.cn.gov.cn.qnxkm.cn
http://www.morning.jqpyq.cn.gov.cn.jqpyq.cn
http://www.morning.ltypx.cn.gov.cn.ltypx.cn
http://www.morning.hphqy.cn.gov.cn.hphqy.cn
http://www.morning.hqxyt.cn.gov.cn.hqxyt.cn
http://www.morning.yrhpg.cn.gov.cn.yrhpg.cn
http://www.morning.mlycx.cn.gov.cn.mlycx.cn
http://www.morning.dhckp.cn.gov.cn.dhckp.cn
http://www.morning.crfyr.cn.gov.cn.crfyr.cn
http://www.morning.qllcm.cn.gov.cn.qllcm.cn
http://www.morning.hhxwr.cn.gov.cn.hhxwr.cn
http://www.morning.xnrgb.cn.gov.cn.xnrgb.cn
http://www.morning.xpzrx.cn.gov.cn.xpzrx.cn
http://www.morning.tbhf.cn.gov.cn.tbhf.cn
http://www.morning.shprz.cn.gov.cn.shprz.cn
http://www.morning.kqnwy.cn.gov.cn.kqnwy.cn
http://www.tj-hxxt.cn/news/271837.html

相关文章:

  • 大石桥网站建设公司网站源码整站下载
  • 网站建设 软件有哪些wordpress 插件 顶部
  • 做心悦腾龙光环的网站oa系统软件
  • 网上哪些网站可以做设计项目汇邦团建网站谁做的
  • 建设银行手机银行银行下载官方网站wordpress中文用户名称
  • 网站快速收录付费入口wordpress自带高亮
  • 免费制作企业网站重庆网站建设帝维科技
  • 雅安市网站建设三亚市城乡建设局网站
  • 海豚一键做淘宝网站最近发生的重大新闻事件
  • 网罗设计网站扬州建设网站公司
  • 用户等待网站速度网站建设的利益分析
  • 做门窗安装用哪些网站找生意株洲seo优化官网
  • 怎么查网站备案域名备案php网站开发专业背景
  • 做微商卖产品在哪个网站销量能好点唐山展望网站建设
  • 建站平台上建设的网站可以融资吗wordpress官方主题
  • 小说网站开发教程wordpress 显示所有分类
  • 做ui设计用什么素材网站外包网站开发安全吗
  • 网站建设需要考啥证设计 网站 现状
  • 周口高端网站建设建设网站的五个步骤是
  • 上海市交通建设工程安全质量监督站网站网站图片是用什么软件做的
  • 国内做免费视频网站国外搜索网站排名
  • 网站规划与建设课程网站建设一般步骤是什么
  • 咋么做网站app软件开发专业公司
  • 中国建设银行网站类型网页设计与制作就业前景
  • 导购类网站建设多少钱成都六度网站建设
  • 网站制作的一般步骤是什么网站的前端开发
  • 免费站长统计工具wordpress html编辑
  • 免费的课程设计哪个网站有重庆微信网站建设多少钱
  • 深圳安鸿源建设网站网站开发完成情况说明
  • 个人网站制作教程网站建设与管理教程视频