博客 / 詳情

返回

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

第五十四章 TCPServer實驗

1)實驗平台:正點原子DNESP32S3開發板

2)章節摘自【正點原子】ESP32-S3使用指南—IDF版 V1.6

3)購買鏈接:https://detail.tmall.com/item.htm?&id=768499342659

4)全套實驗源碼+手冊+視頻下載地址:http://www.openedv.com/docs/boards/esp32/ATK-DNESP32S3.html

5)正點原子官方B站:https://space.bilibili.com/394620890

6)正點原子DNESP32S3開發板技術交流羣:132780729

155537c2odj87vz1z9vj6l

155537nfqovl2gg9faaol9

本章筆者重點講解lwIP的Socket接口如何配置TCP服務器,並在此基礎上實現收發功能。
本章分為如下幾個部分:
54.1 Socket編程TCPServer連接流程
54.2 硬件設計
54.3 軟件設計
54.4 下載驗證

54.1 Socket編程TCPServer連接流程
在實現TCP協議之前,用户需要按照以下步驟配置結構體sockaddr_in的成員變量,以便建立TCPServer連接:
①:配置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綁定本地IP地址和端口號。
⑦:調用函數listen 監聽連接請求
⑧:調用函數accept監聽連接
⑨:調用適當的收發函數來接收或發送數據。
通過遵循這些步驟,用户可成功地配置並建立TCPServer連接,以實現數據的發送和接收。

54.2 硬件設計

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

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的片上資源,因此並沒有相應的連接原理圖。

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

image002

圖54.3.1.1 程序流程圖

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

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

#define LWIP_DEMO_RX_BUFSIZE	100              		/* 最大接收數據長度 */
#define LWIP_DEMO_PORT      	8080                	/* 連接的本地端口號 */
#define LWIP_SEND_THREAD_PRIO	( tskIDLE_PRIORITY + 3 )	/* 發送數據線程優先級 */
/* 接收數據緩衝區 */
uint8_t g_lwip_demo_recvbuf[LWIP_DEMO_RX_BUFSIZE]; 

/* 發送數據內容 */
uint8_t g_lwip_demo_sendbuf[] = "ALIENTEK DATA \r\n";
/* 數據發送標誌位 */
uint8_t g_lwip_send_flag;
int g_sock = -1;
int g_lwip_connect_state = 0;
static void lwip_send_thread(void *arg);


/**
 * @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)
{
    struct sockaddr_in atk_client_addr;
    err_t err;
    int recv_data_len;
    char *tbuf;
    
    lwip_data_send();                           	/* 創建發送數據線程 */
    
    while (1)
    {
sock_start:
        g_lwip_connect_state = 0;
        atk_client_addr.sin_family = AF_INET;             	/* 表示IPv4網絡協議 */
        atk_client_addr.sin_port = htons(LWIP_DEMO_PORT);	/* 端口號 */
        atk_client_addr.sin_addr.s_addr = inet_addr(IP_ADDR);	/* 遠程IP地址 */
        g_sock = socket(AF_INET, SOCK_STREAM, 0);/* 可靠數據流交付服務既是TCP協議 */
        memset(&(atk_client_addr.sin_zero), 0,
               sizeof(atk_client_addr.sin_zero));
        
        tbuf = malloc(200);                                     /* 申請內存 */
        sprintf((char *)tbuf, "Port:%d", LWIP_DEMO_PORT);       /* 客户端端口號 */
        lcd_show_string(5, 170, 200, 16, 16, tbuf, MAGENTA);
        
        /* 連接遠程IP地址 */
        err = connect(g_sock, (struct sockaddr *)&atk_client_addr, 
sizeof(struct sockaddr));

        if (err == -1)
        {
            lcd_show_string(5, 190, 200, 16, 16, "State:Disconnect", MAGENTA);
            g_sock = -1;
            closesocket(g_sock);
            free(tbuf);
            vTaskDelay(10);
            goto sock_start;
        }

        lcd_show_string(5,190,200,16,16,"State:Connection Successful", MAGENTA);
        g_lwip_connect_state = 1;
        
        while (1)
        {
            recv_data_len = recv(g_sock,g_lwip_demo_recvbuf,
                                 LWIP_DEMO_RX_BUFSIZE,0);
            if (recv_data_len <= 0 )
            {
                closesocket(g_sock);
                g_sock = -1;
                lcd_fill(5, 190, lcd_self.width,320, WHITE);
                lcd_show_string(5,190,200,16,16,"State:Disconnect", MAGENTA);
                free(tbuf);
                goto sock_start;
            }
            
            printf("%s\r\n",g_lwip_demo_recvbuf);
            vTaskDelay(10);
        }
    }
}

/**
 * @brief       發送數據線程函數
 * @param       pvParameters : 傳入參數(未用到)
 * @retval      無
 */
void lwip_send_thread(void *pvParameters)
{
    pvParameters = pvParameters;
    
    err_t err;
    
    while (1)
    {
        while (1)
        {
            if(((g_lwip_send_flag & LWIP_SEND_DATA) == LWIP_SEND_DATA) 
&& (g_lwip_connect_state == 1)) /* 有數據要發送 */
            {
                err = write(g_sock, g_lwip_demo_sendbuf,
                            sizeof(g_lwip_demo_sendbuf));
                
                if (err < 0)
                {
                    break;
                }
                
                g_lwip_send_flag &= ~LWIP_SEND_DATA;
            }
            
            vTaskDelay(10);
        }
        
        closesocket(g_sock);
    }
}

上述源碼中,我們首先創建一個發送任務,用來發送ESP32-S3設備的數據,然後配置TCPServer網絡參數,並調用函數connect連接遠程服務器,當連接成功時,系統進入接收輪詢任務,反次,重新連接客户端。發送線程在發送前會檢查標誌位,有效時則通過write發送數據並重置標誌位。

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

image004

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

image005

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

image007

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

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

發佈 評論

Some HTML is okay.