OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 19|回复: 0

《ESP32-P4开发指南— V1.0》第十四章 UART实验

[复制链接]

1216

主题

1230

帖子

2

精华

超级版主

Rank: 8Rank: 8

积分
5236
金钱
5236
注册时间
2019-5-8
在线时间
1323 小时
发表于 3 小时前 | 显示全部楼层 |阅读模式
第十四章 UART实验

1)实验平台:正点原子DNESP32P4开发板

2)章节摘自【正点原子】ESP32-P4开发指南— V1.0

3)购买链接:https://detail.tmall.com/item.htm?id=873309579825

4)全套实验源码+手册+视频下载地址:http://www.openedv.com/docs/boards/esp32/ATK-DNESP32P4.html

5)正点原子官方B站:https://space.bilibili.com/394620890

6)正点原子DNESP32S3开发板技术交流群:132780729


2.jpg

3.png

本章节将展示如何使用ESP32-P4的UART模块进行串口通信,包括配置UART端口、发送和接收数据等内容。通过实验,你将学到如何初始化UART、设置波特率、定义数据传输格式,以及实现ESP32-P4与外部设备之间的串行数据交互。这一章将包含详细的代码示例和配置步骤,帮助你掌握UART通信的基本用法及应用场景。
14.1 UART简介
14.2 硬件设计
14.3 程序设计
14.4 下载验证


14.1 UART简介
在开始学习UART模块之前,了解数据通信的基础概念会对理解串口通信有很大帮助。以下内容概述了数据通信方式、数据传输方向、数据同步方式及通信速率。

14.1.1 数据通信的基础概念
在嵌入式应用中,数据通信是系统间交换信息的核心。单片机与上位机、或与外围器件之间的通信需求促使了多种协议的产生,例如UART、IIC、SPI、CAN 和 USB等。根据通信的实现方式,可以将这些协议从数据传输方式、数据传输方向、以及数据同步方式等方面进行分类,以便更好地理解其特性和应用场景。
1,按数据传输方式分类
按数据通信方式分类,数据传输可分为串行通信和并行通信两种,如下图所示。

第十四章 UART实验511.png
图14.1.1.1 数据传输方式

上图中,串行通信是指数据逐位依次传输,其优点是传输线少、成本低且抗干扰能力强,适合远距离传输,但传输速率相对较低,如UART、IIC、SPI、CAN和USB等。而并行通信则通过多条线同时传输数据,具备较高的传输速率,但需要更多传输线,成本较高且抗干扰能力差,通常用于短距离高速通信,如RGB、FSMC等。
2,按数据传输方向分类
根据数据传输方向,我们可以把通信协议分为单工通信、半双工通信和全双工通信,它们的比较如下图所示。


第十四章 UART实验744.png
图14.1.1.2 数据传输方向

上图中,单工通信指数据单向传输,发送方可以发送信息,但接收方无法回应;半双工通信允许双向传输,但需分时进行,使用同一条线路,常见协议有I2C、CAN和RS-485;全双工通信支持同时双向传输,通常使用两条线路,常见协议有SPI、UART和USB。总结而言,单工为单向,半双工为分时双向,而全双工为同时双向。
3,数据同步方式分类
根据数据同步方式,我们可以把通信协议分为同步通信和异步通信,如下图所示。


第十四章 UART实验965.png
图14.1.1.3 数据同步方式

同步通信和异步通信是两种主要的通信方式。同步通信使用相同的时钟信号进行数据发送和接收,适合高速率和大容量传输,然而其缺点在于需要保持时钟的同步,导致硬件设计较为复杂(SPI、IIC等通信协议)。相对而言,异步通信无需时钟信号,它在数据中加入起始位和停止位,适合点对点传输,硬件结构简单,但传输速率较低(如UART协议)。
根据上述内容,UART是一种串行通信协议,属于全双工的异步通信方式。值得注意的是,同步通信协议能够实现1对多的通信,具有较高的通讯效率;而异步通信协议则仅支持1对1的通信方式,效率相对较低。
4,通信速率
在数字通信系统中,通信速率(或传输速率)指数据在信道中传输的速度,分为两种:传信率和传码率。
1)传信率:每秒钟传输的信息量,即每秒传输的二进制位数,单位为 bit/s(比特每秒),也称为比特率。
2)传码率:每秒钟传输的码元个数,单位为 Baud(波特每秒),也称为波特率。
比特率和波特率这两个概念常常被混淆。比特率相对容易理解,而波特率是指码元的传输,码元是信号调制后的概念。每个码元可以表示一定数量的比特信息。例如,在TTL电平标准的通信中,0V表示逻辑0,5V表示逻辑1,这个码元就表示两种状态。如果信号的电平为0V、2V、4V和6V分别表示二进制数00、01、10、11,那么每个码元就可以表示四种状态。
由此可见,码元携带一定的比特信息,因此比特率和波特率之间存在关系。比特率与波特率的关系可以用以下公式表示:


