提示:本博客作为学习笔记,有错误的地方希望指正

一、ESP32串口介绍

  UART 是一种以字符为导向的通用数据链,可以实现设备间的通信。异步传输的意思是不需要在发送数据上添加时钟信息。这也要求发送端和接收端的速率、停止位、奇偶校验位等都要相同,通信才能成功。
  一个典型的 UART 帧开始于一个起始位,紧接着是有效数据,然后是奇偶校验位(可有可无),最后是停止位。
  ESP32 上的 UART 控制器支持多种字符长度和停止位。另外,控制器还支持软硬件流控和 DMA,可以实现无缝高速的数据传输。开发者可以使用多个 UART 端口,同时又能保证很少的软件开销。
  ESP32 芯片中有 3 个 UART 控制器可供使用,并且兼容不同的 UART 设备。另外,UART 还可以用作红外数据交换 (IrDA) 或 RS-485 调制解调器。
• 可编程收发波特率
• 3 个 UART 的发送 FIFO 以及接收 FIFO 共享 1024 × 8-bit RAM
• 全双工异步通信
• 支持输入信号波特率自检功能
• 支持 5/6/7/8 位数据长度
• 支持 1/1.5/2/3 个停止位
• 支持奇偶校验位
• 支持 RS485 协议
• 支持 IrDA 协议
• 支持 DMA 高速数据通信
• 支持 UART 唤醒模式
• 支持软件流控和硬件流控
  值得注意的是ESP32的三路串口中串口0不支持引脚的修改默认是RGIO1作为RX,GPIO3作为TX,配置的时候需要注意下,串口0默认使用作为下载程序使用和ESP_LOG的输出。UART1默认引脚是GPIO9用作U1RXD,GPIO10用作U1TXD,但是这两个引脚也是用于外接flash的,因此在使用UART1的时候需要设置其他引脚,UART2默认引脚是GPIO16用作U2RXD,GPIO17用作U2TXD。
485通讯规定为2线,半双工,多点通信的标准。
  RS485特点:
• 接口电平低,不易损坏芯片。
• 传输速率高,10 米时, RS485 的数据最高传输速率可达 35Mbps,在 1200m 时,传输速度可达 100Kbps。
• 抗干扰能力强,RS485 接口是采用平衡驱动器和差分接收器的组合,抗共模干扰能力增强,即抗噪声干扰性好。、
• 传输距离远,支持节点多, RS485 总线最长可以传输 1200m 以上(速率≤100Kbps)一般最大支持 32 个节点,如果使用特制的 485 芯片,可以达到 128 个或者 256 个节点,最大的可以支持到 400 个节点。

二、硬件设计

  这里的硬件设置就是使用的是M5Stack的硬件来实现串口通讯协议实验演示的。这里使用串口0作为485通讯实验的测试,实际并没有接入485芯片。
在这里插入图片描述

三、实现代码

  初始化流程
在这里插入图片描述

  初始化代码如下

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_system.h"
#include "nvs_flash.h"
#include "driver/uart.h"
#include "freertos/queue.h"
#include "esp_log.h"
#include "sdkconfig.h"

#define TAG "RS485_ECHO_APP"
// 串口回声虫我理解的含义就是接收到数据给原数据沿路发送出去
// 注意:目标芯片上的某些引脚不能分配给 UART 通信。
// 请参阅所选板和目标的文档以使用 Kconfig 配置引脚。
#define ECHO_TEST_TXD   (CONFIG_ECHO_UART_TXD)              //发送引脚
#define ECHO_TEST_RXD   (CONFIG_ECHO_UART_RXD)              //接收引脚

#define ECHO_TEST_RTS   (CONFIG_ECHO_UART_RTS)              //RS485 半双工模式的 RTS 管理 DE/~RE
#define ECHO_TEST_CTS   (UART_PIN_NO_CHANGE)                //RS485 半双工模式下不使用 CTS
#define BUF_SIZE        (127)                               //buf大小
#define BAUD_RATE       (CONFIG_ECHO_UART_BAUD_RATE)        //波特率大小

#define PACKET_READ_TICS        (100 / portTICK_RATE_MS)    //读包超时时间
#define ECHO_TASK_STACK_SIZE    (2048)                      //回声虫堆栽大小
#define ECHO_TASK_PRIO          (10)                        //任务优先级
#define ECHO_UART_PORT          (CONFIG_ECHO_UART_PORT_NUM) //串口回声虫波特率

