scafel 发表于 2025-6-13 14:41

【灵动微电子MM32F0121测评】使用esp8266实现数据传输

本帖最后由 scafel 于 2025-7-3 08:25 编辑

[!(/source/plugin/zhanmishu_markdown/template/editor/images/upload.svg) 源代码文件:Demo.rar](forum.php?mod=attachment&aid=2420276 "attachment")

#原创申请#

第三篇:【灵动微电子MM32F0121测评】使用esp8266实现数据传输

上篇已成功实现了串口与I2C的通信功能,并完成了LED的显示。接下来,我们将进入物联网(IoT)领域。在物联网项目中,MQTT协议因其轻量级、低功耗和高效性,已成为主流的通信协议。本文将结合ESP8266-01s模块,通过MQTT协议实现LED的远程控制,帮助读者快速掌握物联网设备通信的核心技术。

**硬件清单**

- ESP8266-01s模块
- 板载的LED1和LED2
- 四根杜邦线

**软件和MQTT服务**

- 使用本地搭建的MQTT服务
- 本人编写的小程序

1. 按照接线图链接开发板和ESP8266-01S模块

![微信图片_20250613133518.jpg](data/attachment/forum/202506/13/134926mn0zel2ymil21wcr.jpg "微信图片_20250613133518.jpg")

2. 书写串口代码,并测试是否可用