第十四章 UART实验1611.png
其中 表示码元承载的信息量,也可以理解为码元的进制数。

举个例子: 波特率为100 Baud,即每秒传输100个码元,如果码元采用十六进制编码(即M=16,代入上述式子),那么这时候的比特率就是400 bit/s。如果码元采用二进制编码(即M=2,代入上述式子),那么这时候的比特率就是100 bit/s。
可以看出,在采用二进制编码时,波特率和比特率的数值相等,但它们的意义不同,单位也不同。由于数字系统主要使用二进制,因此很多人习惯性地将波特率和比特率混淆。

14.1.2 串口通信协议
串口通信协议定义了在串口上进行数据交换的规则和格式。常见的串口通信协议包括ASCII协议、Modbus协议、RS-232协议等。协议规定了数据的帧结构、数据格式、校验方式等,确保发送和接收双方按照相同的规则进行数据交换,从而实现数据的正确传输和解析。串口通信协议包数据帧格式如下图所示。

第十四章 UART实验2003.png
图14.1.2.1 串口通信协议数据帧格式

上图中,串口通信协议数据包组成可以分为波特率和数据帧格式两个部分组成。
1,波特率
本章主要讲解串口异步通信。异步通信不需要时钟信号(即上图中的SCLK时钟线),但需要约定两个设备的波特率。波特率表示每秒钟传输的码元符号数量,它决定了数据帧中每个位的时间长度。因此,进行通信的两个设备的波特率必须设置相同。常见的波特率包括4800、9600和115200等。
在UART通信中,若两个设备的波特率设置不一致,会导致严重的通信问题。首先,接收设备可能在错误的时间读取数据位,从而产生数据错误。此外,由于读取时机不当,接收设备可能会错过部分数据,导致数据丢失。同步问题也会随之出现,设备无法正确解析整个数据帧,可能会接收到无法识别的字符。在严重的情况下,通信甚至可能完全中断。因此,确保发送和接收设备的波特率一致是确保UART通信正常进行的关键。
2,数据帧格式
在串口通信中,数据帧格式需要提前约定好,以确保双方设备能够正确解析数据。
1)起始位和停止位
串口通信的一个数据帧是从起始位开始,直到停止位。数据帧中的起始位是由一个逻辑0的数据位表示,而数据帧的停止位可以是0.5、1、1.5或2个逻辑1的数据位表示,只要双方约定一致即可。
2)有效数据位
数据帧的起始位之后,就接着是数据位,也称有效数据位,这就是我们真正需要的数据,有效数据位通常会被约定为5、6、7或者8个位长。 有效数据位是低位(LSB)在前,高位(MSB)在后。
3)校验位
校验位可以认为是一个特殊的数据位。校验位一般用来判断接收的数据位有无错误, 检验方法有:奇检验、偶检验、0检验、1检验以及无检验。 下面分别介绍一下:
①:奇校验是指有效数据为和校验位中“1”的个数为奇数,比如一个8位长的有效数据为10101001,总共有4个“1”,为达到奇校验效果,校验位设置为“1”,最后传输的数据是8位的有效数据加上1位的校验位总共9位。
②:偶校验与奇校验要求刚好相反,要求帧数据和校验位中“1”的个数为偶数,比如数据帧:11001010,此时数据帧“1”的个数为4个,所以偶校验位为“0”。
③:0 校验是指不管有效数据中的内容是什么,校验位总为“0”, 1 校验是校验位总为“1”。无校验是指数据帧中不包含校验位。
本书提供的例程一般是使用无校验的情况。

