ESP32串口通信(胎教级教程)

目录

引言

硬件准备

软件环境

ESP32串口资源及常用API介绍

板上串口资源

UART0

UART1

UART2

常用API

1.uart_driver_install

函数原型

参数

2.uart_param_config

函数原型

参数

3.uart_set_pin

函数原型

参数

4.uart_write_bytes

函数原型

参数

5.uart_read_bytes

函数原型

参数

注意事项

代码部分

1.uart.h

2.uart.c

3.main.c

接线示意

最终效果 


引言

在物联网(IoT)和嵌入式系统开发中,设备之间的通信是实现功能的关键环节之一。其中,串口通信作为一种简单而高效的通信方式,常被用于设备与上位机(如电脑)之间的数据交互。本文不再详细介绍串口通信协议,而是详细介绍如何使用 ESP-IDF框架下,通过ESP32的串口与上位机进行通信。通过本文的介绍,即使是初学者也能快速掌握ESP32串口通信的基本方法,并将其应用到自己的项目中。

硬件准备

1.ESP32-DevKitC开发板,如下图:

 2.USB转TTL模块,就是常用的CH340模块,如下图:

3.一条数据线和杜邦线若干。 

软件环境

1.esp-idf+vscode开发环境,具体安装方法请移步至官方文档或相关教程,这里不作深入探讨。

2.串口上位机,任选即可。

ESP32串口资源及常用API介绍

板上串口资源

ESP32 DevKit-C 开发板基于 ESP32 芯片,该芯片总共支持 3个 UART 接口,分别是 UART0、UART1 和 UART2。

UART0

  • 用途:通常用于调试日志输出和程序下载。

  • 引脚:默认情况下,UART0 的 TX 和 RX 引脚分别连接到开发板的 GPIO1 和 GPIO3。

UART1

  • 用途:用户自定义通信,通常用于与其他设备的串口通信。

  • 引脚:可通过软件配置任意 GPIO 引脚作为 UART1 的 TX 和 RX。

UART2

  • 用途:用户自定义通信,也可以用于与其他设备的串口通信。

  • 引脚:同样可以通过软件配置任意 GPIO 引脚作为 UART2 的 TX 和 RX。

常用API

1.uart_driver_install

该函数用于安装 UART 驱动程序,并为 UART 驱动分配所需的内部资源。

函数原型
esp_err_t uart_driver_install(uart_port_t uart_num, int rx_buffer_size, int tx_buffer_size, int event_queue_size, QueueHandle_t *uart_queue, int intr_alloc_flags);
参数
  • uart_num:UART 端口号(如 UART_NUM_0、UART_NUM_1、UART_NUM_2)。

  • rx_buffer_size:接收缓冲区大小。

  • tx_buffer_size:发送缓冲区大小。

  • event_queue_size:事件队列大小。

  • uart_queue:指向事件队列句柄的指针,如果不需要事件队列,可以传入 NULL

  • intr_alloc_flags:中断分配标志。

2.uart_param_config

该函数用于配置 UART 的通信参数。

函数原型
esp_err_t uart_param_config(uart_port_t uart_num, const uart_config_t *uart_config);
参数
  • uart_num:UART 端口号。

  • uart_config:指向 uart_config_t结构体的指针,该结构体包含波特率、数据位、停止位、奇偶校验位等参数。

3.uart_set_pin

该函数用于将 UART 的信号分配到指定的 GPIO 引脚。

函数原型
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);
参数
  • uart_num:UART 端口号。

  • tx_io_num:TX 信号的 GPIO 引脚编号。

  • rx_io_num:RX 信号的 GPIO 引脚编号。

  • rts_io_num:RTS 信号的 GPIO 引脚编号,如果不使用,可以传入 UART_PIN_NO_CHANGE

  • cts_io_num:CTS 信号的 GPIO 引脚编号,如果不使用,可以传入 UART_PIN_NO_CHANGE

4.uart_write_bytes

该函数用于通过 UART 发送数据。

函数原型
int uart_write_bytes(uart_port_t uart_num, const void *src, size_t size);
参数
  • uart_num:UART 端口号。

  • src:指向要发送的数据的指针。

  • size:要发送的数据的大小。

5.uart_read_bytes

该函数用于从 UART 的接收缓冲区读取数据。

函数原型
int uart_read_bytes(uart_port_t uart_num, void *buf, uint32_t length, TickType_t ticks_to_wait);
参数
  • uart_num:UART 端口号。

  • buf:指向接收缓冲区的指针。

  • length:要读取的最大字节数。

  • ticks_to_wait:等待时间,单位为 FreeRTOS 的 tick。如果设置为 portMAX_DELAY,则会阻塞直到数据可用。

