STM32F103C8T6 BC20模块NBIOT GPS北斗模块采集温湿度和经纬度发送到EMQX

发布于:2025-08-05 ⋅ 阅读:(17) ⋅ 点赞:(0)

云平台配置

访问下载页面:免费试用 EMQX Cloud 或 EMQX Enterprise | 下载 EMQX,根据需求选择对应版本下载。将下载的压缩包上传至服务器(推荐存放于C盘根目录,便于后续操作),并解压至指定路径(例如:C:\emqx)。按住Win+R键,输入cmd后按回车,打开Windows命令行界面。

输入cd C:\emqx\bin(若解压路径不同,请替换为实际路径),按回车进入bin文件夹。

输入emqx start,按回车执行启动命令。

打开浏览器,输入服务器公网 IP 及管理端口:http://公网IP:18083

登录系统:默认用户名:admin默认密码:public

部署在公网服务器后,可通过任意设备访问该 IP 地址,实现远程管理。

设备接线

GPS的天线要放室外。

实物接线

代码

main.c

#include "stm32f10x.h"  
#include "string.h"  
#include "stdio.h" 
#include "delay.h"   
#include "bsp_usart.h"
#include "oled.h"
#include "BC20.h"
#include "bsp_dht11.h"

GPS_Data gps_data = {0};  
float temp,humi;
extern BC20_Status s_bc20_status;
int count=0;
char OLEDBuff[512];
int main(void)
{
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
	SysTick_Init(72);  //系统时钟初始化 
	usart1_init(115200);//串口1初始化
	printf("USART1 OK!\r\n");
	usart2_init(9600);//串口2初始化(BC20模块)
	usart3_init(115200);//串口3初始化	
	OLED_Init();	
	OLED_Clear();
	BC20_Init();	
	// 连接OneNet平台,带重试机制
	int connect_retry = 3;
	while(connect_retry-- > 0) {
		if(BC20_ConnectOneNet() == BC20_OK) {
			break;
		}
		printf("OneNet连接失败,剩余重试次数: %d\r\n", connect_retry);
		delay_ms(2000);
	}
	if(connect_retry <= 0) {
		printf("OneNet连接失败,系统将重启...\r\n");
		delay_ms(2000);
		NVIC_SystemReset();
	}
	DHT11_Init();				//DHT11温湿度传感器初始化
	OLED_ShowString(40,0,"BC20");
	OLED_ShowString(0, 2, "温度:   湿度:   "); 
	OLED_ShowString(0,4,"经度"); 
	OLED_ShowString(0,6,"纬度"); 
	while(1)
	{
			BC20_ProcessReceivedData();

			// 读取温湿度
			if(DHT11_Read_TempAndHumidity(&DHT11_Data) == SUCCESS) {
					temp = DHT11_Data.temp_int + DHT11_Data.temp_deci * 0.1;
					humi = DHT11_Data.humi_int + DHT11_Data.humi_deci * 0.1;
					OLED_ShowNum(40, 2, (int)temp, 2, 16);
					OLED_ShowNum(100, 2, (int)humi, 3, 16);
			} else {
					printf("DHT11读取失败\r\n");
			}
			// 定时发送数据
			count++;
			if(count >= 40) {  // 40 * 50ms = 2秒
					printf("温度: %.1f  湿度: %.1f\r\n", temp, humi);
					count = 0;
					// 获取GPS数据(增加超时限制,避免长时间阻塞)
					static uint32_t gps_retry = 0;
					uint32_t gps_start = 0;  
				  gps_start++;
					if(BC20_GetGPSData(&gps_data) != BC20_OK) 
					{
							gps_retry++;
							printf("GPS数据获取失败,重试次数: %d\r\n", gps_retry);
							if(gps_retry >= 5) {
									BC20_InitGPS();
									gps_retry = 0;
							}
					} else {
							gps_retry = 0;
						  sprintf(OLEDBuff,"%.6f",gps_data.latitude);
						  OLED_ShowString(40,4,OLEDBuff);
						  sprintf(OLEDBuff,"%.6f",gps_data.longitude);
						  OLED_ShowString(40,6,OLEDBuff);
					}
					BC20_SendToOneNet(temp, humi, &gps_data);
			}
			delay_ms(50);
	}
}


bc20.c

#include "BC20.h"
#include "stm32f10x_iwdg.h"
#include "oled.h"
#include "bsp_usart.h"
#include "delay.h"
#include <math.h>

// 静态内部变量
static char s_recv_buf[BC20_BUF_LEN];     // 接收缓冲区
BC20_Status s_bc20_status = {0};          // 模块状态

// 私有函数声明
void BC20_ClearRecvBuf(void);
static BC20_ErrorCode BC20_SendAT(const char *cmd, const char *expected_resp, uint32_t timeout_ms);
static BC20_ErrorCode BC20_SendAT_NOOLED(const char *cmd, const char *expected_resp, uint32_t timeout_ms);
BC20_ErrorCode BC20_InitGPS(void);
static BC20_ErrorCode BC20_ParseGPRMC(const char *rmc_str, GPS_Data *gps);

// 清空接收缓冲区
void BC20_ClearRecvBuf(void) 
{
    memset(s_recv_buf, 0, BC20_BUF_LEN);
    Clear_Buffer_UART2();  // 确保串口2缓冲区也被清空
    delay_ms(50);  // 缩短延迟,避免阻塞
}

// OLED显示AT指令(辅助函数)
void OLED_ShowAT(char* cmd)
{
    char cmd_display[32] = {0};
    if (strncmp(cmd, "AT", 2) == 0) {
        const char *after_at_plus = cmd + 0;
        const char *q_pos = strchr(after_at_plus, '=');
        if (q_pos != NULL) {
            size_t len = q_pos - after_at_plus;
            if (len > 0) {
                strncpy(cmd_display, after_at_plus, len);
                cmd_display[len] = '\0';
            } else {
                strcpy(cmd_display, "+");
            }
        } else {
            strncpy(cmd_display, after_at_plus, sizeof(cmd_display)-1);
            char *newline = strchr(cmd_display, '\r');
            if (newline) *newline = '\0';
            newline = strchr(cmd_display, '\n');
            if (newline) *newline = '\0';
        }
    } else {
        strncpy(cmd_display, cmd, sizeof(cmd_display)-1);
    }
    OLED_Clear();
    OLED_ShowString(0,2,cmd_display);
}