14.1.3 ESP32-P4的UART介绍
在本章节小节中,我们讨论了数据通信的基本概念以及串口通信的协议知识。掌握这些基础知识后,我们才能深入理解UART(通用异步收发传输器)的相关内容。下面,我们来看一下HP系统UART和LP系统的UART特性比较,如下图所示。

第十四章 UART实验3128.png
图14.1.3.1 HP系统UART和LP系统的UART特性比较

上图展示了UART和低功耗(LP)UART功能的对比表。HP系统UART支持高达260*8位的RAM,适用于TX和RX FIFO,而LP UART仅有20 × 8位RAM。两者均支持全双工异步通信、5至8位的数据位、1、1.5或2位的停止位,以及奇偶校验和特殊字符检测功能。HP系统的UART支持更高的波特率、RS485协议、IrDA协议和通过GDMA的高速数据通信,而LP UART不具备这些功能。

14.1.3.1 UART控制器
本小节将重点讲解ESP32-P4的UART控制器,分析其内部工作原理和功能特性。了解ESP32-P4的UART控制器不仅有助于我们在实际开发中灵活运用串口通信,也为深入研究更复杂的通信协议奠定基础。接下来,笔者将详细分析UART控制器的各个功能模块具体实现,如下图所示。


第十四章 UART实验3517.png
图14.1.3.1.1 ESP32-P4的UART控制器结构体图

在UART控制器中,共有四个域:APB_CLK、AHB_CLK、UART_SCLK和UART_FCLK。其中,APB_CLK由AHB_CLK分频产生,两者同步但频率不同;同样,UART_SCLK则由UART_FCLK分频产生,两者同步但频率不同。各个域的功能和作用如下:
1,APB_CLK Domain域
APB_CLK时钟域负责在UART控制器与APB总线之间传输数据。它通过apb_wdata将用户RAM中的数据写入TX_FIFO,充当数据输入缓冲区。当数据写入FIFO后,系统会触发信号,指示数据已准备好处理。同时,apb_rdata用于从RX_FIFO读取数据到RAM。该时钟域主要用于配置寄存器访问和FIFO数据传输,在UART控制器中发挥着关键作用。它提供必要的配置信息,并管理数据的流入和流出。
2,AHP_CLK Domain域
AHB_CLK作为系统主时钟,驱动GDMA等高带宽模块,确保数据在主系统中的快速传输。在上图中,我们可以通过GDMA将RAM中的数据快速搬运到TX_FIFO,以实现高效的数据发送。同样,GDMA还可以将RX_FIFO中接收到的数据直接传输到RAM中,无需经过CPU处理,进一步优化了数据处理的性能。通过AHB_CLK时钟域和GDMA模块的协作,ESP32-P4 的UART控制器实现了高效的数据吞吐和系统资源的优化利用。
3,UART_FCLK Domain域
在UART_FCLK时钟域中,笔者将数据的处理流程分为发送器(Transmitter)和接收器(Receiver)两部分来详细说明。
1)发送器(Transmitter)
在UART的发送数据流程中,数据可以通过APB总线或通用DMA(GDMA)写入TX FIFO。UART模块内的逻辑会监控一级FIFO的状态。当FIFO中有数据可用时,Tx_FIFO_Ctrl控制器会将这些数据搬运到二级 UART0 TX_FIFO(UART0 TX_FIFO是一个特殊RAM,并不占主RAM的内存)。一旦数据在二级UART0 TX_FIFO中准备就绪,UART 的发送状态机(Tx_FSM)将开始逐位发送数据。它根据 FIFO 的状态和 UART 的时钟信号控制数据的输出(txd_out)。
2)接收器(Receiver)
在UART的接收数据流程中,接收信号(rxd_in)进入UART控制器后,首先由波特率检测模块(Baudrate_Detect)确认波特率匹配。接着,Start_Detect检测到数据帧的起始位并启动接收过程。此时,接收状态机(Rx_FSM)开始逐位读取数据并将其存入二级UART0 RX_FIFO。随后,Tx_FIFO_Ctrl 控制器会将这些数据搬运到二级RX_FIFO,并通过APB总线或GDMA存储到RAM中。
4,UART_SCLK Domain域
UART_SCLK时钟域内的结构和关键功能模块。主要包含以下模块:
1)硬件流控:通过标准UART的RTS(请求发送)和CTS(允许发送)信号,确保发送和接收双方的数据流控管理,防止数据溢出。
2)软件流控:在数据加入特殊字符,进一步控制数据流,适用于无需额外硬件支持的场景。
3)发送与接收状态机(Tx_FSM和Rx_FSM):用于控制UART数据的发送和接收过程的数据与比特流转换。
4)波特率与起始信号检测:Baudrate_Detect用于检测波特率,Start_Detect用于检测起始位,以实现通信同步。
5)回环模式(UART_LOOPBACK):支持自测功能,可在不连接外部设备的情况下测试UART模块。
6)低功耗管理:通过Wakeup_Ctrl模块,在UART控制器进入低功耗模式时,wake_up信号将触发芯片唤醒。
7)信号反相功能:提供UART_TXD_INV和UART_RXD_INV信号反相功能,以适应不同的硬件配置需求。
从上图中可以看到,UART_SCLK Domain域的时钟源由XTAL_CLK、RC_FAST_CLK和PLL_F80M_CLK提供。通过HP_SYS_UARTn_CLK_SRC_SEL配置可以选择具体的时钟源,配置后的时钟源经分配器(分频系数的整数和小数部分分别通过寄存器 HP_SYS_CLKRST_UARTn_SCLK_DIV_NUM、HP_SYS_CLKRST_UARTn_SCLK_DIV_NUMERATOR 和 HP_SYS_CLKRST_UARTn_SCLK_DIV_DENOMINATOR 设置,支持从 1 到 256 的范围)处理后为UART_SCLK控制器提供时钟支持。
注意:上述描述适用于高性能(HP)系统中的UART。在低功耗(LP)系统中,UART内核时钟由RC_FAST_CLK、XTAL_DIV_CLK和PLL_F8M_CLK时钟源提供。有关详细信息,请参阅《ESP32-P4技术参考手册》的UART章节。