// UART 的超时阈值 = 接收引脚上状态不变的符号数(~10 次)
#define ECHO_READ_TOUT          (3) // 3.5T * 8 = 28 ticks, TOUT=3 -> ~24..33 ticks
//回声虫发送函数
static void echo_send(const int port, const char* str, uint8_t length)
{
    if (uart_write_bytes(port, str, length) != length) {    //发送数据      
        ESP_LOGE(TAG, "Send data critical failure.");
        // 在此处添加处理发送失败的代码
        abort();
    }
}
// 在UART上使用硬件流控制进行回声测试的示例
static void echo_task(void *arg)
{
    const int uart_num = ECHO_UART_PORT;                    //串口编号
    uart_config_t uart_config = {
        .baud_rate = BAUD_RATE,                             //串口波特率
        .data_bits = UART_DATA_8_BITS,                      //数据位
        .parity = UART_PARITY_DISABLE,                      //奇偶校验
        .stop_bits = UART_STOP_BITS_1,                      //停止为
        .flow_ctrl = UART_HW_FLOWCTRL_DISABLE,              //硬件流孔控制
        .rx_flow_ctrl_thresh = 122,                         //UART硬件RTS阈值
        .source_clk = UART_SCLK_APB,                        //串口时钟
    };
    // Set UART log level
    esp_log_level_set(TAG, ESP_LOG_INFO);                   //设置log打印等级
    ESP_LOGI(TAG, "Start RS485 application test and configure UART.");
    // 安装 UART 驱动(这里我们不需要事件队列)
    // 在这个例子中,我们甚至不使用缓冲区来发送数据。
    // 安装串口驱动 串口编号、接收buf、发送buf、事件队列、分配中断的标志
    ESP_ERROR_CHECK(uart_driver_install(uart_num, BUF_SIZE * 2, 0, 0, NULL, 0));
    // 配置串口参数 串口编号、配置结构体参数
    ESP_ERROR_CHECK(uart_param_config(uart_num, &uart_config));
    ESP_LOGI(TAG, "UART set pins, mode and install driver.");
    // 设置串口引脚 串口编号、接收引脚、发送引脚、rts引脚、cts引脚
    ESP_ERROR_CHECK(uart_set_pin(uart_num, ECHO_TEST_TXD, ECHO_TEST_RXD, ECHO_TEST_RTS, ECHO_TEST_CTS));
    // 设置串口模式 485半双工通讯模式
    ESP_ERROR_CHECK(uart_set_mode(uart_num, UART_MODE_RS485_HALF_DUPLEX));
    // 设置UART TOUT功能的读取超时
    ESP_ERROR_CHECK(uart_set_rx_timeout(uart_num, ECHO_READ_TOUT));
    // 申请动态内存
    uint8_t* data = (uint8_t*) malloc(BUF_SIZE);
    ESP_LOGI(TAG, "UART start recieve loop.\r\n");
    echo_send(uart_num, "Start RS485 UART test.\r\n", 24);
    while(1) {
        //读取串口数据
        int len = uart_read_bytes(uart_num, data, BUF_SIZE, PACKET_READ_TICS);
        //发送数据
        if (len > 0) {
            echo_send(uart_num, "\r\n", 2);                     //发送回车换行
            char prefix[] = "RS485 Received: [";
            echo_send(uart_num, prefix, (sizeof(prefix) - 1));  //发送数据
            ESP_LOGI(TAG, "Received %u bytes:", len);
            printf("[ ");
            for (int i = 0; i < len; i++) {
                printf("0x%.2X ", (uint8_t)data[i]);            //打印16进制数据
                echo_send(uart_num, (const char*)&data[i], 1);  //发送数据
                // 如果您从粘贴中获得返回字符,请添加换行符(粘贴测试多字节收据/缓冲区)
                if (data[i] == '\r') {
                    echo_send(uart_num, "\n", 1);
                }
            }
            printf("] \n");
            echo_send(uart_num, "]\r\n", 3);
        } else {
            // 回声一个“.” 在等待输入时表明程序还活着
            echo_send(uart_num, ".", 1);
            ESP_ERROR_CHECK(uart_wait_tx_done(uart_num, 10));
        }
    }
    vTaskDelete(NULL);
}
void app_main(void)
{
    //没有事件队列的 uart 读/写示例;
    xTaskCreate(echo_task, "uart_echo_task", ECHO_TASK_STACK_SIZE, NULL, ECHO_TASK_PRIO, NULL);
}

四、串口实验演示结果

在这里插入图片描述

五、ESP32串口函数API

5.1、uart_types.h文件中的内容的API

  uart_types.h文件中的内容基本上实现的是一些串口协议的设置结构体

// UART端口号,取值为UART_NUM_0 ~ (UART_NUM_MAX -1)。
typedef int  uart_port_t;

// UART模式选择
typedef enum {
    UART_MODE_UART = 0x00/*!< mode:普通UART模式*/
    UART_MODE_RS485_HALF_DUPLEX = 0x01/*!< mode:由RTS引脚控制的半双工RS485 UART模式*/
    UART_MODE_IRDA = 0x02/*!< mode:IRDA UART模式*/
    UART_MODE_RS485_COLLISION_DETECT = 0x03/*!< mode:RS485碰撞检测UART模式(用于测试目的)*/
    uart_mod_rs485_app_ctrl = 0x04/*!< mode:应用控制RS485 UART模式(用于测试目的)*/
} uart_mode_t;

//UART字长常量
typedef enum {
    UART_DATA_5_BITS = 0x0/*!< 5个字节长度 */
    UART_DATA_6_BITS = 0x1/*!< 6个字节长度 */
    UART_DATA_7_BITS = 0x2/*!< 7个字节长度 */
    UART_DATA_8_BITS = 0x3/*!< 8个字节长度 */
    UART_DATA_BITS_MAX = 0x4,
} uart_word_length_t;

//UART停止位数
typedef enum {
    UART_STOP_BITS_1   = 0x1/*!< 1个字节停止位 */
    UART_STOP_BITS_1_5 = 0x2/*!< 1.5个字节停止位 */
    UART_STOP_BITS_2   = 0x3/*!< 2个字节停止位 */
    UART_STOP_BITS_MAX = 0x4,
} uart_stop_bits_t;

//UART奇偶校验常数
typedef enum {
    UART_PARITY_DISABLE = 0x0/*!<禁用UART奇偶校验*/
    UART_PARITY_EVEN    = 0x2/*!<启用UART偶校验*/
    UART_PARITY_ODD     = 0x3    /*!<启用UART奇偶校验*/
} uart_parity_t;

//UART硬件流控制模式
typedef enum {
    UART_HW_FLOWCTRL_DISABLE = 0x0/*!<禁用硬件流控制*/
    UART_HW_FLOWCTRL_RTS = 0x1/*!<启用RX硬件流控制(rts)*/
    UART_HW_FLOWCTRL_CTS = 0x2/*!<enable TX硬件流控制(cts)*/
    UART_HW_FLOWCTRL_CTS_RTS = 0x3/*!<启用硬件流控制*/
    UART_HW_FLOWCTRL_MAX = 0 x4,
} uart_hw_flowcontrol_t;

//UART信号位图
typedef enum {
    Uart_signal_inv_disable = 0/*!<禁用UART信号逆*/
    UART_SIGNAL_IRDA_TX_INV = (0x1 << 0)/*!<反UART irda_tx信号*/
    UART_SIGNAL_IRDA_RX_INV = (0x1 << 1)/*!<逆UART irda_rx信号*/
    UART_SIGNAL_RXD_INV = (0x1 << 2)/*!<逆UART rxd信号*/
    UART_SIGNAL_CTS_INV = (0x1 << 3)/*!<反转UART cts信号*/
    UART_SIGNAL_DSR_INV = (0x1 << 4)/*!<反转UART dsr信号*/
    UART_SIGNAL_TXD_INV = (0x1 << 5)/*!<逆UART txd信号*/
    UART_SIGNAL_RTS_INV = (0x1 << 6)/*!<反转UART rts信号*/
    UART_SIGNAL_DTR_INV = (0x1 << 7)/*!<反转UART dtr信号*/
} uart_signal_inv_t;

