STM32配合W5500网卡连接MQTT服务器

简介: W5500是一种基于TCP/IP协议的网络通讯芯片,可以提供网络连接功能,相当于是一种嵌入式以太网控制器,具有低功耗、高速传输、易于集成等特点。

【1】W5500网卡

W5500是一种基于TCP/IP协议的网络通讯芯片,可以提供网络连接功能,相当于是一种嵌入式以太网控制器,具有低功耗、高速传输、易于集成等特点。W5500芯片能够支持TCP、UDP、IPv4、ARP、ICMP、IGMP等协议,使得它变得非常适合用于嵌入式设备与互联网之间的通信需求,例如智能家居、工业控制、远程监控等场景。W5500网卡还有一个特点是它支持硬件协议堆栈,这意味着它可以非常快地执行协议栈中的操作,从而大大提高了数据传输的效率。同时,W5500还具有较低的功耗,因此非常适合嵌入式设备这种资源受限的场景。

W5500芯片通过SPI总线与MCU进行通信,MCU需要实现SPI总线协议来控制W5500进行数据交互。

【2】SPI协议

SPI(Serial Peripheral Interface)协议是一种串行外设接口协议,是一种全双工、同步的接口技术,通常用于连接微控制器和外设,例如传感器、存储器、显示器等。SPI协议传输效率高,使用简单,开销较小,因此被广泛应用于嵌入式系统中。

SPI协议使用主从模式,主设备可以控制多个从设备,从设备不能主动向主设备发送数据或信息。SPI协议具有以下几个重要的信号线:

  1. SCLK:时钟线,由主设备提供,用于同步主从设备之间的数据传输。
  2. MOSI(Master Out Slave In):主输出从输入线,由主设备提供,用于向从设备发送数据。
  3. MISO(Master In Slave Out):主输入从输出线,由从设备提供,用于向主设备发送数据。
  4. SS(Slave Select):从设备选择信号线,由主设备提供。当主设备需要与某个从设备通信时,将该线电平拉低,以选择需要通信的从设备。

SPI协议的数据传输是基于数据字节的传输,主设备每次通过MOSI线发送一个字节,从设备通过MISO线接受该字节,并回传一个字节。数据的传输顺序可以根据时钟线(SCLK)的极性和相位配置为四种不同的模式。SPI协议支持的模式受闪存、RAM、I/O和模拟/数字转换器等外设和类型的限制。

【3】W5500建立TCP协议通信

以下是STM32通过W5500建立TCP通信,并访问TCP服务器,完成数据收发的示例代码。

代码中使用了STM32 HAL库,W5500的IP地址和端口号需要根据实际情况进行设置。

#include "main.h"
#include "stdio.h"
#include "stm32f1xx_hal.h"
#include "wizchip_conf.h"
#include "socket.h"
#include "dhcp.h"

/* Private variables */
SPI_HandleTypeDef hspi1;

/* Private function prototypes */
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_SPI1_Init(void);
void W5500_Init(void);
uint8_t socket;
uint8_t buf[1024];

