目录
概述
ESP32-S3 芯片中有三个 UART 控制器可供使用,并且兼容不同的 UART 设备。此外, UART 还可以用作红外数据交换(IrDA)或 RS485 调制解调器。三个 UART控制器分别有一组功 能相同的寄存器,分别为UART0、UART1、UART2,在该实验中我们用到了UART0。 UART 是一种以字符为导向的通用数据链,可以实现设备间的通信。异步通信不需要在发 送数据的过程中添加时钟信息,但这也要求发送端和接收端的速率、停止位以及奇偶校验位等 参数的配置要相同,唯有如此通信才能成功。 UART 数据帧始于一个起始位,接着是有效数据,然后是奇偶校验位,最后才是停止位。 ESP32-S3 芯片上的 UART控制器支持多种字符长度和停止位。另外,控制器还支持软、硬件控 制流和GDMA,可以实现无缝高速的数据传输。
主要特性
- 支持三个可预分频的时钟源
- 可编程收发波特率
- 三个UART的发送FIFO以及接收FIFO共享1024x8-bitRAM
- 全双工异步通信
- 支持输入信号波特率自检功能
- 支持5/6/7/8位数据长度
- 支持1/1.5/2个停止位
- 支持奇偶校验
- 支持AT_CMD特殊字符检测
- 支持RS485协议
- 支持IrDA协议
- 支持GDMA高速数据通信
- 支持UART唤醒模式
- 支持软件流控和硬件流控
UART函数解析
1.头文件
ESP-IDF提供了一套API来配置串口。要使用串口功能,需要导入必要的头文件:
#include "driver/uart.h"
2.配置UART端口
该函数用来设置指定UART端口的通信参数,该函数原型如下所示:
esp_err_t uart_param_config(uart_port_t uart_num, const uart_config_t *uart_config)
入参:
uart_port_t uart_num: //UART外设端口号
①:UART_NUM_0 //串口0
②:UART_NUM_1 //串口1
③:UART_NUM_2 //串口2
uart_config: //指向结构体,看例程
例程:
uart_config_t uart_config; /* 串口配置句柄 */
uart_config.baud_rate = baudrate; /* 波特率 */
uart_config.data_bits = UART_DATA_8_BITS; /* 字长为8位数据格式 */
uart_config.parity = UART_PARITY_DISABLE; /* 无奇偶校验位 */
uart_config.stop_bits = UART_STOP_BITS_1; /* 一个停止位 */
uart_config.flow_ctrl = UART_HW_FLOWCTRL_DISABLE; /* 无硬件控制流 */
uart_config.source_clk = UART_SCLK_APB; /* 配置时钟源 */
uart_config.rx_flow_ctrl_thresh = 122; /* 硬件控制流阈值 */
uart_param_config(USART_UX, &uart_config); /* 配置uart端口 */
uart_config_t结构体参数值描述:
3.配置UART引脚
该函数设置某个管脚的中断服务函数,该函数原型如下所示:
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 外设端口号
UART_NUM_0
UART_NUM_1
UART_NUM_2
tx_io_num //UART发送引脚的GPIO号。若不需要此功能,可将此参数设为-1。
rx_io_num //UART接收引脚的GPIO号。若不需要此功能,可将此参数设为-1。
rts_io_num //UART请求发送(RTS)引脚的GPIO号。若不需要此功能,可将此参数
设为-1,例如:UART_PIN_NO_CHANGE = -1
cts_io_num //UART 清除发送(CTS)引脚的GPIO号。若不需要此功能,可将此参数
设为-1,例如:UART_PIN_NO_CHANGE = -1
例子:
#define USART_UX UART_NUM_0
#define USART_TX_GPIO_PIN GPIO_NUM_43
#define USART_RX_GPIO_PIN GPIO_NUM_44
uart_set_pin(USART_UX, USART_TX_GPIO_PIN,
USART_RX_GPIO_PIN,
UART_PIN_NO_CHANGE,
UART_PIN_NO_CHANGE);
其中 UART_PIN_NO_CHANGE 就是=-1
4.安装程序
该函数用于安装 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 //UART 接收环形缓冲区大小,用于存储接收到的数据。
tx_buffer_size //UART发送环形缓冲区大小,用于存储有待发送的数据。
queue_size //UART 驱动程序内部缓冲队列的大小,用于存储待处理的接收和
发送数据。
uart_queue //指向用户定义的用于接收数据的队列句柄,在接收数据时,接收
到的数据会存储在这个队列中。
intr_alloc_flags //UART 中断分配标志,用于配置中断分配策略。
#define ESP_INTR_FLAG_LEVEL1
#define ESP_INTR_FLAG_LEVEL2
#define ESP_INTR_FLAG_LEVEL3
#define ESP_INTR_FLAG_LEVEL4
#define ESP_INTR_FLAG_LEVEL5
#define ESP_INTR_FLAG_LEVEL6
#define ESP_INTR_FLAG_NMI
#define ESP_INTR_FLAG_SHARED
#define ESP_INTR_FLAG_EDGE
#define ESP_INTR_FLAG_IRAM
#define ESP_INTR_FLAG_INTRDISABLED
例程:
/* 引脚和串口定义 */
#define USART_UX UART_NUM_0
#define USART_TX_GPIO_PIN GPIO_NUM_43
#define USART_RX_GPIO_PIN GPIO_NUM_44
/* 串口接收相关定义 */
#define RX_BUF_SIZE 1024 /* 环形缓冲区大小 */
/* 安装串口驱动 */
uart_driver_install(USART_UX, RX_BUF_SIZE * 2, RX_BUF_SIZE * 2, 20, NULL, 0);
5.获取数据长度
该函数用于获取接收环形缓冲区中缓存的数据长度,其函数原型如下所示:
esp_err_t uart_get_buffered_data_len(uart_port_t uart_num, size_t* size);
入参
uart_num //UART外设端口号
UART_NUM_0
UART_NUM_1
UART_NUM_2
size //结构体size_t指针所接受缓存的数据长度
例程:
uint8_t len = 0;
uart_get_buffered_data_len(USART_UX, (size_t*) &len);
6.接受数据
该函数从UART 接收缓冲区中读取数据,其函数原型如下所示:
int uart_read_bytes(uart_port_t uart_num,
void *buf,
uint32_t length,
TickType_t ticks_to_wait)
入参
uart_num //UART外设端口号
UART_NUM_0
UART_NUM_1
UART_NUM_2
buf //指向缓冲区的指针
length //数据长度
ticks_to_wait //超时等待,RTOS节拍计数
例程:
unsigned char data[RX_BUF_SIZE] = {0};
#define USART_UX UART_NUM_0
uart_read_bytes(USART_UX, data, len, 100);
7.接收数据
该函数将指定的数据写入到 UART 发送缓冲区,并触发数据的发送,其函数原型如下所示:
int uart_write_bytes(uart_port_t uart_num, const void *src, size_t size)
入参
uart_num //UART外设端口号
UART_NUM_0
UART_NUM_1
UART_NUM_2
src //指向源数据缓冲区的指针,包含要发送的数据
size //要发送的数据长度
例程:
unsigned char data[RX_BUF_SIZE] = {0};
#define USART_UX UART_NUM_0
#define USART_TX_GPIO_PIN GPIO_NUM_43
#define USART_RX_GPIO_PIN GPIO_NUM_44
#define RX_BUF_SIZE 1024 /* 环形缓冲区大小 */
uart_write_bytes(USART_UX, (const char*)data, strlen((const char*)data)); /* 写数据 */
strlen函数就是用来计算数组的个数
例程
.h文件
#ifndef _USART_H
#define _USART_H
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "driver/uart.h"
#include "driver/uart_select.h"
#include "driver/gpio.h"
/* 引脚和串口定义 */
#define USART_UX UART_NUM_0
#define USART_TX_GPIO_PIN GPIO_NUM_43
#define USART_RX_GPIO_PIN GPIO_NUM_44
/* 串口接收相关定义 */
#define RX_BUF_SIZE 1024 /* 环形缓冲区大小 */
/* 函数声明 */
void usart_init(uint32_t baudrate); /* 初始化串口 */
void USART_RX_DATA();
#endif
.C文件
#include "usart.h"
uint8_t len = 0;
uint16_t times = 0;
unsigned char data[RX_BUF_SIZE] = {0};
/**
* @brief 初始化串口
* @param baudrate: 波特率, 根据自己需要设置波特率值
* @note 注意: 必须设置正确的时钟源, 否则串口波特率就会设置异常.
* @retval 无
*/
void usart_init(uint32_t baudrate)
{
uart_config_t uart_config; /* 串口配置句柄 */
uart_config.baud_rate = baudrate; /* 波特率 */
uart_config.data_bits = UART_DATA_8_BITS; /* 字长为8位数据格式 */
uart_config.parity = UART_PARITY_DISABLE; /* 无奇偶校验位 */
uart_config.stop_bits = UART_STOP_BITS_1; /* 一个停止位 */
uart_config.flow_ctrl = UART_HW_FLOWCTRL_DISABLE; /* 无硬件控制流 */
uart_config.source_clk = UART_SCLK_APB; /* 配置时钟源 */
uart_config.rx_flow_ctrl_thresh = 122; /* 硬件控制流阈值 */
uart_param_config(USART_UX, &uart_config); /* 配置uart端口 */
/* 配置uart引脚 */
uart_set_pin(USART_UX, USART_TX_GPIO_PIN, USART_RX_GPIO_PIN, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE);
/* 安装串口驱动 */
uart_driver_install(USART_UX, RX_BUF_SIZE * 2, RX_BUF_SIZE * 2, 20, NULL, 0);
}
void USART_RX_DATA()
{
uart_get_buffered_data_len(USART_UX, (size_t*) &len);
if(len>0)
{
memset(data, 0, RX_BUF_SIZE);
printf("\n您发送的消息为:\n");
uart_read_bytes(USART_UX, data, len, 100);
uart_write_bytes(USART_UX, (const char*)data, strlen((const char*)data)); /* 写数据 */
}
}