// 发送AT命令(带OLED显示)
static BC20_ErrorCode BC20_SendAT(const char *cmd, const char *expected_resp, uint32_t timeout_ms) {
    uint32_t count = 0;
    uint32_t max_count = timeout_ms / 10;
    if (timeout_ms % 10 != 0) max_count++;
    
    BC20_ClearRecvBuf();
    
    printf("\r\n【发送AT指令】: %s", cmd);
    USART2_SendStr((char*)cmd);
    OLED_ShowAT((char*)cmd);
    
    while (count < max_count) {
        if (buf_uart2.rx_flag) {
            strncpy(s_recv_buf, buf_uart2.buf, BC20_BUF_LEN-1);
            s_recv_buf[BC20_BUF_LEN-1] = '\0';
            printf("【接收响应】: %s", s_recv_buf);
            
            if (strstr(s_recv_buf, expected_resp) != NULL) {c
                printf("【指令执行成功】\r\n");
                return BC20_OK;
            }
            buf_uart2.rx_flag = 0;
        }
        delay_ms(10);
        count++;
    }
    printf("【指令超时】- 预期响应: %s, 实际接收: %s\r\n", expected_resp, s_recv_buf);
    return BC20_ERR_TIMEOUT;
}

// 发送AT命令(不带OLED显示)- 关键修复:移除成功时的缓冲区清空
static BC20_ErrorCode BC20_SendAT_NOOLED(const char *cmd, const char *expected_resp, uint32_t timeout_ms) {
    uint32_t count = 0;
    uint32_t max_count = timeout_ms / 10;
    if (timeout_ms % 10 != 0) max_count++;
    
    BC20_ClearRecvBuf();
    
    printf("\r\n【发送AT指令】: %s", cmd);
    USART2_SendStr((char*)cmd);
    
    while (count < max_count) {
        if (buf_uart2.rx_flag) {
            strncpy(s_recv_buf, buf_uart2.buf, BC20_BUF_LEN-1);
            s_recv_buf[BC20_BUF_LEN-1] = '\0';
            printf("【接收响应】: %s", s_recv_buf);
            
            if (strstr(s_recv_buf, expected_resp) != NULL) {
                // 关键修复:不在此处清空缓冲区,保留数据供后续解析
                printf("【指令执行成功】\r\n");
                return BC20_OK;
            }
            buf_uart2.rx_flag = 0;
        }
        delay_ms(10);
        count++;
    }
    printf("【指令超时】- 预期响应: %s, 实际接收: %s\r\n", expected_resp, s_recv_buf);
    return BC20_ERR_TIMEOUT;
}

// BC20模块初始化
void BC20_Init(void) {
    BC20_ErrorCode ret;
    BC20_ClearRecvBuf();
    
    printf("\r\n====================================\r\n");
    printf("【开始初始化BC20模块】\r\n");
    
    // 检查模块响应
    printf("【步骤1/5】检查模块响应...\r\n");
    ret = BC20_SendAT("ATi\r\n", "OK", 3000);
    if (ret != BC20_OK) {
        s_bc20_status.err_code = BC20_ERR_RESPONSE;
        printf("【错误】模块无响应\r\n");
        return;
    }
    // 关闭回显
    ret = BC20_SendAT("ATE0\r\n", "OK", 3000);
    if (ret != BC20_OK) {
        s_bc20_status.err_code = BC20_ERR_RESPONSE;
        printf("【错误】关闭回显失败\r\n");
        return;
    }

    // 检查SIM卡
    printf("【步骤2/5】检查SIM卡...\r\n");
    ret = BC20_SendAT("AT+CIMI\r\n", "OK", 3000);
    if (ret != BC20_OK) {
        s_bc20_status.err_code = BC20_ERR_SIM;
        printf("【错误】SIM卡异常\r\n");
        return;
    }
    printf("【SIM卡正常】IMSI: %s\r\n", s_recv_buf + 8);
    BC20_ClearRecvBuf();  // 手动清空,避免影响后续指令
    
    // 检查网络注册
    printf("【步骤3/5】检查网络注册...\r\n");
    ret = BC20_SendAT("AT+CGATT?\r\n", "+CGATT: 1", 10000);
    if (ret != BC20_OK) {
        s_bc20_status.err_code = BC20_ERR_NETWORK;
        printf("【错误】网络注册失败\r\n");
        return;
    }
    BC20_ClearRecvBuf();  // 手动清空
    
    // 检查信号质量
    printf("【步骤4/5】检查信号质量...\r\n");
    ret = BC20_SendAT("AT+CSQ\r\n", "+CSQ", 3000);
    if (ret == BC20_OK) {
        printf("【信号质量信息】: %s\r\n", s_recv_buf);
    }
    BC20_ClearRecvBuf();  // 手动清空
    
    // 初始化GPS
    printf("【步骤5/5】初始化GPS...\r\n");
    if (BC20_InitGPS() != BC20_OK) {
        printf("【警告】GPS初始化失败(不影响主功能)\r\n");
    } else {
        printf("【GPS初始化成功】\r\n");
    }
    
    s_bc20_status.err_code = BC20_OK;
    printf("【BC20模块初始化完成】\r\n");
    printf("====================================\r\n");
}

