打印
[PIC32/SAM]

PIC系列-串口通讯模块

[复制链接]
8842|7
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
kxsi|  楼主 | 2021-8-9 13:21 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式
串口通讯描述
通用异步收发器模块是 PIC32MX 系列器件提供的串行 I/O 模块之一。

UART 模块的主要特性有:

• 全双工 8 位或 9 位数据传输

• 偶校验、奇校验或无奇偶校验选项 (对于 8 位数据)

• 一个或两个停止位

• 硬件自动波特率特性

• 完全集成的波特率发生器,具有 16 位预分频器

• 当器件工作在 80 MHz 时,波特率范围从 76 bps 至 20 Mbps

• 独立的接收和发送 FIFO 数据缓冲区

• 奇偶校验、帧和缓冲区溢出错误检测

• 支持仅在地址检测 (第 9 位 = 1)时产生中断

• 独立的发送和接收中断

• 用于诊断支持的环回模式

• LIN 1.2 协议支持

下图是UART的简化框图,主要有波特率发生器、异步发送器、异步接收器和IrDA编解码器。



使用特权

评论回复
沙发
kxsi|  楼主 | 2021-8-9 13:23 | 只看该作者
寄存器介绍
控制寄存器

每个 UART 模块包含以下特殊功能寄存器

• UxMODE:UARTx 模式寄存器

• UxSTA:UARTx 状态和控制寄存器

• UxTXREG:UARTx 发送寄存器

• UxRXREG:UARTx 接收寄存器

• UxBRG:UARTx 波特率寄存器

每个 UART 模块还具有用于中断控制的相关位

• UxTXIE:发送中断允许控制位

• UxTXIF:发送中断标志状态位

• UxRXIE:接收中断允许控制位

• UxRXIF:接收中断标志状态位

• UxEIE:错误中断允许控制位

• UxEIF:错误中断标志状态位

• UxIP<2:0>:中断优先级控制位

• UxIS<1:0>:中断子优先级控制位



UxMODE :UARTx 模式寄存器



bit 15 ON :UARTx 使能位

1 = 使能 UARTx ; UARTx 根据 UEN<1:0> 和 UTXEN 控制位的定义控制 UARTx 引脚

0 = 禁止 UARTx ;由 PORTx、TRISx 和 LATx 寄存器中的相应位控制所有 UARTx 引脚; UARTx 的功耗最小

bit 14 FRZ :调试异常模式冻结位

1 = 在 CPU 处于调试异常模式时冻结工作

0 = 在 CPU 处于调试异常模式时继续工作

bit 13 SIDL :空闲模式停止位

1 = 在器件进入 Idle(空闲)模式时停止工作

0 = 在 Idle (空闲)模式下继续工作

bit 12 IREN :IrDA 编码器和解码器使能位

1 = 使能 IrDA

0 = 禁止 IrDA

bit 11 RTSMD :UxRTS 引脚模式选择位 (4)

1 = UxRTS 引脚处于单工模式

0 = UxRTS 引脚处于流控制模式

bit 9-8 UEN<1:0> :UARTx 使能位

11 = 使能并使用 UxTX、 UxRX 和 UxBCLK 引脚; UxCTS 引脚由 PORTx 寄存器中的相应位控制

10 = 使能并使用 UxTX、 UxRX、 UxCTS 和 UxRTS 引脚

01 = 使能并使用 UxTX、 UxRX 和 UxRTS 引脚; UxCTS 引脚由 PORTx 寄存器中的相应位控制

00 = 使能并使用UxTX和UxRX引脚;UxCTS和UxRTS/UxBCLK引脚由PORTx寄存器中的相应位控制

bit 7 WAKE :在休眠模式下检测到启动位唤醒使能位

1 = 使能唤醒

0 = 禁止唤醒

bit 6 LPBACK :UARTx 环回模式选择位

1 = 使能环回模式

0 = 禁止环回模式

bit 5 ABAUD :自动波特率使能位

1 = 使能对下一个字符的波特率测量——需要接收同步字符 (0x55);完成时由硬件清零

0 = 禁止波特率测量或测量已完成

bit 4 RXINV :接收极性翻转位

1 = UxRX 的空闲状态为 0

0 = UxTX 的空闲状态为 1

bit 3 BRGH :高波特率使能位

1 = 高速模式——使能 4x 波特率时钟

0 = 标准速度模式——使能 16x 波特率时钟

bit 2-1 PDSEL<1:0> :奇偶校验和数据选择位

11 = 9 位数据,无奇偶校验

10 = 8 位数据,奇校验

01 = 8 位数据,偶校验

00 = 8 位数据,无奇偶校验

bit 0 STSEL :停止选择位

1 = 2 个停止位

0 = 1 个停止位

UxSTA :UARTx 状态和控制寄存器



bit 24 ADM_EN :自动地址检测模式使能位

1 = 使能自动地址检测模式

0 = 禁止自动地址检测模式

bit 23-16 ADDR<7:0> :自动地址掩码位

当 ADM_EN 位为 1 时,该值定义用于自动地址检测的地址字符。

bit 15-14 UTXISEL<1:0> :发送中断模式选择位

对于 UART1 和 UART2 模块:

11 = 保留,不要使用

10 = 当发送缓冲区变为空时产生中断

01 = 当发送完所有字符时产生中断

00 = 当发送缓冲区变为未满 (至少有一个数据空间为空)时产生中断

对于 UART1A、 UART1B、 UART2A、 UART2B、 UART3A 和 UART3B 模块:

11 = 保留,不要使用

10 = 当发送缓冲区为空时产生中断并将中断标志位置为有效

01 = 当发送完所有字符时产生中断并将中断标志位置为有效

00 = 当发送缓冲区至少有一个数据空间为空时产生中断并将中断标志置为有效