//UART源时钟
typedef enum {
    UART_SCLK_APB = 0x0/*!<来自APB的UART源时钟*/
#if SOC_UART_SUPPORT_RTC_CLK
    UART_SCLK_RTC = 0x1/*!< UART源时钟来自RTC*/
# endif
#if SOC_UART_SUPPORT_XTAL_CLK
    UART_SCLK_XTAL = 0x2/*!< UART源时钟来自XTAL*/
# endif
#if SOC_UART_SUPPORT_REF_TICK
    UART_SCLK_REF_TICK = 0x3/*!< UART源时钟来自REF_TICK*/
# endif
} uart_sclk_t;

/*
* @brief 串口AT指令字符配置参数
* 注意此功能在不同芯片上可能不同。请在配置时参考TRM。
*/
typedef struct {
    uint8_t  cmd_char;      /* !< UART AT命令字符配置参数 */
    uint8_t  char_num;      /* !< UART AT命令字符重复编号 */
    uint32_t gap_tout;      /* !< AT命令字符之间的间隔时间(波特率) */
    uint32_t pre_idle;      /* !< 非AT字符和第一个AT字符之间的空闲时间(波特率) */
    uint32_t post_idle;     /* !< 最后一个AT字符和无AT字符之间的空闲时间(波特率) */
} uart_at_cmd_t;

/**
* @brief UART软件流量控制配置参数
*/
typedef struct {
    uint8_t xon_char;       /* !< Xon流控制字符*/
    uint8_t xoff_char;      /* !< Xoff流控制字符*/
    uint8_t xon_thrd;       /* !<如果启用了软件流控制,并且rxfifo中的数据量小于xon_thrd,则发送一个xon_char */
    uint8_t xoff_thrd;      /* !<如果使能了软件流控制,并且rxfifo中的数据量大于xoff_thrd,则发送一个xoff_char */
} uart_sw_flowctrl_t;

/**
* @brief uart_param_config函数的UART配置参数
*/
typedef struct {
    int  baud_rate;                 /* !< UART波特率*/
    uart_word_length_t data_bits;   /* !< UART字节大小*/
    uart_parity_t parity;           /* !< UART校验模式*/
    uart_stop_bits_t stop_bits;     /* !< UART停止位*/
    uart_hw_flowcontrol_t flow_ctrl;/* !< UART HW流量控制模式(cts/rts)*/
    uint8_t rx_flow_ctrl_thresh;    /* !< UART HW RTS阈值*/
    union{
        uart_sclk_t source_clk;     /* !< UART源时钟选择*/
        bool use_ref_tick __attribute__((deprecated));  /* !已弃用方法来选择ref tick clock source,将source_clk字段改为*/
    }} uart_config_t;

5.2、在uart.h文件中的内容的API

  在uart.h文件中的内容就多一些,主要是ESP32串口的配置参数的架构体以及初始化函数和配置函数,还包括了串口事件等参数和函数API。温馨提示:可以给这些API复制到文本编辑器中,例如Vscode中,然后可以快速查找定位即可知道函数功能以及函数参数的含义。

//有效的UART端口号
#define UART_NUM_0 (0)              /*!< UART端口0 */
#define UART_NUM_1 (1)              /*!< UART端口1 */
#if SOC_UART_NUM > 2
#define UART_NUM_2 (2)              /*!< UART端口2 */
# endif
#define UART_NUM_MAX (SOC_UART_NUM) /*!< UART端口max */

/* @brief当调用' uart_set_pin ',而不是GPIO number, ' UART_PIN_NO_CHANGE '
*可提供保持当前分配的引脚。*/
#define UART_PIN_NO_CHANGE (1)

SOC_UART_FIFO_LEN       //< UART 硬件FIFO的长度
SOC_UART_BITRATE_MAX    //<可配置的最大比特率

//UART中断配置参数uart_intr_config函数
typedef struct {
    uint32_t intr_enable_mask;          /* !< UART中断启用掩码,选择uart_xxxx_int _ena_reg (i)下的UART_XXXX_int _ENA_M,连接位或操作符*/
    uint8_t rx_timeout_thresh;          /* !< UART超时中断阈值(单位:发送一个字节的时间)*/
    uint8_t txfifo_empty_intr_thresh;   /* !< UART TX空中断阈值。*/
    uint8_t rxfifo_full_thresh;         /* !< UART RX全中断阈值。*/
} uart_intr_config_t;

//UART事件类型在循环缓冲区中使用
typedef enum {
    UART_DATA ,                         /*!< UART数据事件*/
    UART_BREAK ,                        /*!< UART中断事件*/
    UART_BUFFER_FULL ,                  /*!< UART RX缓冲区完整事件*/
    UART_FIFO_OVF ,                     /*!< UART FIFO溢出事件*/
    UART_FRAME_ERR ,                    /*!< UART RX帧错误事件*/
    UART_PARITY_ERR ,                   /*!< UART RX奇偶校验事件*/
    UART_DATA_BREAK ,                   /*!< UART TX数据和中断事件*/
    UART_PATTERN_DET ,                  /*!< 检测到UART模式*/
    UART_EVENT_MAX ,                    /*!< UART事件最大索引*/
} uart_event_type_t;            

//事件结构用于UART事件队列
typedef struct {
    uart_event_type_t type; /* !< UART事件类型*/
    size_t size;            /* !< UART_DATA事件的UART数据大小*/
    bool timeout_flag;      /* !< UART数据读取超时标志UART_DATA事件(在配置RX TOUT期间没有收到新数据)*/
                            /* !<如果事件是由FIFO-full中断引起的,那么在下一个字节到来之前将没有带有超时标志的事件*/
} uart_event_t;

typedef intr_handle_t uart_isr_handle_t;