// GPS初始化
BC20_ErrorCode BC20_InitGPS(void) {
    BC20_ErrorCode ret;
    
    printf("【启动GNSS】\r\n");
    ret = BC20_SendAT_NOOLED("AT+QGNSSC=1\r\n", "", 5000);
    if (ret != BC20_OK) {
        printf("【错误】启动GNSS失败\r\n");
        return BC20_ERR_GPS;
    }
    BC20_ClearRecvBuf();  // 手动清空
    
    printf("【确认GPS启动状态】\r\n");
    ret = BC20_SendAT_NOOLED("AT+QGNSSC?\r\n", "+QGNSSC: 1", 5000);
    if (ret != BC20_OK) {
        printf("【错误】GPS未启动\r\n");
        return BC20_ERR_GPS;
    }
    BC20_ClearRecvBuf();  // 手动清空
    
    return BC20_OK;
}

// 解析GPRMC语句
static BC20_ErrorCode BC20_ParseGPRMC(const char *rmc_str, GPS_Data *gps) {
    char *token;
    char rmc_copy[BC20_BUF_LEN];
    strncpy(rmc_copy, rmc_str, BC20_BUF_LEN-1);
    rmc_copy[BC20_BUF_LEN-1] = '\0';
    
    // 分割字段(逗号分隔)
    token = strtok(rmc_copy, ",");  // $GNRMC
    if (token == NULL) return BC20_ERR_GPS;
    
    token = strtok(NULL, ",");  // 时间
    token = strtok(NULL, ",");  // 状态(A=有效,V=无效)
    if (token == NULL || strcmp(token, "A") != 0) {
        gps->is_valid = 0;
        printf("【GPS定位无效】状态位为V\r\n");
        return BC20_OK;
    }
    
    // 解析纬度(格式:ddmm.mmmm)
    token = strtok(NULL, ",");  // 纬度值
    if (token == NULL || strlen(token) < 5) {  // 增加长度检查
        printf("【错误】纬度数据无效\r\n");
        return BC20_ERR_GPS;
    }
    float lat_deg = atof(token) / 100;  // dd + mm.mmmm/100
    int deg = (int)lat_deg;
    gps->latitude = deg + (lat_deg - deg) * 100 / 60;
    
    token = strtok(NULL, ",");  // N/S
    if (token != NULL && strcmp(token, "S") == 0) {
        gps->latitude = -gps->latitude;
    }
    
    // 解析经度(格式:dddmm.mmmm)
    token = strtok(NULL, ",");  // 经度值
    if (token == NULL || strlen(token) < 6) {  // 增加长度检查
        printf("【错误】经度数据无效\r\n");
        return BC20_ERR_GPS;
    }
    float lon_deg = atof(token) / 100;  // ddd + mm.mmmm/100
    deg = (int)lon_deg;
    gps->longitude = deg + (lon_deg - deg) * 100 / 60;
    
    token = strtok(NULL, ",");  // E/W
    if (token != NULL && strcmp(token, "W") == 0) {
        gps->longitude = -gps->longitude;
    }
    
    gps->is_valid = 1;
    printf("【GPS定位有效】纬度: %.6f, 经度: %.6f\r\n", gps->latitude, gps->longitude);
    return BC20_OK;
}

// 获取GPS数据 - 修复缓冲区处理
BC20_ErrorCode BC20_GetGPSData(GPS_Data *gps) {
    BC20_ErrorCode ret;
    char *rmc_ptr;
    char *end_ptr;
    
    if(gps == NULL) {
        printf("【错误】GPS数据指针为空\r\n");
        return BC20_ERR_GPS;
    }
    
    // 初始化GPS数据结构
    memset(gps, 0, sizeof(GPS_Data));
    gps->is_valid = 0;
    
    printf("\r\n【获取GPS数据】\r\n");
    // 发送指令获取RMC数据,超时设为5秒
    ret = BC20_SendAT_NOOLED("AT+QGNSSRD=\"NMEA/RMC\"\r\n", "$GNRMC", 5000);
    if (ret != BC20_OK) {
        printf("【错误】获取GPS数据超时\r\n");
        BC20_ClearRecvBuf();  // 超时后清空
        return BC20_ERR_GPS;
    }
    
    // 提取$GNRMC语句(从缓冲区中查找)
    rmc_ptr = strstr(s_recv_buf, "$GNRMC");
    if (rmc_ptr == NULL) {
        printf("【错误】未找到GNRMC语句(缓冲区内容:%s)\r\n", s_recv_buf);
        BC20_ClearRecvBuf();  // 失败后清空
        return BC20_ERR_GPS;
    }
    
    // 截断到换行符,确保解析安全
    end_ptr = strchr(rmc_ptr, '\r');
    if (end_ptr != NULL) {
        *end_ptr = '\0';
    }
    printf("【解析GNRMC数据】: %s\r\n", rmc_ptr);
    
    // 解析RMC数据
    ret = BC20_ParseGPRMC(rmc_ptr, gps);
    if (ret != BC20_OK) {
        gps->is_valid = 0;
        printf("【错误】GNRMC数据解析失败\r\n");
    }
    
    BC20_ClearRecvBuf();  // 解析完成后手动清空缓冲区
    return ret;
}

