飞书文档https://x509p6c8to.feishu.cn/wiki/WFmqwImDViDUezkF7ercZuNDnve
**一、**WiFi 模组应用

当设备需要连接网络,实现远程控制,状态监控时,就需要添加通信模组,常见的通信模组WiFi模组、2G模组、4G模组等:
|----------------------------------------------------------------------------|----------------------------------------------------------------------------|----------------------------------------------------------------------------|
| |
|
|
我们的板卡上没有直接用现成的模组,而是直接把WiFi芯片设计到板卡上:
|----------------------------------------------------------------------------|----------------------------------------------------------------------------|
| |
|
所以,我们就可以基于这个芯片尝试做联网的应用。

因为我们用的是原厂芯片的方案,所以WiFi芯片内是没有程序的,我们需要先到官方下载WiFi的固件进行烧录,烧录成功后,才能用串口驱动WiFi芯片。
**二、**WiFi 模组固件烧录
AT 指令是什么?
ESP-AT 是乐鑫开发的可直接用于量产的物联网应用固件,旨在降低客户开发成本,快速形成产品。通过 ESP-AT 指令,您可以快速加入无线网络、连接云平台、实现数据通信以及远程控制等功能,真正的通过无线通讯实现万物互联。
固件下载
官方AT固件下载(ESP8266是乐鑫的方案)
安信可固件下载(安信可是ESP8266模组厂商)
https://docs.ai-thinker.com/固件汇总

建议直接下载下方固件即可:参考飞书文档
烧录接线
下载AT指令固件到本地后,我们需要先按下方接好线,DC电源头供电,核心板不接,然后只接TX RX GND
部分小伙伴出现电脑USB供电不足导致烧录失败或乱码、无应答问题,可以尝试独立供电,如下图:
- 1、拆除STM32核心板,因为STM32的TX RX和WiFi的共用,避免有数据干扰。
- 2、USB转TTL模块只需要接TXD、RXD、GND到板卡,注意3V3不需要接
- 3、接上电源适配器,按复位按键即可进入烧录(注意烧录模式短接MODE的插针,运行模式断开)

注意,如果使用外部DC头供电,下方的3.3V红色线就不需要接了。

如果接线正常,我们可以在电脑的设备管理器中,可以看到新出现的COM口,每台电脑不一样,可以查看下自己电脑的COM口,下方烧录需要用到。

烧录软件使用
需要使用乐鑫提供的flash_download_tool工具进行固件烧录,下载链接如下。
https://www.espressif.com.cn/zh-hans/support/download/other-tools
[flash_download_tool_3.9.2_0.zip]

下载后直接解压即用,运行烧录工具中的.exe文件,选择型号,选择ESP8266

打开烧录软件,
|------------------------------------------------------------------------------------------------------------------------------------------------------|
| 从"..."选择要烧录的bin文件: xxxESP8266-AT_MQTT-xM.bin,上面下载的固件。 填写烧录地址"0x0",然后勾选固件前面的√,很重要; SPI MODE选择 "DOUT"; "DoNotChgBin"不变; "COM" 选择你电脑的COM口; 波特率默认即可。 |

上述配置完成后, 点击下方START开始烧录,若一直停在等待上电同步,可以点击板卡的RES按钮,就可以开始下载了,下载一般20s左右,如果1S内完成的,一般是上面没勾选,如果长时间没下载完,一般是线有问题,可以换杜邦线重新接稳。
|----------------------------------------------------------------------------|----------------------------------------------------------------------------|
| |
|
下载完成后,拔掉J10的IO0的杜邦线,从下载模式切换到运行模式,打开串口助手,设置波特率115200 8 N 1,按RES按钮,就可以看到设备启动数据,注意
需要接上电源 & 打开开关,能看到如下打印