14.1.3.2 UART控制器TX/RX FIFO
ESP32-P4的每个UART控制器都配备了一个独立的256 * 8位RAM,用于数据的发送和接收,并通过固定地址的4 * 8位异步FIFO接口进行访问。TX FIFO和RX FIFO可分别通过设置UART_CONF0_SYNC_REG寄存器中的UART_TXFIFO_RST位和 UART_RXFIFO_RST位来重置,这些寄存器描述如下图所示。


第十四章 UART实验5793.png
图14.1.3.2.1 UART_TXFIFO_RST和 UART_RXFIFO_RST位描述

每个FIFO缓冲区都具备可配置的中断阈值,以便有效管理数据流。通过UART_CONF1_REG寄存器中的UART_TXFIFO_EMPTY_THRHD位设置TX FIFO的空阈值,当TX FIFO中的数据少于该阈值时,系统会触发UART_TXFIFO_EMPTY_INT中断。同样地,通过UART_RXFIFO_FULL_THRHD位设置RX FIFO的满阈值,当RX FIFO中的数据超过该阈值时,会触发UART_RXFIFO_FULL_INT中断(见下图所示)。此外,当RX FIFO接收的数据超过其容量时,会触发UART_RXFIFO_OVF_INT溢出中断,提示数据溢出情况。

第十四章 UART实验6136.png
图14.1.3.2.2 UART_TXFIFO_EMPTY_THRHD和UART_RXFIFO_FULL_THRHD位描述

FIFO还可以通过寄存器UART_FIFO_REG直接访问,写入UART_RXFIFO_RD_BYTE可将数据放入TX FIFO,读取UART_RXFIFO_RD_BYTE可从RX FIFO中获取数据(见下图所示)。UART控制器的数据管理机制确保ESP32-P4在嵌入式通信中能高效、可靠地传输数据。

第十四章 UART实验6352.png
图14.1.3.2.3 寄存器UART_FIFO_REG描述

上面笔者讲解到,在ESP32-P4芯片中,UART每帧数据位为5~8位。我们可以通过APB总线或GDMA方式将这些数据写入到UART_RXFIFO_RD_BYTE寄存器中,表示UART的发送流程。在此过程中,数据将存储到Tx FIFO中。接收流程则相反:我们通过APB总线或GDMA方式读取UART_RXFIFO_RD_BYTE寄存器,即可获得接收到的5~8位数据。

