完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
使用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个回答
|
|
为了解决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版本,可以尝试更新到最新版本。新版本可能修复了一些已知的问题,或者提供了更好的性能。 |
|
|
|
只有小组成员才能发言,加入小组>>
358 浏览 0 评论
1201 浏览 1 评论
590浏览 6评论
484浏览 5评论
有没有办法在不使用混杂模式的情况下实现Wifi驱动程序接收缓冲区访问中断呢?
468浏览 5评论
467浏览 4评论
445浏览 4评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-12-30 04:05 , Processed in 0.891209 second(s), Total 82, Slave 65 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号