STM32配合W5500网卡连接华为云物联网平台通信

描述

【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.%dn", 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 connectedn");
         mqtt_connected = 1;
         break;
         case MQTT_EVENT_DISCONNECTED: printf("MQTT disconnectedn");
         mqtt_connected = 0;
         break;
         case MQTT_EVENT_PUBLISHED: printf("MQTT message publishedn");
         break;
         case MQTT_EVENT_SUBACK: printf("MQTT subscribed to topicn");
         break;
         case MQTT_EVENT_UNSUBACK: printf("MQTT unsubscribed from topicn");
         break;
         case MQTT_EVENT_DATA: printf("MQTT received messagen");
         printf("Topic: %.*sn", data->topic_name_size, data->topic_name);
         printf("Message: %.*sn", data->data_size, (char *)data->data);
         break;
         default: break;
     }
 }
     
打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分