14.1.3.3 UART波特率的配置
在数据发送或接收之前,UART控制器的波特率需要通过设置相应的寄存器来配置。UART控制器的波特率生成器通过对输入时钟源进行分频来实现。该分频器(对应图14.1.3.1.1中的Divider分频器)可以支持小数分频,通过寄存器UART_CLKDIV_SYNC_REG设置分频值,其中UART_CLKDIV表示整数部分UART_CLKDIV_FRAG表示小数部分(见下图所示)。在80 MHz的输入时钟下,UART控制器可支持的最高波特率为5 MBaud。


第十四章 UART实验6817.png
图14.1.3.3.1 设置分频器的数值

从图片内容可以看到,UART的波特率分频机制通过配置寄存器UART_CLKDIV(位[11:0])和UART_CLKDIV_FRAG(位[19:16])实现更精确的波特率控制。其中,UART_CLKDIV配置波特率生成的整数分频部分,而UART_CLKDIV_FRAG配置小数分频部分,以1/16为单位实现更细微的波特率调整。最终分频值由这两个寄存器的组合决定。波特率分频器的分频值公式为:

第十四章 UART实验7036.png

因此,最终的波特率计算公式为:

第十四章 UART实验7054.png

当输入时钟选择为80MHz的PLL_F80M_CLK时,UART的源时钟频率INPUT_FREQ即为 80 MHz。在此配置下,若寄存器设置为UART_CLKDIV = 694和UART_CLKDIV_FRAG = 7,则UART波特率为:

第十四章 UART实验7177.png

这样设置可以实现更精确的波特率控制,以满足特定通信需求。

14.2 硬件设计

14.2.1 例程功能
若串口调试助手发送“LED_ON”字符串,则打开板上的LED0;若串口调试助手发送“LED_OFF”字符串,则关闭板上的LED0。

14.2.2 硬件资源
1)LED灯
        LED        0        - IO51
2)UART0
        TX                - IO37
        RX                - IO38

14.2.3 原理图
UART相关原理图,如下图所示。

第十四章 UART实验7389.png
图14.2.3.1 UART硬件原理图(底板原理图)

上图使用的是底板的UART,需要使用两个跳线帽将P6排针的1和3引脚以及2和4引脚连接起来。若使用的是核心板的UART,则需要将P3排针的1和3引脚以及2和4引脚连接。

14.3 程序设计

14.3.1 UART的IDF驱动
UART外设驱动位于ESP-IDF的components\esp_driver_uart目录。该目录中的include文件夹存放UART相关的头文件,声明了UART函数和结构体等;而src文件夹则存放实际的UART操作函数。要使用UART功能,必须先导入以下头文件。
#include "driver/uart.h"
接下来,作者将介绍一些常用的UART函数,这些函数的描述及其作用如下:
1,UART配置参数uart_param_config
该函数用于配置UART的参数,包括波特率、数据位、停止位等设置,其函数原型如下:
  1. <font size="3">esp_err_t uart_param_config(uart_port_t uart_num, </font>
  2. <font size="3">const uart_config_t *uart_config);</font>
复制代码
函数形参:

1.png
表14.3.1.1 uart_param_config函数形参描述

返回值:
ESP_OK表示配置成功。
ESP_FAIL表示参数有误,可能是传入的UART端口号超出范围或配置参数无效。
uart_config为指向UART配置结构体的指针。接下来,笔者将详细介绍uart_config_t结构体中的各个成员变量,如下代码所示:
  1. typedef struct {
  2.     int baud_rate;                            /* UART波特率 */
  3.     uart_word_length_t data_bits;             /* UART字节大小 */
  4.     uart_parity_t parity;                     /* UART奇偶校验模式 */
  5.     uart_stop_bits_t stop_bits;            /* UART停止位 */
  6.     uart_hw_flowcontrol_t flow_ctrl;         /* UART硬件流控制模式(CTS/RTS) */
  7.     uint8_t rx_flow_ctrl_thresh;              /* UART硬件RTS阈值 */
  8.     union {
  9.         uart_sclk_t source_clk;               /* UART源时钟选择 */
  10. #if (SOC_UART_LP_NUM >= 1)                                /* 在LP系统中使用 */
  11.         lp_uart_sclk_t lp_source_clk;        /* LP_UART源时钟选择 */
  12. #endif
  13.     };
  14. } uart_config_t;