int main(void)
{
   
  /* MCU Configuration */
  HAL_Init();
  SystemClock_Config();
  MX_GPIO_Init();
  MX_SPI1_Init();

  /* W5500 Initialization */
  W5500_Init();

  /* Connect to TCP Server */
  uint8_t server_ip[4] = {
   192, 168, 1, 100};
  uint16_t server_port = 5000;
  uint8_t connected = 0;

  while (!connected)
  {
   
    if (getSn_SR(socket) == SOCK_CLOSED)
    {
   
      socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
      if (socket == 0xFF)
      {
   
        /* Error: Failed to create socket */
      }
      else
      {
   
        /* Configure socket */
        uint8_t dest_ip[4] = {
   192, 168, 1, 200};
        uint16_t dest_port = 5000;
        uint8_t buf[4];
        IINCHIP_WRITE(Sn_DIPR(socket), dest_ip);
        IINCHIP_WRITE(Sn_DPORT(socket), dest_port);
        IINCHIP_SOCKET_CONTROL(socket, Sn_CR_OPEN);
        HAL_Delay(10);

        /* Try to connect to server */
        IINCHIP_SOCKET_CONTROL(socket, Sn_CR_CONNECT);
        HAL_Delay(1000);
        if (getSn_SR(socket) == SOCK_ESTABLISHED)
        {
   
          connected = 1;
        }
        else
        {
   
          /* Connection failed */
          IINCHIP_SOCKET_CONTROL(socket, Sn_CR_CLOSE);
          HAL_Delay(10);
        }
      }
    }
  }

  /* Send Data to Server */
  uint8_t tx_data[4] = {
   0x01, 0x02, 0x03, 0x04};
  write(socket, tx_data, sizeof(tx_data));

  /* Receive Data from Server */
  int rx_len = 0;
  while (1)
  {
   
    rx_len = getSn_RX_RSR(socket);
    if (rx_len > 0)
    {
   
      read(socket, buf, rx_len);
      /* Data received from server, do something */
    }
= SPI_DIRECTION_2LINES;
hspi1.Init.DataSize = SPI_DATASIZE_8BIT;
hspi1.Init.CLKPolarity = SPI_POLARITY_LOW;
hspi1.Init.CLKPhase = SPI_PHASE_1EDGE;
hspi1.Init.NSS = SPI_NSS_SOFT;
hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_128;
hspi1.Init.FirstBit = SPI_FIRSTBIT_MSB;
hspi1.Init.TIMode = SPI_TIMODE_DISABLE;
hspi1.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
hspi1.Init.CRCPolynomial = 10;
HAL_SPI_Init(&hspi1);
}
/* GPIO Initialization */
static void MX_GPIO_Init(void) 
{
   
GPIO_InitTypeDef GPIO_InitStruct = {
   0};
__HAL_RCC_GPIOA_CLK_ENABLE();
/*Configure GPIO pin : PA4 */
GPIO_InitStruct.Pin = GPIO_PIN_4;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
}
/* System Clock Configuration */
void SystemClock_Config(void) 
{
   
RCC_OscInitTypeDef RCC_OscInitStruct = {
   0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {
   0};
/** Initializes the RCC Oscillators according to the specified parameters
in the RCC_OscInitTypeDef structure. */
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) 
{
   
    Error_Handler();
}
/** Initializes the CPU, AHB and APB buses clocks */
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK) 
{
   
    Error_Handler();
}
}

【4】封装MQTT协议报文

下面使用MQTT client library for Contiki来连接MQTT服务器。这个库适用于不同的平台,包括STM32。在使用前,需要根据需求进行一些配置,例如: 指定MQTT服务器的地址和端口号,配置MQTT客户端ID和主题等。

#include "contiki.h"
#include "contiki-net.h"
#include "mqtt.h"

#include "stm32f1xx_hal.h"
#include "wizchip_conf.h"
#include "w5500.h"

/* MQTT Configuration */
#define SERVER_IP_ADDR "192.168.1.100"
#define SERVER_PORT 1883
#define MQTT_CLIENT_ID "mqtt_stm32"
#define MQTT_TOPIC "example_topic"

/* Network Configuration */
static wiz_NetInfo gWIZNETINFO = {
    .mac = {
   0x01, 0x02, 0x03, 0x04, 0x05, 0x06},
                                   .ip = {
   192, 168, 1, 200},
                                   .sn = {
   255, 255, 255, 0},
                                   .gw = {
   192, 168, 1, 1},
                                   .dns = {
   8, 8, 8, 8},
                                   .dhcp = NETINFO_STATIC };

/* W5500 Buffer */
static uint8_t buf[2048];

/* Prototypes */
static void MX_SPI1_Init(void);
static void MX_GPIO_Init(void);
void SystemClock_Config(void);
void Error_Handler(void);
void W5500_Select(void);
void W5500_UnSelect(void);
uint8_t W5500_WriteByte(uint8_t b);
uint8_t W5500_ReadByte(void);
void MQTT_Callback(struct mqtt_connection *m, void *userdata, mqtt_event_t event, mqtt_data_t *data);