到这里,模组烧录就已经完成啦
注意:
部分小伙伴出现电脑USB供电不足导致烧录失败或乱码问题,可以尝试独立供电,如下图:
- 1、拆除STM32核心板,因为STM32的TX RX和WiFi的共用,避免有数据干扰。
- 2、USB转TTL模块只需要接TXD、RXD、GND到板卡,注意3V3不需要接
- 3、接上电源适配器,按复位按键即可进入烧录(注意烧录模式短接MODE的插针,运行模式断开)
|----------------------------------------------------------------------------|----------------------------------------------------------------------------|
| |
|
三、阿里云物联网云平台
我们WiFi准备好后,
还需要有个路由器,方便WiFi模组连接外网,也可以开手机热点。
最后,还需要有个云服务器做远程控制,或者上报设备状态。

云服务器厂家有很多
阿里云物联网
腾讯物联网
中移动物联网
机智云等等
注意:
由于近期阿里云暂停个人账号开通物联网平台,为了方便大家做实验,这里开放几个测试账号给大家使用
阿里云物联网共享账号 目前只提供购买板卡小伙伴学习使用,可以从旺旺给你发送的资料链接中获取密码。
共享账号已经创建了产品,大家可以拷贝创建好的设备的MQTT连接参数直接使用,然后直接查看第四章。
课程使用阿里云物联网平台,需要我们注册登录下,下方是步骤

点击管理控制台

如果提示未开通,点击开通即可,测试使用是免费的。

选择公共实例,然后鼠标点击"公共实例"进入。

如果尚未开通,需要先进行开通,开通时间一般5min内

创建一个新的产品。

填写产品名称 、所属品类等必要信息,并完成产品创建步骤。
这里我们选择创建一个温湿度检测产品,产品将会影响到后续的通信协议字段。

在创建完成的产品页面上,点击添加设备。


输入设备名称并确认。

至此,阿里云物联网平台创建设备完成。进入设备详情页,查看MQTT连接参数,并进行保存。


至此,平台部分配置完成,
这些参数将用于在ESP-01S / ESP8266上配置AT指令,实现设备与物联网平台之间的通信。
|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| {"clientId":"k0rqhbzuJeE.device1|securemode=2,signmethod=hmacsha256,timestamp=1705652029669|","username":"device1&k0rqhbzuJeE","mqttHostUrl":"iot-06z00dcx1hvlwd3.mqtt.iothub.aliyuncs.com","passwd":"f3c17488453a737afd24edefdd4ec6862848a0ca2f8866b7015f5787b90e68a2","port":1883} |
四、配置WiFi模组连接云平台
连接阿里云服务器
阿里云使用MQTT协议
|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| MQTT(Message Queuing Telemetry Transport,消息队列遥测传输协议),是一种基于发布/订阅(publish/subscribe)模式的"轻量级"通讯协议,该协议构建于TCP/IP协议上,由IBM在1999年发布。 MQTT最大优点在于,用极少的代码和有限的带宽,为连接远程设备提供实时可靠的消息服务。 作为一种低开销、低带宽占用的即时通讯协议,使其在物联网、小型设备、移动应用等方面有较广泛的应用。 MQTT 与 HTTP 一样,MQTT 运行在传输控制协议/互联网协议 (TCP/IP) 堆栈之上。 |

|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| wifi连接服务器用哪种协议? TCP:比较原始,需要自己扩展的功能较多,开发效率低 HTTP:比较重,网页端的协议,占用的带宽较大。 MQTT:适用于物联网设备和传感器等低带宽、不稳定网络环境下的通信。 MQTT 的特性 -协议心跳包仅两个字节 -协议支持QoS(服务质量)设置,可以确保消息传输的可靠性。 QoS 0:最多一次传输。消息发布者只发送一次消息,不考虑它是否被接收。这种传输方式是最快的,但也是最不可靠的,因为消息可能会丢失。 QoS 1:至少一次传输。消息发布者会发送消息并等待确认,如果确认未收到,则会重发消息。这种传输方式可以保证消息最少被传输一次,但可能会重复传输。 QoS 2:恰好一次传输。消息发布者会发送消息并等待确认,如果确认未收到,则会重发消息。接收者会对消息进行去重和重复检查,以确保消息只被传输一次。这种传输方式是最可靠的,但也是最慢的。 -协议支持发布/订阅模式,可以根据应用场景选择不同的模式。 -可扩展设备影子模式 |

我们模组固件是支持MQTT的,我们可以使用串口AT配置模组连接云平台
这里用安信可官方提供的串口助手,调试更加便捷:参考飞书文档