复制代码
上述结构体用于配置UART的通信参数,以下对各个成员做简单介绍。
1)baud_rate:
设置波特率。配置范围:9600 ~ 5M。本章节实验配置为115200波特率。
2)data_bits:
设置UART数据位。此字段可配置为UART_DATA_5_BITS五位、UART_DATA_6_BITS六位、UART_DATA_7_BITS七位、UART_DATA_8_BITS八位。本章节实验配置数据位为8位。
3)parity:
设置奇偶校验位。此字段可配置为UART_PARITY_DISABLE无校验位、UART_PARITY_EVEN偶校验位和UART_PARITY_ODD奇校验位。本章节实验配置为无校验位。
4)stop_bits:
设置停止位。此字段可配置为UART_STOP_BITS_1 1位停止位、UART_STOP_BITS_1_5 1.5位停止位和UART_STOP_BITS_2 2位停止位。本章节实验配置为1位停止位。
5)flow_ctrl
设置硬件流模式。此字段可配置为UART_HW_FLOWCTRL_DISABLE禁用硬件流控、UART_HW_FLOWCTRL_RTS启用接收硬件流、UART_HW_FLOWCTRL_CTS启用发送硬件流和UART_HW_FLOWCTRL_CTS_RTS启用硬件流控。本章节实验配置为禁用硬件流控。
6)rx_flow_ctrl_thresh
设置RTS的阈值。
7)source_clk
UART时钟源。此字段可配置为UART_SCLK_PLL_F80M、UART_SCLK_RT、UART_SCLK_XTAL、UART_SCLK_DEFAULT。一般选择UART_SCLK_DEFAULT。
2,将UART外设的信号分配给GPIO引脚uart_set_pin
该函数用于将UART的TX、RX等信号分配到指定的GPIO引脚,其函数原型如下:
  1. esp_err_t uart_set_pin(uart_port_t uart_num, int tx_io_num,
  2. int rx_io_num, int rts_io_num, int cts_io_num);
复制代码
函数形参:

2.png
表14.3.1.2 uart_set_pin函数形参描述

返回值:
ESP_OK表示配置成功。
ESP_FAIL表示参数有误,可能是传入的UART端口号超出范围或配置参数无效。
3,安装UART驱动uart_driver_install
该函数用于将UART的TX、RX等信号分配到指定的GPIO引脚,其函数原型如下:
  1. esp_err_t uart_driver_install(uart_port_t uart_num, int rx_buffer_size,
  2. int tx_buffer_size, int queue_size,
  3. QueueHandle_t* uart_queue, int intr_alloc_flags);
复制代码
函数形参:

3.png
表14.3.1.3 uart_set_pin函数形参描述

返回值:
ESP_OK表示配置成功。
ESP_FAIL表示参数有误,可能是传入的UART端口号超出范围或配置参数无效。
4,获取UART接收环形缓冲区中缓存数据的长度uart_get_buffered_data_len
该函数用于查询UART端口的接收环形缓冲区中当前缓存的数据长度,其函数原型如下:
  1. esp_err_t uart_get_buffered_data_len(uart_port_t uart_num, size_t* size);
复制代码
函数形参:

4.png
表14.3.1.4 uart_get_buffered_data_len函数形参描述

返回值:
ESP_OK表示操作成功,size指向的变量将包含缓存数据的长度。
ESP_FAIL表示参数错误,可能是因为传入的UART端口号无效或size指针为NULL。
5,从UART缓冲区读取字节uart_read_bytes
该函数用于从指定UART端口的接收缓冲区读取指定数量的字节,其函数原型如下:
  1. int uart_read_bytes(uart_port_t uart_num, void* buf, uint32_t length,
  2. TickType_t ticks_to_wait);
复制代码
函数形参:

5.png
表14.3.1.5 uart_read_bytes函数形参描述

