Complete MQTT Implementation Example for STM32 (STM32F407 + Ethernet)

 Here's a step-by-step guide with code examples to implement MQTT communication on an STM32F407 Discovery board with Ethernet (LAN8720 PHY). We'll use FreeRTOS, LwIP, and Eclipse Paho MQTT.



1. Hardware Setup

  • Board: STM32F407 Discovery (with RMII Ethernet)

  • PHY: LAN8720 (built-in)

  • Network: Router with DHCP

  • MQTT Broker: test.mosquitto.org (public broker)

2. Software Configuration (STM32CubeMX)

  1. Create Project:

    • Select STM32F407VG in CubeMX

    • Enable ETH in Connectivity

    • Enable RMII interface

    • Enable LWIP in Middleware

    • Enable FreeRTOS

  2. Clock Configuration:

    • Set HCLK to 168MHz

    • Enable MCO1 to output 50MHz for PHY

  3. Generate Code:

    • Generate with Toolchain: SW4STM32 (or your preferred IDE)


3. Project Structure

text
YourProject/
├── Core/
│   ├── Inc/
│   │   ├── mqtt_client.h
│   │   ├── network.h
│   ├── Src/
│   │   ├── mqtt_client.c
│   │   ├── network.c
├── LWIP/
├── Middleware/
│   ├── eclipse-paho-mqtt/ (Paho MQTT embedded-C)
├── Drivers/

4. Porting Paho MQTT

  1. Download Paho MQTT Embedded C:

    bash
    git clone https://github.com/eclipse/paho.mqtt.embedded-c
  2. Copy to Project:

    • Add MQTTPacket/src to your project.

    • Exclude SSLSocket.c (unless using TLS).

  3. Modify transport.c for LwIP:

    c
    int transport_sendPacketBuffer(int sock, unsigned char* buf, int buflen) {
        return netconn_write(sock, buf, buflen, NETCONN_COPY);
    }
    
    int transport_getdata(unsigned char* buf, int count) {
        return netconn_recv(sock, buf, count, NETCONN_COPY);
    }

5. Network Initialization

network.c

c
#include "lwip/netif.h"
#include "lwip/dhcp.h"

struct netif gnetif; // Global network interface

void Network_Init(void) {
    ip_addr_t ipaddr, netmask, gw;

    // Initialize LwIP stack
    MX_LWIP_Init();

    // Start DHCP
    netif_set_up(&gnetif);
    dhcp_start(&gnetif);

    // Wait for IP
    while (netif_is_up(&gnetif) == 0 || ip_addr_isany_val(*netif_ip4_addr(&gnetif))) {
        osDelay(100);
    }
}

6. MQTT Client Implementation

mqtt_client.c

c
#include "MQTTClient.h"
#include "network.h"

#define MQTT_BROKER "test.mosquitto.org"
#define MQTT_PORT 1883
#define CLIENT_ID "STM32F407_Client"

Network network;
MQTTClient client;

void messageArrived(MessageData* data) {
    char msg[50];
    memcpy(msg, data->message->payload, data->message->payloadlen);
    printf("Received: %s\n", msg);
}

void MQTT_Init(void) {
    NetworkInit(&network);
    MQTTClientInit(&client, &network, 3000, sendbuf, sizeof(sendbuf), readbuf, sizeof(readbuf));

    MQTTPacket_connectData config = MQTTPacket_connectData_initializer;
    config.clientID.cstring = CLIENT_ID;
    config.keepAliveInterval = 60;
    config.cleansession = 1;

    int rc = MQTTConnect(&client, &config);
    if (rc != 0) printf("MQTT Connect failed: %d\n", rc);
    else printf("Connected to MQTT Broker\n");

    MQTTSubscribe(&client, "stm32/sub", QOS1, messageArrived);
}

void MQTT_Publish(const char* topic, const char* payload) {
    MQTTMessage message;
    message.qos = QOS1;
    message.retained = 0;
    message.payload = (void*)payload;
    message.payloadlen = strlen(payload);
    MQTTPublish(&client, topic, &message);
}

7. Main Application

main.c

c
#include "mqtt_client.h"
#include "cmsis_os.h"

void StartMQTTTask(void const * argument) {
    MQTT_Init();

    while (1) {
        MQTT_Publish("stm32/pub", "{\"temp\":25}");
        osDelay(5000); // Publish every 5 sec
    }
}

int main(void) {
    HAL_Init();
    SystemClock_Config();
    MX_LWIP_Init();
    osThreadDef(MQTT_Task, StartMQTTTask, osPriorityNormal, 0, 1024);
    osThreadCreate(osThread(MQTT_Task), NULL);
    osKernelStart();
}

8. Testing

  1. Connect STM32 to Ethernet.

  2. Monitor Serial Output (UART debug):

    text
    Connected to MQTT Broker
    Published: {"temp":25}
  3. Test with MQTT Client (e.g., mosquitto_sub):

    bash
    mosquitto_sub -h test.mosquitto.org -t "stm32/pub"

9. Troubleshooting

IssueSolution
No Ethernet LinkCheck PHY (LAN8720) reset, RMII pins
DHCP FailsAssign static IP in network.c
MQTT TimeoutVerify broker IP, firewall settings
Memory OverflowAdjust MEM_SIZE in lwipopts.h

10. Enhancements

  • MQTT over TLS: Use mbedTLS for encryption.

  • JSON Payloads: Integrate cJSON for structured data.

  • OTA Updates: Subscribe to firmware topics.

评论

此博客中的热门博文

Detailed Explanation of STM32 HAL Library Clock System

How To Connect Stm32 To PC?

How to add a GPS sensor to ESP32 for Wokwi?