RT1060--串口中断传输详解(SDK)
串口中断传输详解(SDK)
1. evkmimxrt1060_lpuart_interrupt
使用 NXP 的
fsl_lpuart.h
库,通过中断方式实现 LPUART 的数据接收和回显。它使用了一个
ring buffer
来暂存接收到的数据,然后在主循环中将缓冲区的数据发送出去。
代码解释
宏定义:
DEMO_LPUART
: 定义使用的 LPUART 外设为LPUART1
。DEMO_LPUART_CLK_FREQ
: 定义 LPUART 的时钟频率。DEMO_LPUART_IRQn
: 定义 LPUART 的中断号。DEMO_LPUART_IRQHandler
: 定义 LPUART 的中断处理函数名。DEMO_RING_BUFFER_SIZE
: 定义环形缓冲区的大小为 16 字节。
全局变量:
g_tipString
: 提示字符串,程序启动时发送到串口。demoRingBuffer
: 环形缓冲区,用于存储接收到的数据。txIndex
: 发送索引,指向下一个要发送的数据在环形缓冲区中的位置。rxIndex
: 接收索引,指向下一个要写入接收数据的环形缓冲区位置。
DEMO_LPUART_IRQHandler()
函数:LPUART 中断处理函数:
- 如果Rx Data 寄存器满,则:
- 读取receiver register数据: (
LPUART_ReadByte()
)。 - 读完之后检查环形缓冲区是否已满,如果未满,则将接收到的数据写入环形缓冲区,并更新
rxIndex
。
- 读取receiver register数据: (
- 如果Rx Data 寄存器满,则:
main()
函数:- 初始化开发板和 LPUART。
- 发送提示字符串。
- 使能 LPUART 的接收满中断 (
kLPUART_RxDataRegFullInterruptEnable
)。 - 使能 LPUART 中断 (
EnableIRQ(DEMO_LPUART_IRQn)
)。 - 进入主循环:
- 检查 LPUART 发送寄存器是否为空 (
kLPUART_TxDataRegEmptyFlag
)。 - 检查环形缓冲区是否非空。
- 如果发送寄存器为空且缓冲区非空,则从环形缓冲区读取数据 (
demoRingBuffer[txIndex]
),并通过LPUART_WriteByte()
发送出去,并更新txIndex
。
- 检查 LPUART 发送寄存器是否为空 (
数据/中断/callback调用流程图

详细流程解释:
- 中断处理:
- 读取接收到的数据并存入环形缓冲区
demoRingBuffer
。 - 更新接收索引
rxIndex
。
- 读取接收到的数据并存入环形缓冲区
- 主循环处理:
- 主循环不断检查 LPUART 发送寄存器是否为空以及环形缓冲区是否非空。
- 如果条件满足,则从环形缓冲区读取数据,并通过
LPUART_WriteByte()
发送出去。 - 更新发送索引
txIndex
。
- 数据发送: LPUART 硬件将数据发送到串口接收端。
关键点
- 环形缓冲区: 用于在中断处理函数和主循环之间传递数据,避免数据丢失。
- 中断驱动: 使用中断来处理接收事件,提高了 CPU 效率。
- 非阻塞发送: 主循环中轮询检查发送寄存器是否为空和ring buffer非空,用于读取数据并发送,更新
txIndex
;
2. evkmimxrt1060_lpuart_interrupt_transfer
使用 LPUART 进行回显。
程序通过 LPUART 接收用户输入的 8 个字符,然后将这 8 个字符回显给用户终端。
代码解释
代码结构:
宏定义:定义了一些宏和变量,例如使用的 LPUART 实例 (
DEMO_LPUART
)、时钟频率 (DEMO_LPUART_CLK_FREQ
)、回显缓冲区长度 (ECHO_BUFFER_LENGTH
) 。callback声明:声明了一个 LPUART 用户回调函数
LPUART_UserCallback
。变量:定义了一些全局变量,例如用于存储句柄 (
g_lpuartHandle
)、提示信息字符串 (g_tipString
)、发送缓冲区 (g_txBuffer
)、接收缓冲区 (g_rxBuffer
) 等,还有一些标志位用于指示缓冲区状态和传输状态:1
2
3
4volatile bool rxBufferEmpty = true;
volatile bool txBufferFull = false;
volatile bool txOnGoing = false;
volatile bool rxOnGoing = false;**LPUART 用户回调函数 (LPUART_UserCallback)**:该函数会在 LPUART 传输完成 (发送或接收) 时被调用。它更新发送和接收缓冲区的相关标志位 (txBufferFull、txOnGoing、rxBufferEmpty、rxOnGoing)。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17/* LPUART user callback */
void LPUART_UserCallback(LPUART_Type *base, lpuart_handle_t *handle, status_t status, void *userData)
{
userData = userData;
if (kStatus_LPUART_TxIdle == status) // 实际上就是发送完成!
{
txBufferFull = false;
txOnGoing = false;
}
if (kStatus_LPUART_RxIdle == status) // 实际上对应接收完成!
{
rxBufferEmpty = false;
rxOnGoing = false;
}
}主函数 (main)
初始化时钟、引脚复用等。
配置 LPUART:设置波特率、启用发送和接收功能等。
创建 LPUART 传输句柄。
LPUART_TransferCreateHandle(DEMO_LPUART, &g_lpuartHandle, LPUART_UserCallback, NULL);
发送提示信息字符串。
LPUART_TransferSendNonBlocking(DEMO_LPUART, &g_lpuartHandle, &xfer);
进入循环,实现回显功能:
如果接收空闲且接收缓冲区为空,则启动接收数据到接收缓冲区。
LPUART_TransferReceiveNonBlocking(DEMO_LPUART, &g_lpuartHandle, &receiveXfer, NULL);
如果发送空闲且发送缓冲区满,则启动发送数据。
LPUART_TransferSendNonBlocking(DEMO_LPUART, &g_lpuartHandle, &sendXfer);
如果接收非空且发送不满,则将接收缓冲区内容复制到发送缓冲区,并更新缓冲区标志位。
1
2
3memcpy(g_txBuffer, g_rxBuffer, ECHO_BUFFER_LENGTH);
rxBufferEmpty = true;
txBufferFull = true;
流程图:
数据流:
- 初始化阶段:
- 配置 LPUART。
- 发送提示信息:
- 将提示信息字符串拷贝到发送缓冲区。
- 启动发送。
- 回显循环:
- 接收数据:
- 如果接收空闲且接收缓冲区为空,则启动接收数据。
- 接收完成触发回调函数,更新接收缓冲区标志位。
- 发送数据:
- 如果发送空闲且发送缓冲区满,则启动发送数据。
- 发送完成触发回调函数,更新发送缓冲区标志位。
- 复制数据:
- 如果接收非空且发送不满,则将接收缓冲区内容复制到发送缓冲区。
- 更新接收和发送缓冲区标志位。
- 接收数据:
中断和回调流程:
- 当数据接收完成或发送完成后,会产生中断。
- 中断服务程序会将控制权转移到 LPUART 驱动程序。
- 驱动程序会调用用户回调函数
LPUART_UserCallback
。 - 回调函数中,根据传输完成类型 (发送/接收) 更新相关的缓冲区标志位。
注意:
- 该代码使用非阻塞式传输,即发送或接收启动后,程序不会等待传输完成,而是继续执行其他操作。
- 回调函数中只更新了标志位,并没有直接操作数据缓冲区。数据处理是在主循环中进行的。
代码关键点
- 非阻塞传输: 使用了
LPUART_TransferSendNonBlocking
和LPUART_TransferReceiveNonBlocking
函数,这意味着发送和接收操作会在后台进行,不会阻塞主循环。 - 回调函数:
LPUART_UserCallback
函数用于处理传输完成事件。在这个函数中,主要任务是更新标志位,例如txOnGoing
、txBufferFull
、rxOnGoing
和rxBufferEmpty
。 - 缓冲区管理: 使用了
g_txBuffer
和g_rxBuffer
作为发送和接收缓冲区,并通过memcpy
函数在两个缓冲区之间复制数据。 - 主循环逻辑: 主循环负责启动发送和接收操作,并在缓冲区之间复制数据。
1 | graph TD |
代码逻辑解释:
初始化: 程序首先初始化 LPUART 外设,然后发送一个提示信息。
回显循环:
程序进入一个无限循环,不断检查以下条件:
- 接收:
- 如果当前没有正在接收数据 (
!rxOnGoing
) 并且接收缓冲区为空 (rxBufferEmpty
),则启动一次非阻塞的接收操作 (LPUART_TransferReceiveNonBlocking
)。 - 当 LPUART 硬件接收到数据后,
RxDataRegFullFlag
标志位会被置位,触发中断。 - NVIC 接收到中断请求后,会调用中断服务例程。在中断服务例程中,会调用用户定义的回调函数
LPUART_UserCallback
。- 回调函数根据
kStatus_LPUART_RxIdle
状态将rxBufferEmpty
设置为false
,将rxOnGoing
设置为false
,表明接收已完成。
- 回调函数根据
- 如果当前没有正在接收数据 (
- 发送:
- 如果当前没有正在发送数据 (
!txOnGoing
) 并且发送缓冲区已满 (txBufferFull
),则启动一次非阻塞的发送操作 (LPUART_TransferSendNonBlocking
)。 - LPUART 硬件发送完数据后,会产生中断。
- NVIC 处理中断,并调用回调函数
LPUART_UserCallback
。- 回调函数根据
kStatus_LPUART_TxIdle
状态将txBufferFull
设置为false
,将txOnGoing
设置为false
,表明发送已完成。
- 回调函数根据
- 如果当前没有正在发送数据 (
- 数据复制:如果接收缓冲区非空 (
!rxBufferEmpty
) 并且发送缓冲区未满 (!txBufferFull
),则使用memcpy
函数将接收缓冲区的数据复制到发送缓冲区,并将rxBufferEmpty
设置为true
,txBufferFull
设置为true
,为下一次接收和发送做准备。
- 接收:
关于中断和回调
LPUART_UserCallback
是一个用户自定义的回调函数,它会在 LPUART 驱动程序中的中断处理函数 LPUART_TransferHandleIRQ
中,当特定的传输事件发生后被调用。具体来说,以下几种情况下会调用 LPUART_UserCallback
:
- 接收完成: 当使用
LPUART_TransferReceiveNonBlocking
函数启动非阻塞接收,并且所有请求的数据都已接收完毕时,LPUART_TransferHandleIRQ
函数会在处理接收数据就绪中断时调用LPUART_UserCallback
,并传递状态kStatus_LPUART_RxIdle
。 - 发送完成: 当使用
LPUART_TransferSendNonBlocking
函数启动非阻塞发送,并且所有数据都已发送完毕时,LPUART_TransferHandleIRQ
函数会在处理发送完成中断时调用LPUART_UserCallback
,并传递状态kStatus_LPUART_TxIdle
。 - 接收硬件溢出: 当 LPUART 硬件发生接收溢出错误时,
LPUART_TransferHandleIRQ
函数会在处理接收溢出中断时调用LPUART_UserCallback
,并传递状态kStatus_LPUART_RxHardwareOverrun
。这个状态表示有数据在接收之前就被覆盖了,导致数据丢失。
完整的接收流程和发送流程
接收流程:
- 应用程序调用
LPUART_TransferReceiveNonBlocking
函数启动非阻塞接收。 LPUART_TransferReceiveNonBlocking
函数配置 LPUART 硬件,使能接收中断,并将接收请求的信息保存在lpuart_handle_t
结构体中。- LPUART 硬件接收到数据后,触发中断。
- CPU 响应中断,执行中断服务例程
LPUART_TransferHandleIRQ
。 LPUART_TransferHandleIRQ
函数检查中断状态,如果是接收数据就绪中断,则调用LPUART_TransferHandleReceiveDataFull
函数。LPUART_TransferHandleReceiveDataFull
函数将数据从LPUART接收FIFO读取到handle指定的缓冲区。LPUART_TransferHandleReceiveDataFull
函数检查是否所有请求的数据都已接收完毕,如果是,则在LPUART_TransferHandleIRQ
中调用handle->callback
,即LPUART_UserCallback
,并传递kStatus_LPUART_RxIdle
状态。
发送流程:
- 应用程序调用
LPUART_TransferSendNonBlocking
函数启动非阻塞发送。 LPUART_TransferSendNonBlocking
函数配置 LPUART 硬件,使能发送中断,并将发送请求的信息保存在lpuart_handle_t
结构体中。- 当发送数据寄存器为空时,LPUART 硬件触发中断。
- CPU 响应中断,执行中断服务例程
LPUART_TransferHandleIRQ
。 LPUART_TransferHandleIRQ
函数检查中断状态,如果是发送数据寄存器空中断,则调用LPUART_TransferHandleSendDataEmpty
函数。LPUART_TransferHandleSendDataEmpty
函数将数据从handle指定的缓冲区写入LPUART发送FIFO。LPUART_TransferHandleSendDataEmpty
函数检查是否所有数据都已发送完毕。如果是,则当发送完成后,在LPUART_TransferHandleIRQ
中调用handle->callback
,即LPUART_UserCallback
,并传递kStatus_LPUART_TxIdle
状态。
总结:
LPUART_UserCallback
是一个在中断上下文中被调用的回调函数。它允许用户在 LPUART 传输完成后执行自定义的操作,例如:
- 设置标志位,通知应用程序传输已完成。
- 启动下一次传输。
- 处理接收到的数据。
- 进行错误处理。
通过使用回调函数,可以实现事件驱动的编程模型,提高程序的效率和响应性。用户不需要在主循环中轮询 LPUART 的状态,而是通过回调函数在传输完成后得到通知。
因此,LPUART_UserCallback
的调用时机取决于 LPUART 的传输状态和中断事件,主要发生在接收完成、发送完成和接收溢出等情况下。它在整个 LPUART 驱动程序中起到了连接驱动程序和用户应用程序的重要作用。
RT1060--串口中断传输详解(SDK)
https://dustofstars.github.io/NXP/RT1060/rt1060-串口中断传输详解-sdk/