/* MQTT Connection */
static struct mqtt_connection mqtt_conn;
static struct mqtt_message *msg_ptr = NULL;
static uint8_t mqtt_connected = 0;

PROCESS(mqtt_process, "MQTT Process");

AUTOSTART_PROCESSES(&mqtt_process);

/* MQTT Process */
PROCESS_THREAD(mqtt_process, ev, data)
{
   
  PROCESS_BEGIN();

  /* Initialize W5500 */
  reg_wizchip_cs_cbfunc(W5500_Select, W5500_UnSelect);
  reg_wizchip_spi_cbfunc(W5500_ReadByte, W5500_WriteByte);
  wizchip_init(buf, buf);

  /* Configure Network */
  ctlnetwork(CN_SET_NETINFO, (void*)&(gWIZNETINFO));

  /* DHCP Initialization */
  uint8_t /* Enable DHCP */ dhcp_client_start();

/* Wait for DHCP to finish */
while (gWIZNETINFO.dhcp == NETINFO_DHCP) 
{
   
    HAL_Delay(1000);
    // wait for DHCP to finish }
    /* Print IP Address */
    printf("IP address: %d.%d.%d.%d\n", gWIZNETINFO.ip[0], gWIZNETINFO.ip[1], gWIZNETINFO.ip[2], gWIZNETINFO.ip[3]);
    /* Configure MQTT Connection */
    memset(&mqtt_conn, 0, sizeof(mqtt_conn));
    mqtt_conn.state = MQTT_INIT;
    mqtt_conn.host = SERVER_IP_ADDR;
    mqtt_conn.port = SERVER_PORT;
    mqtt_conn.client_id = MQTT_CLIENT_ID;
    mqtt_conn.user_data = NULL;
    mqtt_conn.user_name = NULL;
    mqtt_conn.password = NULL;
    mqtt_conn.protocol_version = MQTT_VERSION_3_1_1;
    mqtt_conn.keep_alive = 60;
    /* Connect to MQTT Server */
    mqtt_connect(&mqtt_conn);
    /* Wait for MQTT Connection to Finish */
    while (!mqtt_connected) 
    {
   
        PROCESS_PAUSE();
    }
    /* Publish Message to MQTT Server */
    static char msg[100] = "Hello from STM32 using MQTT protocol!";
    msg_ptr = mqtt_msg_publish_init(msg, strlen(msg), MQTT_TOPIC, MQTT_QOS_LEVEL_0, MQTT_RETAIN_OFF);
    mqtt_publish(&mqtt_conn, msg_ptr);
    /* Wait for Message to be Sent */
    while (mqtt_conn.out_buffer_sent == 0) 
    {
   
        PROCESS_PAUSE();
    }
    /* Subscribe to MQTT Topic */
    mqtt_subscribe(&mqtt_conn, MQTT_TOPIC, MQTT_QOS_LEVEL_0);
    /* Loop Forever */
    while (1) 
    {
   
        PROCESS_PAUSE();
    }
    PROCESS_END();
}


/* SPI Initialization / static void MX_SPI1_Init(void) { / SPI1 parameter configuration*/
hspi1.Instance = SPI1;
hspi1.Init.Mode = SPI_MODE_MASTER;
hspi1.Init.Direction = SPI_DIRECTION_2LINES;
hspi1.Init.DataSize = SPI_DATASIZE_8BIT;
hspi1.Init.CLKPolarity = SPI_POLARITY_LOW;
hspi1.Init.CLKPhase = SPI_PHASE_1EDGE;
hspi1.Init.NSS = SPI_NSS_SOFT;
hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_128;
hspi1.Init.FirstBit = SPI_FIRSTBIT_MSB;
hspi1.Init.TIMode = SPI_TIMODE_DISABLE;
hspi1.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
hspi1.Init.CRCPolynomial = 10;
HAL_SPI_Init(&hspi1);
}
/* GPIO Initialization */
static void MX_GPIO_Init(void) 
{
   
GPIO_InitTypeDef GPIO_InitStruct = {
   0};
__HAL_RCC_GPIOA_CLK_ENABLE();
/*Configure GPIO pin : PA4 */
GPIO_InitStruct.Pin = GPIO_PIN_4;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
}
/* System Clock Configuration */
void SystemClock_Config(void) 
{
   
RCC_OscInitTypeDef RCC_OscInitStruct = {
   0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {
   0};
/** Initializes the RCC Oscillators according to the specified parameters
in the RCC_OscInitTypeDef structure. */
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) 
{
   
    Error_Handler();
}
/** Initializes the CPU, AHB and APB buses clocks */
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK) 
{
   
    Error_Handler();
}

}

