物联网实战--入门篇之(六)嵌入式-WIFI驱动(ESP8266)

目录

一、WIFI简介

二、基础网络知识

三、思路讲解

四、代码分析

        4.1 状态机制

        4.2 客户端连接

        4.3 应用数据接收处理

        4.4 数据发送

        4.5 主函数调用

        4.6 网络连接ID分配

五、总结


一、WIFI简介

        WIFI在我们生活中太常见了,手机电脑都可以用WiFi连接路由器进行上网,那么在单片机领域又是基于什么物理器件联网的呢?最常见的WIFI模块是ESP8266,以及性能更好的ESP32,还有比较新的BL602等等,种类比较多,那么我们净化器这个项目选择的是成熟稳定且便宜的ESP8266。它可以标准模式下连接路由器,自身也可以作为热点供别人连接,性能还是很强悍的。

        ESP8266文档中心在这儿ESP8266文档中心 | 安信可科技,在这里我们采用AT指令的方式对齐进行驱动,具体文档可以按下图方式下载。AT指令是一个比较规范的底层通讯协议,也没什么神秘的,就是一个比较固定的格式,AT+具体指令=参数  这种模式,AT指令的好处是简单易懂,字符串的形式比较明了,对应的缺点就是没有很灵活,要根据输出内容处理字符串信息,有时候返回的信息不充分或者不完整,对开发人员的程序稳定性有一定的考验。

二、基础网络知识

        这里简要说明下网络的基础知识,主要协议分为TCP和UDP,TCP是比较可靠的连接,数据包会有重发机制,发送方没收到确认就会重新发送,而UDP就不管那么多了,按照目标地址发过去就是了,有没有收到就不管了。

        通常要连接一个服务器需要的信息有目标服务器的IP地址、要连接的端口以及所使用的协议三个,如下图所示。其中IP地址也可以用域名代替,这样模块内部就是需要多个步骤把域名发往域名服务器解析成具体的IP地址;目标端口就是一个数值,服务器需要打开这个端口客户端才能连接成功和发送数据,否则会一直连接错误;协议就是上面所说的TCP和UDP了,我们这里一般都是使用TCP的,后面会讲解的MQTT是基于TCP连接的,用UDP的也有,比如NB-Iot的Coap协议。       

        基本的网络知识就这样了,没有很复杂,会用就行;如果要深入整个网络知识体系,那就学海无涯了,一本TCP/IP协议知识的书比枕头还厚,个人学习推荐LWIP。

三、思路讲解

        既然是驱动程序必然要有比较好的通用性和移植性。ESP8266的基本使用流程是配置WIFI模式以及SSID和密码,然后等到模块连接到指定的路由器上;连接完成后再进行网络方面的设置,比如可以多连接、非透传模式和TCP服务器的建立等等,AT手册里有很多,不一定全用,根据自己的需求增删;最后就是根据应用层的目标服务器信息进行连接和收发数据了。

        整体来讲逻辑不会很复杂,但是细节很多。比如:

        1、ESP8266主体流程要怎么运行,这个过程最好不要有阻塞(就是延时了),这样会影响其它部分代码的运行;

        2、WIFI的名称和密码以及热点名称和密码要如何设置,保存方式下比较耗时的;

        3、如何确定当前的网络状态以及不同的状态要执行什么动作,比如WIFI突然断开了怎么办;

        4、作为TCP客户端连接时候,如何确保连接成功,并且不会重复连接;

        5、如何解决TCP本质上已经断开了,但是模块没有提示的问题,即假连接,此时没法收发数据的;

        6、ESP8266最多只有5个连接资源,客户端和服务端如何分配;

        7、如何处理AT指令返回的信息。        

        针对以上提出的一些问题,通过代码分析进行逐一解答。

四、代码分析
        4.1 状态机制

        首先从整体思路上来讲,就是利用状态机的方式去执行不同的网络状态下的动作,也就是C语言里的switch语句了,这里定义了下图所示的一些状态,具体有注释。

        然后就是设计不同状态下的动作了,也就是网络注册过程,这里使用switch语句进行状态跳转,函数内部间隔运行时间wait_time可以自定义,正常是2秒。

        从起始状态开始,配置一些固定的参数,比如STA+AP两种模式都启用,上电自动连接WIFI以及配置WIFI的用户名和密码,这里参数都是存储到模块的内部FLASH的,比较耗时,所以热点AP的用户名和密码到下一个状态去设置。设置完后再次复位下模块,进入初始化阶段。


