ESP32 IDF开发 驱动篇⑦UART两个串口的使用

ESP32 IDF开发 驱动篇⑦UART两个串口的使用

  • 1、博主写这篇技术文章的目的:
    • 2、Uart库的介绍
    • 3、软件设计
    • 4、实例分析
    • 5、以下是调试的结果:

别迷路-导航栏
快速导航找到你想要的(文章目录)

此篇文章如果对你有用,请点赞收藏,您的支持就是博主坚持的动力。

1、博主写这篇技术文章的目的:

(1)熟悉掌握UART相关API;
(2)掌握esp32 串口的使用方法;

2、Uart库的介绍

ESP32最多只有3个串口上。
有关Uart详细函数请参考msys32\esp-idf\components\driver\include\driver\uart.h
在这里我只做几个重要经常使用的API函数讲解

Uart库函数分为:
(1)、填充uart结构体设置串口基本参数;
(2)、锁定串口引脚;
(3)发送接收串口数据
uart结构体设置串口API:

/**
  * @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);
/**
  * @brief 配置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);

锁定串口引脚API:

/**
  * @brief 设置UART引脚号
  * @note 内部信号可以输出到多个GPIO焊盘。
  *只有一个GPIO垫可以连接输入信号。
  * @note 可能会提供宏'UART_PIN_NO_CHANGE'代替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驱动程序并将UART设置为默认配置。
 *
 * UART ISR处理程序将连接到运行此函数的同一CPU内核。
 *
 * @note 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环形缓冲区的大小。
 *如果设置为零,驱动程序将不使用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);

发送接收串口数据相关API函数

/**
  * @brief 从给定的缓冲区和长度将数据发送到UART端口,将数据发送到TX FIFO就返回
  * @param uart_num UART端口号,最大端口号是(UART_NUM_MAX -1)。
  * @param src数据缓冲区地址 要发送的参数大小数据长度
  * @return
  *-(-1)参数错误
  *-其他(> = 0)推送到TX FIFO的字节数
  */
int uart_write_bytes(uart_port_t uart_num, const char* src, size_t size);
/**
  * @brief 等待直到UART TX FIFO为空。
  * @param uart_num UART端口号,最大端口号是(UART_NUM_MAX -1)。
  * @param ticks_to_wait超时,以RTOS滴答计数
  * @返回
  *-ESP_OK成功
  *-ESP_FAIL参数错误
  *-ESP_ERR_TIMEOUT超时
  */
esp_err_t uart_wait_tx_done(uart_port_t uart_num, TickType_t ticks_to_wait);
/**
  * @brief UART从UART缓冲区读取字节
  *
  * @param uart_num UART端口号,最大端口号是(UART_NUM_MAX -1)。
  * @param buf指向缓冲区的指针。
  * @参数长度数据长度
  * @param ticks_to_wait sTimeout,以实时操作系统滴答计数
  *
  * @返回
  *-(-1)错误
  *-其他(> = 0)从UART FIFO读取的字节数
  */
int uart_read_bytes(uart_port_t uart_num, uint8_t* buf, uint32_t length, TickType_t ticks_to_wait);
/**
  * @brief 清除输入缓冲区,丢弃所有在环形缓冲区中的数据。
  * @note 为了在tx FIFO中发送所有数据,我们可以使用uart_wait_tx_done函数。
  * @param uart_num UART端口号,最大端口号是(UART_NUM_MAX -1)。
  *
  * @返回
  *-ESP_OK成功
  *-ESP_FAIL参数错误
  */
esp_err_t uart_flush_input(uart_port_t uart_num);

3、软件设计

首先我们来分析一下uart的结构体:
第一步:

/**
 * @brief UART uart_param_config函数的配置参数
 */
typedef struct {
    int baud_rate;                      /*!< UART 波特率*/
    uart_word_length_t data_bits;       /*!< UART 数据位,一般8位*/
    uart_parity_t parity;               /*!< UART 奇偶校验模式*/
    uart_stop_bits_t stop_bits;         /*!< UART 停止位*/
    uart_hw_flowcontrol_t flow_ctrl;    /*!< UART 硬件流控制模式(cts / rts)*/
    uint8_t rx_flow_ctrl_thresh;        /*!< UART 硬件流控*/
    union {
        uart_sclk_t source_clk;         /*!< UART 源时钟选择 */
        bool use_ref_tick  __attribute__((deprecated));
    };
} uart_config_t;