// 连接OneNet平台
BC20_ErrorCode BC20_ConnectOneNet(void) {
    BC20_ErrorCode ret;
    char cmd[BC20_BUF_LEN];
    
    printf("\r\n====================================\r\n");
    printf("【开始连接OneNet平台】\r\n");
    
    // 断开现有连接
    printf("【断开现有连接】\r\n");
    BC20_SendAT("AT+QMTDISC=0\r\n", "OK", 3000);
    BC20_SendAT("AT+QMTCLOSE=0\r\n", "OK", 3000);
    
    // 配置MQTT版本
    printf("【配置MQTT版本为3.1.1】\r\n");
    ret = BC20_SendAT("AT+QMTCFG=\"version\",0,4\r\n", "OK", 3000);
    if (ret != BC20_OK) {
        printf("【错误】配置MQTT版本失败\r\n");
        return BC20_ERR_OneNet;
    }
    
    // 连接OneNet服务器
    printf("【连接OneNet MQTT服务器】\r\n");
    snprintf(cmd, BC20_BUF_LEN, "AT+QMTOPEN=0,\"%s\",1883\r\n", OneNet_SERVER);
    ret = BC20_SendAT(cmd, "+QMTOPEN: 0,0", 10000);
    if (ret != BC20_OK) {
        printf("【错误】连接服务器失败\r\n");
        return BC20_ERR_OneNet;
    }
    
    // 登录设备
    printf("【登录设备】\r\n");
    snprintf(cmd, BC20_BUF_LEN, "AT+QMTCONN=0,\"%s\",\"%s\",\"%s\"\r\n",
             OneNet_DEVICE_ID, OneNet_PRODUCT_ID, OneNet_TOKEN);
    ret = BC20_SendAT(cmd, "+QMTCONN: 0,0,0", 10000);
    if (ret != BC20_OK) {
        printf("【错误】设备登录失败\r\n");
        return BC20_ERR_OneNet;
    }
    
    // 订阅主题
    printf("【订阅属性设置主题】\r\n");
    snprintf(cmd, BC20_BUF_LEN, "AT+QMTSUB=0,1,\"$sys/%s/%s/thing/property/set\",2\r\n",OneNet_PRODUCT_ID,OneNet_DEVICE_ID);
    ret = BC20_SendAT(cmd, "+QMTSUB: 0,1,0,0", 5000);
    if (ret != BC20_OK) {
        printf("【错误】订阅主题失败\r\n");
        return BC20_ERR_OneNet;
    }
    
    s_bc20_status.is_connected = 1;
    printf("【OneNet平台连接成功】\r\n");
    printf("====================================\r\n");
    return BC20_OK;
}

// 发送数据到OneNet平台
BC20_ErrorCode BC20_SendToOneNet(float temp, float humi, const GPS_Data *gps) {
    BC20_ErrorCode ret;
    if (!s_bc20_status.is_connected) {
        printf("【错误】未连接到OneNet平台,无法发送数据\r\n");
        return BC20_ERR_OneNet;
    }
    
    char cmd[BC20_BUF_LEN];
    snprintf(cmd, BC20_BUF_LEN, 
             "AT+QMTPUB=0,0,0,0,\"$sys/%s/%s/thing/property/post\","
             "{\"id\":\"123\",\"version\":\"1.0\",\"params\":{"
             "\"temp\":{\"value\":%.1f},"
             "\"humi\":{\"value\":%.1f},"
             "\"map\":{\"value\":{\"Lon\":\"%.6f\",\"Lat\":\"%.6f\"}}"
             "}}\r\n",
		         OneNet_PRODUCT_ID,OneNet_DEVICE_ID,
             temp, humi, gps->longitude, gps->latitude
            );
    
    printf("\r\n【发送数据到OneNet】\r\n");
    ret = BC20_SendAT_NOOLED(cmd, "OK", 5000);
    if (ret == BC20_OK) {
        printf("【数据发送成功】\r\n");
    } else {
        printf("【数据发送失败】\r\n");
    }
    BC20_ClearRecvBuf();  // 发送完成后清空
    return ret;
}

// 处理OneNet接收的数据
void BC20_ProcessReceivedData(void) {
    if (!buf_uart2.rx_flag) {
        return;
    }
    
    // 复制接收数据到处理缓冲区
    char recv_data[BC20_BUF_LEN];
    strncpy(recv_data, buf_uart2.buf, BC20_BUF_LEN-1);
    recv_data[BC20_BUF_LEN-1] = '\0';
    
    // 清除接收标志和缓冲区
    BC20_ClearRecvBuf();
    
    // 检查是否是MQTT接收消息
    if (strstr(recv_data, "+QMTRECV:") == NULL) {
        return;
    }
    printf("\r\n【检测到OneNet下发消息】:%s\r\n", recv_data);
    
    // 解析+QMTRECV格式
    char *topic_str, *payload_str;
    char *token = strtok(recv_data, ",");  // 提取"+QMTRECV:"
    
    // 跳过客户端ID和消息ID
    strtok(NULL, ",");  // 客户端ID
    
    // 提取主题
    topic_str = strtok(NULL, ",");
    if (topic_str == NULL) {
        printf("【解析失败】无主题\r\n");
        return;
    }
    

    payload_str = strtok(NULL, "\r\n");
    if (payload_str == NULL) {
        printf("【解析失败】无消息内容\r\n");
        return;
    }
    
    // 处理payload
    printf("【消息处理】主题:%s,内容:%s\r\n", topic_str, payload_str);
}

bsp_usart.c

#include "stm32f10x.h"
#include "bsp_usart.h"	  
#include "stdio.h"
#include "string.h"
#include "stm32f10x_tim.h"


////////////////////////////////////////////////////////////////////////////////// 	

//////////////////////////////////////////////////////////////////
//加入以下代码,支持printf函数,而不需要选择use MicroLIB	  
#if 1
#pragma import(__use_no_semihosting)             
//标准库需要的支持函数                 
struct __FILE 
{ 
	int handle; 
}; 

FILE __stdout;       
//定义_sys_exit()以避免使用半主机模式    
int _sys_exit(int x) 
{ 
	x = x; 
	return 0;
} 
//重定义fputc函数 
int fputc(int ch, FILE *f)
{ 	
	while((USART1->SR&0X40)==0);//循环发送,直到发送完毕   
	USART1->DR = (u8) ch;      
	return ch;
}
#endif
 
#if EN_USART1

UART_BUF buf_uart1;     //CH340
//初始化IO 串口1 
//bound:波特率
void usart1_init(u32 bound){
   //GPIO端口设置
  GPIO_InitTypeDef GPIO_InitStructure;
	USART_InitTypeDef USART_InitStructure;
	NVIC_InitTypeDef NVIC_InitStructure;
	
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1|RCC_APB2Periph_GPIOA, ENABLE);	//使能USART1,GPIOA时钟
	USART_DeInit(USART1);  //复位串口1
 //USART1_TX   PA.9
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; //PA.9
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;	//复用推挽输出
	GPIO_Init(GPIOA, &GPIO_InitStructure); //初始化PA9
 
	//USART1_RX	  PA.10
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;//浮空输入
	GPIO_Init(GPIOA, &GPIO_InitStructure);  //初始化PA10

  //USART 初始化设置

	USART_InitStructure.USART_BaudRate = bound;//一般设置为115200;
	USART_InitStructure.USART_WordLength = USART_WordLength_8b;//字长为8位数据格式
	USART_InitStructure.USART_StopBits = USART_StopBits_1;//一个停止位
	USART_InitStructure.USART_Parity = USART_Parity_No;//无奇偶校验位
	USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//无硬件数据流控制
	USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;	//收发模式
	USART_Init(USART1, &USART_InitStructure); //初始化串口
	
	USART_Cmd(USART1, ENABLE);                    //使能串口 

	
