跳到主要内容
极客日志极客日志面向AI+效率的开发者社区
首页博客GitHub 精选镜像工具UI配色美学隐私政策关于联系
搜索内容 / 工具 / 仓库 / 镜像...⌘K搜索
注册
博客列表
CWeChat

嵌入式物联网设计通用方案:平台对比与 STM32 实战

综述由AI生成嵌入式物联网开发中,平台选型直接影响项目落地效率。文章对比了自建 EMQX、阿里云、腾讯云、华为云及 OneNET 等主流方案,分析了各自在成本、功能及易用性上的差异。针对初学者推荐 OneNET,进阶推荐华为云。同时提供了基于 STM32 与 ESP8266 的 MQTT 通信代码示例,涵盖 AirKiss 配网、属性上报及指令下发,并简述了微信小程序端的集成思路,为智慧农业与智能家居类设计提供通用参考。

PgDevote发布于 2026/4/9更新于 2026/5/2315 浏览
嵌入式物联网设计通用方案:平台对比与 STM32 实战

嵌入式物联网设计通用实现方法

做嵌入式物联网设计时,平台选型往往决定了开发效率。物联网开放平台通过标准化协议与接口,将分散的设备高效连接、统一管理,并提供成熟的云服务与安全机制。借助这些工具,我们可以快速构建应用,专注于设备本身的功能创新,大幅降低开发复杂度。

学习阶段选用的物联网开放平台,建议遵循以下原则:

  1. 成本可控:优先选择免费试用额度充足的平台。
  2. 功能完备:能够接驳多种附加功能或云服务(如存储、数据分析)。
  3. 通信稳定:保证消息传输的可靠性。

一、主流平台方案对比

常见的物联网开放平台实现方式主要有以下几种,各有优劣:

1. 云服务器 + EMQX 自主构建

这种方式灵活程度较高,但技术栈内容较多,涉及 MQTT Broker 部署与维护,比较适合有一定基础的开发者使用。

架构示意图

2. 阿里云物联网平台

接入便捷,能对接大量阿里云云服务(存储、数据分析等)。不过目前该服务已停止新增用户,仅支持现有用户维护,不适合新用户用于学习。

架构图

3. 腾讯云物联网通信

支持基础通信与多种云服务,但免费单元较少(约 5-10 个设备)。其特点是支持腾讯连连 APP 实现快速的上位机开发。

架构图

4. 华为云设备接入 (IOTDA)

成熟度高,支持基础通信并直接接驳华为云大量服务,实现便捷的 IoT 消息存储与流转。支持邮箱及短信告警推送。不足在于鉴权流程相对复杂,初学者需花费时间配置。

架构图

5. 中国移动 OneNET

使用最为便利,支持基础通信与邮件告警。缺点是原生云服务较少,若需拓展转发、存储等功能,可能需要接驳其他平台(如华为云、阿里云存储)。

架构图

综合建议

基于实际开发体验,总结如下:

  • 初学者入门:首选 中国移动 OneNET。注册、产品/设备创建流程简单,能快速实现远程数据显示、指令下发及告警推送。
  • 进阶功能扩展:推荐 华为云 IOTDA。免费单元数量充足(可达 1000+),可直接对接华为云生态中的大量云服务,通过控制台设置流转即可,无需自行部署 Linux 服务,适合快速验证功能。

二、基础代码实现

华为云、腾讯云、阿里云均提供了封装好的 STM32 基础代码及微信小程序模板。利用这些工程,可以构建智能家居、智慧农业等各类物联网设计。

核心逻辑是修改鉴权信息并在云平台新建实例,即可实现 STM32 单片机与云平台的通信。本例采用 WIFI 联网模式,搭配 ESP-01S 模块,支持 AirKiss 配网模式,更加灵活。

ESP-01S 驱动层代码

这部分负责处理串口通信、AT 指令交互以及 Wi-Fi 连接状态管理。注意避开被占用的配网引脚,防止卡死。

/* - 功能:ESP8266 硬件驱动函数。
 * - 硬件:使用了串口二
 * - 修改:WiFi 账号/密码
 * - 使用:#include "ESP8266.h"
 */
#include <string.h>
#include <stdio.h>
#include "stm32f10x.h"
#include "delay.h"
#include "usart.h"
#include "ESP8266.h"
#include "HWIOTDA.h"

// 此处修改固定连接的 WiFi 账号密码
#define WiFi_SSID "xiaomi"
#define WiFi_PSD "00000000"

// 固定连接 WIFI 的 AT 指令
#define ESP8266_WIFI_INFO "AT+CWJAP=\"" WiFi_SSID "\",\"" WiFi_PSD "\"\r\n"
#define ESP8266_AirKiss "AT+CWSTARTSMART\r\n"