/*
* @brief安装UART驱动程序并设置UART为默认配置。
* UART ISR处理器将被附加到这个函数运行的同一CPU核心上。
* Rx_buffer_size应该大于UART_FIFO_LEN。Tx_buffer_size应该为零或大于UART_FIFO_LEN。
* @param uart_num UART端口号,最大端口号为(UART_NUM_MAX -1)。
* @param rx_buffer_size UART RX环缓冲区大小。
* @param tx_buffer_size UART TX环缓冲区大小。
* 如果设置为0,驱动程序将不会使用TX缓冲区,TX函数将阻塞任务,直到所有数据被发送出去。
* @param queue_size UART事件队列大小/深度。
* @param uart_queue UART事件队列句柄。一旦成功,将在这里编写一个新的队列句柄来提供
* 访问UART事件。如果设置为NULL,驱动程序将不会使用事件队列。
* @param intr_alloc_flags用于分配中断的标志。一个或多个(ORred)
* ESP_intr_FLAG_ *值。更多信息请参见esp_intr_alloc.h。这里没有设置ESP_intr_FLAG_IRAM
* (驱动程序的ISR处理程序不在IRAM中)
* @return
* - ESP_OK成功
* - ESP_FAIL参数错误
*/
esp_err_t uart_driver_install(uart_port_t uart_num, int  rx_buffer_size, int  tx_buffer_size, int  queue_size, QueueHandle_t* uart_queue, int  intr_alloc_flags);

/*
* @brief卸载UART驱动。
* @param uart_num UART端口号,最大端口号为(UART_NUM_MAX -1)。
* @return
* - ESP_OK成功
* - ESP_FAIL参数错误
*/
esp_err_t uart_driver_delete (uart_port_t uart_num);

/**
* @brief检查驱动是否安装
* @param uart_num UART端口号,最大端口号为(UART_NUM_MAX -1)。
* @return
* -真正的驱动程序已安装
* -错误的驱动程序没有安装
*/
bool uart_is_driver_installed (uart_port_t uart_num);

/**
* 设置UART数据位。
* @param uart_num UART端口号,最大端口号为(UART_NUM_MAX -1)。
* @param data_bit UART数据位
* @return
* - ESP_OK成功
* - ESP_FAIL参数错误
*/
esp_err_t uart_set_word_length(uart_port_t uart_num, uart_word_length_t data_bit);

/*
* 获取UART数据位配置。
* @param uart_num UART端口号,最大端口号为(UART_NUM_MAX -1)。
* @param data_bit接收UART数据位值的指针。
* @return
* - ESP_FAIL参数错误
* - ESP_OK Success, result将被放入(*data_bit)
*/
esp_err_t uart_get_word_length(uart_port_t uart_num, uart_word_length_t* data_bit);

/**
* 获取UART数据位配置。
* @param uart_num UART端口号,最大端口号为(UART_NUM_MAX -1)。
* @param data_bit接收UART数据位值的指针。
* @return
* - ESP_FAIL参数错误
* - ESP_OK Success, result将被放入(*data_bit)
*/
esp_err_t uart_get_word_length(uart_port_t uart_num, uart_word_length_t* data_bit);

/**
* 设置UART停止位。
* @param uart_num UART端口号,最大端口号为(UART_NUM_MAX -1)。
* @param stop_bits UART停止位
* @return
* - ESP_OK成功
* - ESP_FAIL失败
*/
esp_err_t uart_set_stop_bits(uart_port_t uart_num, uart_stop_bits_t stop_bits);

/**
* 获取UART停止位配置。
* @param uart_num UART端口号,最大端口号为(UART_NUM_MAX -1)。
* @param stop_bits接受UART停止位值的指针。
* @return
* - ESP_FAIL参数错误
* - ESP_OK Success,结果将被放入(*stop_bit)
*/
esp_err_t uart_get_stop_bits(uart_port_t uart_num, uart_stop_bits_t* stop_bits);

/**
* @brief设置UART校验模式。
* @param uart_num UART端口号,最大端口号为(UART_NUM_MAX -1)。
* @param parity_mode uart奇偶校验配置的enum
* @return
* - ESP_FAIL参数错误
* - ESP_OK成功
*/
esp_err_t uart_set_parity(uart_port_t uart_num, uart_parity_t parity_mode);

/**
* 获取UART奇偶校验模式配置。
* @param uart_num UART端口号,最大端口号为(UART_NUM_MAX -1)。
* @param parity_mode接受UART奇偶校验模式值的指针。
* @return
* - ESP_FAIL参数错误
* - ESP_OK Success,结果将被放入(*parity_mode)
*/
esp_err_t uart_get_parity(uart_port_t uart_num, uart_parity_t* parity_mode);

/**
* 设置UART波特率。
* @param uart_num UART端口号,最大端口号为(UART_NUM_MAX -1)。
* @param baudrate UART波特率。
* @return
* - ESP_FAIL参数错误
* - ESP_OK成功
*/
esp_err_t uart_set_baudrate(uart_port_t uart_num, uint32_t baudrate);

/**
* 获取UART波特率配置。
* @param uart_num UART端口号,最大端口号为(UART_NUM_MAX -1)。
* @param baudrate接受UART波特率值的指针
* @return
* - ESP_FAIL参数错误
* - ESP_OK Success,结果将被输入(*baudrate)
*/
esp_err_t uart_get_baudrate(uart_port_t uart_num, uint32_t* baudrate);

/**
* @brief设置UART线反向模式
* @param uart_num UART端口号,最大端口号为(UART_NUM_MAX -1)。
* @param inverse_mask选择需要反转的连线。使用' uart_signal_inv_t '的ORred掩码
* @return
* - ESP_OK成功
* - ESP_FAIL参数错误
*/
esp_err_t uart_set_line_inverse(uart_port_t uart_num, uint32_t inverse_mask);

/**
* @brief设置硬件流控制。
* @param uart_num UART端口号,最大端口号为(UART_NUM_MAX -1)。
* @param flow_ctrl硬件流控制模式
* @param rx_thresh硬件RX流量控制阈值(0 ~ UART_FIFO_LEN)。
* 只有当UART_HW_FLOWCTRL_RTS设置时,rx_threshresh值才会被设置。
* @return
* - ESP_OK成功
* - ESP_FAIL参数错误
*/
esp_err_t uart_set_hw_flow_ctrl(uart_port_t uart_num, uart_hw_flowcontrol_t flow_ctrl, uint8_t rx_thresh);

