博客 / 詳情

返回

《ESP32-S3使用指南—IDF版 V1.6》第五十二章 UDP實驗

第五十二章 UDP實驗

對於lwIP的Socket的使用方式,它與文件操作非常相似。在文件操作中,我們首先打開文件,然後進行讀/寫操作,最後關閉文件。在TCP/IP網絡通信中,也存在着相同的操作流程,但所使用的接口不再是文件描述符或FILE*,而是被稱為Socket的描述符。通過Socket,我們可以進行讀、寫、打開和關閉操作來進行網絡數據的傳輸。此外,還有一些輔助函數,如查詢域名/IP地址和設置Socket功能等。在本章中,我們將使用Socket編程接口來實現UDP實驗。
本章分為如下幾個部分:
52.1 Socket編程UDP連接流程
52.2 硬件設計
52.3 軟件設計
52.4 下載驗證

52.1 Socket編程UDP連接流程

在實現UDP協議之前,用户需要按照以下步驟配置結構體sockaddr_in的成員變量,以便建立UDP連接:
①:配置ESP32-S3設備連接網絡(必須的,因為WiFi是無線通信,所以需搭建通信橋樑)。
②:將sin_family設置為AF_INET,表示使用IPv4網絡協議。
③:設置sin_port為所需的端口號,例如8080。
④:設置sin_addr.s_addr為本地IP地址。
⑤:調用函數Socket創建Socket連接。請注意,該函數的第二個參數指定連接類型。SOCK_STREAM表示TCP連接,而SOCK_DGRAM表示UDP連接。
⑥:調用函數bind將本地服務器地址與Socket進行綁定。
⑦:調用適當的收發函數來接收或發送數據。
通過遵循這些步驟,用户可以成功地配置並建立UDP連接,以實現數據的發送和接收。

52.2 硬件設計

1.例程功能
本章實驗功能簡介:
本實驗主要通過Socket編程接口實現了一個UDP服務器。這個服務器具有以下功能:
①:可以通過按鍵發送UDP廣播數據給其他UDP客户端。
②:能夠接收其他UDP客户端發送的廣播數據。
③:實時將接收到的數據顯示在LCD屏幕上。
通過這個實驗,用户可深入瞭解UDP協議的工作原理,並掌握如何使用Socket編程接口來實現UDP通信。這對於開發基於UDP的網絡應用程序非常有用,例如實時通信、多播應用等。

2.硬件資源
1)LED燈
LED-IO1
2)XL9555
IIC_INT-IO0(需在P5連接IO0)
IIC_SDA-IO41
IIC_SCL-IO42
3)SPILCD
CS-IO21
SCK-IO12
SDA-IO11
DC-IO40(在P5端口,使用跳線帽將IO_SET和LCD_DC相連)
PWR- IO1_3(XL9555)
RST- IO1_2(XL9555)
4)ESP32-S3內部WiFi

3.原理圖
本章實驗使用的WiFi為ESP32-S3的片上資源,因此並沒有相應的連接原理圖。

52.3 軟件設計

52.3.1 程序流程圖
程序流程圖能幫助我們更好的理解一個工程的功能和實現的過程,對學習和設計工程有很好的主導作用。下面看看本實驗的程序流程圖:

圖52.3.1.1 程序流程圖

52.3.2 程序解析

在本章節中,我們主要關注兩個文件:lwip_demo.c和lwip_demo.h。lwip_demo.h文件主要定義了發送標誌位並聲明瞭lwip_demo函數,這部分相對簡單,所以我們暫不詳細解釋。主要關注點是lwip_demo.c文件中的函數。在lwip_demo函數中,我們配置了相關的UDP參數,並創建了一個名為lwip_send_thread的發送數據線程。這個線程通過調用scokec函數來發送數據到服務器。接下來,我們將分別詳細解釋lwip_demo函數和lwip_send_thread任務。

/* 需要自己設置遠程IP地址 */
#define IP_ADDR   "192.168.101.33"

#define LWIP_DEMO_RX_BUFSIZE         200                    /* 最大接收數據長度 */
#define LWIP_DEMO_PORT               8080                   /* 連接的本地端口號 */
#define LWIP_SEND_THREAD_PRIO    ( tskIDLE_PRIORITY + 3 )     /* 發送數據線程優先級 */

/* 接收數據緩衝區 */
uint8_t g_lwip_demo_recvbuf[LWIP_DEMO_RX_BUFSIZE]; 
/* 發送數據內容 */
char g_lwip_demo_sendbuf[] = "ALIENTEK DATA \r\n";
/* 數據發送標誌位 */
uint8_t g_lwip_send_flag;
static struct sockaddr_in dest_addr;            /* 遠端地址 */
struct sockaddr_in g_local_info;
socklen_t g_sock_fd;                            /* 定義一個Socket接口 */
static void lwip_send_thread(void *arg);
extern QueueHandle_t g_display_queue;           /* 顯示消息隊列句柄 */


