给出一个基于 ESP-IDF 且不占用硬件 UART 的“软串口”实现,利用 RMT 外设 来模拟第三路 UART

下面给出一个基于 ESP-IDF 且不占用硬件 UART 的“软串口”实现,利用 RMT 外设 来模拟第三路 UART(全双工需额外参考开源库,下面示例只给出 TX 与初始化思路,RX 可参考 esp32-rmt-uart 项目):

#include "driver/rmt.h"
#include "driver/gpio.h"
#include "esp_log.h"

static const char *TAG = "soft_uart_rmt";

// ---------------------- 配置项 ----------------------
#define SOFT_UART_TX_GPIO   17      // “软串口”TX 引脚
#define SOFT_UART_RX_GPIO   16      // “软串口”RX 引脚(后面参考库实现)
#define RMT_TX_CHANNEL      RMT_CHANNEL_0
#define RMT_RX_CHANNEL      RMT_CHANNEL_1
#define SOFT_UART_BAUD_RATE 9600    // 波特率
#define RMT_CLK_DIV         80      // 80MHz / 80 = 1MHz → 1µs 精度
// ------------------------------------------------------

static uint32_t bit_ticks;          // 每位脉冲持续时间,单位:RMT tick(µs)

// 初始化 RMT TX,用来输出串口波形
void soft_uart_rmt_tx_init(void)
{
    // 计算每 bit 的时长(µs):1e6 / 波特率
    bit_ticks = 1000000 / SOFT_UART_BAUD_RATE;

    rmt_config_t tx_cfg = {
        .rmt_mode       = RMT_MODE_TX,
        .channel        = RMT_TX_CHANNEL,
        .gpio_num       = SOFT_UART_TX_GPIO,
        .clk_div        = RMT_CLK_DIV,
        .mem_block_num  = 1,
    };
    ESP_ERROR_CHECK(rmt_config(&tx_cfg));
    ESP_ERROR_CHECK(rmt_driver_install(tx_cfg.channel, 0, 0));

    // 闲置状态保持高电平(UART idle = 1)
    gpio_set_direction(SOFT_UART_TX_GPIO, GPIO_MODE_OUTPUT);
    gpio_set_level(SOFT_UART_TX_GPIO, 1);

    ESP_LOGI(TAG, "Soft UART TX initialized on GPIO %d at %d baud", 
             SOFT_UART_TX_GPIO, SOFT_UART_BAUD_RATE);
}

// 通过 RMT 发送单个字节
void soft_uart_rmt_send_byte(uint8_t data)
{
    // 最多 1 起始 + 8 数据 + 1 停止 = 10 个 item
    rmt_item32_t items[10];
    int idx = 0;

    // 1. 起始位:低电平
    items[idx].level0   = 0;
    items[idx].duration0= bit_ticks;
    items[idx].level1   = 1;
    items[idx].duration1= 0;
    idx++;

    // 2. 数据位:LSB 先发
    for (int i = 0; i < 8; i++) {
        items[idx].level0    = (data >> i) & 0x01;
        items[idx].duration0 = bit_ticks;
        items[idx].level1    = 1;
        items[idx].duration1 = 0;
        idx++;
    }

    // 3. 停止位:高电平
    items[idx].level0    = 1;
    items[idx].duration0 = bit_ticks;
    items[idx].level1    = 1;
    items[idx].duration1 = 0;
    idx++;

    // 发送,最后一个参数 true 表示等待发送完成
    ESP_ERROR_CHECK(rmt_write_items(RMT_TX_CHANNEL, items, idx, true));
}

// 发送缓冲区
void soft_uart_rmt_send(const uint8_t *buf, size_t len)
{
    for (size_t i = 0; i < len; i++) {
        soft_uart_rmt_send_byte(buf[i]);
    }
    ESP_LOGI(TAG, "Sent %d bytes via soft UART", len);
}

// ----------------- RX 部分说明 -----------------
// RMT 接收串口需要把外部的高低电平脉冲抓到 RMT FIFO,然后再解析成 bit。
// 这里建议直接使用社区开源项目:https://github.com/lorol/esp32-rmt-uart  
// 它能一并完成 RX/TX,支持多路软串口,并且集成到 ESP-IDF 中。  
// 只需在 components/ 下添加该库,并按文档调用即可。  
// -----------------------------------------------

void app_main(void)
{
    // 1. 初始化软串口 TX
    soft_uart_rmt_tx_init();

    // 2. 示例:发送字符串
    const char *test_str = "Hello from soft UART!\r\n";
    soft_uart_rmt_send((const uint8_t *)test_str, strlen(test_str));

    // 3. 如果需要 RX,请集成 esp32-rmt-uart 库,并配置 RMT_RX_CHANNEL 与 SOFT_UART_RX_GPIO
}

说明:

  • 使用 RMT 硬件定时精确输出每位高低电平,不会像简单 GPIO bit-banging 那样 CPU 占用严重,也能跑到几万 bps。

  • esp32-rmt-uart 项目封装了完整的 RX/TX 逻辑,只需按其 README 添加 component,就能轻松创建全双工“软串口”。

  • 上述示例只演示了如何初始化 TX 并发送数据,如需完整收发,参考 lorol/esp32-rmt-uart,只需配置好 RMT 通道即可。

这样,您就可以在 ESP32-C3 上再增加一条稳定的“软串口”,无需占用任何硬件 UART 口。

给出一个基于 ESP-IDF 且不占用硬件 UART 的“软串口”实现,利用 RMT 外设 来模拟第三路 UART_第1张图片

你可能感兴趣的:(四博智联ESP32-C3模组,单片机,嵌入式硬件,DOIT,四博智联)