/**
* @brief设置软件流量控制。
* @param uart_num UART_NUM_0, UART_NUM_1或UART_NUM_2
* @param开启或关闭开关
* @param rx_thresh_xon低水位标记
* @param rx_thresh_xoff高水位
* @return
* - ESP_OK成功
* - ESP_FAIL参数错误
*/
esp_err_t uart_set_sw_flow_ctrl(uart_port_t uart_num, bool enable, uint8_t rx_thresh_xon, uint8_t rx_thresh_xoff);

/**
* 获取UART硬件流控制配置。
* @param uart_num UART端口号,最大端口号为(UART_NUM_MAX -1)。
* @param flow_ctrl选项用于不同的流控制模式。
* @return
* - ESP_FAIL参数错误
* - ESP_OK Success,结果将被放入(*flow_ctrl)
*/
esp_err_t uart_get_hw_flow_ctrl(uart_port_t uart_num, uart_hw_flowcontrol_t* flow_ctrl);

/**
* @brief清除UART中断状态
* @param uart_num UART端口号,最大端口号为(UART_NUM_MAX -1)。
* @param clr_mask需要清除的中断状态的位掩码。
* @return
* - ESP_OK成功
* - ESP_FAIL参数错误
*/
esp_err_t uart_clear_in t_status(uart_port_t uart_num, uint32_t clr_mask);

/**
* 设置UART中断使能
* @param uart_num UART端口号,最大端口号为(UART_NUM_MAX -1)。
* @param enable_mask启用位掩码。
* @return
* - ESP_OK成功
* - ESP_FAIL参数错误
*/
esp_err_t uart_enable_intr_mask(uart_port_t uart_num, uint32_t enable_mask);

/*
* @brief清除UART中断启用位
* @param uart_num UART端口号,最大端口号为(UART_NUM_MAX -1)。
* @param disable_mask禁用位的位掩码。
* @return
* - ESP_OK成功
* - ESP_FAIL参数错误
*/
esp_err_t uart_disable_intr_mask(uart_port_t uart_num, uint32_t disable_mask);

/*
* 启用UART RX中断(RX_FULL和RX_TIMEOUT中断)
* @param uart_num UART端口号,最大端口号为(UART_NUM_MAX -1)。
* @return
* - ESP_OK成功
* - ESP_FAIL参数错误
*/
esp_err_t uart_enable_rx_intr (uart_port_t uart_num);

/*
* 关闭UART RX中断(RX_FULL和RX_TIMEOUT中断)
* @param uart_num UART端口号,最大端口号为(UART_NUM_MAX -1)。
* @return
* - ESP_OK成功
* - ESP_FAIL参数错误
*/
esp_err_t uart_disable_rx_intr (uart_port_t uart_num);

/*
* @brief关闭UART TX中断(TXFIFO_EMPTY中断)
* @param uart_num UART端口号
* @return
* - ESP_OK成功
* - ESP_FAIL参数错误
*/
esp_err_t uart_disable_tx_intr (uart_port_t uart_num);

/*
打开UART TX中断(TXFIFO_EMPTY中断)
* @param uart_num UART端口号,最大端口号为(UART_NUM_MAX -1)。
* @param启用1:启用;0:禁用
* @param thresh TX中断阈值,0 ~ UART_FIFO_LEN
* @return
* - ESP_OK成功
* - ESP_FAIL参数错误
*/
esp_err_t uart_enable_tx_intr(uart_port_t uart_num, int  enable, int  thresh);

/*
* 注册UART中断处理器(ISR)。
* @note UART ISR处理器将被附加到这个函数运行的同一CPU核心上。
* @param uart_num UART端口号,最大端口号为(UART_NUM_MAX -1)。
* @param fn中断处理函数。
* @param参数参数的处理程序的功能
* @param intr_alloc_flags用于分配中断的标志。一个或多个(ORred)
* ESP_intr_FLAG_ *值。更多信息请参见esp_intr_alloc.h。
* 返回句柄的指针。如果非null,则中断句柄将
* 在这里返回。
* @return
* - ESP_OK成功
* - ESP_FAIL参数错误
*/
esp_err_t uart_isr_register(uart_port_t uart_num, void (*fn)(void*)void* arg, int  intr_alloc_flags, uart_isr_handle_t *handle);

/*
* 免费的UART中断处理程序注册的uart_isr_register。必须在同一个核心调用
* uart_isr_register被调用。
* @param uart_num UART端口号,最大端口号为(UART_NUM_MAX -1)。
* @return
* - ESP_OK成功
* - ESP_FAIL参数错误
*/
esp_err_t uart_isr_free (uart_port_t uart_num);

/*
* 将UART外设的信号分配给GPIO管脚
* 如果为UART信号配置的GPIO号匹配其中一个
* IOMUX信号为该GPIO,信号将直接连接
* 通过IOMUX。否则GPIO与信号将通过
* GPIO矩阵。例如ESP32通话
* ' uart_set_pin(0,1,3, -1, -1) '被执行,因为GPIO1是UART0的
* 默认的TX引脚和GPIO3是UART0的默认RX引脚,两者都是
* 通过IOMUX分别连接U0TXD和U0RXD,共绕过GPIO矩阵。
* 检查是在每针的基础上执行。因此,有可能
* RX引脚通过GPIO矩阵绑定到GPIO上,而TX是绑定的
* 通过IOMUX连接到GPIO。
* @note内部信号可以输出到多个GPIO板。
* 输入信号只能连接一个GPIO板。
* @param uart_num UART端口号,最大端口号为(UART_NUM_MAX -1)。
* @param tx_io_num UART TX引脚GPIO编号。
* @param rx_io_num UART RX引脚GPIO编号。
* @param rts_io_num UART RTS引脚GPIO编号。
* @param cts_io_num UART CTS引脚GPIO编号。
* @return
* - ESP_OK成功
* - ESP_FAIL参数错误
*/
esp_err_t uart_set_pin(uart_port_t uart_num, int  tx_io_num, int  rx_io_num, int  rts_io_num, int  cts_io_num);