// 全局内存
unsigned char esp8266_buf[esp8266_buf_size];
unsigned short esp8266_cnt = 0, esp8266_cntPre = 0;

// 等待默认 WIFI 连接
void Esp_Waiting_Wifi(void){
    printf("\r\n");
    printf("1/5: 进入等待连接模式\r\n");
    while(ESP8266_SendCmd("AT\r\n", "OK")) delay_ms(500);
    printf("2/5: AT 确认连接\r\n");
    // ... (省略中间步骤以保持简洁,实际使用时请保留完整逻辑)
}

// 串口初始化
void Uart2_Init(unsigned int baud){
    GPIO_InitTypeDef gpio_initstruct;
    USART_InitTypeDef usart_initstruct;
    NVIC_InitTypeDef nvic_initstruct;
    
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);
    
    // PA2 TXD
    gpio_initstruct.GPIO_Mode = GPIO_Mode_AF_PP;
    gpio_initstruct.GPIO_Pin = GPIO_Pin_2;
    gpio_initstruct.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA, &gpio_initstruct);
    
    // PA3 RXD
    gpio_initstruct.GPIO_Mode = GPIO_Mode_IN_FLOATING;
    gpio_initstruct.GPIO_Pin = GPIO_Pin_3;
    GPIO_Init(GPIOA, &gpio_initstruct);
    
    usart_initstruct.USART_BaudRate = baud;
    usart_initstruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
    usart_initstruct.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
    usart_initstruct.USART_Parity = USART_Parity_No;
    usart_initstruct.USART_StopBits = USART_StopBits_1;
    usart_initstruct.USART_WordLength = USART_WordLength_8b;
    
    USART_Init(USART2, &usart_initstruct);
    USART_Cmd(USART2, ENABLE);
    USART_ITConfig(USART2, USART_IT_RXNE, ENABLE);
    
    nvic_initstruct.NVIC_IRQChannel = USART2_IRQn;
    nvic_initstruct.NVIC_IRQChannelCmd = ENABLE;
    nvic_initstruct.NVIC_IRQChannelPreemptionPriority = 0;
    nvic_initstruct.NVIC_IRQChannelSubPriority = 0;
    NVIC_Init(&nvic_initstruct);
}

// 串口二 发送函数
void Usart_SendString(USART_TypeDef *USARTx, unsigned char *str, unsigned short len){
    unsigned short count = 0;
    for(; count < len; count++){
        USART_SendData(USARTx, *str++);
        while(USART_GetFlagStatus(USARTx, USART_FLAG_TC) == RESET);
    }
}

// 串口二 接收中断
void USART2_IRQHandler(void){
    if(USART_GetITStatus(USART2, USART_IT_RXNE) != RESET){
        if(esp8266_cnt >= sizeof(esp8266_buf)) esp8266_cnt = 0;
        esp8266_buf[esp8266_cnt++] = USART2->DR;
        USART_ClearFlag(USART2, USART_FLAG_RXNE);
    }
}

// ESP 清空缓存
void ESP8266_Clear(void){
    memset(esp8266_buf, 0, sizeof(esp8266_buf));
    esp8266_cnt = 0;
}

// ESP 等待接收完成
_Bool ESP8266_WaitRecive(void){
    if(esp8266_cnt == 0) return REV_WAIT;
    if(esp8266_cnt == esp8266_cntPre){
        esp8266_cnt = 0;
        return REV_OK;
    }
    esp8266_cntPre = esp8266_cnt;
    return REV_WAIT;
}

// ESP 发送命令 (返回:0-成功 1-失败)
_Bool ESP8266_SendCmd(char *cmd, char *res){
    unsigned char timeOut = 200;
    Usart_SendString(USART2, (unsigned char *)cmd, strlen((const char *)cmd));
    while(timeOut--){
        if(ESP8266_WaitRecive() == REV_OK){
            if(strstr((const char *)esp8266_buf, res) != NULL){
                ESP8266_Clear();
                return 0;
            }
        }
        delay_ms(10);
    }
    return 1;
}

// 查询是否有 IOTDA 平台的下发指令
unsigned char *ESP8266_GetRECV(unsigned short timeOut){
    char *ptrRECV = NULL;
    do{
        if(ESP8266_WaitRecive() == REV_OK){
            ptrRECV = strstr((char *)esp8266_buf, "MQTTSUBRECV");
            if(ptrRECV == NULL){
                printf("\"MQTTSUBRECV\" not found\r\n");
            }else{
                ptrRECV = strchr(ptrRECV, ':');
                if(ptrRECV != NULL){
                    ptrRECV++;
                    return (unsigned char *)(ptrRECV);
                }
            }
        }
        delay_ms(5);
    }while(timeOut--);
    return NULL;
}