bit 13 UTXINV :发送极性翻转位

如果禁止 IrDA 模式 (即, IREN (UxMODE<12>)为 0):

1 = UxTX 的空闲状态为 0

0 = UxTX 的空闲状态为 1

如果使能 IrDA 模式 (即, IREN (UxMODE<12>)为 1):

1 = IrDA 编码的 UxTX 空闲状态为 1

0 = IrDA 编码的 UxTX 空闲状态为 0

bit 12 URXEN :接收器使能位

1 = 使能 UARTx 接收器,由 UARTx 控制 UxRX 引脚 (如果 ON = 1)

0 = 禁止 UARTx 接收器, UARTx 模块忽略 UxRX 引脚。由端口控制 UxRX 引脚。

bit 11 UTXBRK :发送间隔位

1 = 在下次发送时发送间隔字符——启动位后跟随 12 个 0 位,然后是停止位;完成时由硬件清零

0 = 禁止或已完成间隔字符的发送

bit 10 UTXEN :发送使能位

1 = 使能 UARTx 发送器,由 UARTx 控制 UxTX 引脚 (如果 ON = 1)

0 = 禁止 UARTx 发送器,中止所有等待的发送,缓冲区复位。由端口控制 UxTX 引脚。

bit 9 UTXBF :发送缓冲区满状态位 (只读)

1 = 发送缓冲区已满

0 = 发送缓冲区未满,至少还可再写入一个字符

bit 8 TRMT :发送移位寄存器空位 (只读)

1 = 发送移位寄存器为空,同时发送缓冲区为空 (上一次发送已完成)

0 = 发送移位寄存器非空,发送在进行中或在发送缓冲区中排队

bit 7-6 URXISEL<1:0> :接收中断模式选择位

对于 UART1 和 UART2 模块:

11 = 当接收缓冲区变满 (即,有 4 个数据字符)时,中断标志位置 1

10 = 当接收缓冲区 3/4 满 (即,有 3 个数据字符)时,中断标志位置 1

0x = 当接收到一个字符时,中断标志位置 1

对于 UART1A、 UART1B、 UART2A、 UART2B、 UART3A 和 UART3B 模块:

11 = 保留;不要使用

10 = 当接收缓冲区 3/4 满或更满 (即,有 6 个或更多数据字符)时,中断标志位置为有效

01 = 当接收缓冲区 1/2 满或更满 (即,有 4 个或更多数据字符)时,中断标志位置为有效

00 = 当接收缓冲区非空 (即,至少有 1 个数据字符)时,中断标志位置为有效

bit 5 ADDEN :地址字符检测位 (接收数据的 bit 8 = 1)

1 = 使能地址检测模式。如果没有选择 9 位模式,该控制位不起作用。

0 = 禁止地址检测模式

bit 4 RIDLE :接收器空闲位 (只读)

1 = 接收器空闲

0 = 正在接收数据

bit 3 PERR :奇偶校验错误状态位 (只读)

1 = 检测到当前字符的奇偶校验错误

0 = 未检测到奇偶校验错误

bit 2 FERR :帧错误状态位 (只读)

1 = 检测到当前字符的帧错误

0 = 未检测到帧错误

bit 1 OERR :接收缓冲区溢出错误状态位

该位由硬件置 1,且只能用软件清零 (= 0)。清零原来置 1 的 OERR 位将使接收缓冲区和 RSR 复位为空状态。

1 = 接收缓冲区已溢出

0 = 接收缓冲区未溢出

bit 0 URXDA :接收缓冲区数据存在标志位 (只读)

1 = 接收缓冲区中有数据,至少还有一个字符可被读取

0 = 接收缓冲区为空

UxTXREG :UARTx 发送寄存器



bit 8-0 TX<8:0> :待发送字符的 bit 8-0 数据位

UxRXREG :UARTx 接收寄存器



bit 8-0 RX<8:0> :已接收字符的 bit 8-0 数据位

UxBRG :UARTx 波特率寄存器



bit 15-0 BRG<15:0> :波特率分频比位

UART 波特率发生器

UART 模块包含一个专用的 16 位波特率发生器。UxBRG 寄存器控制一个自由运行的 16 位定时器的周期。

串口波特率 = 串口时钟频率/[速度模式*(波特率分频比+1)]

波特率分频比 = 串口时钟频率/[速度模式*串口波特率] - 1

速度模式:高速模式时为4,标准速度模式时为16;

BCLKx 输出

如果使能了 UART 和 BCLKx 输出(即,UEN<1:0> 位(UxMODE<9:8>)= 11),则 BCLKx 引脚将输出 16x 波特率时钟。此功能用于支持外部 IrDA 编 / 解码器 (见图 21-2)。在休眠模式下,BCLKx 输出保持低电平。只要 UART 保持在该模式(即,UEN<1:0> 位(UxMODE<9:8>)= 11),则无论 PORTx 和 TRISx 锁存位状态如何, BCLKx 都强制为输出。

UART 配置

UART 使用标准的不归零(Non-Return-to-Zero,NRZ)格式(1 个启动位、8 或 9 个数据位和1 或 2 个停止位)。硬件提供奇偶校验,可由用户配置为偶校验、奇校验或无奇偶校验。最普通的数据格式是 8 位,无奇偶校验,有 1 个停止位(用 8, N, 1 表示),这是默认的上电复位(Power-on Reset,POR)设置。数据位数、停止位数以及奇偶校验均在 PDSEL<1:0> (UxMODE<2:1>)和STSEL(UxMODE<0>)位中指定。UART 首先发送和接收最低有效位(Least Significant bit,LSb)。 UART 的发送器和接收器在功能上是独立的,但使用相同的数据格式和波特率。

使能 UART