```c
#include <mm32_device.h>
#include <stdio.h>
#include <string.h>
#include "ESP8266.h"



#define RX_BUFFER_SIZE 128
uint8_t Serial_RxPacket; // 定义接收数据包数组
volatile uint8_t RxState = 0;                     // 接收状态机状态
uint8_t pRxPacket = 0;                  //定义表示当前接收数据位置

void ESP8266_Init(void)
{
        GPIO_InitTypeDefGPIO_InitStruct;
    NVIC_InitTypeDefNVIC_InitStruct;
    USART_InitTypeDef USART_InitStruct;

    RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);

    USART_StructInit(&USART_InitStruct);
    USART_InitStruct.USART_BaudRate   = 115200;
    USART_InitStruct.USART_WordLength = USART_WordLength_8b;
    USART_InitStruct.USART_StopBits   = USART_StopBits_1;
    USART_InitStruct.USART_Parity   = USART_Parity_No;
    USART_InitStruct.USART_Mode       = USART_Mode_Rx | USART_Mode_Tx;
    USART_InitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
    USART_Init(USART2, &USART_InitStruct);

    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE);
    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOB, ENABLE);

    GPIO_PinAFConfig(GPIOA, GPIO_PinSource8, GPIO_AF_3);
    GPIO_PinAFConfig(GPIOB, GPIO_PinSource8, GPIO_AF_4);

    GPIO_StructInit(&GPIO_InitStruct);
    GPIO_InitStruct.GPIO_Pin   = GPIO_Pin_8;
    GPIO_InitStruct.GPIO_Speed = GPIO_Speed_High;
    GPIO_InitStruct.GPIO_Mode= GPIO_Mode_AF_PP;
    GPIO_Init(GPIOA, &GPIO_InitStruct);

    GPIO_StructInit(&GPIO_InitStruct);
    GPIO_InitStruct.GPIO_Pin   = GPIO_Pin_8;
    GPIO_InitStruct.GPIO_Mode= GPIO_Mode_FLOATING;
    GPIO_Init(GPIOB, &GPIO_InitStruct);

    NVIC_InitStruct.NVIC_IRQChannel = USART2_IRQn;
    NVIC_InitStruct.NVIC_IRQChannelPriority = 0;
    NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStruct);

        USART_ITConfig(USART2, USART_IT_RXNE, ENABLE);
        USART_ITConfig(USART2, USART_IT_IDLE, ENABLE);

    USART_Cmd(USART2, ENABLE);
}


void ESP8266_SendByte(uint16_t Byte)
{
    USART_SendData(USART2, Byte);                //将字节数据写入数据寄存器,写入后USART自动生成时序波形
        while(USART_GetFlagStatus(USART2, USART_FLAG_TXE) == RESET);        //等待发送完成
        /*下次写入数据寄存器会自动清除发送完成标志位,故此循环后,无需清除标志位*/
        USART_ClearITPendingBit(USART2, USART_IT_RXNE);
}

void ESP8266_SendString(char *String)
{
    USART_ITConfig(USART2, USART_IT_RXNE, DISABLE); // 禁用接收中断
    while (*String != '\0') {
      ESP8266_SendByte(*String++);
    }
    USART_ITConfig(USART2, USART_IT_RXNE, ENABLE); // 重新启用接收中断
}


// 发送AT指令示例
void ESP8266_AT_Command(char *cmd) {
        printf("\r\n AT_Command = %s", cmd);
    char temp;
    snprintf(temp, sizeof(temp), "%s\r\n", cmd); // 安全拼接
    ESP8266_SendString(temp); // 发送命令
}

void Parse_MQTT_Data()
{
        printf("Mqtt_Data:%s", Serial_RxPacket);
        memset(Serial_RxPacket, 0, sizeof(Serial_RxPacket));
}


void USART2_IRQHandler(void)
{
    uint8_t RxData;
    if (USART_GetITStatus(USART2, USART_IT_RXNE) != RESET) {
                RxState = 1;
      RxData = USART_ReceiveData(USART2);
                Serial_RxPacket = RxData;
      // 清除中断标志位
      USART_ClearITPendingBit(USART2, USART_IT_RXNE);
    }
        if (USART_GetITStatus(USART2, USART_IT_IDLE) != RESET) {
      RxData = USART_ReceiveData(USART2);
      // 清除中断标志位
      USART_ClearITPendingBit(USART2, USART_IT_IDLE);
                if(RxState > 0)
                {
                        USART_ITConfig(USART2, USART_IT_RXNE, DISABLE);
                        USART_ITConfig(USART2, USART_IT_IDLE, DISABLE);
                        RxState = 0;
                        pRxPacket = 0;
                        Parse_MQTT_Data();
                        USART_ITConfig(USART2, USART_IT_RXNE, ENABLE);
                        USART_ITConfig(USART2, USART_IT_IDLE, ENABLE);
                }
    }
}
// main函数
#include <stdio.h>
#include <mm32_device.h>
#include "MM_Print.h"
#include "MM_Delay.h"
#include "Onboard_LED.h"
#include "Onboard_KEY.h"
#include "ESP8266.h"


char ESP8266_SEND_STR[] =
{
    {"AT"},
    //0. 设置Wi-Fi模式为 STA模式
    {"AT+CWMODE=1"},
    //1. 连接到AP,"热点名称","密码"
    {"AT+CWJAP=\"CU_ZDR\",\"dbamw4wz\""},
    //2. 配置传输模式为 透传模式
    // {"AT+CIPMODE=1"},
    //3. 配置多重连接模式关闭,关闭多路连接
    // {"AT+CIPMUX=0"},
    //4. 配置MQTT服务客户端 username,password
    {"AT+MQTTUSERCFG=0,1,\"NULL\",\"MEMBER-WSW202410141212003170\",\"2b4eb80c3782b8cd2a35c1a2b6ba18e4\",0,0,\"\""},
    //5. clientID
    {"AT+MQTTCLIENTID=0,\"MEMBER-WSW202410141212003170\""},
    //6. 连接服务器
    {"AT+MQTTCONN=0,\"192.168.1.11\",1883,1"},
    //7. 订阅指令
    {"AT+MQTTSUB=0,\"member/room\",1"},
    //8. 发布消息
    {"AT+MQTTPUB=0,\"member/room\",\"{\\\"message\\\":\\\"online\\\"}\",1,0"},
};

uint8_t Num = 0;
uint8_t KEY_Num = 0;

int main()
{
        MM_InitConsole(9600);
        MM_InitDelay();
        OnBoard_LED_Init();
        OnBoard_KEY_Init();
        ESP8266_Init();
        while(1)
        {
                KEY_Num = OnBoard_KEY_Get();
      if(KEY_Num == 1)
      {
            if(Num <= 6)
            {
               // 本次使用按键进行一步步配置
                ESP8266_AT_Command(ESP8266_SEND_STR);
                Num++;
            }
      
      }
        }
}
```

3. 测试截图

