RT-thread(10) cubeMX+RT-Thread nano +Keil环境下,应用AT指令操作WIFI8266实现通信
WIFI模块程序设计步骤
分为三步:
1、组网
方式1: WIFI模块作为热点,手机或PC接入此热点; 方式2:手机开热点,WIFI模块与PC机接入;方式3:WIFI路由器当“热点”用,WIFI模块、手机及PC机接入。
2、建链接 分为TCP/IP 和UDP等方式,设1个服务器,其他客户端,必须在同一个网内(使用同一个热点)
3、传通信帧,实现应用功能。
ESP8266笔记 ---- 常用AT指令
本段引用来源:ESP8266笔记 ---- 常用AT指令
一般来说,ESP8266 模块默认的波特率是115200,指令以\r\n结尾,所以本文的所有指令都要使用\r\n,后面就不重复了。
还有,发送AT命令后,返回OK即认为设置成功。
一、测试指令
AT(这里应该输入 AT\r\n,为了不繁琐,后面就省略了\r\n,应用时一定要自己加)
返回 OK,说明模块正常。
二、开启/关闭回显(关系到模块是否回发发送的内容)
ATE1 – 打开回显ATE0 – 关闭回显
三、设置 WIFI 模式
3.1、AP 模式(可以理解为热点,别的设备可以连接)
首先,设置为AP 模式: AT+CWMODE=2。
配置热点信息: AT+CWSAP="Eureka1024","123456789",1,3 ---- 热点名为 Eureka1024,密码为 123456789,使用通道 1,加密方式为 WPA2_PSK。
这时候别的设备就可以连接该模块了。
3.2、Station 模式(最常用的模式,用来连接热点,从而接入外部网络)
设置为Station 模式:AT+CWMODE=1 。
连接到指定路由器:AT+CWJAP_DEF="PiWiFi","12345678" 。//wifi名和wifi密码
如果遇到同名的热点,可以通过增加 MAC地址 (下面命令的最后一串字符) 的方式,比如
AT+CWJAP_DEF="PiWiFi","12345678","db:d7:18:d5:a7:54"