通过将ON位(UxMODE<15>)置1来使能UART模块。此外,通过将UTXEN位(UxSTA<10>)和 URXEN 位(UxSTA<12>)置 1 来分别使能 UART 发送器和接收器。一旦将这些使能位置 1,UxTX 和 UxRX 引脚就分别被配置为输出和输入,改写对应 I/O 端口引脚的 TRISx 和 PORTx 寄存器位设置。

禁止 UART

通过清零ON位来禁止UART模块。这是任何复位后的默认状态。如果禁止了UART,所有UART引脚在 PORTx 和 TRISx 寄存器中的相应位控制下用作端口引脚。

禁止 UART 模块会将缓冲区复位为空状态。当禁止模块时,缓冲区中的所有数据都将丢失。

当禁止 UART 模块时,所有与之相关的错误和状态标志都将复位。 UxSTA 寄存器中的 RXDA、OERR、FERR、PERR、UTXEN、URXEN、UTXBRK 和 UTXBF 位被清零,而 RIDLE 和 TRMT位被置 1。其他控制位(包括 ADDEN、RXISEL<1:0> 和 UTXISEL)以及 UxMODE 和 UxBRG寄存器均不受影响。

当 UART 模块处于活动状态时,清零 ON 位将中止所有等待的发送和接收,同时如以上所述那样将模块复位。重新使能 UART 将使用同样的配置重新启动 UART 模块。


使用特权

评论回复
板凳
kxsi|  楼主 | 2021-8-9 13:24 | 只看该作者
UART 发送器
发送器的核心是发送移位寄存器(UxTSR)。UxTSR 从发送FIFO 缓冲区 UxTXREG 中获取数据。通过软件将数据装入 UxTXREG 寄存器。在前一次装入数据的停止位发送之前,不会向 UxTSR 寄存器装入新数据。一旦停止位发送完毕,就会将UxTXREG 寄存器中的新数据 (如果有)装入 UxTSR。



通过将 UTXEN 使能位 (UxSTA<10>)置 1 来使能发送。实际的发送要到 UxTXREG 寄存器装入了数据并且波特率发生器 UxBRG 产生了移位时钟之后才发生。也可以先装入UxTXREG 寄存器,然后将 UTXEN 使能位置 1 来启动发送。通常,第一次开始发送的时候,由于 UxTSR 寄存器为空,这样传输数据到 UxTXREG 寄存器会导致该数据立即传输到 UxTSR。发送期间清零 UTXEN 位将中止发送并复位发送器。因此, UxTX 引脚将恢复到 UTXINV 位(UxSTA<13>)定义的状态。

若要选择 9 位发送, PDSEL<1:0> 位 (UxMODE<2:1>)应设置为 11。

发送缓冲区 (UxTXREG)

发送缓冲区有 9 位宽和 8 级深。算上发送移位寄存器(UxTSR),用户实际有一个最多 9 级深的缓冲区。当 UxTXREG 的内容被传输到 UxTSR 寄存器时,当前缓冲单元就可以写入新数据。每当缓冲区满时,UTXBF(UxSTA<9>)状态位就会置 1。如果用户试图向已满的缓冲区执行写操作,则新数据将不会被 FIFO 接受。

FIFO 在任何器件复位时复位,但当器件进入节能模式或从节能模式唤醒时, FIFO 不受影响。

1 :只有在具有 UART1A、UART1B、UART2A、UART2B、UART3A 和 UART3B 模块的器件中, 8 级深 FIFO 才可用。

2 :只有在具有 UART1 和 UART2 模块的器件中, 4 级深 FIFO 才可用。

发送中断

发送中断标志(UxTXIF)位于相应的中断标志状态(IFS)寄存器中。UTXISEL控制位(UxSTA<15:14>)决定 UART 何时将产生发送中断。当模块第一次使能时, UxTXIF 位被置 1。在工作期间可以在中断模式之间进行切换,但除非缓冲区为空,否则建议不要这么做。

UxTXIF 标志位指示 UxTXREG 寄存器的状态,而 TRMT 位 (UxSTA<8>)指示 UxTSR 寄存器的状态。 TRMT 状态位是只读位,当 UxTSR 寄存器为空时被置 1。因为没有与该位关联的中断逻辑,所以用户必须查询该位以判断 UxTSR 寄存器是否为空。要清除 UART1 和 UART2 模块的中断,必须在关联的 IFSx 寄存器中,将相应的 UxTXIF 标志位清零。

对于 UART1A、UART1B、UART2A、UART2B、UART3A 和 UART3B 模块,当 UTXISEL 控制位规定的中断条件为真时,将会产生中断并将标志位置为有效。这意味着要清除这些模块的中断,在清零相应的 UxTXIF 标志之前,用户应用程序必须确保 UTXISEL 控制位规定的中断条件不再为真。

设置 UART 发送

1. 对UxBRG寄存器进行初始化,设置合适的波特率。

2. 通过写入 PDSEL<1:0> (UxMODE<2:1>)和 STSEL (UxMODE<0>)位来设置数据位数、停止位数和奇偶校验选择。

3. 如果需要发送中断,就要将相应中断允许控制寄存器 (IEC)中的 UxTXIE 控制位置 1。使用相应中断优先级控制(IPC)寄存器中的 UxIP<2:0> 和 UxIS<1:0> 控制位来指定发送中断的中断优先级和子优先级。同时,通过写 UTXISEL(UxSTA<15:14>)位来选择发送中断模式。

4. 通过将 UTXEN(UxSTA<10>)位置 1 来使能发送,与此同时将 UxTXIF 位置 1。UxTXIF位应在 UART 发送中断服务程序中清零。 UxTXIF 位的操作由 UTXISEL 控制位控制。