/*
* @brief手动设置UART RTS引脚级别。
* 注意UART必须配置为禁用硬件流控制。
* @param uart_num UART端口号,最大端口号为(UART_NUM_MAX -1)。
* @param 1级:RTS输出低(活跃);0: RTS输出高(块)
* @return
* - ESP_OK成功
* - ESP_FAIL参数错误
*/
esp_err_t uart_set_rts(uart_port_t uart_num, int  level);

/*
* 手动设置UART DTR引脚级别。
* @param uart_num UART端口号,最大端口号为(UART_NUM_MAX -1)。
* @param level 1: DTR输出低;0: DTR输出高
* @return
* - ESP_OK成功
* - ESP_FAIL参数错误
*/
esp_err_t uart_set_dtr(uart_port_t uart_num, int  level);

/*
* @brief设置UART空闲间隔后tx FIFO是空的
* @param uart_num UART端口号,最大端口号为(UART_NUM_MAX -1)。
* @param idle_num tx FIFO后的空闲间隔为空(单位:发送一个比特所需的时间)
* 在当前波特率下)
* @return
* - ESP_OK成功
* - ESP_FAIL参数错误
*/
esp_err_t uart_set_tx_idle_num(uart_port_t uart_num, uint 16_t idle_num);

/*
* @brief UART配置参数。
* @param uart_num UART端口号,最大端口号为(UART_NUM_MAX -1)。
* @param uart_config UART参数设置
* @return
* - ESP_OK成功
* - ESP_FAIL参数错误
*/
esp_err_t uart_param_config(uart_port_t uart_num, const uart_config_t *uart_config)

/**
* 配置UART中断。
* @param uart_num UART端口号,最大端口号为(UART_NUM_MAX -1)。
* @param intr_conf UART中断设置
* @return
* - ESP_OK成功
* - ESP_FAIL参数错误
*/
esp_err_t uart_intr_config(uart_port_t uart_num, const uart_intr_config_t *intr_conf);

/*
* @brief等待直到UART TX FIFO是空的。
* @param uart_num UART端口号,最大端口号为(UART_NUM_MAX -1)。
* @param ticks_to_wait超时时间,以RTOS计时计数
* @return
* - ESP_OK成功
* - ESP_FAIL参数错误
* - ESP_ERR_TIMEOUT超时时间
*/
esp_err_t uart_wait_tx_done(uart_port_t uart_num, TickType_t ticks_to_wait);

/*
* 从给定的缓冲区和长度发送数据到UART端口。
* 这个函数将不会等待足够的空间在TX FIFO。它将填充可用的TX FIFO,并在FIFO满时返回。
* @注意此函数只应在UART TX缓冲区未启用时使用。
* @param uart_num UART端口号,最大端口号为(UART_NUM_MAX -1)。
* @param缓冲区数据缓冲区地址
* @param len发送的数据长度
* @return
* -(-1)参数错误
* - OTHERS(>=0)发送到TX FIFO的字节数
*/
int  uart_tx_chars(uart_port_t uart_num, const char* buffer, uint32_t len);

/**
* 从给定的缓冲区和长度发送数据到UART端口,
* 如果UART驱动程序的参数tx_buffer_size设置为零:
* 这个函数将不会返回,直到所有的数据已经被发送出去,或至少推入TX FIFO。
* 否则,如果'tx_buffer_size' > 0,这个函数将返回所有的数据复制到tx环缓冲区,
* 然后UART ISR将数据从环形缓冲区逐渐移动到TX FIFO。
* @param uart_num UART端口号,最大端口号为(UART_NUM_MAX -1)。
* @param SRC数据缓冲区地址
* @param size发送的数据长度
* @return
* -(-1)参数错误
* - OTHERS(>=0)发送到TX FIFO的字节数
*/
int  uart_write_bytes(uart_port_t uart_num, const void* src, size_t size);

/**
* 从给定的缓冲区和长度发送数据到UART端口,
* 如果UART驱动程序的参数tx_buffer_size设置为零:
* 此函数将不会返回,直到所有数据和中断信号已被发送。
* 所有数据发送完毕后,发送中断信号。
* 否则,如果'tx_buffer_size' > 0,这个函数将返回所有的数据复制到tx环缓冲区,
* 然后UART ISR将数据从环形缓冲区逐渐移动到TX FIFO。
* 所有数据发送完毕后,发送中断信号。
* @param uart_num UART端口号,最大端口号为(UART_NUM_MAX -1)。
* @param SRC数据缓冲区地址
* @param size发送的数据长度
* @param brk_len中断信号持续时间(单位:在当前波特率下发送一个比特所需的时间)
* @return
* -(-1)参数错误
* - OTHERS(>=0)发送到TX FIFO的字节数
*/
int  uart_write_bytes_with_break(uart_port_t uart_num, const void* src, size_t size, int  brk_len);

/*
* @brief UART从UART buffer中读取字节
* @param uart_num UART端口号,最大端口号为(UART_NUM_MAX -1)。
* @param buf指针指向缓冲区。
* @param length数据长度
* @param ticks_to_wait超时时间,以RTOS计时
* @return
* -(-1)错误
* - OTHERS(>=0)从UART FIFO读取的字节数
*/
int  uart_read_bytes(uart_port_t uart_num, void* buf, uint32_t length, TickType_t ticks_to_wait);

/*
* @brief uart_flush_input的别名。
* UART环缓冲区冲洗。这将丢弃UART RX缓冲区中的所有数据。
* @note不是等待数据发送,这个函数将清除UART rx缓冲区。
* 为了发送所有的数据在tx FIFO,我们可以使用uart_wait_tx_done函数。
* @param uart_num UART端口号,最大端口号为(UART_NUM_MAX -1)。
* @return
* - ESP_OK成功
* - ESP_FAIL参数错误
*/
esp_err_t uart_flush (uart_port_t uart_num);

/*
* @brief清除输入缓冲区,丢弃所有环缓冲区中的数据。
* 为了在tx FIFO中发送所有的数据,我们可以使用uart_wait_tx_done函数。
* @param uart_num UART端口号,最大端口号为(UART_NUM_MAX -1)。
* @return
* - ESP_OK成功
* - ESP_FAIL参数错误
*/
esp_err_t uart_flush_input (uart_port_t uart_num);

