图53.3.1.1 程序流程图
53.3.2 程序解析
在本章节中,我们主要关注两个文件:lwip_demo.c和lwip_demo.h。lwip_demo.h文件主要定义了发送标志位并声明了lwip_demo函数,这部分相对简单,所以我们暂不详细解释。主要关注点是lwip_demo.c文件中的函数。在lwip_demo函数中,我们配置了相关的TCPClient参数,并创建了一个名为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);
/**
* @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设备数据的任务。然后,对TCPClient进行网络参数配置,并调用connect函数来建立与远程服务器的连接。当连接成功时,系统将进入接收轮询任务。如果出现断开连接的情况,系统将尝试重新连接服务器。在发送线程中,发送数据前会检查标志位。如果标志位有效,则通过write函数发送数据并重置标志位。
53.4 下载验证
在程序中,首先需要设置好能够连接的网络账号和密码。然后,使用笔记本电脑作为终端,确保它与ESP32-S3设备处于同一网络段内。当ESP32-S3设备成功连接到网络时,它的LCD显示屏上会显示相应的内容:
图53.4.1 设备连接到网络时,LCD显示的信息
打开网络调试助手,然后配置网络参数,如TCPServer协议、端口号等,设置内容如下图所示。
在确保网络连接正常后,可以通过按下开发板上的KEY0按键来发送数据至网络调试助手。当网络调试助手接收到“ALIENTEK DATA”字符串时,它会在显示区域展示这个信息。此外,用户还可以在调试助手的发送区域自行输入要发送的数据,然后点击发送键,将数据发送至ESP32-S3设备。此时,ESP32-S3的串口将打印接收到的数据,具体操作和输出如下图所示。