5. 通过将 ON (UxMODE<15>)位置 1 来使能 UART 模块。

6. 将数据装入UxTXREG寄存器(开始发送)。

间隔字符的发送

间隔字符发送包含 1 个启动位,随后的 12 个 0 位和 1 个停止位。在 UxTXREG 寄存器中装入数据时,只要 UART 模块使能并且 UTXBRK 和 UTXEN 位置 1,就会发送帧间隔字符。


使用特权

评论回复
地板
kxsi|  楼主 | 2021-8-9 13:24 | 只看该作者
UART接收器
接收器的核心是接收(串行)移位寄存器 (UxRSR)。在 UxRX 引脚上接收数据,并发送到择多检测模块中。在 BRGH = 0 的模式下,择多检测模块以 16 倍波特率的速率工作,并且通过择多检测电路来确定 UxRX 引脚上出现的是高电平还是低电平。在 BRGH = 1 的模式下,择多检测模块以 4 倍波特率的速率工作,并且通过单采样来确定出现的是高电平还是低电平。

在采样到 UxRX引脚上的停止位之后,UxRSR中接收到的数据被传输到接收FIFO(如果未满)。通过将 URXEN 位 (UxSTA<12>)置 1 来使能接收。

接收缓冲区 (UxRXREG )

UART 接收器有一个 9 位宽、最多 8 级深的 FIFO 接收数据缓冲区。UxRXREG 是一个存储器映射的寄存器,可提供对 FIFO 输出的访问。有可能会发生这种情况:FIFO 已满,下一个字开始移入 UxRSR 寄存器,然后发生缓冲区溢出。

接收器错误处理

如果 FIFO 已满且新字符已被完全接收到 UxRSR 寄存器中,则溢出错误位 OERR(UxSTA<1>)将被置 1。UxRSR 中的字不会保留,只要 OERR 位置 1,就将禁止继续向接收 FIFO 传输。用户必须用软件清零 OERR 位,以允许继续接收数据。

若要保存溢出前接收到的数据,用户应先读取所有接收到的字符,然后清零 OERR 位。如果接收到的字符可以丢弃,则用户只要清零 OERR 位即可。这可有效地复位接收 FIFO,同时先前接收到的所有数据都将丢失。

接收 FIFO 中的数据应在清零 OERR 位之前读出。当 OERR 清零时, FIFO 复位,这将导致缓冲区中的所有数据丢失。

接收中断

UART 接收中断标志 (UxRXIF)位于相应的中断标志状态 (IFSx)寄存器中。 RXISEL<1:0>(UxSTA<7:6>)控制位决定 UART 接收器何时产生中断。

要清除UART1和UART2模块的中断,必须在关联的IFSx寄存器中,将相应的UxRXIF标志清零。

对于 UART1A、UART1B、UART2A、UART2B、UART3A 和 UART3B 模块,当 RXISEL 控制位规定的中断条件为真时,将会产生中断。这意味着如果要清除这些模块的中断,在清零相应的UxRXIF 标志之前,用户应用程序必须确保 URXISLE 控制位规定的中断条件不再为真。

RXDA 和 UxRXIF 标志位指示 UxRXREG 寄存器的状态,而 RIDLE 位(UxSTA<4>)指示 UxRSR寄存器的状态。 RIDLE 状态位是只读位,当接收器空闲 (即, UxRSR 寄存器为空)时被置 1。因为没有与该位关联的中断逻辑,所以用户必须查询该位以判断 UxRSR 是否空闲。

设置UART接收

请执行以下步骤设置 UART 接收:

1. 对UxBRG寄存器进行初始化,设置合适的波特率。

2. 通过写入 PDSEL<1:0> (UxMODE<2:1>)和 STSEL (UxMODE<0>)位来设置数据位数、停止位数和奇偶校验选择。

3. 如果需要中断,就要将相应中断允许控制 (IEC)寄存器中的 UxRXIE 位置 1。使用相应中断优先级控制(IPC)寄存器中的 UxIP<2:0> 和 UxIS<1:0> 控制位来指定中断的中断优先级和子优先级。同时,通过写入RXISEL<1:0>(UxSTA<7:6>)位来选择接收中断模式。

4. 通过将 URXEN (UxSTA<12>)位置 1 来使能 UART 接收器。

5. 通过将 ON (UxMODE<15>)位置 1 来使能 UART 模块。

6. 接收中断取决于 RXISEL<1:0> 控制位的设置。如果没有允许接收中断,用户可以查询RXDA 位。 UxRXIF 位应在 UART 接收中断服务程序中清零。

7. 从接收缓冲区中读取数据。如果选择了 9 位发送,则读一个字;否则,读一个字节。每当缓冲区中有数据时, RXDA 状态位 (UxSTA<0>)就会被置 1。

自动波特率支持

要允许系统确定所接收字符的波特率,可以使能 ABAUD 位。如果使能了自动波特率检测(ABAUD = 1),则每当接收到启动位时,UART 就会开始自动波特率测量序列。波特率计算采用自平均的方式。该功能仅在禁止自动唤醒(WAKE = 0)时有效。此外,对于自动波特率操作,LPBACK 必须等于0。当 ABAUD位置1时,BRG 计数器值将被清零并开始检测一个启动位;在这种情况下,启动位定义为高电平到低电平跳变后跟随一个低电平到高电平跳变。

在启动位之后,自动波特率功能需要接收一个 ASCII “U”(55h),以计算相应的比特率。在启动位(上升沿)结束时,BRG 计数器开始使用 F PB /8 时钟计数。在 UxRX 引脚的第 5 个上升沿,统计相应 BRG 总周期数的累计 BRG 计数器值将被传输到 UxBRG 寄存器。ABAUD 位自动清零。

中断