返回值:
-1表示发生错误,例如指定的UART端口无效或其他读取错误。
其他值(>=0)表示成功读取的字节数,可能少于请求的长度。
6,从给定缓冲区和长度向UART端口发送数据uart_write_bytes
该函数用于向指定的UART端口发送数据,其函数原型如下:
  1. int uart_write_bytes(uart_port_t uart_num, const void* src, size_t size);
复制代码
函数形参:

6.png
表14.3.1.6 uart_write_bytes函数形参描述

返回值:
-1表示参数错误,可能是因为指定的UART端口无效或其他问题。
其他值(>=0)表示成功推送到TX FIFO的字节数,这个值可能小于请求发送的长度,具体取决于TX FIFO的可用空间。

14.3.2 程序流程图

第十四章 UART实验11549.png
图14.3.2.1 UART实验程序流程图

14.3.3 程序解析
在04_uart例程中,作者在04_uart\components\BSP路径下新建UART文件夹,并且需要更改CMakeLists.txt内容,以便在其他文件上调用。
1,UART驱动代码
这里我们只讲解核心代码,详细的源码请大家参考光盘本实验对应源码。UART驱动源码包括两个文件:uart.c和uart.h。
下面先解析uart.h的程序。对UART引脚做了相关定义。
  1. <font size="3">/* 引脚和串口定义 */</font>
  2. <font size="3">#define USART_UX            UART_NUM_0</font>
  3. <font size="3">#define USART_TX_GPIO_PIN   GPIO_NUM_37</font>
  4. <font size="3">#define USART_RX_GPIO_PIN   GPIO_NUM_38</font>

  5. <font size="3">/* 串口接收相关定义 */</font>
  6. <font size="3">#define RX_BUF_SIZE         1024        /* 环形缓冲区大小(单位字节) */</font>
复制代码
上述源码是关于串口的配置宏定义,包含串口的管脚配置和接收缓冲区的大小设置。
下面我们再解析uart.c的程序,看一下初始化函数uart_init,代码如下:
  1. <font size="3">/**</font>
  2. <font size="3"> * @brief              初始化UART</font>
  3. <font size="3"> * [url=home.php?mod=space&uid=271674]@param[/url]              baudrate:波特率</font>
  4. <font size="3"> * @retval             无</font>
  5. <font size="3"> */</font>
  6. <font size="3">void uart_init(uint32_t baudrate)</font>
  7. <font size="3">{</font>
  8. <font size="3">    uart_config_t uart0_config = {0};</font>
  9. <font size="3">    uart_config.baud_rate = baudrate;                  /* 设置波特率 */</font>
  10. <font size="3">    uart_config.data_bits = UART_DATA_8_BITS;          /* 数据位 */</font>
  11. <font size="3">    uart_config.parity = UART_PARITY_DISABLE;          /* 无奇偶校验位 */</font>
  12. <font size="3">    uart_config.stop_bits = UART_STOP_BITS_1;          /* 一位停止位 */</font>
  13. <font size="3">    uart_config.flow_ctrl = UART_HW_FLOWCTRL_DISABLE;  /* 无硬件流控 */</font>
  14. <font size="3">    uart_config.source_clk = UART_SCLK_DEFAULT;        /* 选择时钟源 */</font>

  15. <font size="3">    ESP_ERROR_CHECK(uart_param_config(USART_UX, &uart_config));/* UART0配置 */</font>
  16. <font size="3">    /* 设置管脚 */</font>
  17. <font size="3">ESP_ERROR_CHECK(uart_set_pin(USART_UX, USART_TX_GPIO_PIN, USART_RX_GPIO_PIN, </font>
  18. <font size="3">UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE));</font>
  19. <font size="3">    </font>
  20. <font size="3">    /* 安装串口驱动 */</font>
  21. <font size="3">ESP_ERROR_CHECK(uart_driver_install(USART_UX, RX_BUF_SIZE, RX_BUF_SIZE, </font>
  22. <font size="3">0, NULL, 0));</font>
  23. <font size="3">}</font>
