打印
[MM32硬件]

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

[复制链接]
1226|4
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
scafel|  楼主 | 2025-6-13 14:41 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式

[i=s] 本帖最后由 scafel 于 2025-7-3 08:25 编辑 [/i]<br /> <br />

upload 源代码文件:Demo.rar

原创申请

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

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

硬件清单

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

软件和MQTT服务

  • 使用本地搭建的MQTT服务
  • 本人编写的小程序
  1. 按照接线图链接开发板和ESP8266-01S模块

微信图片_20250613133518.jpg

  1. 书写串口代码,并测试是否可用
#include <mm32_device.h>
#include <stdio.h>
#include <string.h>
#include "ESP8266.h"



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

void ESP8266_Init(void)
{
    GPIO_InitTypeDef  GPIO_InitStruct;
    NVIC_InitTypeDef  NVIC_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[RX_BUFFER_SIZE];
    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[pRxPacket++] = 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[][200] =
{
    {"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]);
                Num++;
            }

        }
    }
}
  1. 测试截图

录制_2025_06_13_13_21_38_87900_00_00-00_00_30.gif

录制_2025_06_13_13_21_55_70200_00_00-00_00_30.gif 可见已经实现链接并支持接收不定长的mqtt数据,下一步就是进行mqtt数据解析和实现指令判断等操作

  1. 解析mqtt协议并实现指令控制led灯,开发板按键发送key2到小程序 使用cjson库实现解析,具体解析方式按照自己的处理方式进行即可,无所谓
// 函数:提取以 { 开头、以 } 结尾的数据
   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[length] = '\0'; // 确保字符串以 '\0' 结尾
   return result;
   }
``````c
void to_upper(char *str) {
    strcpy(mqtt_key, str); // 缓冲区溢出!
    int i = 0;
    for (i = 0; mqtt_key[i] != '\0'; i++) {
        mqtt_key[i] = toupper(mqtt_key[i]);
    }
    mqtt_key[i] = '\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();
}
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]);
                Num++;
            }  
        }
        if(KEY_Num == 2)
        {
            ESP8266_AT_Command("AT+MQTTPUB=0,\"member/room\",\"{\\\"message\\\":\\\"KEY2\\\"}\",1,0");
        }
    }
}

420974df32cf51c66d8f09e8126114f500_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 | 只看该作者
能否提供完整的工程代码呢

使用特权

评论回复
5
scafel|  楼主 | 2025-7-3 08:26 | 只看该作者
lemonhub 发表于 2025-7-2 22:36
能否提供完整的工程代码呢

文章最开始有附件下载

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

3

主题

31

帖子

0

粉丝