#if EN_USART1_RX	

	USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//开启相关中断
	USART_ITConfig(USART1, USART_IT_IDLE, ENABLE);//开启相关中断
	USART_ClearFlag(USART1, USART_FLAG_TC);
	//Usart1 NVIC 配置
  NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;//串口1中断通道
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3;//抢占优先级3
	NVIC_InitStructure.NVIC_IRQChannelSubPriority =3;		//子优先级3
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;			//IRQ通道使能
	NVIC_Init(&NVIC_InitStructure);	//根据指定的参数初始化VIC寄存器、

#endif

}

/*********************************串口1的服务函数*************************************************/
void USART1_Send_byte(char data)
{
	while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);
	USART_SendData(USART1, data);
}
/*-------------------------------------------------*/
/*函数名:串口1 发送数组                             */
/*参  数:bound:波特率                             */
/*返回值:无                                        */
/*-------------------------------------------------*/
void USART1_Send(char *Data,uint16_t Len)
{ 
	uint16_t i;
	for(i=0; i<Len; i++)
	{
		USART1_Send_byte(Data[i]);
	}
}
void USART1_SendStr(char*SendBuf)//串口1打印数据
{
	while(*SendBuf)
	{
        while((USART1->SR&0X40)==0);//等待发送完成 
        USART1->DR = (u8) *SendBuf; 
				SendBuf++;
	}
}

/*****************************************************
清空电脑反馈的缓冲数据 串口1
*****************************************************/
void Clear_Buffer_UART1(void)//清空缓存
{
    buf_uart1.index=0;
	  buf_uart1.rx_flag=0;
    memset(buf_uart1.buf,0,BUFLEN);
}
void UART1_receive_process_event(char ch )     //串口2给4g用
{
    if(buf_uart1.index >= BUFLEN)
    {
        buf_uart1.index = 0 ;
    }
    else
    {
        buf_uart1.buf[buf_uart1.index++] = ch;
    }
}

//串口1的接收中断程序
void USART1_IRQHandler(void)                                //串口1中断服务程序
{
		uint8_t Res;
		Res=Res;
    if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)  //接收中断,可以扩展来控制
    {
        Res=USART_ReceiveData(USART1);//接收模块的数据;

        UART1_receive_process_event(Res);//接收模块的数据
    } 
    if(USART_GetITStatus(USART1, USART_IT_IDLE) != RESET)  //模块空闲
    {
        Res=USART_ReceiveData(USART1);//接收模块的数据;

				buf_uart1.rx_flag=1;
    } 

} 


#endif




#if EN_USART2
UART_BUF buf_uart2;     //EC200T
//初始化IO 串口2
//pclk1:PCLK1时钟频率(Mhz)
//bound:波特率 
void usart2_init(u32 bound)
{  	 

    GPIO_InitTypeDef GPIO_InitStructure;
    USART_InitTypeDef USART_InitStructure;
    NVIC_InitTypeDef NVIC_InitStructure;

		RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);	//使能,GPIOA时钟
		RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2,ENABLE);//USART2
		USART_DeInit(USART2);  //复位串口2
	 //USART2_TX   PA.2
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2; //PA.2
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;	//复用推挽输出
    GPIO_Init(GPIOA, &GPIO_InitStructure); //初始化PA2
   
    //USART2_RX	  PA.3
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入
    GPIO_Init(GPIOA, &GPIO_InitStructure);  //初始化PA3

   
   //USART 初始化设置

		USART_InitStructure.USART_BaudRate = bound;//115200
		USART_InitStructure.USART_WordLength = USART_WordLength_8b;//字长为8位数据格式
		USART_InitStructure.USART_StopBits = USART_StopBits_1;//一个停止位
		USART_InitStructure.USART_Parity = USART_Parity_No;//无奇偶校验位
		USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//无硬件数据流控制
		USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;	//收发模式
    USART_Init(USART2, &USART_InitStructure); //初始化串口
    USART_Cmd(USART2, ENABLE);                    //使能串口 




#if EN_USART2_RX	
    USART_ITConfig(USART2, USART_IT_RXNE, ENABLE);//开启相关中断
		USART_ITConfig(USART2, USART_IT_IDLE, ENABLE);//开启相关中断
		
    //Usart1 NVIC 配置
    NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn;//串口1中断通道
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0;//抢占优先级3
    NVIC_InitStructure.NVIC_IRQChannelSubPriority =1;		//子优先级3
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;			//IRQ通道使能
    NVIC_Init(&NVIC_InitStructure);	//根据指定的参数初始化VIC寄存器、
#endif
}


void Clear_Buffer_UART2(void)//清空缓存
{
    buf_uart2.index=0;
	  buf_uart2.rx_flag=0;
    memset(buf_uart2.buf,0,BUFLEN);
}

/*********************************串口2的服务函数*************************************************/
void USART2_Send_byte(char data)
{
	while(USART_GetFlagStatus(USART2, USART_FLAG_TXE) == RESET);
	USART_SendData(USART2, data);
}




/*-------------------------------------------------*/
/*函数名:串口2 发送数组                             */
/*参  数:bound:波特率                             */
/*返回值:无                                        */
/*-------------------------------------------------*/
void USART2_Send(char *Data,uint16_t Len)
{ 
	uint16_t i;
	for(i=0; i<Len; i++)
	{
		USART2_Send_byte(Data[i]);
	}
}