UART 能够产生一些中断,反映在数据通信期间发生的事件。它可以产生以下类型的中断:

• 接收器数据可用中断,通过 UxRXIF 指示。该事件根据RXISEL<1:0>(UxSTA<7:6>)控制位的值而产生。

• 发送器缓冲区为空中断,通过 UxTXIF 指示。该事件根据UTXISEL<1:0>(UxSTA<15:14>)控制位的值而产生。

• UART 错误中断,通过 UxEIF 指示。

- 该事件在发生以下任意错误条件时产生:

• 检测到奇偶校验错误 PERR (UxSTA<3>)

• 检测到帧错误 FERR (UxSTA<2>)

• 发生接收缓冲区溢出条件 OERR (UxSTA<1>)

所有这些中断标志必须用软件清零。

UART 器件通过以下相应的 UART 中断允许位使能为中断源:

• UxRXIE

• UxTXIE

• UxEIE

此外,还必须配置中断优先级位和中断子优先级位:

• UxIP (IPC6<4:2>)和 UxIS (IPC6<1:0>)

I/O引脚控制

通过将 ON 位(UxMODE<15>)、UTXEN 位(UxSTA<10>)和 URXEN 位(UxSTA<12>)置 1使能 UART 模块时, UART 模块将按照 UEN<1:0> (UxMODE<9:8>)位的定义控制 I/O 引脚,改写端口 TRIS 和 LATCH 寄存器位设置。

UxTX 会被强制设为输出,UxRX 设为输入。此外,如果使能了 UxCTS 和 UxRTS,UxCTS 引脚将被强制设为输入,而 UxRTS/BLCKx 引脚则用作 UxRTS 输出。如果使能了 BLCKx,则UxRTS/BLCKx 输出会驱动 16x 波特率输出。

节能模式和调试模式下的UART操作

休眠模式下的操作

当器件进入Sleep(休眠)模式时,系统时钟被禁止。 UART 在 Sleep (休眠)模式下不工作。如果在发送过程中进入 Sleep (休眠)模式,则发送会被中止, UxTX 引脚被驱动为逻辑 1。类似地,如果在接收过程中进入 Sleep(休眠)模式,接收会被中止。RTS 和 BCLK 引脚会被驱动为 0。

(可选) UART 模块可用于在检测到启动位时将 PIC32MX 器件从 Sleep (休眠)模式唤醒。如果 WAKE 位 (UxMODE<7>)在器件进入 Sleep (休眠)模式之前置 1,并且允许 UART 接收中断(UxRXIE = 1),则 UxRX 引脚上的下降沿会产生接收中断并唤醒器件。接收中断选择模式位 (RXISEL)对该功能没有影响。只有 ON (UxMODE<15>)位置 1 时,才会产生唤醒中断。

空闲模式下的操作

当器件进入 Idle (空闲)模式时,系统时钟源保持工作,但 CPU 停止执行代码。 SIDL 位(UxMODE<13>)用于选择在器件进入 Idle(空闲)模式时,UART 模块是停止工作还是继续正常工作。

• 如果 SIDL = 1,则模块在 Idle(空闲)模式下停止工作。模块在 Idle(空闲)模式下停止工作时 (SIDL = 1)执行与在 Sleep (休眠)模式下相同的过程。

• 如果 SIDL = 0,则模块在 Idle (空闲)模式下继续工作。

调试模式下的操作

FRZ 位(UxMODE<14>)决定 CPU 在 Debug(调试)模式下执行调试异常代码(即,应用程序暂停)时, UART 模块是继续运行还是停止。具体地说, FRZ 位会以以下形式影响操作:

• 当 FRZ = 1 且应用程序在 Debug (调试)模式下暂停时,模块会冻结其操作,并且不会更改 UART 模块的状态。在应用程序继续开始执行代码之后,模块将继续工作。

• 如果 FRZ = 0,则在 Debug (调试)模式下,即使应用程序暂停,模块也会继续工作。

各种复位的影响

器件复位:在发生器件复位时,所有 UART 寄存器会被强制设为它们的复位状态。

上电复位:在发生上电复位 (POR)时,所有 UART 寄存器会被强制设为它们的复位状态。

看门狗复位:在发生看门狗复位时,所有 UART 寄存器保持不变。


使用特权

评论回复
5
kxsi|  楼主 | 2021-8-9 13:25 | 只看该作者
使用Harmony配置串口收发
1、在Available Components组件中将UART1添加到Project Graph中;



2、组件添加后,组件初始内容如下;



3、组件配置完成后点击左侧的Generate Code按钮生成代码;

4、生成的代码与原始代码存在差异,需进行确认;

5、代码生成后需要的操作;

        1、系统初始化完成后添加串口初始化函数初始化串口;

        2、添加数据发送及接收函数;

6、编译运行将代码烧录到开发板中;

点击编译按钮,编译提示BUILD SUCCESSFUL,点击烧录,提示Programming/Verify complete,使用USB转串口工具,在电脑上可以看到开发板发送的数据。

串口配置说明



Operating Mode: 运行模式

Blocking mode 阻塞模式

Non-blocking mode 非阻塞模式

Ring buffer mode 环形缓冲模式



Stop Selection bit停止位选择,可选为1位停止位或2位停止位;

Parity and Data Selection bits 奇偶校验和数据选择位

可选9位数据位无奇偶校验、8位数据位奇校验、8位数据位偶校验、8位数据位无校验



UARTx Enable bits UART使能位



UxTX, UxRX and UxBCLK pins are enabled and used; UxCTS is controlled by corresponding bits in the PORTx register 使能并使用 UxTX、 UxRX 和 UxBCLK 引脚; UxCTS 引脚由 PORTx 寄存器中的相应位控制

