基于状态机实现WIFI模组物联网

embedded/2024/9/20 9:21:48/ 标签: 物联网, USART, gd32, c语言, 嵌入式硬件, 单片机

1.0 状态机框架原理

如果成功的话就连接热点,如果失败就返回AT通信检查,如果AT通信检查还是失败就放回硬件复位这个状态,如果热点链接成功,就连接MQTT指令,如果失败就返回AT通信检查,如果成功就连接云平台通信,如果失败就返回AT通信检查这个状态。


2.0 程序编写


在这个过程中使用的是连接固定的热点,后续会连接可变动的WIFI热点,注上面的状态图是基于固定的WIFI热点连接的状态图形。

// 创建枚举类型
typedef enum
{WIFI_COMM_WAIT,WIFI_COMM_OK,WIFI_COMM_FALL,
}WifiCommState_t;

注:WIFI_COMM_WAIT 表示的是正在处理AT指令,WIFI_COMM_OK,表示AT指令发送完成,FALL表示AT指令发送超时,


3.0 Wi-Fi模块与AT命令交互

static WifiCommState_t AtCmdHandle(char *cmd, char* rsp, uint32_t timeoutMs)
{static WifiCommState_t s_commState = WIFI_COMM_OK;static uint64_t s_sendCmdTime;char *recvStrBuf;if (s_commState != WIFI_COMM_WAIT){if (cmd != NULL){SendWifiModuleStr(cmd);}s_commState = WIFI_COMM_WAIT;s_sendCmdTime = GetSysRunTime();}else{if ((GetSysRunTime() - s_sendCmdTime) < timeoutMs){recvStrBuf = RecvWifiModuleStr();if (strstr(recvStrBuf, rsp) != NULL){s_commState = WIFI_COMM_OK;}}else{s_commState = WIFI_COMM_FALL;}}return s_commState;
}

4.0 AT 命令结构体信息

// AT命令信息
typedef struct
{char *cmd;char *rsp;uint32_t timeoutMs;
}AtCmdInfo_t;

5.0 模组初始化命令集

