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

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

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.kler.cn/a/283448.html

相关文章:

  • 移动端【01】面试系统的MVVM重构实践
  • 【Linux】TCP原理
  • Blender进阶:图像纹理节点和映射节点
  • 【C++】类与对象的基础概念
  • 初探鸿蒙:从概念到实践
  • golang分布式缓存项目 Day1 LRU 缓存淘汰策略
  • 2.10鼠标事件
  • MySQL(六)——多表查询
  • ZaKi:Ingonyama的Prover market基础设施
  • 基础概念与简单数据结构的笔记02
  • 数据结构---循环队列---树的基本概念
  • MySQL最左匹配原则
  • DAMA数据管理知识体系(第3章 数据治理)
  • 【STM32】驱动OLED屏
  • 2024高教社杯”全国大学生数学建模竞赛保奖秘诀!!!
  • 众安保险0827一面
  • UnrealEngine学习(02):虚幻引擎编辑器界面详解
  • 【DSP+FPGA】基于DSP+FPGA XC7K325T与TMS320C6678的通用信号处理平台
  • 力扣面试经典算法150题:整数转罗马数字
  • 91.游戏的启动与多开-游戏启动
  • Live800:以客户为中心,构建全方位客户服务策略
  • ThinkPHP之入门讲解
  • C++(this指针/常函数与常对象/拷贝构造函数/赋值函数/静态成员/静态成员函数/单列模式)
  • pdf、mp4、zip、rar、jpg等文件被大量访问造成流量超标解决方案
  • 腾讯提出一种新的针对风格化角色和逼真服装动画的生成3D运动转移方法,生成效果逼真!
  • Excel中使用VBS自定义函数将中文转为拼音首字母