UxTX, UxRX , UxCTS and UxRTS pins are enabled and used 使能并使用 UxTX、 UxRX、 UxCTS 和 UxRTS 引脚

UxTX ,UxRX and UxRTS pins are enabled and used; UxCTS is controlled by corresponding bits in the PORTx register 使能并使用 UxTX、 UxRX 和 UxRTS 引脚; UxCTS 引脚由 PORTx 寄存器中的相应位控制

UxTX and UxRX pins are enabled and used; UxCTS and UxRTS/UxBCLK pins are controlled by corresponding bits in the PORTx register使能并使用UxTX和UxRX引脚;UxCTS和UxRTS/UxBCLK引脚由PORTx寄存器中的相应位控制

UxCTS(允许发送)和 UxRTS(请求发送)可以工作于单工和流控模式,控制数据终端设备之间的发送和接收。BCLKx用于支持外部IrDA编解码器。

Clock Frequency为串口时钟频率

Baud Rate为串口波特率


使用特权

评论回复
6
kxsi|  楼主 | 2021-8-9 13:26 | 只看该作者
实际代码分析
文件plib_uart1.c中

//清除故障标志位
void static UART1_ErrorClear( void )
{
    UART_ERROR errors = UART_ERROR_NONE;
    uint8_t dummyData = 0u;

    errors = (UART_ERROR)(U1STA & (_U1STA_OERR_MASK | _U1STA_FERR_MASK | _U1STA_PERR_MASK));

    if(errors != UART_ERROR_NONE) //存在故障
    {
        /* If it's a overrun error then clear it to flush FIFO */
        if(U1STA & _U1STA_OERR_MASK) //数据溢出错误
        {
            U1STACLR = _U1STA_OERR_MASK;
        }

        /* Read existing error bytes from FIFO to clear parity and framing error flags */
        while(U1STA & _U1STA_URXDA_MASK) //清空FIFO的数据
        {
            dummyData = U1RXREG;
        }

        /* Clear error interrupt flag */
        IFS0CLR = _IFS0_U1EIF_MASK; //错误中断

        /* Clear up the receive interrupt flag so that RX interrupt is not triggered for error bytes */
        IFS0CLR = _IFS0_U1RXIF_MASK; //接收中断
    }

    // Ignore the warning
    (void)dummyData;
}

//串口1初始化
void UART1_Initialize( void )
{
    /* Set up UxMODE bits */
    /* STSEL  = 0 */ //停止位选择0:1位;1:2位
    /* PDSEL = 0 */ //奇偶位数据位选择00:8位数据位无奇偶校验;01:8位数据位偶校验;10:8位数据位奇校验;11:9位数据位无奇偶校验;
    /* UEN = 0 */ //UART使能位
    U1MODE = 0x8; //bit3 高速模式

    /* Enable UART1 Receiver and Transmitter */
    U1STASET = (_U1STA_UTXEN_MASK | _U1STA_URXEN_MASK | _U1STA_UTXISEL1_MASK ); //发送器使能  接收器使能  发送中断模式选择

    /* BAUD Rate register Setup */
    U1BRG = 173; //波特率分频比  波特率=串口时钟频率/[4*(波特率分频率比+1)] 高速模式下为4,标准速度模式下为16

    /* Disable Interrupts */
    IEC0CLR = _IEC0_U1EIE_MASK; //错误中断允许控制位
    IEC0CLR = _IEC0_U1RXIE_MASK; //接收中断允许控制位
    IEC0CLR = _IEC0_U1TXIE_MASK; //发送中断允许控制位

    /* Initialize instance object */
    uart1Obj.rxBuffer = NULL;
    uart1Obj.rxSize = 0;
    uart1Obj.rxProcessedSize = 0;
    uart1Obj.rxBusyStatus = false;
    uart1Obj.rxCallback = NULL;
    uart1Obj.txBuffer = NULL;
    uart1Obj.txSize = 0;
    uart1Obj.txProcessedSize = 0;
    uart1Obj.txBusyStatus = false;
    uart1Obj.txCallback = NULL;
    uart1Obj.errors = UART_ERROR_NONE;

    /* Turn ON UART1 */
    U1MODESET = _U1MODE_ON_MASK; //UART使能
}

//串口设置
bool UART1_SerialSetup( UART_SERIAL_SETUP *setup, uint32_t srcClkFreq )
{
    bool status = false;
    uint32_t baud;
    int32_t brgValHigh = 0;
    int32_t brgValLow = 0;
    uint32_t brgVal = 0;
    uint32_t uartMode;

    if((uart1Obj.rxBusyStatus == true) || (uart1Obj.txBusyStatus == true))
    {
        /* Transaction is in progress, so return without updating settings */
        return status;
    }

    if (setup != NULL)
    {
        baud = setup->baudRate;

        if (baud == 0)
        {
            return status; //波特率位0返回错误
        }

        if(srcClkFreq == 0)
        {
            srcClkFreq = UART1_FrequencyGet(); //获取时钟频率
        }

        /* Calculate BRG value */
        brgValLow = (((srcClkFreq >> 4) + (baud >> 1)) / baud ) - 1; //波特率分频比=串口时钟/(速度模式*波特率)-1
        brgValHigh = (((srcClkFreq >> 2) + (baud >> 1)) / baud ) - 1;

        /* Check if the baud value can be set with low baud settings */
        if((brgValLow >= 0) && (brgValLow <= UINT16_MAX))
        {
            brgVal =  brgValLow;
            U1MODECLR = _U1MODE_BRGH_MASK;
        }
        else if ((brgValHigh >= 0) && (brgValHigh <= UINT16_MAX))
        {
            brgVal = brgValHigh;
            U1MODESET = _U1MODE_BRGH_MASK;
        }
        else
        {
            return status;
        }

        if(setup->dataWidth == UART_DATA_9_BIT) //9位数据宽度
        {
            if(setup->parity != UART_PARITY_NONE)
            {
               return status;
            }
            else //9位数据模式无奇偶校验
            {
               /* Configure UART1 mode */
               uartMode = U1MODE;
               uartMode &= ~_U1MODE_PDSEL_MASK; //奇偶校验和数据选择位
               U1MODE = uartMode | setup->dataWidth;
            }
        }
        else //8位数据宽度
        {
            /* Configure UART1 mode */
            uartMode = U1MODE;
            uartMode &= ~_U1MODE_PDSEL_MASK; //奇偶校验和数据选择位UxMODE<1:0>
            U1MODE = uartMode | setup->parity ;
        }

        /* Configure UART1 mode */
        uartMode = U1MODE;
        uartMode &= ~_U1MODE_STSEL_MASK; //停止位UxMODE<0>
        U1MODE = uartMode | setup->stopBits ;

        /* Configure UART1 Baud Rate */
        U1BRG = brgVal; //波特率分频比位UxBRG<15:0
        status = true;
    }
    return status;
}