从上面的结构我们可以看出我们只需要填充串口的一些基本参数然后使用

esp_err_t uart_param_config(uart_port_t uart_num, const uart_config_t *uart_config)

将参数配置到对应的串口中。
第二步:设置引脚,IO映射,一般只需要设置tx,rx引脚

uart_set_pin(UART_NUM_1, TXD1_PIN, RXD1_PIN, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE);

注册串口主要实现的功能就是为tx FIFO和rx FIFO分配内存,同时创建消息队列

uart_driver_install(UART_NUM_1, RX1_BUF_SIZE * 2, TX1_BUF_SIZE * 2, 0, NULL, 0);

第三部就是数据发送与接收使用函数uart_write_bytes,uart_read_bytes

4、实例分析

在任务中读写串口:
复制上一个工程改名字为 idf_uart即可 文件名字改为idf_uart.C makefile文件也改成 PROJECT_NAME := idf_uart即可,然后复制一下代码测试。

/**********************************************************************
*               文件名:            idf_uart.c
*               创建人:            
*               创建日期:           
*               修改人:
*               修改日期:           
*               版本号:            V1.1
*               备注:
*               公司:
********************************************************************/
#include 
#include "string.h"

#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "driver/uart.h"
#include "driver/gpio.h"
//UART1
#define RX1_BUF_SIZE        (1024)
#define TX1_BUF_SIZE        (512)
#define TXD1_PIN            (GPIO_NUM_5)
#define RXD1_PIN            (GPIO_NUM_4)

//UART0
#define RX0_BUF_SIZE        (1024)
#define TX0_BUF_SIZE        (512)
#define TXD0_PIN            (GPIO_NUM_1)//系统默认的下载口
#define RXD0_PIN            (GPIO_NUM_3)

//任务句柄 
static TaskHandle_t xHandleTaskUart0 = NULL;
static TaskHandle_t xHandleTaskUart1 = NULL;