void USART2_SendStr(char*SendBuf)//串口1打印数据
{
	while(*SendBuf)
	{
        while((USART2->SR&0X40)==0);//等待发送完成 
        USART2->DR = (u8) *SendBuf; 
        SendBuf++;
	}
}


void usart2_receive_process_event(unsigned char ch )     //串口2给4g用
{
    if(buf_uart2.index >= BUFLEN)
    {
        buf_uart2.index = 0 ;
    }
    else
    {
        buf_uart2.buf[buf_uart2.index++] = ch;
			
    }
}
void USART2_IRQHandler(void)                            //串口2接收函数
{
		char Res;
		Res=Res;
    if(USART_GetITStatus(USART2, USART_IT_RXNE) != RESET)  //接收中断,可以扩展来控制
    {
        Res=USART_ReceiveData(USART2);//接收模块的数据;
        usart2_receive_process_event(Res);//接收模块的数据
    } 
    if(USART_GetITStatus(USART2, USART_IT_IDLE) != RESET)  //模块空闲
    {
        Res=USART_ReceiveData(USART2);//接收模块的数据;
        buf_uart2.rx_flag=1;
		 } 
}


#endif


#if EN_USART3

UART_BUF buf_uart3;     //TTL
void usart3_init(u32 bound)
{
    //GPIO端口设置
    GPIO_InitTypeDef GPIO_InitStructure;
		USART_InitTypeDef USART_InitStructure;
		NVIC_InitTypeDef NVIC_InitStructure;
		 
		RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);	//使能,GPIOA时钟
		RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3,ENABLE);//USART3
		USART_DeInit(USART3);  //复位串口3
	 //USART3_TX   PB10
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10; //PB10
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;	//复用推挽输出
    GPIO_Init(GPIOB, &GPIO_InitStructure); //初始化PA2
   
    //USART3_RX	  PB11
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入
    GPIO_Init(GPIOB, &GPIO_InitStructure);  //初始化PB11

  
   //USART 初始化设置

		USART_InitStructure.USART_BaudRate = bound;//115200
		USART_InitStructure.USART_WordLength = USART_WordLength_8b;//字长为8位数据格式
		USART_InitStructure.USART_StopBits = USART_StopBits_1;//一个停止位
		USART_InitStructure.USART_Parity = USART_Parity_No;//无奇偶校验位
		USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//无硬件数据流控制
		USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;	//收发模式
    USART_Init(USART3, &USART_InitStructure); //初始化串口
	
    USART_Cmd(USART3, ENABLE);                    //使能串口 

#if EN_USART3_RX	

	USART_ITConfig(USART3, USART_IT_RXNE, ENABLE);//开启相关中断
	USART_ITConfig(USART3, USART_IT_IDLE, ENABLE);//开启相关中断
	USART_ClearFlag(USART3, USART_FLAG_TC);
	//Usart3 NVIC 配置
  NVIC_InitStructure.NVIC_IRQChannel = USART3_IRQn;//串口3中断通道
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=1;//抢占优先级1
	NVIC_InitStructure.NVIC_IRQChannelSubPriority =3;		//子优先级3
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;			//IRQ通道使能
	NVIC_Init(&NVIC_InitStructure);	//根据指定的参数初始化VIC寄存器、
#endif
	
}


void USART3_Send_byte(char data)
{
	while(USART_GetFlagStatus(USART3, USART_FLAG_TXE) == RESET);
	USART_SendData(USART3, data);
}


/*-------------------------------------------------*/
/*函数名:串口2 发送数组                             */
/*参  数:bound:波特率                             */
/*返回值:无                                        */
/*-------------------------------------------------*/
void USART3_Send(char *Data,uint16_t Len)
{ 
	uint16_t i;
	for(i=0; i<Len; i++)
	{
		USART3_Send_byte(Data[i]);
	}
}




void USART3_SendStr(char*SendBuf)//串口3打印数据
{
	while(*SendBuf)
	{
        while((USART3->SR&0X40)==0);//等待发送完成 
        USART3->DR = (u8) *SendBuf; 
        SendBuf++;
	}
}


/*****************************************************
清空电脑反馈的缓冲数据 串口1
*****************************************************/
void Clear_Buffer_UART3(void)//清空缓存
{
    buf_uart3.index=0;
	  buf_uart3.rx_flag=0;
    memset(buf_uart3.buf,0,BUFLEN);
}
void USART3_receive_process_event(char ch )     //串口2给4g用
{
    if(buf_uart3.index >= BUFLEN)
    {
        buf_uart3.index = 0 ;
    }
    else
    {
        buf_uart3.buf[buf_uart3.index++] = ch;
    }
} 
void USART3_IRQHandler(void)                                //串口3中断服务程序
{
		char Res;
		Res=Res;
    if(USART_GetITStatus(USART3, USART_IT_RXNE) != RESET)  //接收中断,可以扩展来控制
    {
        Res=USART_ReceiveData(USART3);//接收模块的数据;
        USART3_receive_process_event(Res);
    } 
    if(USART_GetITStatus(USART3, USART_IT_IDLE) != RESET)  //模块空闲
    {
        Res=USART_ReceiveData(USART3);//接收模块的数据;
				buf_uart3.rx_flag=1;
    } 
} 	

#endif




oled.c

#include "oled.h"
#include "stdlib.h"
#include "oledfont.h"  	 
#include "delay.h"
//OLED的显存
//存放格式如下.
//[0]0 1 2 3 ... 127	
//[1]0 1 2 3 ... 127	
//[2]0 1 2 3 ... 127	
//[3]0 1 2 3 ... 127	
//[4]0 1 2 3 ... 127	
//[5]0 1 2 3 ... 127	
//[6]0 1 2 3 ... 127	
//[7]0 1 2 3 ... 127 			   

