【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協議具有以下幾個重要的信號線:
- SCLK:時鐘線,由主設備提供,用于同步主從設備之間的數據傳輸。
- MOSI(Master Out Slave In):主輸出從輸入線,由主設備提供,用于向從設備發送數據。
- MISO(Master In Slave Out):主輸入從輸出線,由從設備提供,用于向主設備發送數據。
- 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;
}
}
-
單片機
+關注
關注
6035文章
44554瀏覽量
634642 -
物聯網
+關注
關注
2909文章
44557瀏覽量
372778 -
網卡
+關注
關注
4文章
307瀏覽量
27374 -
STM32
+關注
關注
2270文章
10895瀏覽量
355740 -
華為云
+關注
關注
3文章
2445瀏覽量
17408
發布評論請先 登錄
相關推薦
評論