static void vTaskUart0(void *pvParameters);
static void vTaskUart1(void *pvParameters);
/***********************************************************************
* 函数:  
* 描述:   串口配置初始化
* 参数:
* 返回: 无
* 备注:
************************************************************************/
void uart_init(void)
{
    //串口配置结构体
    uart_config_t uart0_config = {
        .baud_rate = 115200,
        .data_bits = UART_DATA_8_BITS,
        .parity    = UART_PARITY_DISABLE,
        .stop_bits = UART_STOP_BITS_1,
        .flow_ctrl = UART_HW_FLOWCTRL_DISABLE,
        .source_clk = UART_SCLK_APB,
    };
    //注采用以下方式初始化参数,系统启动或会出现rx flow thresh error的错误,但不影响使用
    //串口参数配置->uart0
    // uart0_config.baud_rate = 115200;                 //波特率
    // uart0_config.data_bits = UART_DATA_8_BITS;           //数据位
    // uart0_config.parity = UART_PARITY_DISABLE;           //校验位
    // uart0_config.stop_bits = UART_STOP_BITS_1;           //停止位
    // uart0_config.flow_ctrl = UART_HW_FLOWCTRL_DISABLE;   //硬件流控
    uart_param_config(UART_NUM_0, &uart0_config);       //设置串口
    //IO映射-> T:IO1  R:IO3;系统默认的下载就就是1,3所以可以不用设置管脚
    //uart_set_pin(UART_NUM_0, TXD0_PIN, RXD0_PIN, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE);
    //注册串口服务即使能+设置缓存区大小
    uart_driver_install(UART_NUM_0, RX0_BUF_SIZE * 2, TX0_BUF_SIZE * 2, 0, NULL, 0);
    uart_config_t uart1_config;
        //串口参数配置->uart1
    uart1_config.baud_rate = 115200;                    //波特率
    uart1_config.data_bits = UART_DATA_8_BITS;          //数据位
    uart1_config.parity = UART_PARITY_DISABLE;          //校验位
    uart1_config.stop_bits = UART_STOP_BITS_1;          //停止位
    uart1_config.flow_ctrl = UART_HW_FLOWCTRL_DISABLE;  //硬件流控
    uart_param_config(UART_NUM_1, &uart1_config);       //设置串口
    //IO映射-> T:IO4  R:IO5
    uart_set_pin(UART_NUM_1, TXD1_PIN, RXD1_PIN, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE);
    //注册串口服务即使能+设置缓存区大小
    uart_driver_install(UART_NUM_1, RX1_BUF_SIZE*2, TX1_BUF_SIZE*2, 0, NULL, 0);
}
/***********************************************************************
* 函数:  
* 描述:   主函数
* 参数:
* 返回: 无
* 备注:
************************************************************************/
void app_main()
{    
    //串口初始化
    uart_init();
    //创建串口0任务
    xTaskCreate(vTaskUart0,         // 任务函数              
            "vTaskUart0",           // 任务名
            4096,                   // 任务栈大小,单位 word,也就是 4 字节 
            NULL,                   // 任务参数  
            2,                      // 任务优先级
            xHandleTaskUart0);      // 任务句柄 

    //创建串口1任务
    xTaskCreate(vTaskUart1,         // 任务函数              
            "vTaskUart1",           // 任务名
            4096,                   // 任务栈大小,单位 word,也就是 4 字节 
            NULL,                   // 任务参数  
            3,                      // 任务优先级
            xHandleTaskUart1);      // 任务句柄 

    //串口0数据发送测试     

    uart_write_bytes(UART_NUM_0, "vTaskUart0 Task Create OK ", strlen("vTaskUart0 Task Create OK "));
    
    //串口1数据发送测试     
    uart_write_bytes(UART_NUM_1, "vTaskUart1 Task Create OK ", strlen("vTaskUart1 Task Create OK "));
}
/***********************************************************************
* 函数:  
* 描述:   串口0回调函数
* 参数:
* 返回: 无
* 备注:
************************************************************************/
static void vTaskUart0(void *pvParameters)
{
    uint8_t* data = (uint8_t*) malloc(RX0_BUF_SIZE+1);
    for (;;) 
    {
        //获取串口1接收的数据
        int rxBytes = uart_read_bytes(UART_NUM_0, data, RX0_BUF_SIZE, 10 / portTICK_RATE_MS);//10ms读一次,一个系统滴答
        if (rxBytes > 0) {
            data[rxBytes] = 0;
            //将接收到的数据发出去
            uart_write_bytes(UART_NUM_0, (char *)data, rxBytes);
        }
    }
    free(data);
}
/***********************************************************************
* 函数:  
* 描述:   串口1回调函数
* 参数:
* 返回: 无
* 备注:
************************************************************************/
static void vTaskUart1(void *pvParameters)
{
    uint8_t* data = (uint8_t*) malloc(RX1_BUF_SIZE+1);
    for (;;)  
    {
        int rxBytes = uart_read_bytes(UART_NUM_1, data, RX1_BUF_SIZE, 10 / portTICK_RATE_MS);//10ms读一次,一个系统滴答
        if (rxBytes > 0) {
            data[rxBytes] = 0;
            //将接收到的数据发出去
            uart_write_bytes(UART_NUM_1, (char *)data, rxBytes);
        }
    }
    free(data);
}

5、以下是调试的结果:

ESP32 IDF开发 驱动篇⑦UART两个串口的使用_第1张图片

在这里插入图片描述
我发现系统启动后出现了如下的错误不影响使用,但是这个错误看着令人很不爽。
经过博主研究一番,发现通过一下方式初始化参数时就会出现错误

//串口参数配置->uart0
uart0_config.baud_rate = 115200;                    //波特率
uart0_config.data_bits = UART_DATA_8_BITS;          //数据位
uart0_config.parity = UART_PARITY_DISABLE;          //校验位
uart0_config.stop_bits = UART_STOP_BITS_1;          //停止位
uart0_config.flow_ctrl = UART_HW_FLOWCTRL_DISABLE;  //硬件流控

换成这种方式初始化参数就没有问题

uart_config_t uart0_config = {
.baud_rate = 115200,
.data_bits = UART_DATA_8_BITS,
.parity = UART_PARITY_DISABLE,
.stop_bits = UART_STOP_BITS_1,
.flow_ctrl = UART_HW_FLOWCTRL_DISABLE,
.source_clk = UART_SCLK_APB,
};

ESP32 IDF开发 驱动篇⑦UART两个串口的使用_第2张图片
ESP32 IDF开发 驱动篇⑦UART两个串口的使用_第3张图片

串口1多打印了“vTaskUart1 Task Create OK ”原因是在下载过程中系统重启的原因导致。
所有文章源代码:https://download.csdn.net/download/lu330274924/88518092

你可能感兴趣的:(ESP32,IDF小白到大师实战,单片机,嵌入式硬件,芯片)