注意事项

  • 引脚复用:ESP32 的 GPIO 引脚具有多种功能,因此在使用 UART1 和 UART2 时,需要通过软件配置来指定具体的引脚,下图来自乐鑫官方文档,可以看到还是有很多引脚可以映射为串口通信引脚的。本文配置为使用UART_NUM_1,TX和RX分别是引脚22和23。

  • 硬件限制:UART0 的引脚通常用于调试和程序下载,不建议更改其默认配置。

  • 通信速率:ESP32 的 UART 接口支持高达 5 Mbps 的通信速率。

代码部分

1.uart.h

主要是引脚分配和接收缓冲区定义以及相关函数声明。

/**
 * @file uart.h
 * @brief 
 * @author XJJane_^o^ (13778247139@163.com)
 * @version 1.0
 * @date 2025-05-25
 * 
 * @copyright Copyright (c) 2025  
 * 
 * @par 修改日志:
 */


#ifndef _UART_H
#define _UART_H

#include <stdint.h>
#include "driver/uart.h"
#include "driver/gpio.h"
#include "esp_log.h"
#include "esp_err.h"
#include <string.h>

#define UART_NUM UART_NUM_1
#define UART_TX_PIN 22
#define UART_RX_PIN 23
#define UART_BUF_SIZE 1024
#define UART_TAG "UART"
static uint8_t s_uart2_rx_buf[UART_BUF_SIZE];


void uart_init(uint32_t baud_rate);
void uart_transmit(const char* data);
void uart_receive(void);


#endif


2.uart.c

具体函数实现,包括串口初始化,串口发送函数,串口接收函数。

/**
 * @file uart.c
 * @brief 
 * @author XJJane_^o^ (13778247139@163.com)
 * @version 1.0
 * @date 2025-05-25
 * 
 * @copyright Copyright (c) 2025
 * 
 * @par 修改日志:
 */
#include "uart.h"

/**
 * @brief 串口初始化
 * @param  baud_rate   波特率
 */
void uart_init(uint32_t baud_rate){
    const uart_config_t uart_config = {
        .baud_rate = baud_rate,
        .data_bits = UART_DATA_8_BITS,  // 8位数据位
        .parity = UART_PARITY_DISABLE,  // 无校验位
        .stop_bits = UART_STOP_BITS_1,  // 1位停止位
        .flow_ctrl = UART_HW_FLOWCTRL_DISABLE,  // 禁用流控
        .source_clk = UART_SCLK_DEFAULT,  // 使用默认时钟源
    };
    ESP_ERROR_CHECK(uart_driver_install(UART_NUM, UART_BUF_SIZE, 0, 0, NULL, 0)); // 串口驱动安装
    ESP_ERROR_CHECK(uart_param_config(UART_NUM, &uart_config)); // 串口参数配置
    ESP_ERROR_CHECK(uart_set_pin(UART_NUM, UART_TX_PIN, UART_RX_PIN, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE)); // 串口引脚配置
}

/**
 * @brief 串口发送
 * @param  data   要发送的字符串
 */
void uart_transmit(const char* data){
    uart_write_bytes(UART_NUM, data, strlen(data));
    ESP_LOGI(UART_TAG,"TX -> %s",data);
}


/**
 * @brief 串口接收
 */
void uart_receive(void){
    int len = uart_read_bytes(UART_NUM,s_uart2_rx_buf,sizeof(s_uart2_rx_buf)-1,pdMS_TO_TICKS(10));
    if(len > 0){
        s_uart2_rx_buf[len] = '\0';
        ESP_LOGI(UART_TAG,"RX -> %s",s_uart2_rx_buf);
    }
}

3.main.c

创建2个任务,一个用于发送(以1秒间隔不停发送字符串给上位机),一个用于接收(不停接收来自上位机的消息)。

/**
 * @file main.c
 * @brief 
 * @author XJJane_^o^ (13778247139@163.com)
 * @version 1.0
 * @date 2025-05-25
 * 
 * @copyright Copyright (c) 2025
 * 
 * @par 修改日志:
 */
#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "uart.h"

/**
 * @brief 串口发送任务
 */
void uart_transmit_task(void){
    while(1){
        uart_transmit("Hello XJJane_^o^");
        vTaskDelay(pdMS_TO_TICKS(1000));
    }
}


/**
 * @brief 串口接收任务
 */
void uart_receive_task(void){
    while(1){
        uart_receive();
    }
}
void app_main(void)
{
    uart_init(115200);
    xTaskCreatePinnedToCore(uart_transmit_task, "uart_transmit_task", 2048, NULL, 5, NULL, 1);
    xTaskCreatePinnedToCore(uart_receive_task, "uart_receive_task", 2048, NULL, 6, NULL, 1);
    
}

接线示意

最终效果 

上位机设置1秒定时发送(左),打开esp-idf的串口监视器(右),最终效果如下:

最终效果

PS:完整代码工程请读者移步至我的gitee仓库:ESP32_UartDemo: 实现ESP32与上位机的串口通信

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值