国内flash网站,中装建设股票行情,wordpress配置文件数据库连接,桂林到阳朔多少公里#x1f431;作者#xff1a;一只大喵咪1201 #x1f431;专栏#xff1a;《智能家居项目》 #x1f525;格言#xff1a;你只管努力#xff0c;剩下的交给时间#xff01; 如上图整个智能家居程序总体框架图#xff0c;还剩下网络子系统没有实现#xff0c;以及最终… 作者一只大喵咪1201 专栏《智能家居项目》 格言你只管努力剩下的交给时间 如上图整个智能家居程序总体框架图还剩下网络子系统没有实现以及最终的业务子系统没有实现。 认识esp8266 | 网络子系统 认识esp8266网络子系统应用层管理层EPS8226设备层AT命令层UART设备层 内核和芯片抽象层硬件操作单元测试 源码及资源 认识esp8266 如上图所示是乐鑫的多种网卡芯片本喵使用的是其中的ESP8266具体性能参数可以参照上图。 如上图所示该芯片只用连接四个引脚除开供电的正负外剩下的两个引脚分别是串口的发送端和接收端和MCU相连。
通过串口发送指令给esp8266芯片让其做相应的操作但是这些指令并不是随意发送的而是要按照一定的规定。 如上图所示我们通过串口给esp8266芯片发送AT指令芯片会解析指令并做出响应指令正确会返回OK错误返回ERROR也是通过串口返回给MCU。 AT指令AT command set叫做AT指令集或AT命令集一般称其为AT指令。 如上图所示是ESP8266AT指令的参考手册需要的小伙伴自取(文章末尾会放资源链接)。 如上图在手册中给了一些演示示例模仿这些实例中AT指令的用法就可以去操作esp8266。
本喵这里将提前写好的代码烧录到板子里来演示一下esp8266的简单使用这部分测试代码本喵就不讲解了可以自取(文章末尾会放资源链接)只是一些简单的串口基本配置后面本喵会直接使用这些配置。 用串口助手发送内容给MCU(UART1)MCU就将对应的内容发送给esp8266(UART3)。esp8266的反馈给MCU什么内容MCU就将对应的内容通过串口助手发给我们。 将开发板和PC端连好并烧好程序后打开串口调试助手 如上图通过串口助手发送指令AT用来测试esp8266的通信是否正常当接收到OK时说明此时和MCU的通信是正常的。 注意AT指令必须以回车换行结束所以在串口调试助手中必须勾选发送新行。 接下来就是配置esp8266的网络连接了
配置 WiFi 模式 发送指令ATCWMODE3将esp8266配置成softAPstation模式此时该模块自己就是一个网络热点而且也可以连接其他热点受到反馈OK以后说明设置成功。 如上图是可以配置的模式其中1表示Station模式表示该模块可以接入网络2表示SoftAP表示该模块可以作为一个热点(就像我们的WIFI路由器)3表示两种模式都有具体用法自行去查阅手册。
连接路由器 发送指令ATCWJAPWIFI名称,密码 让esp8266模块连接WIFI第一个中的字符串是WIFI名称该模块不支持5G所以不要连接后缀有5G的网络第一个中的字符串就是WIFI密码。
指令发出后得到绿色框中的反馈最终返回OK说明WIFI连接成功此时该模块就连网了。
查询 ESP8266 设备的 IP 地址 发送指令ATCIFSR查询该模块的IP地址和MAC地址如上图中绿色框中的就是该模块的IP地址和MAC地址。
这里有两个IP地址和MAC地址APIP,192.168.4.1表示该模块作为热点的IP地址是192.168.4.1。
STAIP,192.168.2.15表示该模块接入到网络中的IP地址是192.168.2.15同一个局域网中的其他网络设备可以通过这个IP地址找到该模块所以我们使用的也是这个IP地址。
至于MAC地址这里我们并不会用到。
设置单连接 发送指令ATCIPMUX0将该模块设置成单连接模式得到反馈OK说明设置成功。 单连接模式就是和该模块进行网络通信的设备只有一个多连接则是有多个。 创建 UDP 传输 如上图可以在你正在用的PC端或者其他PC端打开sscom软件但是PC端必须和esp8266处于同一个局域网在左下角设置本地端口号8080远端IP地址(模块IP地址)以及远端端口号。 本地IP地址是由路由器分配的打开软件后自动就有端口号由我们自己决定。 再通过串口助手发送ATCIPSTARTUDP,192.168.119.1,8080,1112,2指令让esp8266模块和PC端的sscom建立UDP连接其中192.168.119.1是远端sscom的IP地址8080是远端的端口号1112是自己(模块)的端口号。
最后一个参数设置为2时表示UDP通信的远端可变而不是只能固定一个远端和esp8266模块通信。
发送数据 发送指令ATCIPSEND7后得到反馈OK和一个表示可以发送数据了该指令等号后面的7表示要发送7个字节(包括回车换行)。 发送123456后得到了模块的反馈Rev 7 bytes表示受到了7个字节数据以及SEND OK表示发送成功。 如上图所示此时在远端的sscom中就可以看到esp8266发送来的数据。
接收数据 如上图用远端的sscom向esp8266发送数据abcdefg。 此时esp8266模块就受到了远端发送来的数据并通过串口调试助手给我们显示出来。
断开 UDP 传输 发送指令ATCIPCLOSE得到反馈OK后说明该模块和远端断开UDP连接此时模块就接收不到远端发送的数据了并且也不能无法向远端发送数据除非重新建立UDP连接。
现在已经认识了esp8266模块接下来就该实现我们的网络子系统了。
网络子系统 如上图所示是网络子系统的层次示意图只看网络子系统它是从网卡设备管理层开始的上面两层是最后要将网卡设备作为一个输入设备接入到输入子系统中现在先只从网卡设备管理层开始往下看。
应用层
管理层 如上图所示网卡设备有很多比如本喵使用的esp8266esp32自带的网卡或者Linux网卡等等为了方便维护和扩展将所有的网卡设备放在管理层中管理起来首先要做的就是抽象描述网卡设备的结构体 如上图所示是网卡设备NetDevice结构体的定义和注册网卡设备以及获取网卡设备的函数声明。
在网卡设备结构体中由于可以将实例化不同类型的网卡设备对象所以要有一个名字name来标识不同的网卡。
在前面介绍esp8266模块时模块和远端进行通信时必须有模块IP地址模块端口号远端IP地址远端端口号所以描述网卡设备时要有char ip[20]数组用来存放模块的IP地址char mac[6]来存放模块的MAC地址(虽然当前用不到)。
每一个网卡设备在使用之前和其他设备一样都需要进行初始化所以要有初始化的方法Init函数指针。
网卡设备要和连接局域网的WIFI所以提供一个Connect方法来连接网络在参数中传入WIFI名称和WIFI密码。
网卡设备在连接上WIFI后局域网中的路由器会给网卡分配一个IP地址为了方便获取网卡的IP地址以及其它信息需要一个GetInfo接口。
网卡设备要和远端建立通信提供了一个CreateTransfer方法在创建连接时需要指定连接类型Type以及网卡的端口号至于远端的IP地址本喵内嵌到了程序中因为和我们进行通信的远端并不会改变。
网络通信结束后需要和远端端口连接同样也提供了一个CloseTransfer方法用来端口连接。
网卡设备是肯定要和远端进行通信的所以必须有发送数据Send和接收数据Recv的方法这个项目中网卡设备并不会给远端发送数据这里只是为了完善才写上的。
在接收数据时接收到是数据保存到Data中还有要接收到的数据长度这两个参数都是输出型参数最后还要有超时时间不能一直处于接收状态超出这个时间就退出接收。 如上图源文件中代码所示创建了一个全局的pNetDevice链表用来管理网卡设备并且实现了注册网卡设备和获取网卡设备函数。 此时管理网卡设备的方法已经有了接下来就是实现网卡设备的管理系统了net_system 如上图网卡管理系统中只有添加所有网络设备以及获取指定网络设备的方法在添加所有网络设备函数的实现中由于目前只有ESP8266所以只有一个AddNetDeviceESP8266函数有其他网络设备只需要再增加相应的添加函数即可。 EPS8226设备层
管理层和系统层等上层已经实现了接下来就是实现ESP8266了 如上图头文件代码所示仅有一个添加ESP8266网卡设备的函数声明供上层net_system添加所有设备时调用。由于NetDevice结构体中所有函数的实现都是static类型的所以都不用在这里声明。 如上图源文件中代码是NetDevice结构体中那些方法的实现初始化的时候先设置esp8266芯片的复位引脚(本喵使用的这一款不用设置)接下来就是初始化MEC和esp8266芯片进行通信的接口然后就是配置WIFI模式以及设置成单连接状态。 对于ESP8266芯片的配置是按照前面演示过程中的方式配置的可以对照这里和前面演示部分的标号来看。 在给ESP8266发送指令时使用ATCommandSend函数(暂时还没有实现)来发送指令AT指令也可以使用OtherCommandSend函数来发送其他类型的指令处理发送指令本身还需要设定超时时间即使没有设置成功在一定时间后也要返回。 AT指令的发送函数在AT层实现这样同样是为了实现分层将ESP8266模块和指令类型解耦。 在发送指令时先要将不同的形参拼接成一个完整的AT字符串指令使用sprintf库函数即可。
对于接收数据的函数ESP8266Recv的实现在还是内部调用了ATDataRecv这是针对AT指令的接收数据方式其他指令模式对应的方式不同所以这个函数也是在AT层实现的。 对于获取ESP8266IP地址及网卡信息的函数本喵要单独讲解一下 如上图代码所示当发送指令ATCIFSR后MCU会受到esp8266芯片发送来的设备信息包括两个IP地址和两个MAC地址以及一个OK反馈。
我们要从这一整个字符串中解析出我们需要的IP地址所以使用strstrC库函数查找子串CIFSR:STAIP,\该字串后面的内容就是我们需要的IP地址然后将IP地址按字节放入ESP8266网卡设备结构体变量的ip成员数组中。 字符串中要注意转义字符。 由于调用ESP8266GetInfo函数时传入一个输出型参数所以在函数调用结束之前将获取到的IP地址使用strcpyC库函数拷贝给输出型参数。 如上图代码所示创建一个ESP8266的全局结构体变量并且初始化结构体中的成员网卡设备名字就是esp8266IP地址和MAC地址给一个初始值再用前面实现的那些函数来初始化函数指针。
添加网卡设备的函数中调用net_device设备管理层中的注册函数。 AT命令层 现在管理层已经实现接下来就是实现AT命令层了。 如上图代码所示在AT层中包含接口初始化发送指令的函数发送指令并接收数据的函数以及接收数据的函数。
在源文件中创建了一个全局的接口设备变量在当前层是不用关心该结构是UART还是I2C的初始化中需要先获得接口设备然后调用它的初始化方法。 如上图所示是发送AT指令的函数实现指令内容是在设备层调用该函数时传入的在发送指令时调用接口设备的Write方法将指令写入后再写回车换行。 为了防止干扰在每次发送指令cmd之前都调用InvalidRecvBuf方法清空环形缓冲区。 指令通过结构设备发送给ESP8266模块以后要等待该模块的反馈在等待之前获取一下当前的时间pre然后再等待反馈。
等待反馈的过程中使用接口设备的ReadByte方法一个字节一个字节读取数据读取到的数据按顺序放入buf中当读取到’\n’字符时判断前一个是否是\r如果是说明得到完整的一行数据。
再判断该行数据中是否有OK或者ERROR如果有则得到反馈如果没有则再接收下一行数据将前面的抛弃。 如上图所示代码是判断OK和ERROR的函数。
每接收一个字节数据并判断完成后还需进行超时判断再获取当前程序所在位置的时间now如果当前时间比pre前一刻时间大说明程序在指向并耗费时间所以超时时间iTimeoutMS减一并且更新前一刻时间pre当超时时间变为0后说明已经超时了但仍然没有得到想要的则超时返回。 为了方便调试在config.h中增加了答应调试信息的功能 如上图所示如果需要打印调试信息则在这里定义DEBUG之后就可以使用debug_printf打印调试信息到串口了(UART1)。 如上图所示是发送AT指令并且接收ESP8266的全部反馈信息的同样在通过接口写指令之前要将缓冲区清空然后等待模块的返回信息等待裸机和ATCommandSend一样只是这里要将所有返回的数据都保存到传入的Data数组中。 如上图所示代码是用来接收ESP8266通过接口发送给MCU的数据的就像在认识esp8266模块的时候用远端sscom发送数据到模块此时就调用该函数来接收这些数据。
接收到的数据格式是IPD,8:1234样子的其中前缀IPD表示这是接收到的网络数据,逗号后面的数字8表示有效数据的大小是8个字节:冒号之后的是有效数据。
采用状态机模型将接收网络数据分为三个阶段分别是起始阶段INIT_STATUS解析有效数据长度阶段LEN_STATUS接收有效数据阶段DATA_STATUS。
最开始处于INIT_STATUS阶段通过接口设备中的ReadByte方法接收数据在读取到的数据中查找是否存在IPD子串如果存在说明这是网络数据状态变为LEN_STATUS并且将接收到的前缀丢弃掉因为后面不用再用到了。
再继续接收数据如果接收到的数据中有冒号:说明此时已经读取到了长度冒号前面的数据就是有效数据的长度解析出有效数据的长度将状态变为DATA_STATUS并且丢掉前面的数据也是因为以后不用了。
此时接收到的数据就是有效数据是真正需要的数据每接收一个字节的数据就放入到传入的数组中直到接收的数据长度和前面解析出的长度相符才停止接收。
同样也有超时处理就不多解释了。
UART设备层
此时就可以继续实现串口设备层了。 前面的AT层一直都在使用接口设备来收发数据但是接口设备并没有实现只是空头支票接下来就是实现接口设备了。AT指令一般有UART和I2C两种传输方式由于本喵使用的是UART方式所以这里也只实现这一种方式 如上图所示定义了描述串口设备的结构体包含串口设备的名称初始化方法清空缓冲区的方法以及通过串口读写数据的方法还有一个过去串口设备环形缓冲区的函数声明。
使用typedef给UARTDevice重命名为ATInerFaceDevice将pUARTDevice重命名为pATInterFaceDevice此时在就实现了封装在AT层之间使用重命名后的类型即可。 如上图所示代码创建一个全局的环形缓冲区供串口设备读写数据并且创建了串口设备的全局变量并进行了初始化实现了串口设备中的各种方法。
内核和芯片抽象层
接下来就是实现老生常谈的部分了内核抽象层和芯片抽象层。
在操作串口设备的时候不同类型的操作系统操作方式不同和之前一样要抽象出一层内核抽象层和芯片抽象层分层原因和依据本喵就不再说了前面已经说过好多次了。 如上图代码所示内核抽象层中只有对串口的写函数并没有实现读等其他操作因为给esp8266模块写数据采用直接写的方式而读数据采用中断的方式所以读函数会在中断部分实现。 如上图代码所示在芯片抽象层中写数据函数会调用一个USART_SendBytes这是对于HAL库方式的其他方式则调用相应的函数即可本喵这里并没有列举。
硬件操作
最后就是硬件操作我们整个网络子系统的实现完整了。
硬件操作就是具体操作本喵使用的STM32F103ZET6芯片的UART3了 如上图所示头文件包含串口3使能发送多个字节数据以及注册输入处理回调函数的函数声明。 如上图源文件代码所示实现了串口3的中断使能函数以及发生多个字节数据的函数发生多个字节时通过检测寄存器中SR位来判断一个字节是发送完成如果完成则发送下一个直到所有字节都发送完这里并没有使用中断发送方式。 串口3中断使能函数中也只使能了接收中断。 定义了一个接收中断函数中的回调函数该函数是一个全局的函数指针在中断函数中会回调该函数来用指定的方式处理接收到的数据。
在中断函数中先定义了一个静态的环形缓冲区这是串口的标配缓冲区结构给用串口3的环形缓冲区来初始化它当数据到来时将接收到的数据按字节放入该缓冲区中一份。
如果回调函数指针不为空则再调用回调函数来处理这个数据现在不考虑回调函数只有Recv方法来接收网络数据。
单元测试
接下来就是测试我们的代码能否正常执行接收到网络数据 如上图代码所示首先就是添加网卡设备并初始化等一系列基本操作。一开始要先延时2s让ESP8266模块启动完成然后连接到WIFI连接过程放在一个循环中如果连接成功则跳出死循环否则就一直连因为如果没有脸上WIFI我们的测试就没有意义。
连接成功以后就是创建网络连接指定连接类型(本喵仅实现了UDP连接)和模块的端口号创建成功则继续否则直接返回。
最后在一个死循环中不断获取网络数据使用网卡设备中的Recv方法如果接收到则通过URAT1打印出来。 如上图所示将代码烧录到开发板中并且上电以后通过串口调试助手可以看到上面信息准备工作全部完成后开始循环检测网络数据的到来。 如上图所示在远端发送数据ESP8266就将接收到的数据通过串口调试助手打印出来此时说明我们的网卡设备可以正常工作。
源码及资源
本文所用到的所有工具手册以及源码都放在这里传送门需要的小伙伴自取。