AT指令如下:
|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 连接阿里云AT指令介绍 AT+CWMODE=3 设置ESP模块为Station+SoftAP模式; AT+CWJAP="SSID","PWD" 设置ESP模块连接无线网络 *注意双引号为英文; AT+MQTTUSERCFG=0,1,"NULL","username","password",0,0,"" MQTT用户属性,username和passwd与下图对应 AT+MQTTCLIENTID=0,"clientId" 设置MQTT 的clientId参数;clientId也与下图对应 AT+MQTTCONN=0,"host",1883,1 连接 MQTT Broker;host与下图mqttHostUrl对应。 AT+MQTTCLEAN 断开MQTT连接。 AT+RST 复位ESP-01S / ESP8266模块; 需要注意AT+MQTTCLIENTID指令中的clientId中的逗号前需要加\符号进行转义, 假设clientId为"xxx|securemode=2,signmethod=hmacsha256,timestamp=xxx|", 那么AT指令应为AT+MQTTCLIENTID=0,"xxx|securemode=2\,signmethod=hmacsha256\,timestamp=xxx|" 下方是我账号的设备信息,可以参考下,替换为自己平台的信息: AT+CWMODE=3 AT+CWJAP="leo","123456789" AT+MQTTUSERCFG=0,1,"NULL","device1&kxxxxxxJeE","f3c17488453a7xxxxxxx015f5787b90e68a2",0,0,"" AT+MQTTCLIENTID=0,"k0rqhxxxxeE.device1|securemode=2\,signmethod=hmacsha256\,timestamp=1705652029669|" AT+MQTTCONN=0,"iot-06z0xxxxxxlwd3.mqtt.iothub.aliyuncs.com",1883,1 更多AT指令可以参考官方文档 https://docs.espressif.com/projects/esp-at/en/release-v2.2.0.0_esp8266/Get_Started/index.html |

发送完以上指令后,在阿里云物联网平台中刷新设备网页,你将会看到设备已成功上线的信息。

状态上报**-** 发布
回到平台的产品界面,点击Topic类列表,点击物模型通信,可以看到你自己的状态上报Topic
/sys/xxxx/${deviceName}/thing/event/property/post

然后看下我们这个产品的功能定义中,有哪些需要上报的字段

这里,我们使用当前温度为例,记录标识符CurrentTemperature,当然,我们也可以点击"编辑"添加、删除、修改功能模块。
拿到标识符后,我们就可以通过下方MQTT指令上报状态

|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| C AT+MQTTPUB=0,"topic字段","data字段",1,0 通过 topic 发布 MQTT消息 特别注意,空格,英文符号 注意,topic中的deviceName改为你创建的设备名称: AT+MQTTPUB=0,"/sys/k0rqhbzuJeE/device1/thing/event/property/post","{\"params\":{\"CurrentTemperature\":33}}",1,0 |
然后,我们就可以在设备界面看到上报的温度数据啦:

控制接收**-** 订阅
回到平台的产品界面,点击Topic类列表,点击物模型通信,可以看到你自己的设备设置的Topic
/sys/k0rqhbzuJeE/${deviceName}/thing/service/property/set

然后通过串口调试助手订阅主题

|----------------------------------------------------------------------------------------------------------------------------|
| AT+MQTTSUB=0,"topic字段",1 订阅指定 MQTT topic 特别注意,空格,英文符号 AT+MQTTSUB=0,"/sys/k0rqhbzuJeE/device1/thing/service/property/set",1 |
然后我们可以增加一个开关控制字段

我们随便添加一个支持读写的属性,也可以自己自定义


记得点击发布上线

发布成功后,我们可以模拟手机端操作这个字段,发送控制指令给模组。

修改对应属性,点击设置

然后我们就可以在串口调试助手看到接收的指令

**五、**STM32 驱动 WiFi 模组
前面我们都是使用串口助手发送指令驱动WiFi模组的,那接下来,我们就可以用STM32替换串口助手驱动WiFi模组啦。
开始这个章节时,可以把下方USB转串口部分拔掉。

这部分的原理图是这样的,因为模组使用串口通信,所以我们只需要关注PC10和PC11的USART3。