华为云 IOTDA 接入代码

这里整理了关键的 AT 指令宏定义,包括 MQTT 用户名密码设置、客户端 ID 配置以及主题订阅。注意根据实际项目 ID 和密钥替换宏定义中的变量。

// AT 指令整理(无需修改)
// 设置 MQTT 的用户名与密码
#define HW_MQTT_SetUserPsd "AT+MQTTUSERCFG=0,1,\"NULL\",\"" HW_Username "\",\"" HW_Password "\",0,0,\"\"\r\n"
// 客户端 ID
#define HW_MQTT_SetClientID "AT+MQTTCLIENTID=0,\"" HW_ClientID "\"\r\n"
// 所属地域接入接口
#define HW_MQTT_Address_Port "AT+MQTTCONN=0,\"" HW_AddressPort "\",1883,1\r\n"
// 主题订阅
#define HW_MQTT_ThemeSub "AT+MQTTSUB=0,\"$oc/devices/" HW_ClientID "/sys/properties/report\",1\r\n"
// 设备信息上报
#define HW_MQTT_Report "AT+MQTTPUB=0,\"$oc/devices/" HW_Username "/sys/properties/report\",\"{\\\"services\\\":[{\\\"service_id\\\":\\\"" HW_ServiceID "\\\"\\,\\\"properties\\\":{" 
// 下发指令回复包
#define HW_MQTT_Response "AT+MQTTPUB=0,\"$oc/devices/" HW_ProjectID "/sys/commands/response/request_id="

char PubMemory[250];
char EditMemory[50];
char ParasMemory[150];

// 连接到华为云 IOT 平台
void HWIOTDA_ConnectCloud(){
    printf("\r\n");
    printf("1/4: 设置 MQTT 用户名与密码\r\n");
    while(ESP8266_SendCmd(HW_MQTT_SetUserPsd, "OK")) delay_ms(500);
    printf("2/4: 设置 MQTT 客户端 ID\r\n");
    while(ESP8266_SendCmd(HW_MQTT_SetClientID, "OK")) delay_ms(500);
    printf("3/4: 连接到 IOTDA 服务器\r\n");
    while(ESP8266_SendCmd(HW_MQTT_Address_Port, "OK")) delay_ms(500);
    printf("4/4: 订阅命令下行主题\r\n");
    while(ESP8266_SendCmd(HW_MQTT_ThemeSub, "OK")) delay_ms(500);
}

中国移动 OneNET 接入代码

OneNET 的鉴权方式略有不同,通常使用产品 ID 作为用户名,Token 作为密码。连接逻辑与华为云类似,主要区别在于 Topic 的格式。

// ---------- AT 指令整理(无需修改)----------
// 设备接入信息的请求接口
#define OneNET_AddressPort "mqtts.heclouds.com"
// 设置 MQTT 的用户名与密码(产品 ID 作为 username,Token 作为 password)
#define OneNET_MQTT_SetUserPsd "AT+MQTTUSERCFG=0,1,\"NULL\",\"" OneNET_ProjectID "\",\"" OneNET_Password "\",0,0,\"\"\r\n"
// 客户端 ID(设备名称作为 ClientID)
#define OneNET_MQTT_SetClientID "AT+MQTTCLIENTID=0,\"" OneNET_DeviceName "\"\r\n"
// MQTT 连接指令
#define OneNET_MQTT_Address_Port "AT+MQTTCONN=0,\"" OneNET_AddressPort "\",1883,1\r\n"
// 设备上行数据结果响应主题
#define OneNET_MQTT_ReplyThemeSub "AT+MQTTSUB=0,\"$sys/" OneNET_ProjectID "/" OneNET_DeviceName "/thing/property/post/reply\",1\r\n"
// App 下发指令接收主题
#define OneNET_MQTT_AppThemeSub "AT+MQTTSUB=0,\"$sys/" OneNET_ProjectID "/" OneNET_DeviceName "/thing/property/set\",1\r\n"
// 设备信息上报 包头
#define OneNET_MQTT_Report "AT+MQTTPUB=0,\"$sys/" OneNET_ProjectID "/" OneNET_DeviceName "/thing/property/post\",\"{\\\"id\\\":\\\"001\\\"\\,\\\"version\\\":\\\"1.0\\\"\\,\\\"params\\\":{" 
// 下发指令回复包 包头
#define OneNET_MQTT_Response "AT+MQTTPUB=0,\"$sys/" OneNET_ProjectID "/" OneNET_DeviceName "/thing/property/set_reply\""