/*		
================================================================================
描述 : 网络注册函数
输入 : 
输出 : 
================================================================================
*/
void drv_esp8266_reg_process(void)
{static u32 last_sec_time=0, wait_time=2;static char cmd_buff[100]={0};u32 now_sec_time=drv_get_sec_counter();if(now_sec_time-last_sec_time>wait_time){switch(g_sEsp8266Work.state){case ESP8266_STATE_START:{delay_os(2000);drv_esp8266_uart_send("ATE0\r\n");delay_os(200);         drv_esp8266_send_at("CWMODE_DEF=3");//WiFi模式  STA+APdelay_os(200); drv_esp8266_send_at("CWAUTOCONN=1");//上电自动连接delay_os(200);   if(strlen(g_sEsp8266Work.sta_ssid)>0){sprintf(cmd_buff, "CWJAP_DEF=\"%s\",\"%s\"", g_sEsp8266Work.sta_ssid,             g_sEsp8266Work.sta_passwd);drv_esp8266_send_at(cmd_buff);delay_os(1000);          }                   drv_esp8266_send_at("RST");//复位模块        g_sEsp8266Work.state=ESP8266_INIT;		wait_time=3;			break;}case ESP8266_INIT:{drv_esp8266_uart_send("ATE0\r\n");delay_os(200);     if(strlen(g_sEsp8266Work.ap_ssid)>0){sprintf(cmd_buff, "CWSAP_DEF=\"%s\",\"%s\",5,3,4,0", g_sEsp8266Work.ap_ssid, g_sEsp8266Work.ap_passwd);drv_esp8266_send_at(cmd_buff);delay_os(1000);           }       wait_time=3;g_sEsp8266Work.state=ESP8266_WIFI_CONNECT;			break;}          case ESP8266_WIFI_CONNECT://等待WIFI连接成功{drv_esp8266_send_at("CIPSTATUS");//查询网络连接信息wait_time=5;break;}case ESP8266_NET_CFG://网络配置{printf("### ESP8266_NET_CFG\n");drv_esp8266_send_at("CIPMODE=0");//非透传模式delay_os(200);    drv_esp8266_send_at("CIPMUX=1");//使能多连接delay_os(200);if(g_sEsp8266Work.listen_port>0){sprintf(cmd_buff, "CIPSERVER=1,%d", g_sEsp8266Work.listen_port);drv_esp8266_send_at(cmd_buff);	 //建立TCP服务器delay_os(200);             }       g_sEsp8266Work.state=ESP8266_STATE_OK;	wait_time=2;break;}      case ESP8266_STATE_OK:{drv_esp8266_connect_process();drv_esp8266_send_at("CIPSTATUS");//查询网络连接信息wait_time=5;break;}      }last_sec_time=drv_get_sec_counter();}
}

        初始化阶段主要设置热点AP的用户名和密码,剩下的就是等待模块自己连接上路由器了,如果没有指定名称的路由器,那就只能一直在这里等待了。在这期间,驱动会主动去查询网络状态,即drv_esp8266_send_at("CIPSTATUS"),我们需要根据模块的返回信息自己去判断网络状态,具体手册说明和代码解析如下图所示。

        

        WIFI连接成功后就是配置一些网络信息了,在这里根据自己的需求配置了非透传模式、多连接和建立服务器三个内容。

        至此,整个网络注册流程也就完成了,最后就是间隔查询网络状态,如果变化去做相对应的动作就行了。

        4.2 客户端连接

        网络可以用后,最麻烦的还是TCP的连接了,首先要说明的是客户端连接的结构体定义,如下所示。ESP8266最多只有5个连接,我们这里就定义了5个客户端的数组,结构体内部除了必要的网络信息外还有连接状态、心跳周期和保活时间等参数,这是为了连接的稳定而设计了,当网络因为不可控因素断开后模块又没有具体返回信息,这时可以根据应用层的保活时间来判断是否需要重新连接。

        具体代码如下,有连接需求的就进行连接操作,在这里,先对模块的返回信息做个及时处理,这样多个连接时才不会分不清是哪个连接的返回信息,比如"ALREADY CONNECTED"信息它没有具体的识别参数。


/*		
================================================================================
描述 : 客户端连接管理任务
输入 : 
输出 : 
================================================================================
*/
void drv_esp8266_connect_process(void)
{u32 now_sec_time=drv_get_sec_counter();for(u8 i=0; i<MAX_LINK_NUM; i++){Esp8266ClientStruct *pClient=&g_sEsp8266Work.client_list[i];if(pClient->dst_port>0)//有连接需求{if(pClient->conn_state==0){drv_esp8266_client_connect(pClient->sock_id, pClient->type, pClient->dst_addr, pClient->dst_port);delay_os(1000);char *pData=(char*)g_sEsp8266Work.pUART->pBuff;  
//        printf("***8266 recv=%s\n", pData);        if(strstr(pData, "ALREADY CONNECTED")!=NULL){printf("sock_id=%d, already connected!\n", i);pClient->conn_state=1;pClient->keep_time=now_sec_time;UART_Clear(g_sEsp8266Work.pUART);//清理串口数据     }else if(strstr(pData, ",CONNECT")!=NULL){printf("sock_id=%d, new connected!\n", i);pClient->conn_state=1;pClient->keep_time=now_sec_time;UART_Clear(g_sEsp8266Work.pUART);//清理串口数据             }else if(strstr(pData, ",CLOSED")!=NULL){printf("sock_id=%d, error close!\n", i);pClient->conn_state=0;UART_Clear(g_sEsp8266Work.pUART);//清理串口数据             }        }else{int det_time=now_sec_time-pClient->keep_time;if(det_time>pClient->heart_time)//心跳超时{printf("sock_id=%d, heart time out!\n", i);drv_esp8266_close(pClient->sock_id);}}} } }  

        同时,已经连接成功的就要检测是否保活超时,超时就要重连了,保活的keep_time在收到数据时都会自动更新为最新时间。

        这个连接函数是在网络状态正常的状态下调用的,调用间隔是5秒。

        4.3 应用数据接收处理

        数据接收部分首先涉及的就是UART篇章的串口接收了,首先也是利用接收长度判断是否接收完成,完了之后通过关键字"+IPD,"判断是否为接收的数据,随即一步步解析连接ID和数据长度,最后就可以把应用层数据拿去接收处理了。

        这里要重点讲下接收处理函数,它的定义如下图所示,属于回调函数,这样做的好处是应用层可以根据具体需求设计自己的处理函数,保证了驱动程序的通用性。

        净化器这个项目的WIFI接收处理函数是在应用层的MQTT文件内注册的,具体如下,因为我们在应用层是采用ESP8266的网络连接ID=3来建立MQTT连接的,所以这里在app_esp8266_recv函数中把连接ID为3的数据保存进MQTT的环形缓冲区内,这个环形缓冲区是MQTT使用的内容,这里暂时给他理解成一个缓存空间即可。至于后续怎么处理,那是MQTT的事情了,至此,ESP8266的数据接收任务也就完成了。

        4.4 数据发送

        ESP8266的数据发送较为简单,先发送相关AT指令,然后立即发送数据内容即可。

        4.5 主函数调用

        剩下的就是提供运行主程序供应用层调用就行了,这里的运行节奏比较快,正常20ms运行一次。

        4.6 网络连接ID分配

        细心的同学会发现,这个项目我的连接ID是3,不是从0开始,这是为什么呢?因为我们模块是有热点的,可以作为服务器,那么其它设备连接我们的时候模块内部会自动占用一个连接ID,而且正常是从0开始的,如果有作为服务器的需求,那么就要提前做好准备,自己的使用的连接ID最好从高位开始,ESP8266的连接ID是0~4,总的5个,为了保险起见,我们可以选择3或4,这样就比较不会冲突了。这里的核心还是开发者自己要提前规划好使用的连接ID。

五、总结

        ESP8266总体来讲不复杂,就是细节比较多,驱动程序要做到稳定好用不容易,像使用AT指令的通讯模块都有这个特点,比如以后可能会用到的4G模块,那个相对更复杂些。

        在这里主要是想通过代码解读的方式让大家理解背后的设计思想,既然是以项目为中心的教程,那稳定通用是我们考虑的主要因素,在其它教程应该比较少有考虑到后续问题,大多只是带大家连个阿里云或者其他什么平台就完事了,对网络不稳定、连接意外断开、代码阻塞等问题都没有过多说明,这里主要就是要让大家学会技术以外的设计思想。

   本项目的交流QQ群:701889554

   写于2024-3-31

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

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

相关文章

2024品牌私域运营:「去中心化」正在成为企业决胜关键

越来越多的品牌选择以DTC模式与消费者互动和销售。通过与消费者建立紧密联系&#xff0c;不仅可提供更具成本效益的规模扩张方式&#xff0c;还能控制品牌体验、获取宝贵的第一方数据并提升盈利能力。许多企业采取的DTC私域策略以交易为中心的方法往往导致了成本上升和运营复杂…

【Blockchain】区块链浏览器 | 以太坊Etherscan比特币Blockchain门罗币Monero

区块链浏览器概述 区块链浏览器是一种软件,它使用API(应用程序编程接口)和区块链节点从区块链中提取各种数据&#xff0c;然后使用数据库来排列搜索到的数据&#xff0c;并以可搜索的格式将数据呈现给用户。 用户的输入是资源管理器上的可搜索项&#xff0c;然后通过数据库上…

市场复盘总结 20240329

仅用于记录当天的市场情况&#xff0c;用于统计交易策略的适用情况&#xff0c;以便程序回测 短线核心&#xff1a;不参与任何级别的调整&#xff0c;采用龙空龙模式 一支股票 10%的时候可以操作&#xff0c; 90%的时间适合空仓等待 二进三&#xff1a; 进级率中 60% 最常用…

STM32系统结构及总线介绍

1、学习路径 STM32中文参考手册中的第二章存储器和总线构架 2、系统架构&#xff08;中等容量芯片stm32f103c8&#xff09; 在小容量、中容量和大容量产品中,主系统由以下部分构成: 四个驱动单元&#xff1a; CortexTM-M3内核DCode总线&#xff08;D-bus&#xff09;&#…

霍尼韦尔大路灯怎么样?书客、雷士、霍尼韦尔护眼落地灯实测PK!

生活在快节奏的时代中&#xff0c;当代青少年都顶着很大的压力&#xff0c;熬夜学习是家常便饭&#xff0c;有时还需要借助电子产品来辅助学习&#xff0c;再加上许多家长都不太注重孩子的视力健康问题&#xff0c;孩子长时间处于一个不良的环境光下学习&#xff0c;眼睛极易疲…

PyLMKit(9):ChatTable与你的表格聊天,表格问答

功能介绍 与你的结构化数据聊天&#xff1a;支持主流数据库、表格型excel等数据&#xff01; ChatDB&#xff1a;支持数据库问答ChatTable&#xff1a;支持txt,excel,csv等pandas dataframe表格的问答 1.下载安装 pip install pylmkit -U pip install pandasql2.ChatTable实…

【AI+儿童绘本】从0到1制作儿童绘本故事操作思路

今天刷了会小H书&#xff0c;无意刷到一些 睡前儿童绘本故事&#xff0c; 下面一堆评论说 求软件什么的&#xff0c;博主只是引流没做任何回复。 这里写一篇文章科普下吧&#xff0c;免得有人被割韭菜。 制作儿童绘本&#xff0c; 大概这几个步骤。1、写生动有趣的故事&#x…

隐私计算实训营学习六:隐语PIR介绍及开发指南

文章目录 一、隐语实现的PIR总体介绍1.1 PIR的定义和种类1.2 隐语PIR功能分层 二、Index PIR-SealPIR介绍三、Keyword PIR- Labeled PSI介绍四、隐语PIR后续计划 一、隐语实现的PIR总体介绍 1.1 PIR的定义和种类 PIR(Private Information Retrieval PIR)隐匿查询&#xff1a;…

使用VNP时 本地服务/Dbeaver 无法连接数据库

在家使用VPN连接&#xff0c;启动本地Eclipse 的springboot 服务时&#xff0c;无法正常连接数据库。 解决方法: 在启动项配置中增加 -Djava.net.preferIPv4Stacktrue 之后&#xff0c;使用 Dbeaver时&#xff0c;也出现如下连接异常&#xff1a; 解决方法&#xff1a; 在dbe…

C语言:文件操作(2)

4.2 fputc的使用 这里写自定义目录标题 fputc的定义&#xff1a; 主要功能&#xff1a;一个字符一个字符的写进文件&#xff0c;将int类型的字符character写进文件流&#xff08;FILE* stream&#xff09;中&#xff0c;返回一个整形。如果成功fputc会返回写进文件的字符&…

城市雨量水位监测站

TH-SW2在繁华的现代都市中&#xff0c;有这样一个默默奉献的守护者&#xff0c;它时刻监测着城市的雨量和水位&#xff0c;为城市的安全提供着重要的保障。它就是我们今天要介绍的——城市雨量水位监测站。 一、雨量水位监测站的重要性 城市雨量水位监测站是城市防洪排涝体系的…

全局UI方法-弹窗三-文本滑动选择器弹窗(TextPickDialog)

1、描述 根据指定的选择范围创建文本选择器&#xff0c;展示在弹窗上。 2、接口 TextPickDialog(options?: TextPickDialogOptions) 3、TextPickDialogOptions 参数名称 参数类型 必填 参数描述 rang string[] | Resource 是 设置文本选择器的选择范围。 selected nu…

AI图像重绘解决方案

高质量的图像素材往往成本高昂且制作周期长&#xff0c;给企业带来了不小的困扰。美摄科技凭借其领先的AI图像重绘解决方案&#xff0c;为企业提供了一种高效、便捷且成本可控的图像优化途径&#xff0c;助力企业重塑视觉形象&#xff0c;引领市场新风尚。 美摄科技的AI图像重…

NASA数据集——2014 年、2015 年和 2017 年北美地区土壤地球物理属性值(源层厚度 (ALT)、介电常数、土壤水分剖面、表面粗糙度)

ABoVE: AirSWOT Color-Infrared Imagery Over Alaska and Canada, 2017 简介 文件修订日期&#xff1a;2019-04-25 数据集版本: 1 摘要 本数据集提供了根据 2014 年、2015 年和 2017 年 8 月和 10 月在阿拉斯加北部 12 个研究地点&#xff08;除个别地点外&#xff09;采集…

LLM大语言模型(八):ChatGLM3-6B使用的tokenizer模型BAAI/bge-large-zh-v1.5

背景 BGE embedding系列模型是由智源研究院研发的中文版文本表示模型。 可将任意文本映射为低维稠密向量&#xff0c;以用于检索、分类、聚类或语义匹配等任务&#xff0c;并可支持为大模型调用外部知识。 BAAI/BGE embedding系列模型 模型列表 ModelLanguageDescriptionq…

CCIE-11-IPSec-VPN

目录 实验条件网络拓朴实验目的 开始配置1. R2 Ping R3确定基础网络是通的2. 配置R23. 配置R34. 测试 实验条件 网络拓朴 实验目的 为PC1和PC2建立IPSec VPN PC1可以ping通PC2 开始配置 1. R2 Ping R3确定基础网络是通的 R2#show ip int br Interface IP…

UE5启用SteamOSS流程

一、安装OnlineSubsystemSteam插件 1、在UE里安装OnlineSubsystemSteam 2、设置默认开始地图 3、设置DefaultEngine.ini文件&#xff1a; 打开项目根目录/Config/DefaultEngine.ini文件 打开官网的配置说明 复制并粘贴到该文件中 4、设置运行模式 5、测试 确保Steam平台已…

【MATLAB源码-第24期】基于matlab的水声通信中海洋噪声的建模仿真,对比不同风速的影响。

操作环境&#xff1a; MATLAB 2022a 1、算法描述 水声通信&#xff1a; 水声通信是一种利用水中传播声波的方式进行信息传递的技术。它在水下环境中被广泛应用&#xff0c;特别是在海洋科学研究、海洋资源勘探、水下军事通信等领域。 1. **传输媒介**&#xff1a;水声通信利…

人工智能本地化的时代即将到来

2024 年 3 月 26 日&#xff0c;我有幸应邀参加了在北京凤凰中心举办的AI PC发布会。在这次活动中&#xff0c;英特尔展示了基于第一代酷睿 Ultra 高能效 X86 处理器的商用客户端&#xff0c;充分展现了 AI 加速下企业业务数字化的新趋势。英特尔成功地实现了对 AIGC 的最后一公…

51单片机学习笔记11 使用DS18B20温度传感器

51单片机学习笔记11 使用DS18B20温度传感器 一、DS18B20简介1. 主要特点2. 工作原理3. 引脚说明4. ROM 二、1-wire协议简介1. 总线结构&#xff1a;2. 通信方式&#xff1a;3. 数据传输&#xff1a;4. 设备识别&#xff1a;5. 供电方式&#xff1a;6. 应用场景&#xff1a;7. 优…