• ESP32——串口通讯应用实例


    一、简述

    串口通讯为RS232通讯,接收采用中断方式(数据处理是消息队列+消息缓冲区),发送是查询方式(利用通知确定要发送的数据内容)。

    本程序参考乐鑫官方示例,但做了如下修改:

    1. 采用消息缓冲区进行接收数据处理,是因为当数据较长时接收中断并不能一次接收到一帧完整数据(取决于默认设置)。

    2. 采用通知实现发送数据内容选择,是为了更高效的对发送进行控制。

    二、代码

    首先在一个公共头文件def.h声明一个通知变量,为的是在主函数中发送通知给串口处理源文件的发送任务函数。

    extern TaskHandle_t UartTxTask_NotifyHandle;

    串口处理头文件uhf.h中内容。

    1. #define UART_UHF UART_NUM_2
    2. esp_err_t uart2_init(int baud,int bufSize);

    串口处理源文件uhf.c中变量定义部分

    1. static const char *UART2_TAG = "uart2_events";
    2. static QueueHandle_t uart2_rx_queue;
    3. static uint8_t uart2_send_buf[512]={1,2,3,4,5,6,7,8};
    4. static uint8_t uart2_recv_buf[512];
    5. static int uart2_sendnum;
    6. static int uart2_recvnum;
    7. static MessageBufferHandle_t uart2_MsgBufHandle;
    8. TaskHandle_t UartTxTask_NotifyHandle;

    串口处理源文件uhf.c中实现串口初始化和发送接收任务创建部分

    1. //-------------------------串口2初始化---------------------------
    2. esp_err_t uart2_init(int baud,int bufSize)
    3. {
    4. esp_log_level_set(UART2_TAG, ESP_LOG_INFO);
    5. /* Configure parameters of an UART driver,
    6. * communication pins and install the driver */
    7. uart_config_t uart_config = {
    8. .baud_rate = baud,
    9. .data_bits = UART_DATA_8_BITS,
    10. .parity = UART_PARITY_DISABLE,
    11. .stop_bits = UART_STOP_BITS_1,
    12. .flow_ctrl = UART_HW_FLOWCTRL_DISABLE,
    13. .source_clk = UART_SCLK_APB,
    14. };
    15. //Install UART driver, and get the queue.
    16. uart_driver_install(UART_UHF, bufSize * 2, bufSize * 2, 20, &uart2_rx_queue, 0);
    17. uart_param_config(UART_UHF, &uart_config);
    18. //Set UART log level
    19. esp_log_level_set(UART2_TAG, ESP_LOG_INFO);
    20. //Set UART pins
    21. uart_set_pin(UART_UHF, 21, 19, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE);
    22. //Reset the pattern queue length to record at most 20 pattern positions.
    23. uart_pattern_queue_reset(UART_UHF, 20);
    24. uart_enable_rx_intr(UART_UHF);
    25. //创建发送和接收任务
    26. uart2_MsgBufHandle = xMessageBufferCreate(1500);
    27. if(uart2_MsgBufHandle != NULL){
    28. xTaskCreate(uart2_event_task, "uart2_event_task", bufSize*2, NULL, configMAX_PRIORITIES-1, NULL);
    29. xTaskCreate(uart2_rx_task, "uart2_rx_task", bufSize*2, NULL, configMAX_PRIORITIES-3, NULL);
    30. xTaskCreate(uart2_tx_task, "uart2_tx_task", bufSize*2, NULL, configMAX_PRIORITIES-5, &UartTxTask_NotifyHandle);
    31. }
    32. return ESP_OK;
    33. }

    串口处理源文件uhf.c中接收中断处理和数据缓存和解析,根据通讯协议确定接收数据是否完成和正确(协议不同处理方式需做相应调整)。

    1. //-------------------------串口2接收任务---------------------------
    2. static void uart2_rx_task(void *arg)
    3. {
    4. static const char *TX_TASK_TAG = "TX_TASK";
    5. int len = 0;
    6. uint16_t crc;
    7. int num;
    8. static uint8_t frame_buf[512];
    9. static int frame_header = 0;
    10. BaseType_t xHigherPriorityTaskWoken = pdFALSE;
    11. esp_log_level_set(TX_TASK_TAG, ESP_LOG_INFO);
    12. while (1) {
    13. vTaskDelay(10 / portTICK_PERIOD_MS);
    14. num = xMessageBufferReceiveFromISR(uart2_MsgBufHandle,frame_buf,sizeof(frame_buf),&xHigherPriorityTaskWoken);
    15. datacopy(&uart2_recv_buf[uart2_recvnum],frame_buf,num);
    16. uart2_recvnum += num;
    17. //接收数据长度需满足最小要求
    18. if((uart2_recvnum-frame_header) < 9) continue;
    19. //定位帧头位置
    20. if(uart2_recv_buf[frame_header] != 0x5A){
    21. frame_header++;
    22. continue;
    23. }
    24. //找到了正取的帧头,然后需要判断是否是一组完整的数据帧,CRC校验是否正确
    25. len = uart2_recv_buf[frame_header+5]*256 + uart2_recv_buf[frame_header+6];
    26. if((uart2_recvnum-frame_header) >= (len + 9))
    27. {
    28. // if(DEBUG_ON) printf("uart2 recv end,data len = %4d \r\n", uart2_recvnum);
    29. // for(int i=0;i
    30. crc = crc16_CCITT(&uart2_recv_buf[frame_header+1],len + 9-3);
    31. if((((crc & 0xff00)>>8) != uart2_recv_buf[len + 9-2]) || ((crc & 0x00ff) != uart2_recv_buf[len + 9-1]))
    32. {
    33. frame_header++;
    34. if(DEBUG_ON) printf("uart2 crc error!\r\n");
    35. }
    36. else//找到正取的数据帧
    37. {
    38. datacopy(frame_buf,&uart2_recv_buf[frame_header],len + 9);
    39. uart2_recvnum = uart2_recvnum - frame_header - len - 9;
    40. if(uart2_recvnum > 0) datacopy(uart2_recv_buf,&uart2_recv_buf[frame_header+len + 9],uart2_recvnum);
    41. //处理接收到的数据
    42. frame_handing(frame_buf);
    43. }
    44. }
    45. }
    46. }
    47. //-------------------------串口2接收事件---------------------------
    48. static void uart2_event_task(void *pvParameters)
    49. {
    50. uart_event_t event;
    51. BaseType_t xHigherPriorityTaskWoken = pdFALSE;
    52. uint8_t* dtmp = (uint8_t*) malloc(256);
    53. for(;;) {
    54. //Waiting for UART event.
    55. if(xQueueReceive(uart2_rx_queue, (void * )&event, (portTickType)portMAX_DELAY)) {
    56. bzero(dtmp, 256);
    57. // if(DEBUG_ON) ESP_LOGI(UART2_TAG, "uart[%d] event:", UART_UHF);
    58. switch(event.type) {
    59. //Event of UART receving data
    60. /*We'd better handler data event fast, there would be much more data events than
    61. other types of events. If we take too much time on data event, the queue might
    62. be full.*/
    63. case UART_DATA:
    64. // if(DEBUG_ON) ESP_LOGI(UART2_TAG, "[UART event DATA]: %d", event.size);
    65. uart_read_bytes(UART_UHF, dtmp, event.size, portMAX_DELAY);
    66. //xMessageBufferSend(MsgBufHandle,dtmp,event.size, portMAX_DELAY);
    67. xMessageBufferSendFromISR(uart2_MsgBufHandle,dtmp,event.size, &xHigherPriorityTaskWoken);
    68. break;
    69. //Event of HW FIFO overflow detected
    70. case UART_FIFO_OVF:
    71. if(DEBUG_ON) ESP_LOGI(UART2_TAG, "hw fifo overflow");
    72. // If fifo overflow happened, you should consider adding flow control for your application.
    73. // The ISR has already reset the rx FIFO,
    74. // As an example, we directly flush the rx buffer here in order to read more data.
    75. uart_flush_input(UART_UHF);
    76. xQueueReset(uart2_rx_queue);
    77. break;
    78. //Event of UART ring buffer full
    79. case UART_BUFFER_FULL:
    80. if(DEBUG_ON) ESP_LOGI(UART2_TAG, "ring buffer full");
    81. // If buffer full happened, you should consider encreasing your buffer size
    82. // As an example, we directly flush the rx buffer here in order to read more data.
    83. uart_flush_input(UART_UHF);
    84. xQueueReset(uart2_rx_queue);
    85. break;
    86. //Event of UART RX break detected
    87. case UART_BREAK:
    88. if(DEBUG_ON) ESP_LOGI(UART2_TAG, "uart rx break");
    89. break;
    90. //Event of UART parity check error
    91. case UART_PARITY_ERR:
    92. if(DEBUG_ON) ESP_LOGI(UART2_TAG, "uart parity error");
    93. break;
    94. //Event of UART frame error
    95. case UART_FRAME_ERR:
    96. if(DEBUG_ON) ESP_LOGI(UART2_TAG, "uart frame error");
    97. break;
    98. default:
    99. if(DEBUG_ON) ESP_LOGI(UART2_TAG, "uart event type: %d", event.type);
    100. break;
    101. }
    102. }
    103. }
    104. free(dtmp);
    105. dtmp = NULL;
    106. vTaskDelete(NULL);
    107. }

    串口处理源文件uhf.c中发送处理

    1. //-------------------------串口2发送任务---------------------------
    2. static void uart2_tx_task(void *arg)
    3. {
    4. static const char *TX_TASK_TAG = "TX_TASK";
    5. uint32_t ulNotifiedValue = 0;
    6. esp_log_level_set(TX_TASK_TAG, ESP_LOG_INFO);
    7. while (1) {
    8. vTaskDelay(10 / portTICK_PERIOD_MS);
    9. xTaskNotifyWait(0, ULONG_MAX,&ulNotifiedValue, pdMS_TO_TICKS(0));
    10. if((ulNotifiedValue & 0x0100) == 0x0100)//停止
    11. {
    12. stop();
    13. uart_write_bytes(UART_UHF, uart2_send_buf, uart2_sendnum);
    14. if(DEBUG_ON) printf("Send stop to UHF!\n");
    15. }
    16. else if((ulNotifiedValue & 0x0200) == 0x0200)//读TID
    17. {
    18. stop();
    19. uart_write_bytes(UART_UHF, uart2_send_buf, uart2_sendnum);
    20. vTaskDelay(50 / portTICK_PERIOD_MS);//发送间隔
    21. read_tid();
    22. uart_write_bytes(UART_UHF, uart2_send_buf, uart2_sendnum);
    23. if(DEBUG_ON) printf("Send read TID to UHF!\n");
    24. }
    25. ulNotifiedValue = 0;
    26. }
    27. }

    main.c文件中主函数

    1. void app_main(void)
    2. {
    3. uart2_init(115200,2048);
    4. read = 1;
    5. while (1)
    6. {
    7. vTaskDelay(5000 / portTICK_PERIOD_MS);
    8. if(read){
    9. read = 0;
    10. xTaskNotify(UartTxTask_NotifyHandle,0x0200,eSetBits);//读TID
    11. }
    12. else{
    13. read = 1;
    14. xTaskNotify(UartTxTask_NotifyHandle,0x0100,eSetBits);//停止
    15. }
    16. }
    17. }
  • 相关阅读:
    pandas使用str函数和contains函数删除dataframe中单个指定字符串数据列包含特定字符串列表中的其中任何一个字符串的数据行
    垃圾回收之G1收集过程
    【云计算网络安全】僵尸网络详解:工作原理、控制和保护方法
    ARM 架构是什么?
    布谷蓝途:易知微「可视大脑助力智慧教育」主题分享精彩实录
    计算机专业英语词汇
    设备的分配与回收(考虑因素,数据结构,分配步骤)
    Move 双子星之一 Sui 生态有哪些项目值得关注
    MapReduce框架原理
    【星球】【slam】研讨会(4)你真的适合读博吗?
  • 原文地址:https://blog.csdn.net/tsliuch/article/details/125887650