/* Error Handler */
void Error_Handler(void) 
{
   
while (1) 
{
   
    // error } }
    /* W5500 Select */
    void W5500_Select(void) 
    {
   
        HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_RESET);
    }
    /* W5500 Unselect */
    void W5500_UnSelect(void) 
    {
   
        HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_SET);
    }
    /* W5500 Write Byte */
    uint8_t W5500_Writebyte(uint8_t b) 
    {
   
        uint8_t res;
        HAL_SPI_TransmitReceive(&hspi1, &b, &res, 1, HAL_MAX_DELAY);
        return res;
    }

/* W5500 Read
byte */ uint8_t W5500_Readbyte(void) 
{
   
    uint8_t b = 0xff;
    HAL_SPI_TransmitReceive(&hspi1, &b, &b, 1, HAL_MAX_DELAY);
    return b;
}
/* MQTT Callback */
void MQTT_Callback(struct mqtt_connection *m, void *userdata, mqtt_event_t event, mqtt_data_t *data) 
{
   
    switch (event) 
    {
   
        case MQTT_EVENT_CONNECTED: printf("MQTT connected\n");
        mqtt_connected = 1;
        break;
        case MQTT_EVENT_DISCONNECTED: printf("MQTT disconnected\n");
        mqtt_connected = 0;
        break;
        case MQTT_EVENT_PUBLISHED: printf("MQTT message published\n");
        break;
        case MQTT_EVENT_SUBACK: printf("MQTT subscribed to topic\n");
        break;
        case MQTT_EVENT_UNSUBACK: printf("MQTT unsubscribed from topic\n");
        break;
        case MQTT_EVENT_DATA: printf("MQTT received message\n");
        printf("Topic: %.*s\n", data->topic_name_size, data->topic_name);
        printf("Message: %.*s\n", data->data_size, (char *)data->data);
        break;
        default: break;
    }
}
相关实践学习
消息队列RocketMQ版:基础消息收发功能体验
本实验场景介绍消息队列RocketMQ版的基础消息收发功能,涵盖实例创建、Topic、Group资源创建以及消息收发体验等基础功能模块。
消息队列 MNS 入门课程
1、消息队列MNS简介 本节课介绍消息队列的MNS的基础概念 2、消息队列MNS特性 本节课介绍消息队列的MNS的主要特性 3、MNS的最佳实践及场景应用 本节课介绍消息队列的MNS的最佳实践及场景应用案例 4、手把手系列:消息队列MNS实操讲 本节课介绍消息队列的MNS的实际操作演示 5、动手实验:基于MNS,0基础轻松构建 Web Client 本节课带您一起基于MNS,0基础轻松构建 Web Client
目录
相关文章
|
2月前
|
IDE 网络安全 开发工具
IDE之vscode:连接远程服务器代码(亲测OK),与pycharm链接服务器做对比(亲自使用过了),打开文件夹后切换文件夹。
本文介绍了如何使用VS Code通过Remote-SSH插件连接远程服务器进行代码开发,并与PyCharm进行了对比。作者认为VS Code在连接和配置多个服务器时更为简单,推荐使用VS Code。文章详细说明了VS Code的安装、远程插件安装、SSH配置文件编写、服务器连接以及如何在连接后切换文件夹。此外,还提供了使用密钥进行免密登录的方法和解决权限问题的步骤。
556 0
IDE之vscode:连接远程服务器代码(亲测OK),与pycharm链接服务器做对比(亲自使用过了),打开文件夹后切换文件夹。
|
2月前
|
IDE 网络安全 开发工具
IDE之pycharm:专业版本连接远程服务器代码,并配置远程python环境解释器(亲测OK)。
本文介绍了如何在PyCharm专业版中连接远程服务器并配置远程Python环境解释器,以便在服务器上运行代码。
345 0
IDE之pycharm:专业版本连接远程服务器代码,并配置远程python环境解释器(亲测OK)。
|
2月前
|
存储 网络协议 Java
【网络】UDP回显服务器和客户端的构造,以及连接流程
【网络】UDP回显服务器和客户端的构造,以及连接流程
55 2
|
2月前
|
Apache 数据中心 Windows
将网站迁移到阿里云Windows系统云服务器,访问该站点提示连接被拒绝,如何处理?
将网站迁移到阿里云Windows系统云服务器,访问该站点提示连接被拒绝,如何处理?
|
2月前
|
弹性计算 安全 Windows
通过远程桌面连接Windows服务器提示“由于协议错误,会话将被中断,请重新连接到远程计算机”错误怎么办?
通过远程桌面连接Windows服务器提示“由于协议错误,会话将被中断,请重新连接到远程计算机”错误怎么办?
|
12天前
|
人工智能 弹性计算 编解码
阿里云GPU云服务器性能、应用场景及收费标准和活动价格参考
GPU云服务器作为阿里云提供的一种高性能计算服务,通过结合GPU与CPU的计算能力,为用户在人工智能、高性能计算等领域提供了强大的支持。其具备覆盖范围广、超强计算能力、网络性能出色等优势,且计费方式灵活多样,能够满足不同用户的需求。目前用户购买阿里云gpu云服务器gn5 规格族(P100-16G)、gn6i 规格族(T4-16G)、gn6v 规格族(V100-16G)有优惠,本文为大家详细介绍阿里云gpu云服务器的相关性能及收费标准与最新活动价格情况,以供参考和选择。
|
17天前
|
机器学习/深度学习 人工智能 弹性计算
什么是阿里云GPU云服务器?GPU服务器优势、使用和租赁费用整理
阿里云GPU云服务器提供强大的GPU算力,适用于深度学习、科学计算、图形可视化和视频处理等多种场景。作为亚太领先的云服务提供商,阿里云的GPU云服务器具备灵活的资源配置、高安全性和易用性,支持多种计费模式,帮助企业高效应对计算密集型任务。
|
19天前
|
存储 分布式计算 固态存储
阿里云2核16G、4核32G、8核64G配置云服务器租用收费标准与活动价格参考
2核16G、8核64G、4核32G配置的云服务器处理器与内存比为1:8,这种配比的云服务器一般适用于数据分析与挖掘,Hadoop、Spark集群和数据库,缓存等内存密集型场景,因此,多为企业级用户选择。目前2核16G配置按量收费最低收费标准为0.54元/小时,按月租用标准收费标准为260.44元/1个月。4核32G配置的阿里云服务器按量收费标准最低为1.08元/小时,按月租用标准收费标准为520.88元/1个月。8核64G配置的阿里云服务器按量收费标准最低为2.17元/小时,按月租用标准收费标准为1041.77元/1个月。本文介绍这些配置的最新租用收费标准与活动价格情况,以供参考。
|
17天前
|
机器学习/深度学习 人工智能 弹性计算
阿里云GPU服务器全解析_GPU价格收费标准_GPU优势和使用说明
阿里云GPU云服务器提供强大的GPU算力,适用于深度学习、科学计算、图形可视化和视频处理等场景。作为亚太领先的云服务商,阿里云GPU云服务器具备高灵活性、易用性、容灾备份、安全性和成本效益,支持多种实例规格,满足不同业务需求。
|
25天前
|
弹性计算
阿里云2核16G服务器多少钱一年?亲测价格查询1个月和1小时收费标准
阿里云2核16G服务器提供多种ECS实例规格,内存型r8i实例1年6折优惠价为1901元,按月收费334.19元,按小时收费0.696221元。更多规格及详细报价请访问阿里云ECS页面。
63 9