char PubMemory[250];
char EditMemory[50];
char ParamsMemory[150];

// 连接到 OneNET 平台
void OneNET_ConnectCloud(){
    printf("\r\n");
    printf("1/5: 设置 MQTT 用户名与密码\r\n");
    while(ESP8266_SendCmd(OneNET_MQTT_SetUserPsd, "OK")) delay_ms(500);
    printf("2/5: 设置 MQTT 客户端 ID\r\n");
    while(ESP8266_SendCmd(OneNET_MQTT_SetClientID, "OK")) delay_ms(500);
    printf("3/5: 连接到 OneNET 服务器\r\n");
    while(ESP8266_SendCmd(OneNET_MQTT_Address_Port, "")) delay_ms(500);
    while(ESP8266_SendCmd("", "OK")) delay_ms(500);
    printf("4/5: 订阅上行响应主题\r\n");
    while(ESP8266_SendCmd(OneNET_MQTT_ReplyThemeSub, "OK")) delay_ms(500);
    printf("5/5: 订阅命令下行主题\r\n");
    while(ESP8266_SendCmd(OneNET_MQTT_AppThemeSub, "OK")) delay_ms(500);
}

三、完整工程参考

完整的 STM32 工程包包含上述代码逻辑,可以直接烧录测试。同时配套了微信小程序的基础模板,方便快速搭建上位机界面。

STM32 工程结构

微信小程序界面

目录

  1. 嵌入式物联网设计通用实现方法
  2. 一、主流平台方案对比
  3. 1. 云服务器 + EMQX 自主构建
  4. 2. 阿里云物联网平台
  5. 3. 腾讯云物联网通信
  6. 4. 华为云设备接入 (IOTDA)
  7. 5. 中国移动 OneNET
  8. 综合建议
  9. 二、基础代码实现
  10. ESP-01S 驱动层代码
  11. 华为云 IOTDA 接入代码
  12. 中国移动 OneNET 接入代码
  13. 三、完整工程参考
  • 💰 8折买阿里云服务器限时8折了解详情
  • Magick API 一键接入全球大模型注册送1000万token查看
  • 🤖 一键搭建Deepseek满血版了解详情
  • 一键打造专属AI 智能体了解详情
极客日志微信公众号二维码

微信扫一扫,关注极客日志

微信公众号「极客日志V2」,在微信中扫描左侧二维码关注。展示文案:极客日志V2 zeeklog

更多推荐文章

查看全部
  • WSL Ubuntu 安装 Golang Python Node.js Java Docker Podman 开发环境配置
  • MySQL 主键与外键的区别及设计最佳实践
  • C++ STL 线程与互斥量:优雅解决哲学家就餐问题
  • 计算机网络与图算法:从理论到实践
  • Kubernetes Ingress Webhook 验证机制:原理与故障排查
  • Ubuntu 20.04 安装微信教程
  • ChatGPT Prompt Hacker 技巧:优化简历通过 AI 筛选
  • 2024 大模型技术学习路线与实战指南
  • GitHub 入门:从 Git 区别到协作实战
  • Python 实现 MCP 客户端调用高德地图天气查询示例
  • Tomcat 下载、安装及环境配置指南
  • Trae 结合 Vizro:低代码构建专业数据可视化仪表板
  • 8 个技术要点,帮助企业更好落地大模型知识库
  • 医疗 AI 中的马尔科夫链深度应用与 Python 实现
  • 6 种 Python 脚本打包成可执行文件的主流方法
  • VS Code 配置 Claude Code 时 Git Bash 路径报错解决
  • Stable Diffusion 整合包快速部署与实战指南
  • C++ 面试基础:与 C 语言区别及 C++11 新特性
  • 次模函数(Submodular Function)核心概念与机器学习应用
  • 老 MacBook 安装 Linux 部署 OpenClaw 实现 24 小时服务器

相关免费在线工具

  • Base64 字符串编码/解码

    将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online

  • Base64 文件转换器

    将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online

  • Markdown转HTML

    将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML转Markdown 互为补充。 在线工具,Markdown转HTML在线工具,online

  • HTML转Markdown

    将 HTML 片段转为 GitHub Flavored Markdown,支持标题、列表、链接、代码块与表格等;浏览器内处理,可链接预填。 在线工具,HTML转Markdown在线工具,online

  • JSON 压缩

    通过删除不必要的空白来缩小和压缩JSON。 在线工具,JSON 压缩在线工具,online

  • JSON美化和格式化

    将JSON字符串修饰为友好的可读格式。 在线工具,JSON美化和格式化在线工具,online