//自动波特率查询
bool UART1_AutoBaudQuery( void )
{
    if(U1MODE & _U1MODE_ABAUD_MASK) //自动波特率使能位
        return true;
    else
        return false;
}

//自动波特率设置
void UART1_AutoBaudSet( bool enable )
{
    if( enable == true )
    {
        U1MODESET = _U1MODE_ABAUD_MASK; //自动波特率使能位
    }

    /* Turning off ABAUD if it was on can lead to unpredictable behavior, so that direction of control is not allowed in this function. */
}

//串口1数据读取
bool UART1_Read(void* buffer, const size_t size )
{
    bool status = false;
    uint8_t* lBuffer = (uint8_t* )buffer;

    if(lBuffer != NULL)
    {
        /* Check if receive request is in progress */
        if(uart1Obj.rxBusyStatus == false)
        {
            /* Clear error flags and flush out error data that may have been received when no active request was pending */
            UART1_ErrorClear();

            uart1Obj.rxBuffer = lBuffer;
            uart1Obj.rxSize = size;
            uart1Obj.rxProcessedSize = 0;
            uart1Obj.rxBusyStatus = true;
            uart1Obj.errors = UART_ERROR_NONE;

            status = true;

            /* Enable UART1_FAULT Interrupt */
            IEC0SET = _IEC0_U1EIE_MASK; //错误中断允许控制位

            /* Enable UART1_RX Interrupt */
            IEC0SET = _IEC0_U1RXIE_MASK; //接收中断允许控制位
        }
    }
    return status;
}

//串口1数据写入
bool UART1_Write( void* buffer, const size_t size )
{
    bool status = false;
    uint8_t* lBuffer = (uint8_t*)buffer;

    if(lBuffer != NULL)
    {
        /* Check if transmit request is in progress */
        if(uart1Obj.txBusyStatus == false)
        {
            uart1Obj.txBuffer = lBuffer;
            uart1Obj.txSize = size;
            uart1Obj.txProcessedSize = 0;
            uart1Obj.txBusyStatus = true;
            status = true;

            /* Initiate the transfer by writing as many bytes as we can */
            while((!(U1STA & _U1STA_UTXBF_MASK)) && (uart1Obj.txSize > uart1Obj.txProcessedSize) ) //发送缓冲区满
            {
                if (( U1MODE & (_U1MODE_PDSEL0_MASK | _U1MODE_PDSEL1_MASK)) == (_U1MODE_PDSEL0_MASK | _U1MODE_PDSEL1_MASK)) //奇偶校验和数据选择位
                {
                    /* 9-bit mode */
                    U1TXREG = ((uint16_t*)uart1Obj.txBuffer)[uart1Obj.txProcessedSize++];
                }
                else
                {
                    /* 8-bit mode */
                    U1TXREG = uart1Obj.txBuffer[uart1Obj.txProcessedSize++];
                }
            }
            IEC0SET = _IEC0_U1TXIE_MASK;
        }
    }
    return status;
}

//读取故障
UART_ERROR UART1_ErrorGet( void )
{
    UART_ERROR errors = uart1Obj.errors;

    uart1Obj.errors = UART_ERROR_NONE;

    /* All errors are cleared, but send the previous error state */
    return errors;
}

//
void UART1_ReadCallbackRegister( UART_CALLBACK callback, uintptr_t context )
{
    uart1Obj.rxCallback = callback;

    uart1Obj.rxContext = context;
}

//查询串口发送忙状态
bool UART1_ReadIsBusy( void )
{
    return uart1Obj.rxBusyStatus;
}

//获取接收计数
size_t UART1_ReadCountGet( void )
{
    return uart1Obj.rxProcessedSize;
}

//串口读取中止
bool UART1_ReadAbort(void)
{
    if (uart1Obj.rxBusyStatus == true)
    {
        /* Disable the fault interrupt */
        IEC0CLR = _IEC0_U1EIE_MASK; //错误中断允许控制位

        /* Disable the receive interrupt */
        IEC0CLR = _IEC0_U1RXIE_MASK; //接收中断允许控制位

        uart1Obj.rxBusyStatus = false;

        /* If required application should read the num bytes processed prior to calling the read abort API */
        uart1Obj.rxSize = uart1Obj.rxProcessedSize = 0;
    }

    return true;
}

//
void UART1_WriteCallbackRegister( UART_CALLBACK callback, uintptr_t context )
{
    uart1Obj.txCallback = callback;

    uart1Obj.txContext = context;
}

//获取串口写入忙状态
bool UART1_WriteIsBusy( void )
{
    return uart1Obj.txBusyStatus;
}