/**
 * @brief       發送數據線程
 * @param       無
 * @retval      無
 */
void lwip_data_send(void)
{
xTaskCreate(lwip_send_thread, "lwip_send_thread", 4096, 
NULL, LWIP_SEND_THREAD_PRIO, NULL);
}

/**
 * @brief       lwip_demo實驗入口
 * @param       無
 * @retval      無
 */
void lwip_demo(void)
{
    char *tbuf;
    lwip_data_send();                                      /* 創建發送數據線程 */
    /* 遠端參數設置 */
    dest_addr.sin_addr.s_addr = inet_addr(IP_ADDR);          /* 目標地址 */
    dest_addr.sin_family = AF_INET;
    dest_addr.sin_port = htons(LWIP_DEMO_PORT);             /* 目標端口 */
    
    g_local_info.sin_family = AF_INET;                       /* IPv4地址 */
    g_local_info.sin_port = htons(LWIP_DEMO_PORT);          /* 設置端口號 */
    g_local_info.sin_addr.s_addr = htons(INADDR_ANY);       /* 設置本地IP地址 */

    g_sock_fd = socket(AF_INET, SOCK_DGRAM, 0);        /* 建立一個新的socket連接 */
    
    tbuf = malloc(200);                                    /* 申請內存 */
    sprintf((char *)tbuf, "Port:%d", LWIP_DEMO_PORT);       /* 客户端端口號 */
    lcd_show_string(0, 170, 200, 16, 16, tbuf, MAGENTA);
    
    /* 建立綁定 */
    bind(g_sock_fd, (struct sockaddr *)&g_local_info, sizeof(g_local_info));

    while (1)
    {
        memset(g_lwip_demo_recvbuf, 0, sizeof(g_lwip_demo_recvbuf));
        recv(g_sock_fd, (void *)g_lwip_demo_recvbuf,
             sizeof(g_lwip_demo_recvbuf), 0);
        printf("%s\r\n",g_lwip_demo_recvbuf);
    }
}

/**
 * @brief       發送數據線程函數
 * @param       pvParameters : 傳入參數(未用到)
 * @retval      無
 */
void lwip_send_thread(void *pvParameters)
{
    pvParameters = pvParameters;

    while (1)
    {    /* 有數據要發送 */
        if ((g_lwip_send_flag & LWIP_SEND_DATA) == LWIP_SEND_DATA)    
        {
            printf("send\r\n");
            sendto(g_sock_fd,                           /* scoket */
                  (char *)g_lwip_demo_sendbuf,         /* 發送的數據 */
                  sizeof(g_lwip_demo_sendbuf), 0,        /* 發送的數據大小 */
                  (struct sockaddr *)&dest_addr,       /* 接收端地址信息 */ 
                  sizeof(dest_addr));                   /* 接收端地址信息大小 */

            g_lwip_send_flag &= ~LWIP_SEND_DATA;
        }
        
        vTaskDelay(100);
   }
}

在源碼中,lwip_demo函數通過lwip_data_send創建了發送數據的線程lwip_send_thread,並配置了Socket的UDP協議。該線程在發送前會檢查標誌位,有效時則通過sendto發送數據並重置標誌位。同時,需設置目標IP地址以確保數據正確發送。此外,主函數的循環中不斷通過recv接收數據並使用串口輸出接收的數據。

52.4 下載驗證

在程序中,首先需要設置好能夠連接的網絡賬號和密碼。然後,使用筆記本電腦作為終端,確保它與ESP32-S3設備處於同一網絡段內。當ESP32-S3設備成功連接到網絡時,它的LCD顯示屏上會顯示相應的內容:

圖52.4.1 設備連接到網絡時,LCD顯示的信息
打開網絡調試助手,然後配置網絡參數,如UDP協議、端口號、目標主機設置等,設置內容如下圖所示。

在確保網絡連接正常後,可以通過按下開發板上的KEY0按鍵來發送數據至網絡調試助手。當網絡調試助手接收到“ALIENTEK DATA”字符串時,它會在顯示區域展示這個信息。此外,用户還可以在調試助手的發送區域自行輸入要發送的數據,然後點擊發送鍵,將數據發送至ESP32-S3設備。此時,ESP32-S3的串口將打印接收到的數據,具體操作和輸出如下圖所示。

圖52.4.3 接收網絡調試助手的數據

user avatar
0 位用戶收藏了這個故事!

發佈 評論

Some HTML is okay.