/*
* @brief UART获取RX环缓冲区缓存的数据长度
* @param uart_num UART端口号,最大端口号为(UART_NUM_MAX -1)。
* @param size size_t的指针,用于接受缓存数据的长度
* @return
* - ESP_OK成功
* - ESP_FAIL参数错误
*/
esp_err_t uart_get_buffered_data_len(uart_port_t uart_num, size_t* size);

/*
* @brief UART禁用模式检测功能。
* 专为应用程序如“AT命令”。
* 当硬件检测到一系列相同的字符时,将触发中断。
* @param uart_num UART端口号,最大端口号为(UART_NUM_MAX -1)。
* @return
* - ESP_OK成功
* - ESP_FAIL参数错误
*/
esp_err_t uart_disable_pattern_det_intr (uart_port_t uart_num);

#if CONFIG_IDF_TARGET_ESP32
/*
* @brief UART启用模式检测功能。
* 专为应用程序如“AT命令”。
* 当硬件检测到一系列相同的字符时,将触发中断。
* @注意此函数仅适用于esp32。此函数已弃用,请使用
* uart_enable_pattern_det_baud_intr代替。
* @param uart_num UART端口号。
* @param pattern_chr模式字符。
* @param chr_num字符数,8位值。
* @param chr_tout每个模式字符之间的间隔超时,24位值,单位是APB (80Mhz)时钟周期。
* 当持续时间小于这个值,它将不接受这个数据作为at_cmd字符。
* @param post_idle最后一个模式字符后的空闲时间,24位值,单位是APB (80Mhz)时钟周期。
* 当持续时间小于这个值,它将不接受前一个数据作为最后一个at_cmd字符
* @param pre_idle第一个模式字符前的空闲时间,24位值,单位是APB (80Mhz)时钟周期。
* 当持续时间小于这个值,它将不接受这个数据作为第一个at_cmd字符。
* @return
* - ESP_OK成功
* - ESP_FAIL参数错误
*/
esp_err_t uart_enable_pattern_det_intr(uart_port_t uart_num, char pattern_chr, uint8_t chr_num, int  chr_tout, int  post_idle, int  pre_idle) __attribute__((deprecated));
# endif

/*
* @brief UART启用模式检测功能。
* 专为应用程序如“AT命令”。
* 当硬件检测到一系列相同的字符时,将触发中断。
* @param uart_num UART端口号。
* @param pattern_chr模式字符。
* @param chr_num字符数,8位值。
* @param chr_tout每个模式字符之间的间隔超时时间,16位值,单位是您配置的波特率周期。
* 当持续时间大于这个值,它将不接受这个数据为at_cmd字符。
* @param post_idle最后一个模式字符后的空闲时间,16位值,单位是您配置的波特率周期。
* 当持续时间小于这个值,它将不接受前一个数据作为最后一个at_cmd字符
* @param pre_idle第一个模式字符前的空闲时间,16位值,单位是您配置的波特率周期。
* 当持续时间小于这个值,它将不接受这个数据作为第一个at_cmd字符。
* @return
* - ESP_OK成功
* - ESP_FAIL参数错误
*/
esp_err_t uart_enable_pattern_det_baud_intr(uart_port_t uart_num, char pattern_chr, uint8_t chr_num, int  chr_tout, int  post_idle, int  pre_idle);

/*
* 返回在缓冲区中最近的检测到的模式位置。
* 检测到的图案的位置保存在一个队列中,
* 这个函数将退出第一个模式位置,并将指针移动到下一个模式位置。
* 如果RX缓冲区已满且流控制未启用,
* 由于溢出,检测到的模式可能无法在rx缓冲区中找到。
* 以下api将修改模式位置信息:
* uart_flush_input, uart_read_bytes, uart_driver_delete, uart_pop_pattern_pos
* 确保对模式队列和rx数据缓冲区的原子访问是应用程序的责任
* 当使用模式检测特征。
* @param uart_num UART端口号,最大端口号为(UART_NUM_MAX -1)。
* @return
* -(-1)没有找到当前索引或参数错误的模式
* -其他的模式位置在rx缓冲区。
*/
int  uart_pattern_pop_pos (uart_port_t uart_num);

/*
* 返回在缓冲区中最近的检测到的模式位置。
* 检测到的图案的位置保存在一个队列中,
* 这个函数对队列不做任何操作。
* 如果RX缓冲区已满且流控制未启用,
* 由于溢出,检测到的模式可能无法在rx缓冲区中找到。
* 以下api将修改模式位置信息:
* uart_flush_input, uart_read_bytes, uart_driver_delete, uart_pop_pattern_pos
* 确保对模式队列和rx数据缓冲区的原子访问是应用程序的责任
* 当使用模式检测特征。
* @param uart_num UART端口号,最大端口号为(UART_NUM_MAX -1)。
* @return
* -(-1)没有找到当前索引或参数错误的模式
* -其他的模式位置在rx缓冲区。
*/
int  uart_pattern_get_pos (uart_port_t uart_num);

/*
* 分配一个给定长度的新内存来保存rx缓冲区中检测到的模式位置。
* @param uart_num UART端口号,最大端口号为(UART_NUM_MAX -1)。
* @param queue_length检测到的模式的最大队列长度。
* 如果队列长度不够大,一些模式位置可能会丢失。
* 设置此值为数据缓冲区可同时保存模式的最大数量。
* @return
* - ESP_ERR_NO_MEM内存不足
* -未安装ESP_ERR_INVALID_STATE驱动程序
* - ESP_FAIL参数错误
* - ESP_OK成功
*/
esp_err_t uart_pattern_queue_reset(uart_port_t uart_num, int  queue_length);

/*
* @brief UART设置通信模式
* @note这个函数必须在uart_driver_install()之后,当驱动对象初始化时执行。
* @param uart_num要配置的Uart编号,最大端口号为(UART_NUM_MAX -1)。
* @param mode UART UART模式设置
* @return
* - ESP_OK成功
* - ESP_ERR_INVALID_ARG参数错误
*/
esp_err_t uart_set_mode(uart_port_t uart_num, uart_mode_t mode);

