乐鑫技术交流
直播中

杨秀英

7年用户 1411经验值
私信 关注
[问答]

ESP32-S3使用tcp_server例程,将网络数据和串口数据透传延迟过高怎么解决?

使用tcp_server例程修改,将tcp数据与串口数据进行透传,串口→tcp的数据延迟很低,基本都在10ms以内,但是tcp→串口的数据延迟就很高,会达到100ms以上,回环测试的延迟也在60ms以上,通过逻辑分析仪抓取到大部分时间耗费在recv函数上,请问下这种问题是在idf里普遍存在的还是我的工程设置有问题或者环境原因?但是在使用modbus TCP例程的时候,返回数据的延迟却特别低,基本都在5ms以内。
以下是代码,工程由v5.1创建Code: Select all
/* BSD Socket API Example   This example code is in the Public Domain (or CC0 licensed, at your option.)   Unless required by applicable law or agreed to in writing, this   software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR   CONDITIONS OF ANY KIND, either express or implied.*/#include #include #include "freertos/FreeRTOS.h"#include "freertos/task.h"#include "esp_system.h"#include "esp_wifi.h"#include "esp_event.h"#include "esp_log.h"#include "nvs_flash.h"#include "esp_netif.h"#include "protocol_examples_common.h"#include "lwip/err.h"#include "lwip/sockets.h"#include "lwip/sys.h"#include #include "driver/uart.h"#include "driver/gpio.h"#define PORT                        CONFIG_EXAMPLE_PORT#define KEEPALIVE_IDLE              CONFIG_EXAMPLE_KEEPALIVE_IDLE#define KEEPALIVE_INTERVAL          CONFIG_EXAMPLE_KEEPALIVE_INTERVAL#define KEEPALIVE_COUNT             CONFIG_EXAMPLE_KEEPALIVE_COUNTstatic const char *TAG = "example";int tcp_sock = 0;QueueHandle_t uart_queue = NULL;static void do_retransmit(const int sock){    int len;    char rx_buffer[128];    do {        len = recv(sock, rx_buffer, sizeof(rx_buffer) - 1, 0);        if (len < 0)        {            ESP_LOGE(TAG, "Error occurred during receiving: errno %d", errno);        }        else if (len == 0)        {            ESP_LOGW(TAG, "Connection closed");        }         else        {            uart_write_bytes(UART_NUM_1, rx_buffer, len);            rx_buffer[len] = 0; // Null-terminate whatever is received and treat it like a string            ESP_LOGI(TAG, "Received %d bytes: %s", len, rx_buffer);                        int to_write = len;            while (to_write > 0) {                int written = send(sock, rx_buffer + (len - to_write), to_write, 0);                if (written < 0) {                    ESP_LOGE(TAG, "Error occurred during sending: errno %d", errno);                    // Failed to retransmit, giving up                    return;                }                to_write -= written;            }        }    } while (len > 0);}static void tcp_server_task(void *pvParameters){    char addr_str[128];    int addr_family = (int)pvParameters;    int ip_protocol = 0;    int keepAlive = 1;    int keepIdle = KEEPALIVE_IDLE;    int keepInterval = KEEPALIVE_INTERVAL;    int keepCount = KEEPALIVE_COUNT;    struct sockaddr_storage dest_addr;#ifdef CONFIG_EXAMPLE_IPV4    if (addr_family == AF_INET) {        struct sockaddr_in *dest_addr_ip4 = (struct sockaddr_in *)&dest_addr;        dest_addr_ip4->sin_addr.s_addr = htonl(INADDR_ANY);        dest_addr_ip4->sin_family = AF_INET;        dest_addr_ip4->sin_port = htons(PORT);        ip_protocol = IPPROTO_IP;    }#endif#ifdef CONFIG_EXAMPLE_IPV6    if (addr_family == AF_INET6) {        struct sockaddr_in6 *dest_addr_ip6 = (struct sockaddr_in6 *)&dest_addr;        bzero(&dest_addr_ip6->sin6_addr.un, sizeof(dest_addr_ip6->sin6_addr.un));        dest_addr_ip6->sin6_family = AF_INET6;        dest_addr_ip6->sin6_port = htons(PORT);        ip_protocol = IPPROTO_IPV6;    }#endif    int listen_sock = socket(addr_family, SOCK_STREAM, ip_protocol);    if (listen_sock < 0) {        ESP_LOGE(TAG, "Unable to create socket: errno %d", errno);        vTaskDelete(NULL);        return;    }    int opt = 1;    setsockopt(listen_sock, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));#if defined(CONFIG_EXAMPLE_IPV4) && defined(CONFIG_EXAMPLE_IPV6)    // Note that by default IPV6 binds to both protocols, it is must be disabled    // if both protocols used at the same time (used in CI)    setsockopt(listen_sock, IPPROTO_IPV6, IPV6_V6ONLY, &opt, sizeof(opt));#endif    ESP_LOGI(TAG, "Socket created");    int err = bind(listen_sock, (struct sockaddr *)&dest_addr, sizeof(dest_addr));    if (err != 0) {        ESP_LOGE(TAG, "Socket unable to bind: errno %d", errno);        ESP_LOGE(TAG, "IPPROTO: %d", addr_family);        goto CLEAN_UP;    }    ESP_LOGI(TAG, "Socket bound, port %d", PORT);    err = listen(listen_sock, 1);    if (err != 0) {        ESP_LOGE(TAG, "Error occurred during listen: errno %d", errno);        goto CLEAN_UP;    }    while (1) {        ESP_LOGI(TAG, "Socket listening");        struct sockaddr_storage source_addr; // Large enough for both IPv4 or IPv6        socklen_t addr_len = sizeof(source_addr);        int sock = accept(listen_sock, (struct sockaddr *)&source_addr, &addr_len);        if (sock < 0) {            ESP_LOGE(TAG, "Unable to accept connection: errno %d", errno);            break;        }        tcp_sock = sock;        // Set tcp keepalive option        setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, &keepAlive, sizeof(int));        setsockopt(sock, IPPROTO_TCP, TCP_KEEPIDLE, &keepIdle, sizeof(int));        setsockopt(sock, IPPROTO_TCP, TCP_KEEPINTVL, &keepInterval, sizeof(int));        setsockopt(sock, IPPROTO_TCP, TCP_KEEPCNT, &keepCount, sizeof(int));        // Convert ip address to string#ifdef CONFIG_EXAMPLE_IPV4        if (source_addr.ss_family == PF_INET) {            inet_ntoa_r(((struct sockaddr_in *)&source_addr)->sin_addr, addr_str, sizeof(addr_str) - 1);        }#endif#ifdef CONFIG_EXAMPLE_IPV6        if (source_addr.ss_family == PF_INET6) {            inet6_ntoa_r(((struct sockaddr_in6 *)&source_addr)->sin6_addr, addr_str, sizeof(addr_str) - 1);        }#endif        ESP_LOGI(TAG, "Socket accepted ip address: %s", addr_str);        do_retransmit(sock);        shutdown(sock, 0);        close(sock);    }CLEAN_UP:    close(listen_sock);    vTaskDelete(NULL);}void diaodian(){}void uart_read_task(void *arg){    uart_event_t event;    uint8_t uart_data[1024] = {0};    while (1)    {        if(xQueueReceive(uart_queue, (void*)&event, portMAX_DELAY))        {            //接收到串口数据            memset(uart_data, 0, sizeof(uart_data));            switch (event.type)            {            case UART_DATA:                ESP_LOGI(TAG, "串口数据事件");                uart_read_bytes(UART_NUM_1, uart_data, event.size, portMAX_DELAY);  //接收串口数据                send(tcp_sock, uart_data, event.size, 0);   //发送数据到网口                break;                        default:                ESP_LOGI(TAG, "其他串口事件,事件类型:%d", event.type);                break;            }        }    }    vTaskDelete(NULL);}void app_main(void){    uart_config_t uart_cfg = {        .baud_rate = 115200,        .parity = UART_PARITY_DISABLE,        .stop_bits = UART_STOP_BITS_1,        .flow_ctrl = UART_HW_FLOWCTRL_DISABLE,        .source_clk = UART_SCLK_DEFAULT,    };    uart_driver_install(UART_NUM_1, 2 * 1024, 2 * 1024, 10, &uart_queue, 0);    uart_param_config(UART_NUM_1, &uart_cfg);    uart_set_pin(UART_NUM_1, GPIO_NUM_4, GPIO_NUM_5, -1, -1);    xTaskCreate(uart_read_task, "read_task", 5 * 1024, NULL, 3, NULL);        ESP_ERROR_CHECK(nvs_flash_init());    ESP_ERROR_CHECK(esp_netif_init());    ESP_ERROR_CHECK(esp_event_loop_create_default());    /* This helper function configures Wi-Fi or Ethernet, as selected in menuconfig.     * Read "Establishing Wi-Fi or Ethernet Connection" section in     * examples/protocols/README.md for more information about this function.     */    ESP_ERROR_CHECK(example_connect());#ifdef CONFIG_EXAMPLE_IPV4    xTaskCreate(tcp_server_task, "tcp_server", 4096, (void*)AF_INET, 5, NULL);#endif#ifdef CONFIG_EXAMPLE_IPV6    xTaskCreate(tcp_server_task, "tcp_server", 4096, (void*)AF_INET6, 5, NULL);#endif}
下图是串口与tcp透传的时间