![录制_2025_06_13_13_21_38_87900_00_00-00_00_30.gif](data/attachment/forum/202506/13/135313bqkkbw6q3o7wtvgl.gif "录制_2025_06_13_13_21_38_879 00_00_00-00_00_30.gif")

![录制_2025_06_13_13_21_55_70200_00_00-00_00_30.gif](data/attachment/forum/202506/13/135313yxq0em11mhqhqxce.gif "录制_2025_06_13_13_21_55_702 00_00_00-00_00_30.gif")
可见已经实现链接并支持接收不定长的mqtt数据,下一步就是进行mqtt数据解析和实现指令判断等操作

4. 解析mqtt协议并实现指令控制led灯,开发板按键发送key2到小程序
   使用cjson库实现解析,具体解析方式按照自己的处理方式进行即可,无所谓

```c
// 函数:提取以 { 开头、以 } 结尾的数据
   char* extract_bracket_data(char* input_str) {
   if (input_str == NULL) {return NULL;}
   // 1. 定位第一个 '{' 的位置
   const char* start = strchr(input_str, '{');
   if (start == NULL) {
   return NULL; // 没有找到 '{'
   }
   // 2. 从 start 开始查找对应的 '}'
   const char* end = strchr(start, '}');
   if (end == NULL) {
   return NULL; // 没有找到 '}'
   }
   // 3. 计算子字符串长度(包括 '{' 和 '}')
   size_t length = end - start + 1;
   // 4. 分配内存并复制数据
   char* result = (char*)malloc(length + 1); // +1 用于终止符
   if (result == NULL) {
   return NULL; // 内存分配失败
   }
   strncpy(result, start, length);
   result = '\0'; // 确保字符串以 '\0' 结尾
   return result;
   }
``````c
void to_upper(char *str) {
    strcpy(mqtt_key, str); // 缓冲区溢出!
    int i = 0;
    for (i = 0; mqtt_key != '\0'; i++) {
      mqtt_key = toupper(mqtt_key);
    }
    mqtt_key = '\0';
}


void Action_MqttKey()
{
    // Parse_MQTT_Data();
    to_upper(MQTT_Data);
    if(strcmp(mqtt_key, "LED1") == 0)
    {
      OnBoard_LED_Toggle(GPIOB, 14);
    }
        if(strcmp(mqtt_key, "LED2") == 0)
    {
      OnBoard_LED_Toggle(GPIOB, 15);
    }
    Clear_MQTT_Data();
}
```

```c
int main()
{
        MM_InitConsole(9600);
        MM_InitDelay();
        OnBoard_LED_Init();
        OnBoard_KEY_Init();
        ESP8266_Init();
        while(1)
        {
                KEY_Num = OnBoard_KEY_Get();
      if(KEY_Num == 1)
      {
            if(Num <= 6)
            {
                ESP8266_AT_Command(ESP8266_SEND_STR);
                Num++;
            }
      }
                if(KEY_Num == 2)
                {
                        ESP8266_AT_Command("AT+MQTTPUB=0,\"member/room\",\"{\\\"message\\\":\\\"KEY2\\\"}\",1,0");
                }
        }
}
```

!(data/attachment/forum/202506/13/144039m8dly8yq0cnya33j.gif "420974df32cf51c66d8f09e8126114f5 00_00_00-00_00_30~2.gif")

**总结**

通过ESP8266和MQTT协议,我们成功实现了LED的远程控制,验证了物联网设备通信的基本流程。此项目可作为智能家居、工业自动化等场景的入门基础。后续可通过添加传感器、优化代码逻辑,进一步扩展功能。

雨果喝水 发表于 2025-6-30 22:17

推荐使用 3.3V 逻辑电平转换器确保信号兼容性

jf101 发表于 2025-6-30 23:21

使用esp8266实现数据传输

lemonhub 发表于 2025-7-2 22:36

能否提供完整的工程代码呢

scafel 发表于 2025-7-3 08:26

lemonhub 发表于 2025-7-2 22:36
能否提供完整的工程代码呢

文章最开始有附件下载
页: [1]
查看完整版本: 【灵动微电子MM32F0121测评】使用esp8266实现数据传输