//获取发送计数
size_t UART1_WriteCountGet( void )
{
    return uart1Obj.txProcessedSize;
}

//串口错误中断服务函数
static void UART1_FAULT_InterruptHandler (void)
{
    /* Save the error to be reported later */
    uart1Obj.errors = (UART_ERROR)(U1STA & (_U1STA_OERR_MASK | _U1STA_FERR_MASK | _U1STA_PERR_MASK)); //接收缓冲区溢出错误状态位 帧错误状态位(只读) 奇偶校验错误状态位 (只读)

    /* Disable the fault interrupt */
    IEC0CLR = _IEC0_U1EIE_MASK; //错误中断允许控制位

    /* Disable the receive interrupt */
    IEC0CLR = _IEC0_U1RXIE_MASK; //接收中断允许控制位

    /* Clear rx status */
    uart1Obj.rxBusyStatus = false;

    UART1_ErrorClear();

    /* Client must call UARTx_ErrorGet() function to get the errors */
    if( uart1Obj.rxCallback != NULL )
    {
        uart1Obj.rxCallback(uart1Obj.rxContext);
    }
}

//串口接收中断服务函数
static void UART1_RX_InterruptHandler (void)
{
    if(uart1Obj.rxBusyStatus == true)
    {
        while((_U1STA_URXDA_MASK == (U1STA & _U1STA_URXDA_MASK)) && (uart1Obj.rxSize > uart1Obj.rxProcessedSize) ) //接收缓冲区数据存在标志位(只读)
        {
            if (( U1MODE & (_U1MODE_PDSEL0_MASK | _U1MODE_PDSEL1_MASK)) == (_U1MODE_PDSEL0_MASK | _U1MODE_PDSEL1_MASK))
            {
                /* 9-bit mode */
                ((uint16_t*)uart1Obj.rxBuffer)[uart1Obj.rxProcessedSize++] = (uint16_t )(U1RXREG);
            }
            else
            {
                /* 8-bit mode */
                uart1Obj.rxBuffer[uart1Obj.rxProcessedSize++] = (uint8_t )(U1RXREG);
            }
        }

        /* Clear UART1 RX Interrupt flag */
        IFS0CLR = _IFS0_U1RXIF_MASK; //接收中断标志状态位

        /* Check if the buffer is done */
        if(uart1Obj.rxProcessedSize >= uart1Obj.rxSize)
        {
            uart1Obj.rxBusyStatus = false;

            /* Disable the fault interrupt */
            IEC0CLR = _IEC0_U1EIE_MASK; //错误中断允许控制位

            /* Disable the receive interrupt */
            IEC0CLR = _IEC0_U1RXIE_MASK; //接收中断允许控制位


            if(uart1Obj.rxCallback != NULL)
            {
                uart1Obj.rxCallback(uart1Obj.rxContext);
            }
        }
    }
    else
    {
        // Nothing to process
        ;
    }
}

//串口发送中断服务函数
static void UART1_TX_InterruptHandler (void)
{
    if(uart1Obj.txBusyStatus == true)
    {
        while((!(U1STA & _U1STA_UTXBF_MASK)) && (uart1Obj.txSize > uart1Obj.txProcessedSize) ) //发送缓冲区满状态位(只读)
        {
            if (( U1MODE & (_U1MODE_PDSEL0_MASK | _U1MODE_PDSEL1_MASK)) == (_U1MODE_PDSEL0_MASK | _U1MODE_PDSEL1_MASK))
            {
                /* 9-bit mode */
                U1TXREG = ((uint16_t*)uart1Obj.txBuffer)[uart1Obj.txProcessedSize++];
            }
            else
            {
                /* 8-bit mode */
                U1TXREG = uart1Obj.txBuffer[uart1Obj.txProcessedSize++];
            }
        }

        /* Clear UART1TX Interrupt flag */
        IFS0CLR = _IFS0_U1TXIF_MASK;

        /* Check if the buffer is done */
        if(uart1Obj.txProcessedSize >= uart1Obj.txSize)
        {
            uart1Obj.txBusyStatus = false;

            /* Disable the transmit interrupt, to avoid calling ISR continuously */
            IEC0CLR = _IEC0_U1TXIE_MASK; //发送中断标志状态位

            if(uart1Obj.txCallback != NULL)
            {
                uart1Obj.txCallback(uart1Obj.txContext);
            }
        }
    }
    else
    {
        // Nothing to process
        ;
    }
}

//串口服务函数
void UART_1_InterruptHandler (void)
{
    /* Call Error handler if Error interrupt flag is set */
    if ((IFS0 & _IFS0_U1EIF_MASK) && (IEC0 & _IEC0_U1EIE_MASK))
    {
        UART1_FAULT_InterruptHandler();
    }
    /* Call RX handler if RX interrupt flag is set */
    if ((IFS0 & _IFS0_U1RXIF_MASK) && (IEC0 & _IEC0_U1RXIE_MASK))
    {
        UART1_RX_InterruptHandler();
    }
    /* Call TX handler if TX interrupt flag is set */
    if ((IFS0 & _IFS0_U1TXIF_MASK) && (IEC0 & _IEC0_U1TXIE_MASK))
    {
        UART1_TX_InterruptHandler();
    }
}


使用特权

评论回复
7
kxsi|  楼主 | 2021-8-9 13:27 | 只看该作者
实验验证

点击编译按钮,编译提示BUILD SUCCESSFUL,点击烧录,提示Programming/Verify complete,

使用USB转串口工具,在电脑上可以看到开发板发送的数据。


使用特权

评论回复
8
skyred| | 2021-8-10 17:52 | 只看该作者
学习了。
之前用PIC还是,用汇编,每次用烧录器烧完,再焊接到板子上试

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

44

主题

3304

帖子

2

粉丝