以下是使用modbus TCP例程的延迟时间

                                                                                                                                                                       

回帖(1)

王银喜

2024-6-6 18:11:23
为了解决ESP32-S3使用tcp_server例程时,tcp→串口数据延迟过高的问题,我们可以尝试以下几个步骤:

1. 优化代码结构:确保代码逻辑清晰,避免不必要的循环和条件判断。这有助于减少处理时间,从而降低延迟。

2. 使用中断:在ESP32-S3中,可以使用中断来处理串口数据的接收和发送。这样,当有数据到达时,中断会被触发,从而立即处理数据,而不是等待主循环去检查。

3. 调整任务优先级:在FreeRTOS中,可以为不同的任务设置不同的优先级。将串口数据处理任务的优先级设置得更高,以确保它能够更快地被执行。

4. 减少数据包大小:尝试减小TCP数据包的大小,这样可以减少每次处理数据所需的时间,从而降低延迟。

5. 检查网络环境:确保网络环境稳定,没有丢包或延迟过高的问题。网络环境不佳可能会导致数据传输延迟增加。

6. 检查串口配置:确保串口配置正确,包括波特率、数据位、停止位和奇偶校验位等。错误的配置可能会导致数据传输效率降低,从而增加延迟。

7. 分析modbus TCP例程:由于modbus TCP例程的延迟较低,可以分析其代码,看看是否有可以借鉴的地方。可能modbus TCP例程在某些方面做了优化,导致延迟降低。

8. 更新ESP-IDF版本:如果使用的是较旧的ESP-IDF版本,可以尝试更新到最新版本。新版本可能修复了一些已知的问题,或者提供了更好的性能。

举报

更多回帖

发帖
×
20
完善资料,
赚取积分