#if OLED_MODE==1
//向SSD1106写入一个字节。
//dat:要写入的数据/命令
//cmd:数据/命令标志 0,表示命令;1,表示数据;
void OLED_WR_Byte(u8 dat,u8 cmd)
{
	DATAOUT(dat);	    
	if(cmd)
	  OLED_DC_Set();
	else 
	  OLED_DC_Clr();		   
	OLED_CS_Clr();
	OLED_WR_Clr();	 
	OLED_WR_Set();
	OLED_CS_Set();	  
	OLED_DC_Set();	 
} 	    	    
#else
//向SSD1106写入一个字节。
//dat:要写入的数据/命令
//cmd:数据/命令标志 0,表示命令;1,表示数据;
void OLED_WR_Byte(u8 dat,u8 cmd)
{	
	u8 i;			  
	if(cmd)
	  OLED_DC_Set();
	else 
	  OLED_DC_Clr();		  

	for(i=0;i<8;i++)
	{			  
		OLED_SCLK_Clr();
		if(dat&0x80)
		   OLED_SDIN_Set();
		else 
		   OLED_SDIN_Clr();
		OLED_SCLK_Set();
		dat<<=1;   
	}				 		  

	OLED_DC_Set();   	  
} 
#endif
	void OLED_Set_Pos(unsigned char x, unsigned char y) 
{ 
	OLED_WR_Byte(0xb0+y,OLED_CMD);
	OLED_WR_Byte(((x&0xf0)>>4)|0x10,OLED_CMD);
	OLED_WR_Byte((x&0x0f)|0x01,OLED_CMD); 
}   	  
//开启OLED显示    
void OLED_Display_On(void)
{
	OLED_WR_Byte(0X8D,OLED_CMD);  //SET DCDC命令
	OLED_WR_Byte(0X14,OLED_CMD);  //DCDC ON
	OLED_WR_Byte(0XAF,OLED_CMD);  //DISPLAY ON
}
//关闭OLED显示     
void OLED_Display_Off(void)
{
	OLED_WR_Byte(0X8D,OLED_CMD);  //SET DCDC命令
	OLED_WR_Byte(0X10,OLED_CMD);  //DCDC OFF
	OLED_WR_Byte(0XAE,OLED_CMD);  //DISPLAY OFF
}		   			 
//清屏函数,清完屏,整个屏幕是黑色的!和没点亮一样!!!	  
void OLED_Clear(void)  
{  
	u8 i,n;		    
	for(i=0;i<8;i++)  
	{  
		OLED_WR_Byte (0xb0+i,OLED_CMD);    //设置页地址(0~7)
		OLED_WR_Byte (0x00,OLED_CMD);      //设置显示位置—列低地址
		OLED_WR_Byte (0x10,OLED_CMD);      //设置显示位置—列高地址   
		for(n=0;n<128;n++)OLED_WR_Byte(0,OLED_DATA); 
	} //更新显示
}


//在指定位置显示一个字符,包括部分字符
//x:0~127
//y:0~63
//mode:0,反白显示;1,正常显示				 
//size:选择字体 16/12 
void OLED_ShowChar(u8 x,u8 y,u8 chr)
{      	
	unsigned char c=0,i=0;	
		c=chr-' ';//得到偏移后的值			
		if(x>Max_Column-1){x=0;y=y+2;}
		if(SIZE ==16)
			{
			OLED_Set_Pos(x,y);	
			for(i=0;i<8;i++)
			OLED_WR_Byte(F8X16[c*16+i],OLED_DATA);
			OLED_Set_Pos(x,y+1);
			for(i=0;i<8;i++)
			OLED_WR_Byte(F8X16[c*16+i+8],OLED_DATA);
			}
			else {	
				OLED_Set_Pos(x,y+1);
				for(i=0;i<6;i++)
				OLED_WR_Byte(F6x8[c][i],OLED_DATA);
				
			}
}
//m^n函数
u32 oled_pow(u8 m,u8 n)
{
	u32 result=1;	 
	while(n--)result*=m;    
	return result;
}				  
//显示2个数字
//x,y :起点坐标	 
//len :数字的位数
//size:字体大小
//mode:模式	0,填充模式;1,叠加模式
//num:数值(0~4294967295);	 		  
void OLED_ShowNum(u8 x,u8 y,u32 num,u8 len,u8 size)
{         	
	u8 t,temp;
	u8 enshow=0;						   
	for(t=0;t<len;t++)
	{
		temp=(num/oled_pow(10,len-t-1))%10;
		if(enshow==0&&t<(len-1))
		{
			if(temp==0)
			{
				OLED_ShowChar(x+(size/2)*t,y,' ');
				continue;
			}else enshow=1; 
		 	 
		}
	 	OLED_ShowChar(x+(size/2)*t,y,temp+'0'); 
	}
} 


//显示汉字
static void OLED_ShowCHinese(uint8_t x,uint8_t y,char *str)
{      			    
	uint16_t k;
	uint16_t HZnum;
	HZnum=sizeof(tfont16)/sizeof(typFNT_GB16);	//自动统计汉字数目
	for (k=0;k<HZnum;k++) 
	{
	  if ((tfont16[k].Index[0]==*(str))&&(tfont16[k].Index[1]==*(str+1)))
	  { 	
				uint8_t t,adder=0;
				OLED_Set_Pos(x,y);	
					for(t=0;t<16;t++)
					{
							OLED_WR_Byte(tfont16[k].Msk[t],OLED_DATA);
							adder+=1;
					 }	
					OLED_Set_Pos(x,y+1);	
					for(t=0;t<16;t++)
						{	
							OLED_WR_Byte(tfont16[k].Msk[t+16],OLED_DATA);
							adder+=1;
						}
		}				  	
		continue;  //查找到对应点阵字库立即退出,防止多个汉字重复取模带来影响
	}
	
}