复制代码
该函数用于初始化ESP32的UART0串口。它接受一个波特率参数,并根据该参数配置串口的各项设置。函数内部创建一个uart_config_t结构体,设置波特率为传入值,数据位为8位,禁用奇偶校验,设置为1位停止位,并禁用硬件流控制。然后,使用uart_param_config函数配置参数,并通过uart_set_pin函数指定TX和RX引脚。最后,函数调用uart_driver_install安装UART驱动,设置接收和发送的缓冲区大小为定义的RX_BUF_SIZE,以准备进行数据通信。通过这个函数,用户可以轻松配置UART0以满足特定的通信需求。
2,CMakeLists.txt文件
本例程的功能实现主要依靠UART驱动。要在main函数中,成功调用UART文件中的内容,就得需要修改BSP文件夹下的CMakeLists.txt文件,修改如下:
  1. <font size="3">set(src_dirs</font>
  2. <font size="3">            LED</font>
  3. <font size="3">            UART)</font>

  4. <font size="3">set(include_dirs</font>
  5. <font size="3">            LED</font>
  6. <font size="3">            UART)</font>

  7. <font size="3">set(requires</font>
  8. <font size="3">            driver)</font>

  9. <font size="3">idf_component_register(        SRC_DIRS ${src_dirs} INCLUDE_DIRS ${include_dirs} </font>
  10. <font size="3">REQUIRES ${requires})</font>

  11. <font size="3">component_compile_options(-ffast-math -O3 -Wno-error=format=-Wno-format)</font>
复制代码

3,main.c驱动代码
在main.c里面编写如下代码。
  1. <font size="3">void app_main(void)</font>
  2. <font size="3">{</font>
  3. <font size="3">    esp_err_t ret;</font>
  4. <font size="3">    uint16_t len = 0;</font>
  5. <font size="3">    char data[10] = {0};</font>
  6. <font size="3">    char *a = "LED_ON";</font>
  7. <font size="3">    char *b = "LED_OFF";</font>

  8. <font size="3">    ret = nvs_flash_init();     /* 初始化NVS */</font>

  9. <font size="3">    if(ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND)</font>
  10. <font size="3">    {</font>
  11. <font size="3">        ESP_ERROR_CHECK(nvs_flash_erase());</font>
  12. <font size="3">        ESP_ERROR_CHECK(nvs_flash_init());</font>
  13. <font size="3">    }</font>

  14. <font size="3">    led_init();                 /* 初始化LED */</font>
  15. <font size="3">    uart_init(115200);           /* 初始化串口0 */</font>

  16. <font size="3">    while(1)</font>
  17. <font size="3">    {</font>
  18. <font size="3">        uart_get_buffered_data_len(USART_UX, (size_t*) &len);</font>

  19. <font size="3">        if (len > 0)</font>
  20. <font size="3">        {</font>
  21. <font size="3">            uart_read_bytes(USART_UX, data, len, 100);</font>
  22. <font size="3">            data[len] = '\0';</font>

  23. <font size="3">            if (strcmp(a, data) == 0)</font>
  24. <font size="3">            {</font>
  25. <font size="3">                LED0(0);</font>
  26. <font size="3">            }</font>
  27. <font size="3">            else if (strcmp(b, data) == 0)</font>
  28. <font size="3">            {</font>
  29. <font size="3">                LED0(1);</font>
  30. <font size="3">            }</font>

  31. <font size="3">            memset(data, 0, 10);</font>
  32. <font size="3">        }</font>

  33. <font size="3">        vTaskDelay(pdMS_TO_TICKS(10));    /* 延时10ms */</font>
  34. <font size="3">    }</font>
  35. <font size="3">}</font>
复制代码
app_main函数中首先初始化LED和UART。接着,通过UART接收指令以控制LED状态:接收到字符串“LED_ON”时,点亮LED0;接收到“LED_OFF”时,熄灭LED0。

14.4 下载验证
程序下载完成后,首先使用Type-C数据线将其C口连接至开发板上的UART接口,然后将其A口连接至PC。接着,打开串口上位机,并根据程序配置设置串口的波特率、停止位等参数以建立连接。此时,在上位机发送 “LED_ON” 字符串,开发板上的LED0被点亮;若发送字符串“LED_OFF”,则LED0熄灭。这操作展示了UART串口实现与开发板的实时交互控制。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则


关闭

原子哥极力推荐上一条 /1 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2025-12-17 13:24

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

快速回复 返回顶部 返回列表