[ESP32]UART串口使用

[ESP32]UART串口使用

ESP32里面有3个串口,uart0默认作为log和console输出,我们可以使用uart1和uart2。
它们默认的管脚如下:

UARTGPIOUARTGPIO
U0_RXDGPIO3U0_CTSGPIO19
U0_TXDGPIO1U0_RTSGPIO22
U1_RXDGPIO9U1_CTSGPIO6
U1_TXDGPIO10U1_RTSGPIO11
U2_RXDGPIO16U2_CTSGPIO8
U2_TXDGPIO17U2_RTSGPIO7

在这里插入图片描述
如果是使用ESP32的模组,因为接SPI Flash,会占用GPIO6~GPIO11,所以uart1使用默认管脚的时候会有冲突,我们需要把管脚配置到其它的GPIO上,万幸可以这样进行管理配置。

esp32的串口使用可以分为4步:

  1. 设置串口参数,包括波特率,奇偶校验,数据位与停止位等
  2. 设置串口使用的GPIO管脚
  3. 安装驱动,为uart分配资源
  4. 进行串口通信

1 设置串口参数

调用uart_param_config()方法设置

uart_config_t uart_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_CTS_RTS,	//流控
    .rx_flow_ctrl_thresh = 122,		//硬件RTS阈值
};
// Configure UART parameters
ESP_ERROR_CHECK(uart_param_config(UART_NUM_2, &uart_config));

2 配置串口管脚

通过uart_set_pin()设置串口的映射管脚,使用默认的话,可以用UART_PIN_NO_CHANGE,尽量指定一个吧,默认的貌似不太靠谱。uart_set_pin()参数从左到右分别是:TXD,RXD,RTS,CTS。

// Set UART pins(TX: IO16 (UART2 default), RX: IO17 (UART2 default), RTS: IO18, CTS: IO19)
ESP_ERROR_CHECK(uart_set_pin(UART_NUM_2, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE, 18, 19));

3 安装uart驱动

使用uart_driver_install()函数安装,函数原型如下:

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)

消息队列,可以为NULL,长度为0,如果不处理中断事件,则最后一个参数也为0;
若tx_buffer_size为0,即没有发送缓冲区,则uart_write_bytes()的时候,会阻塞等待所以数据发送完才会返回。
rx_buffer_size不能为空,最好为UART_FIFO_LEN(128)整数倍。

// Setup UART buffered IO with event queue
const int uart_buffer_size = (1024 * 2);
QueueHandle_t uart_queue;
// Install UART driver using an event queue here
ESP_ERROR_CHECK(uart_driver_install(UART_NUM_2, uart_buffer_size, \
                                        uart_buffer_size, 10, &uart_queue, 0));

串口读写数据

发数据

通过uart_write_bytes()发送数据,如果没有设置发送缓冲区,数据发送完都会返回,如果设置了发送缓冲区,则会把发送数据拷贝到缓冲区之后返回,uart的中断服务程序会把发送缓冲区里面的数据移动tx FIFO然后发送出去。

// Write data to UART.
char* test_str = "This is a test string.\n";
uart_write_bytes(uart_num, (const char*)test_str, strlen(test_str));

uart_write_bytes_with_break()也是发送程序,但是它会在发送完数据之后,设置TX低电平一段时间(RTOS任务节拍为单位)

// Write data to UART, end with a break signal.
uart_write_bytes_with_break(uart_num, "test break\n",strlen("test break\n"), 100);

uart_tx_chars()也是发送程序,但是它会直接把数据写到硬件的Tx FIFO,返回写入的数据长度。

uart_wait_tx_done() 会检查硬件Tx FIFO的状态,当它为空或超时时返回。

// Wait for packet to be sent
const int uart_num = UART_NUM_2;
ESP_ERROR_CHECK(uart_wait_tx_done(uart_num, 100)); // wait timeout is 100 RTOS ticks (TickType_t)

收数据

当串口接收到数据时,它会保存到Rx FIFO里面,我们可以通过 uart_read_bytes()读出,这个函数会阻塞待在那里,直到读满需要的字节,或是超时。
当然我们也可以先获取FIFO里面的数据长度[uart_get_buffered_data_len()],然后再读取相应的内容,这样就不会造成不必要的阻塞。

// Read data from UART.
const int uart_num = UART2;
uint8_t data[128];
int length = 0;
ESP_ERROR_CHECK(uart_get_buffered_data_len(uart_num, (size_t*)&length));
length = uart_read_bytes(uart_num, data, length, 100);

如果不需要FIFO里面的内容可以调用:uart_flush().

使用GPIO16作为TXD,GPIO17作为RXD,每2秒发送一个Hello world,短接这两个管脚即可看到结果。
参考代码:

/* UART asynchronous example, that uses separate RX and TX tasks

   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 "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_system.h"
#include "esp_log.h"
#include "driver/uart.h"
#include "string.h"
#include "driver/gpio.h"

static const int RX_BUF_SIZE = 1024;
static const int uart_num = UART_NUM_2;
#define TXD_PIN (GPIO_NUM_16)
#define RXD_PIN (GPIO_NUM_17)

void init(void) {
    const uart_config_t uart_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,
        .rx_flow_ctrl_thresh = 122,		//
    };
    // We won't use a buffer for sending data.
    uart_driver_install(uart_num, RX_BUF_SIZE * 2, 0, 0, NULL, 0);
    uart_param_config(uart_num, &uart_config);
    uart_set_pin(uart_num, TXD_PIN, RXD_PIN, 
        UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE);
    
}

int sendData(const char* logName, const char* data)
{
    const int len = strlen(data);
    const int txBytes = uart_write_bytes(uart_num, data, len);
    ESP_LOGI(logName, "Wrote %d bytes", txBytes);
    return txBytes;
}

static void tx_task(void *arg)
{
    static const char *TX_TASK_TAG = "TX_TASK";
    esp_log_level_set(TX_TASK_TAG, ESP_LOG_INFO);
    while (1) {
        sendData(TX_TASK_TAG, "Hello world");
        vTaskDelay(2000 / portTICK_PERIOD_MS);
    }
}

static void rx_task(void *arg)
{
    static const char *RX_TASK_TAG = "RX_TASK";
    int rxBytes;
    size_t buf_ok;
    uint32_t cnt=0;
    esp_log_level_set(RX_TASK_TAG, ESP_LOG_INFO);
    uint8_t* data = (uint8_t*) malloc(RX_BUF_SIZE+1);
    while (1) {
        ESP_ERROR_CHECK(uart_get_buffered_data_len(uart_num, &buf_ok));
        if (buf_ok>0) {
            ESP_LOGI(RX_TASK_TAG, "read Begin");
            rxBytes = uart_read_bytes(uart_num, data, buf_ok, 1000 / portTICK_RATE_MS);
            if (rxBytes > 0) {
                data[rxBytes] = 0;
                ESP_LOGI(RX_TASK_TAG, "Read %d(%d) bytes: '%s'", rxBytes, buf_ok, data);
                ESP_LOG_BUFFER_HEXDUMP(RX_TASK_TAG, data, rxBytes, ESP_LOG_INFO);
            }
            ESP_LOGI(RX_TASK_TAG, "Recv Task cnt=%d.", cnt);
        }
        cnt++;
        vTaskDelay(100 / portTICK_PERIOD_MS);
    }
    free(data);
}

void app_main(void)
{
    init();
    xTaskCreate(rx_task, "uart_rx_task", 1024*2, NULL, configMAX_PRIORITIES, NULL);
    xTaskCreate(tx_task, "uart_tx_task", 1024*2, NULL, configMAX_PRIORITIES-1, NULL);
}

参考:
https://docs.espressif.com/projects/esp-idf/zh_CN/latest/esp32/api-reference/peripherals/uart.html

  • 8
    点赞
  • 77
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
ESP32是一款集成了Wi-Fi和蓝牙功能的芯片,它支持多种通信接口,包括UART(通用异步收发器)。 UART是一种常见的串行通信接口,用于在芯片之间传输数据。ESP32具有多个UART端口,可以与外部设备进行串行通信。每个UART口都有自己的引脚用于数据传输和控制信号。 在ESP-IDF开发框架中,可以使用UART驱动程序来配置和控制ESP32UART端口。您可以通过设置波特率、数据位、停止位、奇偶校验等参数来配置UART。然后,您可以使用UART驱动程序的API来发送和接收数据。 以下是一个使用ESP-IDF的UART示例代码,演示如何初始化和使用UART: ```c #include <stdio.h> #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "driver/uart.h" #define UART_NUM UART_NUM_1 #define BUF_SIZE (1024) void uart_task(void *pvParameters) { uart_config_t uart_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 }; uart_param_config(UART_NUM, &uart_config); uart_set_pin(UART_NUM, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE); uart_driver_install(UART_NUM, BUF_SIZE, 0, 0, NULL, 0); uint8_t *data = (uint8_t *) malloc(BUF_SIZE); while (1) { int len = uart_read_bytes(UART_NUM, data, BUF_SIZE, 20 / portTICK_RATE_MS); if (len > 0) { uart_write_bytes(UART_NUM, (const char *) data, len); } } free(data); vTaskDelete(NULL); } void app_main() { xTaskCreate(uart_task, "uart_task", 2048, NULL, 10, NULL); } ``` 这段代码创建了一个FreeRTOS任务,该任务初始化了UART并在一个循环中读取数据并将其发送回去。您可以根据自己的需求修改代码中的参数和逻辑。 请注意,以上示例仅供参考,具体的UART配置和使用方法可能因开发环境和需求而异。在您的具体应用中,可能需要根据芯片厂商提供的文档和SDK进行更详细的配置和使用

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值