获取 IP 地址:AT+CIPSTA?
设置模块开机自动连接热点:AT+CWAUTOCONN=1,模块上电后就会自动连接之前连接过的路由器(存储过名字和密码)。
扫描附近的 AP 热点信息:AT+CWLAP,包括的信息有(热点名,热点 MAC 地址,加密方式等),由于串口助手显示中文乱码,所以显示很奇怪,不过还好,都不用打码了,哈哈。
断开连接:AT+CWQAP
四、 简单的网络通信
4.1、简单的实现连接
在PC机上,打开网络调试助手,选择 TCP Server,会自动生成本地主机地址和本地主机端口号,点击打开,如下图所示:
接着在PC机上使用串口助手对 ESP8266 模块进行操作(电路已连接,PC机插上USB转串口模块,USB转串口模块接WIFI模块)。(前提是模块已经连接 wifi 成功,注意与PC机使用相同的”WIFI热点“,或则PC机接入工作在AP模式的WIFI模块”热点“)
首先,建立 TCP 连接,(可能会失败,可以按这个来设置ESP8266 TCP ERROR CLOSED的常见原因及解决办法,连手机的热点就可以,连电脑生成的热点就失败,不知道为啥,最好多试几次)
串口助手输入如下指令:AT+CIPSTART="TCP","192.168.0.107",8080
连接成功:
之后,使用键入指令: AT+CIPSEND=10,其中10指的是这次发送数据的长度。
串口助手界面显示 >,然后发送数据即可:
这是网络调试助手会接收到数据:
此时再通过 TCP Server 发送“hello,boy”,
串口接收端会打印 Client 收到的数据,结果如下图:
4.2、透传模式
前面在使用 TCP 进行数据发送时,在每次发送数据之前都要指定发送数据的长度,这样很不方便进行数据的处理。
使用透传模式可以解决这个问题。
使用 AT+CIPMODE=1 指令开启透传模式,开启透传模式后只需要在第一次发送数据时使用 AT+CIPSEND 指令来告诉 ESP8266 开始透传发送,随后我们直接发送想要的数据即可,如下操作所示:
此时你会看到接收到的数据:
若要结束透传模式,要有两个步骤:
1、发送 +++ 这三个字符,值得注意的是该命令没有换行符,不然后失败。
2、接着发送 AT+CIPMODE=0 命令即可退出透传模式,即回到正常的模式。
4.3、使用 SmartConfig 为设备配网
未成功,后补充
4.4、获取网络时间
先使用 AT+CIPSNTPCFG=1,8 来设置时区,这里设置的是 东八区。
然后使用 AT+CIPSNTPTIME? 来获取网络时间,如下所示:
WIFI模块的模式及设置AT指令如下
TCP通信测试:
(1) STA模式: 1.ESP8266 Client: -> AT+CWMODE=1 //设为STA模式 -> AT+CWJAP_DEF="FAE","123456789." //连接无线网络Wi-Fi -> AT+CIPSTART="TCP","192.168.0.116",8888 //连接服务端 -> AT+CIPSEND=5 //启动发送 2.ESP8266 Server: -> AT+CWMODE=1 //设置为 STA 模式 -> AT+CWJAP_DEF="FAE","123456789." //连接无线网络 wifi -> AT+CIPMUX=1 //开启多连接 -> AT+CIPSERVER=1,5000 //开启服务端 -> AT+CIFSR //查看 mac 地址和 IP -> AT+CIPSEND=0,5 //启动发送 (2)AP模式 ESP8266 Client: -> AT+CWMODE=2 //设置为AP模式 -> AT+CWSAP="ESP8266","12345678",11,3 //开启wifi热点 -> AT+CIPSTART="TCP","192.168.4.2",8888 //连接服务端 -> AT+CIPSEND=5 //启动发送 ESP8266 Server: -> AT+CWMODE=2 //设为AP模式 -> AT+CWSAP="ESP8266","12345678",11,3 //开启wifi热点 -> AT+CIPMUX=1 //开启多连接 -> AT+CIPSERVER=1,5000 //开启服务端 -> AT+CIFSR -> AT+CIPSEND=0,5
根据电路连接,cubeMX配置STM32G070RB,配置RT-thread nano
按照WIFI模块作为热点,作为TCP Server 的代码设计
AT指令操作WIFI模块的硬件驱动函数 wifi8266_uart_bsp.h
/** **************************************************************************************************** * @file wifi8266_uart_bsp.h * @author * @version V1.0 * @date 2023-02-22 * @brief * @license **************************************************************************************************** * @attention * AT指令操作WIFI模块的硬件驱动函数 * **************************************************************************************************** */ #ifndef __WIFI8266_UART_BSP_H #define __WIFI8266_UART_BSP_H //#include "./SYSTEM/sys/sys.h" #include "stm32g0xx_hal.h" /** *是否使用RT—thread操作系统 * WIFI_USING_RT_THREAD_OS用于定义系统文件夹是否支持OS * 0,不支持OS * 1,支持OS */ #define WIFI_USING_RT_THREAD_OS 1 /* 如果使用os,则包括下面的头文件即可. */ #if WIFI_USING_RT_THREAD_OS #include <rtthread.h> /* os 使用 */ #endif /* 引脚定义 */ #define WIFI8266_UART_TX_GPIO_PORT GPIOD #define WIFI8266_UART_TX_GPIO_PIN GPIO_PIN_5 #define WIFI8266_UART_TX_GPIO_CLK_ENABLE() do{ __HAL_RCC_GPIOD_CLK_ENABLE(); }while(0) /* PC口时钟使能 */ #define WIFI8266_UART_RX_GPIO_PORT GPIOD #define WIFI8266_UART_RX_GPIO_PIN GPIO_PIN_6 #define WIFI8266_UART_RX_GPIO_CLK_ENABLE() do{ __HAL_RCC_GPIOD_CLK_ENABLE(); }while(0) /* PD口时钟使能 */ #define WIFI8266_UART_INTERFACE USART2 #define WIFI8266_UART_IRQn USART2_IRQn #define WIFI8266_UART_IRQHandler USART2_IRQHandler #define WIFI8266_UART_CLK_ENABLE() do{ __HAL_RCC_UART5_CLK_ENABLE(); }while(0) /* UART5时钟使能 */ /* UART收发缓冲大小 */ #define WIFI8266_UART_RX_BUF_SIZE 256 #define WIFI8266_UART_TX_BUF_SIZE 256 #ifdef WIFI_USING_RT_THREAD_OS /*防止多个线程访问WIFI,调用wifi接口函数时使用*/ void wifi8266_lock(void); //获取互斥量 void wifi8266_unlock(void); //释放互斥量 /*用于接收帧处理函数与接收中断通信*/ //uint8_t wifi8266_wait_event(rt_int32_t timeout);//已接收帧,但串口没有接收到新的字节。等待这种情况 uint8_t wifi8266_take_sem(rt_int32_t timeout);//已接收帧,但串口没有接收到新的字节。等待这种情况 #endif /* 操作函数 */ void wifi_delay_ms(uint16_t n); /*等待WIFI8266应答的延时函数*/ void wifi8266_uart_printf(char *fmt, ...); /* WIFI8266 UART printf */ void wifi8266_uart_rx_restart(void); /* WIFI8266 UART重新开始接收数据 */ uint8_t *wifi8266_uart_rx_get_frame(void); /* 获取WIFI8266 UART接收到的一帧数据 */ uint16_t wifi8266_uart_rx_get_frame_len(void); /* 获取WIFI8266 UART接收到的一帧数据的长度 */ void wifi8266_uart_init(uint32_t baudrate); /* WIFI8266 UART初始化 */ #endif
AT指令操作WIFI模块的硬件驱动函数 wifi8266_uart_bsp.c
/** **************************************************************************************************** * @file wifi8266_uart_bsp.h * @author * @version V1.0 * @date 2023-02-22 * @brief * @license **************************************************************************************************** * @attention * AT指令操作WIFI模块的硬件驱动函数 * **************************************************************************************************** */ #include <wifi8266_uart_bsp.h> #include "usart.h" #include <stdarg.h> #include <stdio.h> #include <string.h> static UART_HandleTypeDef g_uart_handle; /* WIFI8266 UART */ static struct { uint8_t buf[WIFI8266_UART_RX_BUF_SIZE]; /* 帧接收缓冲 */ struct { uint16_t len : 15; /* 帧接收长度,sta[14:0] */ uint16_t finsh : 1; /* 帧接收完成标志,sta[15] */ } sta; /* 帧状态信息 */ } g_uart_rx_frame = {0}; /* WIFI8266 UART接收帧缓冲信息结构体 */ static uint8_t g_uart_tx_buf[WIFI8266_UART_TX_BUF_SIZE]; /* WIFI8266 UART发送缓冲 */ #if WIFI_USING_RT_THREAD_OS ///* 定义事件控制块(句柄) 及代码*/ //static rt_event_t WIFI8266_IT_event = RT_NULL;// 中断向通信线程发送的事件句柄 //#define WIFI8266_RX_IT_EVENT (0x0001 << 0) //设置事件掩码的位0 WIFI8266发来的数据RX中断触发 接收结束事件 /* 定义信号量*/ rt_sem_t WIFI8266_RX_IT_sem = RT_NULL; /* 定义互斥量控制块 */ static rt_mutex_t WIFI8266_usart_mux = RT_NULL; // 防止多个线程同时使用WIFI及相应的串口外设 #endif /** * @brief 等待WIFI8266应答的延时函数 * @param 无 * @retval 无 */ //static void delay_one_ms(void)/*等待WIFI8266应答的延时函数*/ { uint16_t i; /* 下面的时间是通过逻辑分析仪测试得到的。 工作条件:CPU主频72MHz ,MDK编译环境,1级优化 循环次数为10时,SCL频率 = 205KHz 循环次数为7时,SCL频率 = 347KHz, SCL高电平时间1.5us,SCL低电平时间2.87us 循环次数为5时,SCL频率 = 421KHz, SCL高电平时间1.25us,SCL低电平时间2.375us */ for (i = 0; i < 1366; i++); } //__weak void wifi_delay_ms(uint16_t n) { uint16_t i; for (i = 0; i < n; i++) delay_one_ms(); } /** * @brief WIFI8266 UART printf * @param fmt: 待打印的数据 * @retval 无 */ void wifi8266_uart_printf(char *fmt, ...) { va_list ap;//定义一具VA_LIST型的变量,包括 #include <stdarg.h> uint16_t len; va_start(ap, fmt);//用VA_START宏初始化变量刚定义的VA_LIST变量 vsprintf((char *)g_uart_tx_buf, fmt, ap);//具VA_LIST型的变量 va_end(ap);//最后用VA_END宏结束可变参数的获取 len = strlen((const char *)g_uart_tx_buf); HAL_UART_Transmit(&g_uart_handle, g_uart_tx_buf, len, HAL_MAX_DELAY); } /** * @brief WIFI8266 UART重新开始接收数据 * @param 无 * @retval 无 */ void wifi8266_uart_rx_restart(void) { g_uart_rx_frame.sta.len = 0; g_uart_rx_frame.sta.finsh = 0; } /** * @brief 获取WIFI8266 UART接收到的一帧数据 * @param 无 * @retval NULL: 未接收到一帧数据 * 其他: 接收到的一帧数据 */ uint8_t *wifi8266_uart_rx_get_frame(void) { if (g_uart_rx_frame.sta.finsh == 1) { g_uart_rx_frame.buf[g_uart_rx_frame.sta.len] = '\0';//末尾加字符串结束符 return g_uart_rx_frame.buf; } else { return NULL; } } /** * @brief 获取WIFI8266 UART接收到的一帧数据的长度 * @param 无 * @retval 0 : 未接收到一帧数据 * 其他: 接收到的一帧数据的长度 */ uint16_t wifi8266_uart_rx_get_frame_len(void) { if (g_uart_rx_frame.sta.finsh == 1) { return g_uart_rx_frame.sta.len; } else { return 0; } } /** * @brief WIFI8266 UART初始化 * @param baudrate: UART通讯波特率 * @retval 无 */ void wifi8266_uart_init(uint32_t baudrate) { g_uart_handle.Instance = WIFI8266_UART_INTERFACE; /* WIFI8266 UART */ g_uart_handle.Init.BaudRate = baudrate; /* 波特率 */ g_uart_handle.Init.WordLength = UART_WORDLENGTH_8B; /* 数据位 */ g_uart_handle.Init.StopBits = UART_STOPBITS_1; /* 停止位 */ g_uart_handle.Init.Parity = UART_PARITY_NONE; /* 校验位 */ g_uart_handle.Init.Mode = UART_MODE_TX_RX; /* 收发模式 */ g_uart_handle.Init.HwFlowCtl = UART_HWCONTROL_NONE; /* 无硬件流控 */ g_uart_handle.Init.OverSampling = UART_OVERSAMPLING_16; /* 过采样 */ HAL_UART_Init(&g_uart_handle); /* 使能WIFI8266 UART * HAL_UART_Init()会调用函数HAL_UART_MspInit() * 该函数定义在文件usart.c中 */ __HAL_UART_ENABLE_IT(&g_uart_handle, UART_IT_IDLE);// 开空闲中断 __HAL_UART_ENABLE_IT(&g_uart_handle, UART_IT_RXNE);// 开接收非空中断 #if WIFI_USING_RT_THREAD_OS /* 创建一个事件*/ // WIFI8266_IT_event = rt_event_create("wifi_IT_event", /* 事件标志组名字*/ // RT_IPC_FLAG_PRIO); /* 事件模式FIFO(0x00)*/ // if (WIFI8266_IT_event == RT_NULL) // rt_kprintf("error@ %s %s:%d,The mux for WIFI can‘t be created!r\n", __FILE__, __FUNCTION__, __LINE__);//当前行所在文件名、函数名、第**行代码 /* 创建一个互斥信号*/ WIFI8266_usart_mux = rt_mutex_create("test_mux",RT_IPC_FLAG_PRIO); if (WIFI8266_usart_mux == RT_NULL) rt_kprintf("error@ %s %s:%d,The mux for WIFI can‘t be created!r\n", __FILE__, __FUNCTION__, __LINE__);//当前行所在文件名、函数名、第**行代码 /* 创建一个信号*/ WIFI8266_RX_IT_sem = rt_sem_create("binary_sem", 0, RT_IPC_FLAG_FIFO); if (WIFI8266_RX_IT_sem == RT_NULL) rt_kprintf("error@ %s %s:%d,The semphore for WIFI can‘t be created!r\n", __FILE__, __FUNCTION__, __LINE__);//当前行所在文件名、函数名、第**行代码 #endif } /** * @brief WIFI8266_UART互斥锁 * @param baudrate: UART通讯波特率 * @retval 无 */ #if WIFI_USING_RT_THREAD_OS void wifi8266_lock(void) { rt_mutex_take( WIFI8266_usart_mux,RT_WAITING_FOREVER); //获取互斥量 } void wifi8266_unlock(void) { rt_mutex_release( WIFI8266_usart_mux ); //释放互斥量 } #endif /** * @brief 线程调用的应用函数与串口通信中断同步事件 * @param timeout: 延时多少ticks * @retval 无 */ #if WIFI_USING_RT_THREAD_OS //uint8_t wifi8266_wait_event(rt_int32_t timeout) //{ // rt_err_t uwRet = RT_EOK; // rt_uint32_t EventID; ///**等待触发事件,启动通信一次**/ ////while(1) ////{ // uwRet=rt_event_recv(WIFI8266_IT_event, /* 事件对象句柄 */ // WIFI8266_RX_IT_EVENT,/* 接收线程感兴趣的事件 */ // RT_EVENT_FLAG_OR|RT_EVENT_FLAG_CLEAR,/* 接收选项 */ // timeout,/* 指定超时事件, 100 ticks */ // &EventID); /* 指向接收到的事件 */ // if(-RT_ETIMEOUT == uwRet){ // rt_kprintf("error@ %s %s:%d, WIFI8266_RX_IT_EVENT:time out!r\n", __FILE__, __FUNCTION__, __LINE__);//当前行所在文件名、函数名、第**行代码 // return 1;//超时 // } // if(-RT_ERROR == uwRet){ // rt_kprintf("error@ %s %s:%d,WIFI8266_RX_IT_EVENT:ERROR!r\n", __FILE__, __FUNCTION__, __LINE__);//当前行所在文件名、函数名、第**行代码 // return 2;//错误 // } // if (EventID != ( WIFI8266_RX_IT_EVENT ) )/* 如果事件接收完成并且正确 */ // rt_kprintf("error@ %s %s:%d,WIFI8266_RX_IT_EVENT: ID incorrect!r\n", __FILE__, __FUNCTION__, __LINE__);//当前行所在文件名、函数名、第**行代码 // return 0; //// } //} //void wifi8266_send_event(void) //{ // /* 发送一个事件 UART_TX_IT_EVENT */ // rt_event_send(WIFI8266_IT_event,WIFI8266_RX_IT_EVENT); //} #endif /** * @brief 线程调用的应用函数与串口通信中断同步信号 * @param timeout: 延时多少ticks * @retval 无 */ #if WIFI_USING_RT_THREAD_OS uint8_t wifi8266_take_sem(rt_int32_t timeout) { rt_err_t uwRet = RT_EOK; //WIFI8266_RX_IT_sem->value =0;//信号值清零 uwRet = rt_sem_take(WIFI8266_RX_IT_sem, timeout);//等待信号量 if(-RT_ETIMEOUT == uwRet){ rt_kprintf("error@ %s %s:%d, WIFI8266_RX_IT_sem:time out!r\n", __FILE__, __FUNCTION__, __LINE__);//当前行所在文件名、函数名、第**行代码 return 1;//超时 } if(-RT_ERROR == uwRet){ rt_kprintf("error@ %s %s:%d,WIFI8266_RX_IT_sem:ERROR!r\n", __FILE__, __FUNCTION__, __LINE__);//当前行所在文件名、函数名、第**行代码 return 2;//错误 } /* 如果信号接收完成并且正确 */ return 0; } uint8_t wifi8266_release_sem(void) { rt_sem_release(WIFI8266_RX_IT_sem);//放出信号量 return 0; } #endif /** * @brief WIFI8266 UART中断回调函数 * @param 无 * @retval 无 */ void WIFI8266_UART_IRQHandler(void) { uint8_t tmp; if (__HAL_UART_GET_FLAG(&g_uart_handle, UART_FLAG_ORE) != RESET) /* UART接收过载错误中断 */ { __HAL_UART_CLEAR_OREFLAG(&g_uart_handle); /* 清除接收过载错误中断标志 */ (void)g_uart_handle.Instance->ISR;//SR; /* 先读SR寄存器,再读DR寄存器 */ (void)g_uart_handle.Instance->RDR;//DR; } if (__HAL_UART_GET_FLAG(&g_uart_handle, UART_FLAG_RXNE) != RESET) /* UART接收中断 */ { HAL_UART_Receive(&g_uart_handle, &tmp, 1, HAL_MAX_DELAY); /* UART接收数据 */ if (g_uart_rx_frame.sta.len < (WIFI8266_UART_RX_BUF_SIZE - 1)) /* 判断UART接收缓冲是否溢出 * 留出一位给结束符'\0' */ { g_uart_rx_frame.buf[g_uart_rx_frame.sta.len] = tmp; /* 将接收到的数据写入缓冲 */ g_uart_rx_frame.sta.len++; /* 更新接收到的数据长度 */ } else /* UART接收缓冲溢出 */ { g_uart_rx_frame.sta.len = 0; /* 覆盖之前收到的数据 */ g_uart_rx_frame.buf[g_uart_rx_frame.sta.len] = tmp; /* 将接收到的数据写入缓冲 */ g_uart_rx_frame.sta.len++; /* 更新接收到的数据长度 */ } } if (__HAL_UART_GET_FLAG(&g_uart_handle, UART_FLAG_IDLE) != RESET) /* UART总线空闲中断 */ { g_uart_rx_frame.sta.finsh = 1; /* 标记帧接收完成 */ __HAL_UART_CLEAR_IDLEFLAG(&g_uart_handle); /* 清除UART总线空闲中断 */ #if WIFI_USING_RT_THREAD_OS //wifi8266_send_event(); /* 发送事件,通知帧接收完成 */ wifi8266_release_sem(); /* 发送信号,通知帧接收完成 */ #endif } }
AT指令操作WIFI模块的应用函数 wifi_8266_app.h
/** **************************************************************************************************** * @file wifi_8266_app.h * @author * @version V1.0 * @date 2023-02-22 * @brief * @license **************************************************************************************************** * @attention * AT指令操作WIFI模块的应用函数 * **************************************************************************************************** */ #ifndef __WIFI_8266_APP_H #define __WIFI_8266_APP_H #include "stm32g0xx_hal.h" #include <wifi8266_uart_bsp.h> /*网络设置*/ #define WIFI_SSID "REGAIN_001" /*WIFI热点名称*/ #define WIFI_PWD "1234567899" /*WIFI热点密码*/ #define WIFI_AP_TCP_SERVER_IP "192.168.8.1" /*设置WIFI服务器的IP*/ #define WIFI_AP_TCP_SERVER_PORT "8181" /*设置WIFI服务器端口*/ /* 引脚定义 */ #define WIFI8266_RST_GPIO_PORT GPIOC #define WIFI8266_RST_GPIO_PIN GPIO_PIN_4 #define WIFI8266_RST_GPIO_CLK_ENABLE() do{ __HAL_RCC_GPIOC_CLK_ENABLE(); }while(0) /* PC口时钟使能 */ /* IO操作 */ #define WIFI8266_RST(x) do{ x ? \ HAL_GPIO_WritePin(WIFI8266_RST_GPIO_PORT, WIFI8266_RST_GPIO_PIN, GPIO_PIN_SET) : \ HAL_GPIO_WritePin(WIFI8266_RST_GPIO_PORT, WIFI8266_RST_GPIO_PIN, GPIO_PIN_RESET); \ }while(0) /* 错误代码 */ #define WIFI8266_EOK 0 /* 没有错误 */ #define WIFI8266_ERROR 1 /* 通用错误 */ #define WIFI8266_ETIMEOUT 2 /* 超时错误 */ #define WIFI8266_EINVAL 3 /* 参数错误 */ /* TCP客户端与服务器间通信使用,本机WIFI模块作为服务器 */ typedef struct { char data[WIFI8266_UART_RX_BUF_SIZE];/* 帧接收的数据 */ uint16_t linkNo; /* 收到网络连接的ID号*/ uint16_t len; /* 数据长度 */ } TCP_FRAME_TYPE; extern volatile TCP_FRAME_TYPE g_uart_tcp_frame; /* 操作函数 */ uint8_t wifi8266_init(uint32_t baudrate); /* WIFI8266初始化 */ void wifi8266_hw_reset(void); /* WIFI8266硬件复位 */ uint8_t wifi8266_send_at_cmd(char *cmd, char *ack, uint32_t timeout); /* WIFI8266发送AT指令 */ uint8_t wifi8266_restore(void); /* WIFI8266恢复出厂设置 */ uint8_t wifi8266_at_test(void); /* WIFI8266 AT指令测试 */ uint8_t wifi8266_sw_reset(void); /* WIFI8266软件复位 */ uint8_t wifi8266_ate_config(uint8_t cfg); /* WIFI8266设置回显模式 */ uint8_t wifi8266_set_mode(uint8_t mode); /* 设置WIFI8266工作模式 1 STA,2 AP,3AP+STA*/ /*WIFI的IP地址*/ uint8_t wifi8266_cipap_set(char *ip); /*AT+CIPAP WIFI模块AP模式的IP设置*/ uint8_t wifi8266_get_ip(char *buf); /* WIFI8266获取热点分配的IP地址 */ /*WIFI组网*/ uint8_t wifi8266_join_ap(char *ssid, char *pwd); /* WIFI8266连接外部WIFI热点 */ uint8_t wifi8266_set_ap(char *ssid, char *pwd,uint8_t channel, /*设置WIFI8266模块成WIFI热点,及其账户密码等信息*/ uint8_t encryptionMethod, uint8_t maxConnection, uint8_t broadCast); /*WIFI模块作为TCP Server通信*/ uint8_t wifi8266_cipmux_set(uint8_t setMux); /*AT+CIPMUX WIFI模块AP模式多连接*/ uint8_t wifi8266_servicer_set(uint8_t Enable,char *port); /*AT+CIPMUX=1 ,AT+CIPSERVER指令,将WIFI模块设置为TCP服务器*/ uint8_t wifi8266_connect_tcp_server(char *server_ip, char *server_port); /* WIFI8266连接外部TCP服务器 */ uint8_t wifi8266_tcp_server_receive(uint32_t timeout); /* WIFI8266连接外部TCP服务器 +IPD*/ uint8_t wifi8266_servicer_get_data(void); /*解析通信帧,得到客户端发来的信息*/ uint8_t wifi8266_tcp_server_sendcmd( uint16_t linkNo,uint16_t len); /*向客户端发送数据帧的AT指令及客户端链接号,数据字节数*/ uint8_t wifi8266_servicer_sendData(void); /*向客户端发送数据帧*/ /*WIFI模块透传*/ uint8_t wifi8266_enter_unvarnished(void); /* WIFI8266进入透传 */ void wifi8266_exit_unvarnished(void); /* WIFI8266退出透传 */ uint8_t wifi8266_connect_atkcld(char *id, char *pwd); /* WIFI8266连接原子云服务器 */ uint8_t wifi8266_disconnect_atkcld(void); /* WIFI8266断开原子云服务器连接 */ #endif
AT指令操作WIFI模块的应用函数 wifi_8266_app.c
/** **************************************************************************************************** * @file wifi_8266_app.c * @author * @version V1.0 * @date 2023-02-22 * @brief * @license **************************************************************************************************** * @attention * AT指令操作WIFI模块的应用函数 * **************************************************************************************************** */ #include <wifi_8266_app.h> #include <string.h> #include <stdio.h> #include <stdlib.h> //字符串和数值间转换 /*TCP帧信息*/ volatile TCP_FRAME_TYPE g_uart_tcp_frame={0}; /** * @brief WIFI8266硬件初始化 * @param 无 * @retval 无 * @attention WIFI模块复位引脚,设置GPIO引脚控制复位 */ static void wifi8266_hw_init(void) { GPIO_InitTypeDef gpio_init_struct; WIFI8266_RST_GPIO_CLK_ENABLE(); gpio_init_struct.Pin = WIFI8266_RST_GPIO_PIN; gpio_init_struct.Mode = GPIO_MODE_OUTPUT_PP; gpio_init_struct.Pull = GPIO_NOPULL; gpio_init_struct.Speed = GPIO_SPEED_FREQ_HIGH; HAL_GPIO_Init(WIFI8266_RST_GPIO_PORT, &gpio_init_struct); } /** * @brief WIFI8266硬件复位 * @param 无 * @retval 无 */ /*来自WIFI模块的应答*/ void wifi8266_hw_reset(void) { WIFI8266_RST(0); wifi_delay_ms(100); WIFI8266_RST(1); wifi_delay_ms(500); } /** * @brief WIFI8266发送AT指令 * @param cmd : 待发送的AT指令 * ack : 等待的响应 * timeout: 等待超时时间 * @retval WIFI8266_EOK : 函数执行成功 * WIFI8266_ETIMEOUT: 等待期望应答超时,函数执行失败 */ uint8_t wifi8266_send_at_cmd(char *cmd, char *ack, uint32_t timeout) { uint8_t *ret = NULL; uint8_t ubRet; wifi8266_uart_rx_restart(); wifi8266_uart_printf("%s\r\n", cmd); //发送AT指令 if ((ack == NULL) || (timeout == 0)) { return WIFI8266_EOK; } else { #ifndef WIFI_USING_RT_THREAD_OS while (timeout > 0)//延时循环查询WIFI回传通信帧,判断是否接收 { ret = wifi8266_uart_rx_get_frame(); if (ret != NULL) { if (strstr((const char *)ret, ack) != NULL)//在ret字符串中查找 ack字符串 { return WIFI8266_EOK; } else { wifi8266_uart_rx_restart();//清零RX缓冲 } } timeout--; wifi_delay_ms(1); } #endif #ifdef WIFI_USING_RT_THREAD_OS receive: //ubRet = wifi8266_wait_event(timeout);//已接收帧,但串口没有接收到新的字节。等待这种情况 ubRet = wifi8266_take_sem(timeout);//已接收帧,但串口没有接收到新的字节。等待这种情况 if( ubRet ==0){//从通信帧中查找ack ret = wifi8266_uart_rx_get_frame(); if (ret != NULL) { if (strstr((const char *)ret, ack) != NULL)//在ret字符串中查找 ack字符串 { return WIFI8266_EOK;//从通信帧中找到ack } else { wifi8266_uart_rx_restart();//清零RX缓冲 goto receive;//从通信帧中没有找到ack,再次接收新的帧 } } else{// ret没有字符串 wifi8266_uart_rx_restart();//清零RX缓冲 return WIFI8266_ERROR; } } if(ubRet ==1){ /*超时,没有接收数据*/ return WIFI8266_ETIMEOUT; } if(ubRet ==2){ /*错误,没有接收数据*/ return WIFI8266_ERROR; } #endif return WIFI8266_ERROR; } } /** * @brief WIFI8266初始化 * @param baudrate: WIFI8266 UART通讯波特率 * @retval WIFI8266_EOK : WIFI8266初始化成功,函数执行成功 * WIFI8266_ERROR: WIFI8266初始化失败,函数执行失败 */ uint8_t wifi8266_init(uint32_t baudrate) { wifi8266_hw_init(); /* WIFI8266硬件初始化 */ wifi8266_hw_reset(); /* WIFI8266硬件复位 */ wifi8266_uart_init(baudrate); /* WIFI8266 UART初始化 */ if (wifi8266_at_test() != WIFI8266_EOK) /* WIFI8266 AT指令测试 */ { return WIFI8266_ERROR; } return WIFI8266_EOK; } /** * @brief WIFI8266恢复出厂设置 * @param 无 * @retval WIFI8266_EOK : 恢复出场设置成功 * WIFI8266_ERROR: 恢复出场设置失败 */ /*来自WIFI模块的应答*/ //AT+RESTORE //OK // ... //ready uint8_t wifi8266_restore(void) { uint8_t ret; ret = wifi8266_send_at_cmd("AT+RESTORE", "ready", 30000); if (ret == WIFI8266_EOK) { return WIFI8266_EOK; } else { return WIFI8266_ERROR; } } /** * @brief WIFI8266 AT指令测试 * @param 无 * @retval WIFI8266_EOK : AT指令测试成功 * WIFI8266_ERROR: AT指令测试失败 */ /*来自WIFI模块的应答*/ //AT //OK uint8_t wifi8266_at_test(void) { uint8_t ret; uint8_t i; for (i=0; i<10; i++) { ret = wifi8266_send_at_cmd("AT", "OK", 500); if (ret == WIFI8266_EOK) { return WIFI8266_EOK; } } return WIFI8266_ERROR; } /** * @brief 设置WIFI8266工作模式 * @param mode: 1,Station模式 * 2,AP模式 * 3,AP+Station模式 * @retval WIFI8266_EOK : 工作模式设置成功 * WIFI8266_ERROR : 工作模式设置失败 * WIFI8266_EINVAL: mode参数错误,工作模式设置失败 */ /*来自WIFI模块的应答*/ //AT+CWMODE=1 //OK uint8_t wifi8266_set_mode(uint8_t mode) { uint8_t ret; switch (mode) { case 1: { ret = wifi8266_send_at_cmd("AT+CWMODE_DEF=1", "OK", 500); /* Station模式 */ break; } case 2: { ret = wifi8266_send_at_cmd("AT+CWMODE_DEF=2", "OK", 500); /* AP模式 */ break; } case 3: { ret = wifi8266_send_at_cmd("AT+CWMODE_DEF=3", "OK", 500); /* AP+Station模式 */ break; } default: { return WIFI8266_EINVAL; } } if (ret == WIFI8266_EOK) { return WIFI8266_EOK; } else { return WIFI8266_ERROR; } } /** * @brief WIFI8266软件复位 * @param 无 * @retval WIFI8266_EOK : 软件复位成功 * WIFI8266_ERROR: 软件复位失败 *//*来自WIFI模块的应答*/ //AT+RST //OK // ets Jan 8 2013,rst cause:2, boot mode:(3,7) // ... //ready uint8_t wifi8266_sw_reset(void) { uint8_t ret; ret = wifi8266_send_at_cmd("AT+RST", "ready", 10000); if (ret == WIFI8266_EOK) { return WIFI8266_EOK; } else { return WIFI8266_ERROR; } } /** * @brief WIFI8266设置回显模式 * @param cfg: 0,关闭回显 * 1,打开回显 * @retval WIFI8266_EOK : 设置回显模式成功 * WIFI8266_ERROR: 设置回显模式失败 * @specifi 回显,在WIFI模块返回应答的时候,首先返回发给它的指令。关闭时,直接返回应答。 *//*来自WIFI模块的应答*/ //ATE1 //OK uint8_t wifi8266_ate_config(uint8_t cfg) { uint8_t ret; switch (cfg) { case 0: { ret = wifi8266_send_at_cmd("ATE0", "OK", 500); /* 关闭回显 */ break; } case 1: { ret = wifi8266_send_at_cmd("ATE1", "OK", 500); /* 打开回显 */ break; } default: { return WIFI8266_EINVAL; } } if (ret == WIFI8266_EOK) { return WIFI8266_EOK; } else { return WIFI8266_ERROR; } } /** * @brief WIFI8266连接WIFI * @param ssid: WIFI名称 * pwd : WIFI密码 * @retval WIFI8266_EOK : WIFI连接成功 * WIFI8266_ERROR: WIFI连接失败 */ /*来自WIFI模块的应答*/ uint8_t wifi8266_join_ap(char *ssid, char *pwd) { uint8_t ret; char cmd[64]; sprintf(cmd, "AT+CWJAP_DEF=\"%s\",\"%s\"", ssid, pwd);//组合AT指令字符串 ret = wifi8266_send_at_cmd(cmd, "WIFI GOT IP", 10000); if (ret == WIFI8266_EOK) { return WIFI8266_EOK; } else { return WIFI8266_ERROR; } } /** * @brief WIFI8266设置WIFI热点的账户密码等信息 * @param ssid: WIFI名称 * pwd : WIFI密码 * channel: 无线信道 * encryptionMethod:加密方法 * maxConnection: 最多连接数,不超过4 * broadCast: 广播名称,0或1 * @retval WIFI8266_EOK : WIFI连接成功 * WIFI8266_ERROR: WIFI连接失败 * wifi8266_set_ap("REGAIN_001","1234567899",10,4,1,0); */ /*来自WIFI模块的应答*/ //AT+CWSAP="REGAIN_001","1234567899",10,4,1,0 //OK uint8_t wifi8266_set_ap(char *ssid, char *pwd,uint8_t channel, uint8_t encryptionMethod,uint8_t maxConnection, uint8_t broadCast)//WIFI8266设置WIFI热点的账户密码等信息 { uint8_t ret; char cmd[128]; sprintf(cmd, "AT+CWSAP_DEF=\"%s\",\"%s\",%d,%d,%d,%d", ssid, pwd,channel,encryptionMethod,maxConnection,broadCast);//组合AT指令字符串 ret = wifi8266_send_at_cmd(cmd, "OK", 8000); if (ret == WIFI8266_EOK) { return WIFI8266_EOK; } else { return WIFI8266_ERROR; } } /** * @brief WIFI8266获取IP地址 * @param buf: IP地址,需要16字节内存空间 * @retval WIFI8266_EOK : 获取IP地址成功 * WIFI8266_ERROR: 获取IP地址失败 */ /*来自WIFI模块的应答*/ //AT+CIFSR //+CIFSR:APIP,"192.168.4.1" //+CIFSR:APMAC,"32:83:98:82:4f:34" //OK uint8_t wifi8266_get_ip(char *buf) { uint8_t ret; char *p_start; char *p_end; ret = wifi8266_send_at_cmd("AT+CIFSR", "OK", 500); if (ret != WIFI8266_EOK) { return WIFI8266_ERROR; } p_start = strstr((const char *)wifi8266_uart_rx_get_frame(), "\""); p_end = strstr(p_start + 1, "\""); *p_end = '\0'; sprintf(buf, "%s", p_start + 1); return WIFI8266_EOK; } /** * @brief WIFI8266作为客户端,连接TCP服务器 * @param server_ip : TCP服务器IP地址 * server_port: TCP服务器端口号 * @retval WIFI8266_EOK : 连接TCP服务器成功 * WIFI8266_ERROR: 连接TCP服务器失败 */ uint8_t wifi8266_connect_tcp_server(char *server_ip, char *server_port) { uint8_t ret; char cmd[64]; sprintf(cmd, "AT+CIPSTART=\"TCP\",\"%s\",%s", server_ip, server_port); ret = wifi8266_send_at_cmd(cmd, "CONNECT", 5000); if (ret == WIFI8266_EOK) { return WIFI8266_EOK; } else { return WIFI8266_ERROR; } } /** * @brief 作为客户端,WIFI8266进入透传 * @param 无 * @retval WIFI8266_EOK : 进入透传成功 * WIFI8266_ERROR: 进入透传失败 *@attention CIPMUX and CIPSERVER must be 0 */ uint8_t wifi8266_enter_unvarnished(void) { uint8_t ret; ret = wifi8266_send_at_cmd("AT+CIPMODE=1", "OK", 500); ret += wifi8266_send_at_cmd("AT+CIPSEND", ">", 500); if (ret == WIFI8266_EOK) { return WIFI8266_EOK; } else { return WIFI8266_ERROR; } } /** * @brief WIFI8266退出透传 * @param 无 * @retval 无 */ void wifi8266_exit_unvarnished(void) { wifi8266_uart_printf("+++"); } /** * @brief AT+CIPMUX 多连接 * @param setMux 0,1 * @retval WIFI8266_EOK : 成功 * WIFI8266_ERROR: 失败 */ /*来自WIFI模块的应答*/ //AT+CIPMUX=1 //OK uint8_t wifi8266_cipmux_set(uint8_t setMux)/*AT+CIPMUX 多连接*/ { uint8_t ret; char cmd[64]; sprintf(cmd, "AT+CIPMUX=%d", setMux); ret = wifi8266_send_at_cmd(cmd, "OK", 500); if (ret == WIFI8266_EOK) { return WIFI8266_EOK; } else { return WIFI8266_ERROR; } } /** * @brief AT+CIPAP AP模式的IP设置 * @param setMux 0,1 * @retval WIFI8266_EOK : 成功 * WIFI8266_ERROR: 失败 */ /*来自WIFI模块的应答*/ //AT+CIPAP="192.168.5.1" //OK uint8_t wifi8266_cipap_set(char *ip)/*AT+CIPAP AP模式的IP设置*/ { uint8_t ret; char cmd[64]; sprintf(cmd, "AT+CIPAP=\"%s\"", ip); ret = wifi8266_send_at_cmd(cmd, "OK", 500); if (ret == WIFI8266_EOK) { return WIFI8266_EOK; } else { return WIFI8266_ERROR; } } /** * @brief AT+CIPMUX=1 ,AT+CIPSERVER指令,将 WIFI模块设置为TCP服务器 * @param Enable 0,1 ;port 端口号字符串 * @retval WIFI8266_EOK : 成功 * WIFI8266_ERROR: 失败 */ /*来自WIFI模块的应答*/ //AT+CIPSERVER=1,8080 //OK uint8_t wifi8266_servicer_set(uint8_t Enable,char *port)/*AT+CIPMUX=1 ,AT+CIPSERVER指令,将WIFI模块设置为TCP服务器*/ { uint8_t ret; char cmd[64]; ret = wifi8266_send_at_cmd("AT+CIPMUX=1","OK",500);//多接入模式 sprintf(cmd, "AT+CIPSERVER=%d,%s", Enable,port);//服务器开启及端口设置 ret += wifi8266_send_at_cmd(cmd, "OK", 500); if (ret == WIFI8266_EOK) { return WIFI8266_EOK; } else { return WIFI8266_ERROR; } } /** * @brief AT+CIPSERVER=0 关闭TCP服务器,注意需要重启WIFI模块 * @param 无 * @retval WIFI8266_EOK : 成功 * WIFI8266_ERROR: 失败 */ /*来自WIFI模块的应答*/ //AT+CIPSERVER=0 //OK uint8_t wifi8266_servicer_reset(void)/*AT+CIPSERVER=0 关闭 WIFI模块TCP服务器,注意需要重启WIFI模块*/ { uint8_t ret; ret = wifi8266_send_at_cmd("AT+CIPSERVER=0", "OK", 500); if (ret == WIFI8266_EOK) { return WIFI8266_EOK; } else { return WIFI8266_ERROR; } } /** * @brief WIFI8266作为TCP服务器,启动向客户端发送帧 * AT指令 AT+CIPSEND * @param linkNo :收到客户端网络连接的ID号 * len; :数据长度 * @retval WIFI8266_EOK : 函数执行成功 * WIFI8266_ETIMEOUT: 等待期望应答超时,函数执行失败 * @global g_uart_tcp_frame * 数据帧的 客户端链接号linkNo,长度len,及数据帧data */ uint8_t wifi8266_tcp_server_sendcmd( uint16_t linkNo,uint16_t len) { //uint8_t *ret = NULL; uint8_t ubRet; char cmd[128]; sprintf(cmd, "AT+CIPSEND=%d,%d", linkNo, len);//组合AT指令字符串 ubRet = wifi8266_send_at_cmd(cmd, ">", 8000); return ubRet; } /** * @brief 向远端发送数据 * @param 无 * @retval WIFI8266_EOK : 成功 * WIFI8266_ERROR: 失败 * @global g_uart_tcp_frame * 数据帧的 客户端链接号linkNo,长度len,及数据帧data */ //> // 提示符>出现后,串口发送字节 //busy s... //Recv 4 bytes //SEND OK uint8_t wifi8266_servicer_sendData(void)/*向客户端发送数据帧*/ { uint8_t ret; ret = wifi8266_send_at_cmd(( char*)g_uart_tcp_frame.data, "SEND OK", 500);//发送数据data帧 if (ret == WIFI8266_EOK) { return WIFI8266_EOK; } else { return WIFI8266_ERROR; } } /** * @brief WIFI8266作为TCP服务器,接收+IPD * @param timeout: 等待超时时间 * @retval WIFI8266_EOK : 函数执行成功 * WIFI8266_ETIMEOUT: 等待期望应答超时,函数执行失败 */ /*来自WIFI模块的通信帧*/ //+IPD,0,3:ACK //接客户端0发来的3BYTES帧,是 ACK uint8_t wifi8266_tcp_server_receive(uint32_t timeout) /* WIFI8266连接外部TCP服务器 +IPD*/ { uint8_t *ret = NULL; uint8_t ubRet; wifi8266_uart_rx_restart(); #ifdef WIFI_USING_RT_THREAD_OS receive: //ubRet = wifi8266_wait_event(timeout);//已接收帧,但串口没有接收到新的字节。等待这种情况 ubRet = wifi8266_take_sem(timeout);//已接收帧,但串口没有接收到新的字节。等待这种情况 if( ubRet ==0){//从通信帧中查找ack ret = wifi8266_uart_rx_get_frame(); if (ret != NULL) { if (strstr((const char *)ret, "+IPD") != NULL)//在ret字符串中查找+IPD字符串 { return WIFI8266_EOK;//从通信帧中找到+IPD } else { wifi8266_uart_rx_restart();//清零RX缓冲 goto receive;//从通信帧中没有找到ack,再次接收新的帧 } } else{// ret没有字符串 wifi8266_uart_rx_restart();//清零RX缓冲 return WIFI8266_ERROR; } } if(ubRet ==1){ /*超时,没有接收数据*/ return WIFI8266_ETIMEOUT; } if(ubRet ==2){ /*错误,没有接收数据*/ return WIFI8266_ERROR; } #endif return WIFI8266_ERROR; } /** * @brief 取出接收远端发来的数据 * @param 无 * @retval WIFI8266_EOK : 成功 * WIFI8266_ERROR: 失败 */ /*来自WIFI模块的通信帧*/ //+IPD,0,3:ACK //接客户端0发来的3BYTES帧,是 ACK uint8_t wifi8266_servicer_get_data(void)/*解析通信帧,得到客户端发来的信息*/ { uint8_t ret; char *p_start; char *p_end; char buf[3]; ret = WIFI8266_EOK; /*取帧内data部分*/ p_start = strstr((const char *)wifi8266_uart_rx_get_frame(), ":"); sprintf((char*)g_uart_tcp_frame.data, "%s", p_start + 1);//数据 /*取帧内len部分*/ p_start = strstr((const char *)wifi8266_uart_rx_get_frame(), ","); p_start = strstr(p_start + 1, ","); p_end = strstr(p_start + 1, ":"); *p_end = '\0';//字符串结束符号 if(p_end-p_start>sizeof(buf)+1) return WIFI8266_ERROR; sprintf(buf, "%s", p_start + 1); g_uart_tcp_frame.len = atoi(buf);//字符串转整数 /*取帧内link No部分*/ p_start = strstr((const char *)wifi8266_uart_rx_get_frame(), ","); p_end = strstr(p_start + 1, ","); *p_end = '\0';//字符串结束符号 if(p_end-p_start>sizeof(buf)+1) return WIFI8266_ERROR; sprintf(buf, "%s", p_start + 1); g_uart_tcp_frame.linkNo= atoi(buf);//字符串转整数 if (ret == WIFI8266_EOK) { return WIFI8266_EOK; } else { return WIFI8266_ERROR; } }
AT指令操作WIFI模块的线程 wifi_8266_rtth.h
#ifndef WIFI_8266_RTTH_H #define WIFI_8266_RTTH_H #include "stm32g0xx_hal.h" uint8_t wifi_tcpserver_rtthread_Init(void); #endif
AT指令操作WIFI模块的线程 wifi_8266_rtth.c
#include "wifi_8266_rtth.h" #include <rtthread.h> #include <wifi_8266_app.h> #include <string.h> #include <stdio.h> #include <stdlib.h> //字符串和数值间转换 /* RT-Thread 定义线程控制块指针 */ static rt_thread_t tcp_server_thread = RT_NULL; /* RT-Thread 线程入口函数声明 */ static void tcp_server_thread_entry(void* parameter); uint8_t wifi_tcp_server_check(void);/*检查WIFI模块配置是否正确*/ /** * @brief WIFI8266硬件初始化 * @param 无 * @retval 无 * @attention WIFI模块复位引脚,设置GPIO引脚控制复位 */ uint8_t wifi_tcpserver_rtthread_Init(void) { /*创建线程控制块,并赋给一个该类型指针变量f*/ tcp_server_thread= /* 线程控制块指针 */ rt_thread_create( "tcp_server", /* 线程名字 */ tcp_server_thread_entry, /* 线程入口函数 */ RT_NULL, /* 线程入口函数参数 */ 512, /* 线程栈大小 */ 3, /* 线程的优先级 */ 20); /* 线程时间片 */ /* 启动线程,开启调度 */ if (tcp_server_thread != RT_NULL) rt_thread_startup(tcp_server_thread); else return 1; return 0; } /** * @brief WIFI8266硬件初始化 * @param 无 * @retval 无 * @attention WIFI模块复位引脚,设置GPIO引脚控制复位 */ static void tcp_server_thread_entry(void* parameter) { wifi8266_uart_init(115200); if(WIFI8266_EOK != wifi8266_at_test()){ /* WIFI8266 AT指令测试 */ rt_kprintf("%s %s:%d error!\r\n", __FILE__, __FUNCTION__, __LINE__);//当前行所在文件名、函数名、第**行代码 rt_thread_delay(100); } /*组网参数设置*/ if(WIFI8266_EOK !=wifi_tcp_server_check())/*检查WIFI模块配置是否正确*/ { if(WIFI8266_EOK != wifi8266_cipap_set(WIFI_AP_TCP_SERVER_IP)){ /*WIFI模块的IP设置*/ rt_kprintf("%s %s:%d error!\r\n", __FILE__, __FUNCTION__, __LINE__);//当前行所在文件名、函数名、第**行代码 rt_thread_delay(100); } if(WIFI8266_EOK != wifi8266_set_mode(2)){ /* 设置WIFI8266工作模式 sta+ap */ rt_kprintf("%s %s:%d error!\r\n", __FILE__, __FUNCTION__, __LINE__);//当前行所在文件名、函数名、第**行代码 rt_thread_delay(100); } if(WIFI8266_EOK != wifi8266_set_ap(WIFI_SSID,WIFI_PWD,10,4,1,0)){ /* WIFI8266软件复位,新设置的工作模式生效*/ rt_kprintf("%s %s:%d error!\r\n", __FILE__, __FUNCTION__, __LINE__);//当前行所在文件名、函数名、第**行代码 rt_thread_delay(100); } if(WIFI8266_EOK != wifi8266_sw_reset()){ /* WIFI8266软件复位,新设置的工作模式生效*/ rt_kprintf("%s %s:%d error!\r\n", __FILE__, __FUNCTION__, __LINE__);//当前行所在文件名、函数名、第**行代码 rt_thread_delay(100); } } /*网络链接参数设置*/ if(WIFI8266_EOK != wifi8266_servicer_set(1,WIFI_AP_TCP_SERVER_PORT)){ /*AT+CIPMUX=1 ,AT+CIPSERVER指令,将WIFI模块设置为TCP服务器*/ rt_kprintf("%s %s:%d error!\r\n", __FILE__, __FUNCTION__, __LINE__);//当前行所在文件名、函数名、第**行代码 rt_thread_delay(100); } /*服务器侦听数据包,侦听客户端发来通信帧,解析通信帧,AT指令启动发送,发送数据帧*/ while(1) { if(WIFI8266_EOK !=wifi8266_tcp_server_receive(100)){ /* WIFI8266作为服务器,接收+IPD开始的通信帧*/ continue; } /*解析通信帧,得到客户端发来的信息*/ if(WIFI8266_EOK !=wifi8266_servicer_get_data()){ rt_kprintf("%s %s:%d error!\r\n", __FILE__, __FUNCTION__, __LINE__); }; if( 0== g_uart_tcp_frame.len) continue; /*AT指令通知WIFI模块作为TCP server发送链接号,数据字节数*/ sprintf((char*)g_uart_tcp_frame.data, "success transfer!linkNo:%d", g_uart_tcp_frame.linkNo);//组合AT指令字符串 g_uart_tcp_frame.len = strlen((char*)g_uart_tcp_frame.data); if(WIFI8266_EOK != wifi8266_tcp_server_sendcmd( g_uart_tcp_frame.linkNo,g_uart_tcp_frame.len)){ rt_kprintf("%s %s:%d error!\r\n", __FILE__, __FUNCTION__, __LINE__); }; /*向客户端发送数据帧*/ if(WIFI8266_EOK != wifi8266_servicer_sendData()){ rt_kprintf("%s %s:%d error!\r\n", __FILE__, __FUNCTION__, __LINE__); }; rt_thread_delay(50); } } /** * @brief 检查WIFI模块配置是否正确 * @param 无 * @retval 无 * @attention WIFI模块复位引脚,设置GPIO引脚控制复位 */ uint8_t wifi_tcp_server_check(void)/*检查WIFI模块配置是否正确*/ { uint8_t ret; ret = wifi8266_send_at_cmd("AT+CWMODE?","2",500); //AP模式? ret += wifi8266_send_at_cmd("AT+CWSAP?",WIFI_SSID,500); //热点名称? ret += wifi8266_send_at_cmd("AT+CIFSR",WIFI_AP_TCP_SERVER_IP,500); //IP地址? if (ret == WIFI8266_EOK) { return WIFI8266_EOK; } else { return WIFI8266_ERROR; } }
主函数,作为线程,演示功能(PC机WIFI链接模块AP,在PC机上设置TCP Client并发数据给在模块上的TCP server)
/* USER CODE END Header */ /* Includes ------------------------------------------------------------------*/ #include "main.h" #include "usart.h" #include "gpio.h" #include <rtthread.h> #include <wifi_8266_app.h> #include "wifi_8266_rtth.h" #include <string.h> #include <stdio.h> #include <stdlib.h> //字符串和数值间转换 /* Private includes ----------------------------------------------------------*/ /* USER CODE BEGIN Includes */ /* USER CODE END Includes */ /* Private typedef -----------------------------------------------------------*/ /* USER CODE BEGIN PTD */ /* USER CODE END PTD */ /* Private define ------------------------------------------------------------*/ /* USER CODE BEGIN PD */ /* USER CODE END PD */ /* Private macro -------------------------------------------------------------*/ /* USER CODE BEGIN PM */ /* USER CODE END PM */ /* Private variables ---------------------------------------------------------*/ /* USER CODE BEGIN PV */ /* USER CODE END PV */ /* Private function prototypes -----------------------------------------------*/ void SystemClock_Config(void); /* USER CODE BEGIN PFP */ /* USER CODE END PFP */ /* Private user code ---------------------------------------------------------*/ /* USER CODE BEGIN 0 */ /* USER CODE END 0 */ /** * @brief The application entry point. * @retval int */ uint8_t count; int main(void) { /* USER CODE BEGIN 1 */ /* USER CODE END 1 */ /* MCU Configuration--------------------------------------------------------*/ /* Reset of all peripherals, Initializes the Flash interface and the Systick. */ HAL_Init(); /* USER CODE BEGIN Init */ /* USER CODE END Init */ /* Configure the system clock */ SystemClock_Config(); /* USER CODE BEGIN SysInit */ /* USER CODE END SysInit */ /* Initialize all configured peripherals */ MX_GPIO_Init(); MX_USART1_UART_Init(); MX_USART2_UART_Init(); /* USER CODE BEGIN 2 */ wifi_tcpserver_rtthread_Init(); // 启动 wifi线程 /* USER CODE END 2 */ /* Infinite loop */ /* USER CODE BEGIN WHILE */ count =0; //wifi8266_at_test(); while (1) { count++; /* USER CODE END WHILE */ /* USER CODE BEGIN 3 */ } /* USER CODE END 3 */ }
特殊:需要修改 线程 堆栈 要足够大,例如512bytes。WIFI线程需要较大的RAM作为线程堆栈。否者出现奇怪的内核错误。

(USB转串口模块RX 接WIFI模块发送TX端,PC机开始TCP Client端)
注意事项:
1、注意RT-thread 线程堆栈THREAD_STACK_SIZE大小,因为通信时使用较多数组作为缓存器,使用较多RAM。分配过小,导致RT-thread内核程序错误。
2、注意AT指令使用顺序,重启动使得设置生效。
3、考虑AT指令,STM32下达命令帧到接收应答帧有时间间隔,这里使用USART接收RX中断服务过程中发送rtth内核信号量方式解决。

浙公网安备 33010602011771号