/*
* @brief设置RX fifo满的uart阈值
* @note如果应用程序使用更高的波特率,它是观察字节
* 在硬件RX fifo被覆盖,然后这个阈值可以减少
* @param uart_num UART_NUM_0, UART_NUM_1或UART_NUM_2
* @param threshold RX fifo全中断的阈值
* @return
* - ESP_OK成功
* - ESP_ERR_INVALID_ARG参数错误
* -未安装ESP_ERR_INVALID_STATE驱动程序
*/
esp_err_t uart_set_rx_full_threshold(uart_port_t uart_num, int  threshold);

/*
* @brief设置uart阈值为空的fifo
* @param uart_num UART_NUM_0, UART_NUM_1或UART_NUM_2
* @param threshold TX fifo空中断产生的阈值
* @return
* - ESP_OK成功
* - ESP_ERR_INVALID_ARG参数错误
* -未安装ESP_ERR_INVALID_STATE驱动程序
*/
esp_err_t uart_set_tx_empty_threshold(uart_port_t uart_num, int  threshold);

/**
* @brief UART为TOUT特性设置阈值超时
* @param uart_num要配置的Uart编号,最大端口号为(UART_NUM_MAX -1)。
* @param tout_thresh以uart符号周期定义超时阈值。阈值的最大值为126。
* tout_thresh = 1,定义了TOUT中断超时,等于当前波特率下一个符号(~11位)的传输时间。
* 时间过了会触发UART_RXFIFO_TOUT_int 中断。如果tout_thresh == 0,
* 禁用TOUT功能。
* @return
* - ESP_OK成功
* - ESP_ERR_INVALID_ARG参数错误
* -未安装ESP_ERR_INVALID_STATE驱动程序
*/
esp_err_t uart_set_rx_timeout(uart_port_t uart_num, const uint8_t tout_thresh);

/**
* @brief为RS485模式返回碰撞检测标志
* 函数返回碰撞检测标志到collision_flag指向的变量。
* *collision_flag = true,如果检测到碰撞,否则它等于false。
* 这个函数应该在实际传输完成时执行(在uart_write_bytes()之后)。
* @param uart_num配置的最大端口号为(UART_NUM_MAX -1)。
* @param collision_flag bool类型变量的指针,返回碰撞标志。
* @return
* - ESP_OK成功
* - ESP_ERR_INVALID_ARG参数错误
*/
esp_err_t uart_get_collision_flag(uart_port_t uart_num, bool* collision_flag);

/**
* 设置RX引脚信号边缘的数量,用于灯光休眠唤醒
* UART可以用来唤醒系统从轻度睡眠。这个特性很有用
* 通过计数RX引脚上的正边的数量,并将计数与
* 阈值。当计数超过阈值时,系统将被唤醒
* 光睡觉。提供阈值设置功能。
* 停止位和奇偶校验位(如果启用)也会影响边缘的数量。
* 例如,ASCII码97的字母“a”在网络上被编码为0100001101
* (与8n1配置),包括启动和停止位。这个序列有3个
* 正边缘(从0过渡到1)。因此,唤醒系统
* 当'a'被发送时,设置wakeup_threshold=3。
* 触发唤醒的字符没有被UART接收(即它不能
* 从UART FIFO获得)。根据波特率,几个字符
* 后即不受理。请注意,当芯片进入和退出
* 轻睡眠模式,APB频率将会改变。确保UART有
* 始终正确的波特率,选择REF_TICK作为UART时钟源,
* 将uart_config_t中的use_ref_tick字段设置为true。
* @note在ESP32中,唤醒信号只能通过IO_MUX(即IO_MUX)输入。
* GPIO3应该配置为function_1来唤醒UART0,
* GPIO9应该配置为function_5来唤醒UART1), UART2
* 不支持轻睡眠唤醒功能。
* @param uart_num UART编号,最大端口号为(UART_NUM_MAX -1)。
* @param wakeup_threshold RX边缘的数量,为轻睡眠唤醒,值为3 ..0 x3ff。
* @return
* - ESP_OK表示成功
* - uart_num不正确或wakeup_threshold不正确时为ESP_ERR_INVALID_ARG
* 在[3,0x3ff]范围之外。
*/
esp_err_t uart_set_wakeup_threshold(uart_port_t uart_num, int  wakeup_threshold);

/**
* 获取RX引脚信号边缘的数量为轻睡眠唤醒。
* 关于UART的解释请参见uart_set_wakeup_threshold的描述
* 唤醒功能。
* @param uart_num UART编号,最大端口号为(UART_NUM_MAX -1)。
* @param[out] out_wakeup_threshold输出,设置为wakeup的当前值
* 给定UART的阈值。
* @return
* - ESP_OK表示成功
* -如果out_wakeup_threshold为NULL,则ESP_ERR_INVALID_ARG
*/
esp_err_t uart_get_wakeup_threshold(uart_port_t uart_num, int * out_wakeup_threshold);

/**
* @brief等待直到UART tx内存空和最后一个字符发送ok(轮询模式)。
* @param uart_num UART编号
* * @return
* - ESP_OK表示成功
* - ESP_ERR_INVALID_ARG参数错误
* -未安装ESP_FAIL驱动
*/
esp_err_t uart_wait_tx_idle_polling (uart_port_t uart_num);

/**
* 配置TX信号回RX模块,仅供测试使用。
* @param uart_num UART编号
* @param loop_back_en设置为true以启用回循环函数,否则设置为false。
* * @return
* - ESP_OK表示成功
* - ESP_ERR_INVALID_ARG参数错误
* -未安装ESP_FAIL驱动
*/
esp_err_t uart_set_loop_back(uart_port_t uart_num, bool loop_back_en);

/**
* 配置UART RX超时中断的行为。
* 当always_rx_timeout为true时,即使FIFO已满也会触发超时中断。
* 这个函数可以导致额外的超时中断触发只发送超时事件。
* 只有当你想确保超时中断总是发生在字节流之后,才调用这个函数。
* @param uart_num UART编号
* @param always_rx_timeout_en设置为false启用超时中断的默认行为,
*设置为true总是触发超时中断。
*/
Void uart_set_always_rx_timeout(uart_port_t uart_num, bool always_rx_timeout_en);

Logo

CSDN联合极客时间,共同打造面向开发者的精品内容学习社区,助力成长!

更多推荐