//显示一个字符号串(中文也可以)
void OLED_ShowString(uint8_t x,uint8_t y,char *chr)
{
		unsigned char j=0;		 	
  	uint8_t bHz=0;     //字符或者中文 
    while(chr[j]!=0)//数据未结束
    { 
      if(!bHz)
       {
	        if(chr[j]>0x80)bHz=1;//中文 
	        else              //字符
	        {
							OLED_ShowChar(x,y,chr[j]);
								x+=8;
							if(x>120){x=0;y+=2;}
								j++;
						
	        }
        }else//中文 
        {
					bHz = 0;
					OLED_ShowCHinese(x,y,&chr[j]);
					x+=16;
					if(x>114){x=0;y+=2;}
					j+=2;
        }
    }
}


/***********功能描述:显示显示BMP图片128×64起始点坐标(x,y),x的范围0~127,y为页的范围0~7*****************/
void OLED_DrawBMP(unsigned char x0, unsigned char y0,unsigned char x1, unsigned char y1,unsigned char BMP[])
{ 	
 unsigned int j=0;
 unsigned char x,y;
  
  if(y1%8==0) y=y1/8;      
  else y=y1/8+1;
	for(y=y0;y<y1;y++)
	{
		OLED_Set_Pos(x0,y);
    for(x=x0;x<x1;x++)
	    {      
	    	OLED_WR_Byte(BMP[j++],OLED_DATA);	    	
	    }
	}
} 


//初始化SSD1306					    
void OLED_Init(void)
{ 	
 
 	 
 	GPIO_InitTypeDef  GPIO_InitStructure;
 	
 	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);	 //使能A端口时钟
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5|GPIO_Pin_7;	 
 	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; 		 //推挽输出
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//速度50MHz
 	GPIO_Init(GPIOA, &GPIO_InitStructure);	  //初始化GPIOD3,6
 	GPIO_SetBits(GPIOA,GPIO_Pin_5|GPIO_Pin_7);	
	
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);	 //使能A端口时钟
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_1;	 
 	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; 		 //推挽输出
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//速度50MHz
 	GPIO_Init(GPIOB, &GPIO_InitStructure);	  //初始化GPIOD3,6
 	GPIO_SetBits(GPIOB,GPIO_Pin_0|GPIO_Pin_1);	



 
  OLED_RST_Set();
	delay_ms(100);
	OLED_RST_Clr();
	delay_ms(200);
	OLED_RST_Set(); 
					  
	OLED_WR_Byte(0xAE,OLED_CMD);//--turn off oled panel
	OLED_WR_Byte(0x00,OLED_CMD);//---set low column address
	OLED_WR_Byte(0x10,OLED_CMD);//---set high column address
	OLED_WR_Byte(0x40,OLED_CMD);//--set start line address  Set Mapping RAM Display Start Line (0x00~0x3F)
	OLED_WR_Byte(0x81,OLED_CMD);//--set contrast control register
	OLED_WR_Byte(0xCF,OLED_CMD); // Set SEG Output Current Brightness
	OLED_WR_Byte(0xA1,OLED_CMD);//--Set SEG/Column Mapping     0xa0左右反置 0xa1正常
	OLED_WR_Byte(0xC8,OLED_CMD);//Set COM/Row Scan Direction   0xc0上下反置 0xc8正常
	OLED_WR_Byte(0xA6,OLED_CMD);//--set normal display
	OLED_WR_Byte(0xA8,OLED_CMD);//--set multiplex ratio(1 to 64)
	OLED_WR_Byte(0x3f,OLED_CMD);//--1/64 duty
	OLED_WR_Byte(0xD3,OLED_CMD);//-set display offset	Shift Mapping RAM Counter (0x00~0x3F)
	OLED_WR_Byte(0x00,OLED_CMD);//-not offset
	OLED_WR_Byte(0xd5,OLED_CMD);//--set display clock divide ratio/oscillator frequency
	OLED_WR_Byte(0x80,OLED_CMD);//--set divide ratio, Set Clock as 100 Frames/Sec
	OLED_WR_Byte(0xD9,OLED_CMD);//--set pre-charge period
	OLED_WR_Byte(0xF1,OLED_CMD);//Set Pre-Charge as 15 Clocks & Discharge as 1 Clock
	OLED_WR_Byte(0xDA,OLED_CMD);//--set com pins hardware configuration
	OLED_WR_Byte(0x12,OLED_CMD);
	OLED_WR_Byte(0xDB,OLED_CMD);//--set vcomh
	OLED_WR_Byte(0x40,OLED_CMD);//Set VCOM Deselect Level
	OLED_WR_Byte(0x20,OLED_CMD);//-Set Page Addressing Mode (0x00/0x01/0x02)
	OLED_WR_Byte(0x02,OLED_CMD);//
	OLED_WR_Byte(0x8D,OLED_CMD);//--set Charge Pump enable/disable
	OLED_WR_Byte(0x14,OLED_CMD);//--set(0x10) disable
	OLED_WR_Byte(0xA4,OLED_CMD);// Disable Entire Display On (0xa4/0xa5)
	OLED_WR_Byte(0xA6,OLED_CMD);// Disable Inverse Display On (0xa6/a7) 
	OLED_WR_Byte(0xAF,OLED_CMD);//--turn on oled panel
	
	OLED_WR_Byte(0xAF,OLED_CMD); /*display ON*/ 
	OLED_Clear();
	OLED_Set_Pos(0,0); 	
}  

效果--串口调试信息

在左侧导航栏中依次选择 「工具」→「WebSocket」,进入 WebSocket 交互页面。

输入目标服务器的 IP 地址,填写 WebSocket 服务端口,输入需要监听的主题,完成后点击「订阅」按钮,建立主题监听。输入数据上报的目标主题,用于后续发送消息。

在[订阅消息列表]中可实时查看上报的数据内容。

平台数据下发操作

在消息输入框中,输入需要下发的指令内容,确认发布主题为设备订阅的目标主题,点击[发送]按钮,平台将通过WebSocket向设备推送指令。

在串口调试助手中,可实时监控设备接收数据的状态:

STM32F103C8T6+BC20+DHT11+Emqx代码链接: https://pan.baidu.com/s/1gxcBwb2ZM6VUQ8sBIEOlEw 提取码: 7n73