/*模组初始化命令集*/
static AtCmdInfo_t g_checkModuleCmdTable[] = {{.cmd = "ATE0\r\n",        // 关闭回显.rsp = "OK",.timeoutMs = 1000,},{.cmd = "AT+CWMODE=1\r\n",.rsp = "OK",.timeoutMs = 1000,	},
};

对应在AT指令说明文档中的命令是:ATE 表示的是开启和关闭回显

.cmd = "AT+CWMODE=1\r\n",

注:这个指令是用于设置WIFI的工作模式,该指令表示的原因是设置WIFI的工作指令为客户端的工作模式。

  1. .cmd = "AT+CWMODE=1\r\n":

    • 这是AT命令的字符串表示形式,用于设置Wi-Fi模块的工作模式。
    • AT+CWMODE=1 表示设置Wi-Fi模块工作在Station模式(客户端模式),即Wi-Fi模块将连接到一个现有的Wi-Fi网络。
    • \r\n 是回车换行符,通常用于表示命令的结束。
  2. .rsp = "OK":

    • 这是指令成功执行后期望从Wi-Fi模块接收到的响应字符串。
    • 在许多情况下,Wi-Fi模块会在成功执行AT命令后返回 "OK"
  3. .timeoutMs = 1000:

    • 这是一个整数,表示在等待Wi-Fi模块响应时的超时时间,单位是毫秒。
    • 在本例中,超时时间为1000毫秒(1秒)。

4.0 检查WIFI模组的工作状态

WifiCommState_t CheckWifiModuleWork(void)
{WifiCommState_t commState;static uint8_t retryCount = 0;static AtCheckModuleCmdType cmdType = AT_E0;switch (cmdType){case AT_E0:commState = AtCmdHandle(g_checkModuleCmdTable[AT_E0].cmd, g_checkModuleCmdTable[AT_E0].rsp,g_checkModuleCmdTable[AT_E0].timeoutMs);if (commState == WIFI_COMM_OK){retryCount = 0;cmdType = AT_CWMODE_1;}else if (commState == WIFI_COMM_FALL){retryCount++;if (retryCount == 3){retryCount = 0;return WIFI_COMM_FALL;}}break;case AT_CWMODE_1:commState = AtCmdHandle(g_checkModuleCmdTable[AT_CWMODE_1].cmd, g_checkModuleCmdTable[AT_CWMODE_1].rsp,g_checkModuleCmdTable[AT_CWMODE_1].timeoutMs);if (commState == WIFI_COMM_OK){cmdType = AT_E0;return WIFI_COMM_OK;}else if (commState == WIFI_COMM_FALL){return WIFI_COMM_FALL;}break;}return WIFI_COMM_WAIT;
}

5.0 创建AT指令表

static AtCmdInfo_t g_ConnectApCmdTable[] = {{.cmd = "AT+CWJAP=\"%s\",\"%s\"\r\n",   // 这里的\是给编译器用的//.cmd = "AT+CWJAP=\"HIKE_5F\\,2.4G\",\"hike666666\"\r\n",.rsp = "GOT IP",.timeoutMs = 15000,},
};

注:"AT+CWJAP=\"%s\",\"%s\"\r\n" 此处这条AT指令的格式为什么是这样,主要原因是AT手册规定的格式就是这个样子:在程序中凡是AT指令出现, " \ 都需要在前面添加\号进行转义,具体如下所示:


6.0 AT+CWJAP 命令详解

注:

  • AT+CWJAP: 这是Wi-Fi模块用于连接到无线接入点(Access Point, AP)的AT命令。
  • SSID: 服务集标识符(Service Set Identifier),它是用来唯一标识一个无线网络的名字。
  • PWD: 密码,指的是Wi-Fi网络的安全密钥或密码。
AT+CWJAP="SSID","password"
  • SSID 替换为你要连接的Wi-Fi网络的名称。
  • password 替换为对应的Wi-Fi网络密码。

7.0 检查WIFI连接函数

typedef enum 
{AT_CWJAP_SSID_PWD,
} AtConnectApCmdType;static char g_apSsid[20] = "HIKE_5F_2.4G";
static char g_apPwd[20] = "hike666666";WifiCommState_t CheckWifiConnect(void)
{WifiCommState_t commState;static AtConnectApCmdType cmdType = AT_CWJAP_SSID_PWD;static uint8_t retryCount = 0;char cmdStrBuf[256];switch (cmdType){		case AT_CWJAP_SSID_PWD:sprintf(cmdStrBuf, g_ConnectApCmdTable[AT_CWJAP_SSID_PWD].cmd, g_apSsid, g_apPwd);commState = AtCmdHandle(cmdStrBuf, g_ConnectApCmdTable[AT_CWJAP_SSID_PWD].rsp, g_ConnectApCmdTable[AT_CWJAP_SSID_PWD].timeoutMs);if (commState == WIFI_COMM_OK){retryCount = 0;return WIFI_COMM_OK;}else if (commState == WIFI_COMM_FAIL){retryCount++;if (retryCount == 3){retryCount = 0;return WIFI_COMM_FAIL;}}break;}return WIFI_COMM_WAIT;	
}

8.0 枚举WIFI工作状态

typedef enum
{CHECK_WIFI_MODULE,CHECK_WIFI_CONNECT,CONNECT_MQTT_SERVER,COMM_MQTT_SERVER,HWRESET_WIFI_MODULE,WIWI_MODULE_ERROR,
} WifiWorkState_t;

注:一以上各个枚举变量的含义:

这个枚举类型 WifiWorkState_t 定义了一系列的状态,用于描述Wi-Fi模块在执行特定任务时的不同阶段。这些状态可以帮助我们跟踪Wi-Fi模块的工作流程。下面是每个枚举成员的含义:

  1. CHECK_WIFI_MODULE:

    • 这个状态表示正在检查Wi-Fi模块的基本功能或状态。这可能是初始化过程的一部分,用于验证Wi-Fi模块是否准备好接受进一步的命令。
  2. CHECK_WIFI_CONNECT:

    • 这个状态表示正在检查Wi-Fi模块是否已成功连接到Wi-Fi网络。这通常发生在Wi-Fi模块尝试连接到一个接入点之后。
  3. CONNECT_MQTT_SERVER:

    • 这个状态表示Wi-Fi模块正在尝试连接到MQTT服务器。一旦Wi-Fi连接建立,下一步就是与MQTT服务器建立连接。
  4. COMM_MQTT_SERVER:

    • 这个状态表示Wi-Fi模块已经成功连接到了MQTT服务器,并且正在与其进行通信。这可能涉及到发布消息、订阅主题等MQTT协议的交互。
  5. HWRESET_WIFI_MODULE:

    • 这个状态表示正在对Wi-Fi模块执行硬件重置。这可能是因为遇到一些无法通过软件解决的问题,或者是为了确保Wi-Fi模块回到一个已知的初始状态。
  6. WIWI_MODULE_ERROR:

    • 这个状态表示Wi-Fi模块遇到了错误。这可能是由于硬件故障、软件错误或其他未知问题引起的。当Wi-Fi模块无法正常工作时,它可能会进入这个状态。

9.0 WIFI网络工作任务函数

void WifiNetworkTask(void)
{WifiCommState_t commState;static WifiWorkState_t workState = CHECK_WIFI_MODULE;static uint8_t hwresetCnt = 0;switch (workState){case CHECK_WIFI_MODULE:commState = CheckWifiModuleWork();if (commState == WIFI_COMM_OK){workState = CHECK_WIFI_CONNECT;}else if (commState == WIFI_COMM_FAIL){workState = HWRESET_WIFI_MODULE;}break;case CHECK_WIFI_CONNECT:commState = CheckWifiConnect();if (commState == WIFI_COMM_OK){workState = CONNECT_MQTT_SERVER;}else if (commState == WIFI_COMM_FAIL){workState = CHECK_WIFI_MODULE;}break;		case CONNECT_MQTT_SERVER:break;case COMM_MQTT_SERVER:break;case HWRESET_WIFI_MODULE:if (hwresetCnt < 1)                 // 如果AT命令不通,硬件复位1次{HwresetWifiModule();DelayNms(1000);workState = CHECK_WIFI_MODULE;hwresetCnt++;}else{printf("wifi module error!\n");workState = WIWI_MODULE_ERROR;  // 如果硬件复位1次,AT命令还是不通,就不再执行WIFI任务的业务逻辑,直接退出,避免影响其他任务}break;default:break;}
}

10.0 网络连接成功


http://www.ppmy.cn/embedded/101593.html

相关文章

不平衡分类阈值移动的简单介绍

不平衡分类阈值移动的简单介绍 分类预测模型通常涉及预测类别标签。 尽管如此&#xff0c;许多机器学习算法能够预测类别成员的概率或得分&#xff0c;并且必须对其进行解释&#xff0c;然后才能将其映射到明确的类别标签。这是通过使用阈值&#xff08;例如 0.5&#xff09;…

小乌龟运动控制-1 小乌龟划圆圈

目录 第一章 小乌龟划圆圈 第二章 小乌龟走方形 文章目录 目录前言一、准备工作步骤一&#xff1a;创建ROS工作空间步骤二&#xff1a;创建ROS包和节点步骤三&#xff1a;编写Python代码步骤四&#xff1a;运行ROS节点总结 前言 本教程将教会你如何使用Python编写ROS小海龟节…

鸿蒙内核源码分析(用户态锁篇) | 如何使用快锁Futex(上)

快锁上下篇 鸿蒙内核实现了Futex&#xff0c;系列篇将用两篇来介绍快锁&#xff0c;主要两个原因: 网上介绍Futex的文章很少&#xff0c;全面深入内核介绍的就更少&#xff0c;所以来一次详细整理和挖透。涉及用户态和内核态打配合&#xff0c;共同作用&#xff0c;既要说用户…

WPF书籍阅读不指南

<wpf编程宝典> 对于刚匆忙学完 c# 的我来说,非常费劲. 只能 依靠<WPF深入浅出>>来对照看. ...就算是两本书互相看,还是十分难受,非常不理解...... 古老丛书<<windows Presentation Foundation 编程指南>> 一本 非常非常厚 的书,看着也难受,案例非常…

设计模式——创建型模式

工厂方法模式 简称工厂模式。 为一类对象的共有接口抽象出基类&#xff0c;工厂生产基类。 class PhoneFactory {static std::shared_ptr<Phone> Make();};class Phone {virtual void call() 0; };class XiaoMiPhone final : public Phone {void call() override; };…

【前端面试】操作系统

进程与线程 进程线程定义是计算机中的程序关于某数据集合上的一次运行活动&#xff0c;是系统进行资源分配和调度的基本单位是进程中的一个实体&#xff0c;是CPU调度和分派的基本单位&#xff0c;共享进程的资源资源分配拥有独立的内存空间和系统资源共享进程的内存和资源开销…

STM32-PWM驱动呼吸灯——HAL库

&#xff08;根据B站up主keysking的STM32教程视频的笔记&#xff09; 【STM32】动画讲解轻松学会STM32的PWM_哔哩哔哩_bilibili 什么是PWM&#xff1f; PWM&#xff0c;全称为脉冲宽度调制&#xff08;Pulse Width Modulation&#xff09;&#xff0c;是一种调制技术&#xf…

RabbitMQ中如何通过死信交换机实现延时队列

RabbitMQ中如何通过死信交换机实现延时队列 在RabbitMQ中&#xff0c;关于如何通过死信交换机实现延时队列的逻辑和原理&#xff0c;可以详细表述如下&#xff1a; 逻辑概述 消息发送&#xff1a; 生产者将消息发送到RabbitMQ的某个交换机&#xff08;Exchange&#xff09;&a…

js监听鼠标单击和双击事件,冲突问题处理

在浏览器中&#xff0c;单击事件通常会在双击事件之前触发&#xff0c;因此在处理单击和双击事件时&#xff0c;双击操作往往会先触发一次单击事件&#xff0c;这会导致意外的行为。 要解决这个问题&#xff0c;可以通过延迟处理单击事件&#xff0c;给浏览器一些时间来判断用…

VScode的python虚拟环境

1 创建虚拟环境&#xff08;venv&#xff09; 在VSCode中打开项目文件夹&#xff0c;键盘按住快捷键ctrl shift p&#xff0c;打开命令面板&#xff0c;输入python:创建环境 选择venv&#xff0c;输入解释器路径&#xff0c;此时左侧文件夹内会出现一个.venv文件夹 2 激活虚拟…

大模型分布式训练技术(DP、DDP和FSDP)

目录 数据并行&#xff08;PyTorch DP&#xff09; 分布式数据并行&#xff08;PyTorch DDP&#xff09; DP 与 DDP 的区别 补充说明&#xff1a;DP与DDP数据传输过程 完全分片数据并行(PyTorch FSDP) 补充说明&#xff1a;ZeRO FSDP DDP 与 FSDP 的区别 DP、DDP和FSD…

PYQT上位机开发--安装python环境

知不足而奋进 望远山而前行 目录 文章目录 前言 Python环境安装 第一个python程序 下载VSCode 推荐插件 必装 必选配置 勾选Run in Terminal(可以不用配置) 在文件目录运行代码 自动猜测编码(可以不用配置) 设置新建文件编码 可选配置 文件自动保存 修改字号字体(可以先不用配置…

Rust语言实现图像编码转换

一、概述 Rust 作为一门现代系统编程语言&#xff0c;不仅具有出色的性能和高安全性&#xff0c;其生态系统也在不断壮大。在图像处理方面&#xff0c;image-rs 库是 Rust 社区中广泛使用的开源库&#xff0c;它提供了丰富的图像编解码功能。本文将带你深入了解如何使用 image…

Debian常用包管理命令用法详解

文章目录 apt-get/apt-cacheaptdpkgdpkg-sourcedebuild dpkg和apt是两个不同的工具用于管理Debian系列Linux发行版上的软件包。dpkg是底层工具&#xff0c;负责直接安装、删除和管理软件包文件(.deb)。它不会自动处理软件包的依赖关系&#xff0c;需要用户手动处理。apt是一个高…

算法备案与安全评估最详细流程说明

一、“深度合成算法”与“生成合成类算法”的区别 在《深度合成管理规定》发布之初&#xff0c;市场曾对“深度合成技术”与“生成合成类技术”的关系展开讨论。根据《深度合成管理规定》的规定&#xff0c;“深度合成技术&#xff0c;是指利用深度学习”从文意本身分析&#…

最大限度地提高精细调整和 RAG 语言模型的 GPU 效率

在部署和管理 LLM/SLM 时最大化性能和最小化费用的实用策略。 可扩展性和成本难题 让我们直接进入问题的核心——扩展大型语言模型&#xff0c;特别是微调和检索增强生成 (RAG) 模型&#xff0c;是一项资源密集型工作&#xff0c;会很快耗尽您的 GPU 预算。作为一个亲身应对这些…

OpenCV Lesson 3 : Mask operations on matrices

矩阵上的掩码运算 Mask operations on matrices are quite simple. The idea is that we recalculate each pixel’s value in an image according to a mask matrix (also known as kernel). This mask holds values that will adjust how much influence neighboring pixels…

【CSS】tailwindcss 如何关闭默认样式

关闭 Preflight 默认样式 在你的 tailwind.config.js 文件中设置 preflight: false: module.exports {corePlugins: {preflight: false,} }这将禁用 Tailwind 的默认样式,包括 Preflight。 关键点 Preflight 是一个包含基础样式的预设,用于解决跨浏览器不一致性和设计系统…

学习前端面试知识(14)

2024-8-21 打卡第十四天 js的数据类型 基本类型&#xff1a;String&#xff0c;Number&#xff0c;Object&#xff0c;Null&#xff0c;undefined&#xff0c;Boolean es6之后引入&#xff1a;Symbol&#xff0c;BigInt 判断方式&#xff1a;typeof&#xff0c;instanceof…

百度最新旗舰大模型文心4.0 Turbo精调服务上线

8月21日&#xff0c;百度智能云宣布&#xff0c;推出文心旗舰大模型ERNIE 4.0 Turbo精调服务&#xff0c;帮助企业利用自身业务数据&#xff0c;训练出更适合企业应用场景的大模型&#xff0c;极大提升模型在业务中的使用效果&#xff0c;即日起企业用户可登录百度智能云官网进…