创建工程,打开UART4

同时,开启串口中断

配置DMA

调整 DMA 初始化顺序 ( 重要 )

为了更直观看到设备运行状态,打开USART1作为日志口。

生成工程,然后参考串口章节,添加日志打印重定向

main.c
/* USER CODE BEGIN Includes */
#include <stdio.h>
/* USER CODE END Includes */
/* USER CODE BEGIN 2 */
printf("app init\n");
/* USER CODE END 2 */
/* USER CODE BEGIN 4 */
int fputc(int ch, FILE *f)
{
HAL_UART_Transmit(&huart1 , (uint8_t *)&ch, 1, 0xFFFF);
return ch;
}
添加最简单的AT指令发送和接收判断,通过串口中断+DMA不定长接收
main.c
/* USER CODE BEGIN Includes */
#include <stdio.h>
#include <stdbool.h>
#include <string.h>
/* USER CODE END Includes */
/* USER CODE BEGIN 0 */
#define AT "AT\r\n"
#define ACK_OK "OK"
#define BUFFER_SIZE 256
uint8_t rx_buf[BUFFER_SIZE]; //应用处理buffer
bool rx_status = false;
extern DMA_HandleTypeDef hdma_uart4_rx;
uint8_t dma_rxbuf[BUFFER_SIZE]; //DMA接收buffer
static void init(void);
/* USER CODE END 0 */
/* USER CODE BEGIN 2 */
printf("app init\n");
__HAL_UART_ENABLE_IT(&huart4,UART_IT_IDLE);
HAL_UART_Receive_DMA(&huart4,dma_rxbuf,sizeof(dma_rxbuf));
init();
/* USER CODE END 2 */
/* USER CODE BEGIN 4 */
void copy_to_rx_buf(uint8_t *ack,uint8_t len){
if(rx_status)
return;
if(len > sizeof(rx_buf))
return;
memcpy(rx_buf,ack,len);
rx_status = true;
}
bool send_cmd(uint8_t *cmd,uint8_t *ack){
int time_out = 500;
memset(rx_buf,0,sizeof(rx_buf));
printf("send ----> %s\n",cmd);
HAL_UART_Transmit_DMA(&huart4 , (uint8_t *)cmd, strlen((const char *)cmd));
while (time_out --)
{
if(rx_status){
printf("read ----> %s\n",rx_buf);
if(strstr((const char*)rx_buf,(const char*) ack) != NULL){
printf("ack ok\n");
rx_status = false;
return true;
}
memset(rx_buf,0,sizeof(rx_buf));
rx_status = false;
}
HAL_Delay(10);
}
printf("ack fail\n");
return false;
}
void init(){
send_cmd((uint8_t *)AT,(uint8_t *)ACK_OK);
HAL_Delay(500);
}
void UART_IDLEHandler(){
if(__HAL_UART_GET_FLAG(&huart4, UART_FLAG_IDLE) == SET) //如果串口处于空闲状态
{
__HAL_UART_CLEAR_FLAG(&huart4, UART_FLAG_IDLE);//清空空闲状态标志
HAL_UART_DMAStop(&huart4); //关闭DMA传输
//计算接收到的数据长度 ,已接收长度=需要接收总长度-剩余待接收长度
uint8_t rlen = BUFFER_SIZE - __HAL_DMA_GET_COUNTER(&hdma_uart4_rx);
//进行数据处理
copy_to_rx_buf(dma_rxbuf,rlen);
//重新打开DMA接收
HAL_UART_Receive_DMA(&huart4,dma_rxbuf,sizeof(dma_rxbuf));
}
}
int fputc(int ch, FILE *f)
{
HAL_UART_Transmit(&huart1 , (uint8_t *)&ch, 1, 0xFFFF);
return ch;
}
/* USER CODE END 4 */
mian.h
/* USER CODE BEGIN EFP */
void UART_IDLEHandler(void);
/* USER CODE END EFP */
stm32f1xx_it.c
void UART4_IRQHandler(void)
{
/* USER CODE BEGIN UART4_IRQn 0 */
/* USER CODE END UART4_IRQn 0 */
HAL_UART_IRQHandler(&huart4);
/* USER CODE BEGIN UART4_IRQn 1 */
UART_IDLEHandler();
/* USER CODE END UART4_IRQn 1 */
}
烧录运行:

工程参考飞书文档
然后我们可以所有初始化AT指令全部加上,并且发布和订阅对应消息,最终实现温度上报和控制指令接收的功能。
最终版本的main.c如下
/* USER CODE BEGIN Header */
/**
******************************************************************************
* @file : main.c
* @brief : Main program body
******************************************************************************
* @attention
*
* Copyright (c) 2024 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "dma.h"
#include "usart.h"
#include "gpio.h"
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include <stdio.h>
#include <stdbool.h>
#include <string.h>
/* 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 */
#define AT "AT\r\n"
#define AT_WIFI_MODE "AT+CWMODE=3\r\n"
#define AT_SET_PSW "AT+CWJAP=\"Kang\",\"555883200\"\r\n"
#define AT_SET_MQTT_CFG "AT+MQTTUSERCFG=0,1,\"NULL\",\"device1&k0rqhbzuJeE\",\"f3c17488453a737afd24edefdd4ec6862848a0ca2f8866b7015f5787b90e68a2\",0,0,\"\"\r\n"
#define AT_SET_MQTT_CLENTID "AT+MQTTCLIENTID=0,\"k0rqhbzuJeE.device1|securemode=2\\,signmethod=hmacsha256\\,timestamp=1705652029669|\"\r\n"
#define AT_SET_MQTT_CONN "AT+MQTTCONN=0,\"iot-06z00dcx1hvlwd3.mqtt.iothub.aliyuncs.com\",1883,1\r\n"
#define AT_MQTT_SUB "AT+MQTTSUB=0,\"/sys/k0rqhbzuJeE/device1/thing/service/property/set\",1\r\n"
#define AT_MQTT_PUB "AT+MQTTPUB=0,\"/sys/k0rqhbzuJeE/device1/thing/event/property/post\",\"{\\\"params\\\":{\\\"CurrentTemperature\\\":%d}}\",1,0\r\n"
#define ACK_OK "OK"
#define BUFFER_SIZE 256
uint8_t rx_buf[BUFFER_SIZE]; //应用处理buffer
uint8_t tx_buf[BUFFER_SIZE]; //发送buffer
bool rx_status = false;
extern DMA_HandleTypeDef hdma_uart4_rx;
uint8_t dma_rxbuf[BUFFER_SIZE]; //DMA接收buffer
static void init(void);
static bool send_cmd(uint8_t *cmd,uint8_t *ack);
static void read_cmd(void);
/* USER CODE END 0 */
/**
* @brief The application entry point.
* @retval int
*/
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_DMA_Init();
MX_USART1_UART_Init();
MX_UART4_Init();
/* USER CODE BEGIN 2 */
printf("app init\n");
__HAL_UART_ENABLE_IT(&huart4,UART_IT_IDLE);
HAL_UART_Receive_DMA(&huart4,dma_rxbuf,sizeof(dma_rxbuf));
init();
printf("wifi init finish\n");
uint8_t temperature = 20;
uint8_t send_count = 0;
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
send_count ++;
if(send_count >= 10){
//10s上报一条
send_count = 0;
sprintf((char *)tx_buf,"AT+MQTTPUB=0,\"/sys/k0rqhbzuJeE/device1/thing/event/property/post\",\"{\\\"params\\\":{\\\"CurrentTemperature\\\":%d}}\",1,0\r\n", temperature);
send_cmd(tx_buf,(uint8_t *)ACK_OK);
temperature ++;
if(temperature > 100)
temperature = 20;
}
read_cmd();
HAL_Delay(1000);
}
/* USER CODE END 3 */
}
/**
* @brief System Clock Configuration
* @retval None
*/
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
/** Initializes the RCC Oscillators according to the specified parameters
* in the RCC_OscInitTypeDef structure.
*/
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;
RCC_OscInitStruct.HSIState = RCC_HSI_ON;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
Error_Handler();
}
/** Initializes the CPU, AHB and APB buses clocks
*/
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
{
Error_Handler();
}
}
/* USER CODE BEGIN 4 */
void copy_to_rx_buf(uint8_t *ack,uint8_t len){
if(rx_status)
return;
if(len > sizeof(rx_buf))
return;
memcpy(rx_buf,ack,len);
rx_status = true;
}
bool send_cmd(uint8_t *cmd,uint8_t *ack){
int time_out = 500;
memset(rx_buf,0,sizeof(rx_buf));
printf("send ----> %s\n",cmd);
HAL_UART_Transmit_DMA(&huart4 , (uint8_t *)cmd, strlen((const char *)cmd));
while (time_out --)
{
if(rx_status){
printf("read ----> %s\n",rx_buf);
if(strstr((const char*)rx_buf,(const char*) ack) != NULL){
printf("ack ok\n");
rx_status = false;
return true;
}
memset(rx_buf,0,sizeof(rx_buf));
rx_status = false;
}
HAL_Delay(10);
}
printf("ack fail\n");
return false;
}
void read_cmd(){
if(rx_status){
printf("read ----> %s\n",rx_buf);
rx_status = false;
}
}
void init(){
send_cmd((uint8_t *)AT,(uint8_t *)ACK_OK);
HAL_Delay(500);
send_cmd((uint8_t *)AT_WIFI_MODE,(uint8_t *)ACK_OK);
HAL_Delay(500);
send_cmd((uint8_t *)AT_SET_PSW,(uint8_t *)ACK_OK);
HAL_Delay(500);
send_cmd((uint8_t *)AT_SET_MQTT_CFG,(uint8_t *)ACK_OK);
HAL_Delay(500);
send_cmd((uint8_t *)AT_SET_MQTT_CLENTID,(uint8_t *)ACK_OK);
HAL_Delay(500);
send_cmd((uint8_t *)AT_SET_MQTT_CONN,(uint8_t *)ACK_OK);
HAL_Delay(500);
send_cmd((uint8_t *)AT_MQTT_SUB,(uint8_t *)ACK_OK);
HAL_Delay(500);
}
void UART_IDLEHandler(){
if(__HAL_UART_GET_FLAG(&huart4, UART_FLAG_IDLE) == SET) //如果串口处于空闲状态
{
__HAL_UART_CLEAR_FLAG(&huart4, UART_FLAG_IDLE);//清空空闲状态标志
HAL_UART_DMAStop(&huart4); //关闭DMA传输
//计算接收到的数据长度 ,已接收长度=需要接收总长度-剩余待接收长度
uint8_t rlen = BUFFER_SIZE - __HAL_DMA_GET_COUNTER(&hdma_uart4_rx);
//进行数据处理
copy_to_rx_buf(dma_rxbuf,rlen);
//重新打开DMA接收
HAL_UART_Receive_DMA(&huart4,dma_rxbuf,sizeof(dma_rxbuf));
}
}
int fputc(int ch, FILE *f)
{
HAL_UART_Transmit(&huart1 , (uint8_t *)&ch, 1, 0xFFFF);
return ch;
}
/* USER CODE END 4 */
/**
* @brief This function is executed in case of error occurrence.
* @retval None
*/
void Error_Handler(void)
{
/* USER CODE BEGIN Error_Handler_Debug */
/* User can add his own implementation to report the HAL error return state */
__disable_irq();
while (1)
{
}
/* USER CODE END Error_Handler_Debug */
}
#ifdef USE_FULL_ASSERT
/**
* @brief Reports the name of the source file and the source line number
* where the assert_param error has occurred.
* @param file: pointer to the source file name
* @param line: assert_param error line source number
* @retval None
*/
void assert_failed(uint8_t *file, uint32_t line)
{
/* USER CODE BEGIN 6 */
/* User can add his own implementation to report the file name and line number,
ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
/* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */
设备连接平台成功后,每间隔10s上报一次温度数据


在云平台设置灯开关,设备也会收到消息


工程参考:飞书文档
上面的工程仅仅使用数据复制的方式进行拷贝处理,当交互频繁时,可能会出现丢失指令的情况,下方的工程使用环形缓冲区,可以避免指令丢失情况。
参考飞书文档
手机APP开发参考