S32K144——lpuart 串口调试记

大插曲

我一开始检查了时钟,接口,发现怎么都跑不通,调试了两天。不是代码卡在某个函数里面,就是代码可以运行,但是没有现象。

直摇人,同事调出来了,我才发现

是我搞错接口了???? 但是不对啊!IAR 代码文件的注释上写的串口是 PTD13/PTD14

而且用 IAR 的例程也跑的通,从来没想过是串口初始化的问题。我反向定位为什么 IAR 的历程可以把串口跑通,发现。。。。

好好好,你用 if/else 初始化是吧

这个故事告诉我们不要随意相信代码注释,请以原理图为准。。。。

正文开始:

基本配置

根据自己板子的接口

进行 pin 配置,我的板子是 PTC8 和 PTC9

在lpuart模块里进行配置,设置波特率;device那里,有的时候默认的是错的,注意校对


 

在 main.c 中编辑代码

  1. 打开时钟,初始化pin口

  1. 初始化串口

  1. 发送

  1. 结果

S32K144 lpuart 相关信息(待完善)

S32K144可以有三个 LPUART 实例,发送、接收数据缓存区为 4 字节

LPUART 发射器框图

LPUART 接收器框图

寄存器定义

波特率生成

AI 生成的 lpuart_driver

前置知识

串口的三种工作模式:

  • 轮询:CPU 不停的查询串口状态标志(如 “是否有数据待接收”“发送缓冲区是否为空”),只有满足状态时才执行收发操作。
  • 中断:串口硬件主动触发中断,CPU 在 ISR 里面处理收发逻辑,在没有触发中断的时间里,CPU 可以执行其他任务。
  • 阻塞:调用收发函数后,函数不返回,直到操作完成,对调用者呈现“阻塞等待”的效果。通过信号量,把任务切换到等待队列,CPU 去执行其他任务,等信号量释放,任务由等待队列切换到就绪队列,等待 CPU 调度继续运行。适用于单任务场景下的确定性收发(如发送配置指令后,必须等确认才能继续)。

ISR 是如何安装的

回调函数

回调函数是啥:

普通的函数调用

回调函数 callback:

红色函数的就是callback,需要用户自己定义。它可以让代码更好的复用(你需要用什么函数,你就定义成什么函数)。回调函数往往依赖函数指针实现。

关于函数指针可以看 C语言指针进阶(一)——深入详解“函数指针”与“指针函数”-优快云博客

  • 用途:
  • 加快UI的相应速度
  • 提高系统的实时性
  • 高效分配各个线程的线程栈
  • 本程序中:接收回调函数的安装函数。

C
安装接收回调函数,返回值为 uart_callback_t(lpuart_driver.h)
uart_callback_t LPUART_DRV_InstallRxCallback(uint32_t instance,
                                             uart_callback_t function,
                                             void * callbackParam)
{
    DEV_ASSERT(instance < LPUART_INSTANCE_COUNT);

    lpuart_state_t * lpuartState = (lpuart_state_t *)s_lpuartStatePtr[instance];

    uart_callback_t currentCallback = lpuartState->rxCallback;
    lpuartState->rxCallback = function;
    lpuartState->rxCallbackParam = callbackParam;

    return currentCallback;
}

Plain Text
callback.h

typedef void (*uart_callback_t)(void *driverState, uart_event_t event, void *userData);
//
这个地方定义了一个 函数指针类型 uart_callback_t, 需传入 void*, uart_event_t, void* 三个量,无返回值

Q:如果我们要实现接收一个以 ‘\0’ 结尾的字符串,我们该怎么办?

A:我们需要开辟(定义)一个 buffer 用于存储字符串和一个指向 buffer 的指针 bufferIdx,然后通过 LPUART_DRV_ReceiveData(INST_LPUART1, buffer[0], 1U) 接收一个字节存入buffer,然后我们通过接收回调函数,判断那个buffer是否填入了一个字节(事件UART_EVENT_RX_FULL),如果是,就判断被填入被填入的是不是结束符还有是不是要超出 buffer 大小了,如果都不是就移动指针,并使用 LPUART_DRV_SetRxBuffer 配置串口接收的缓冲区信息(告诉硬件 “下一次收到的数据应该存到哪里,以及接收多少字节”),然后串口的工作模式,有数据传来时就触发下一次的接收

'\0' 和 '0' 的区别

结尾交付物提议

要不要我帮你整理一份LPUART 驱动核心结构体与函数速查表?表格会包含 “结构体成员说明”“函数功能 + 参数 + 返回值”,方便你后续开发时快速查阅,不用反复翻看驱动代码。

  • Ipuart_driver.h解析

  • 一、重要结构体(驱动的 “数据骨架”)

    结构体名

    核心作用

    核心成员

    成员类型

    成员说明

    使用场景

    lpuart_user_config_t

    存储用户配置参数

    transferType

    枚举

    传输方式:LPUART_USING_INTERRUPTS(中断)/LPUART_USING_DMA(DMA)

    初始化前,用户配置通信参数(波特率、校验等),作为LPUART_DRV_Init参数

    baudRate

    uint32_t

    波特率(如 9600、115200)

    parityMode

    枚举

    校验模式:LPUART_PARITY_DISABLED(无校验)/ 奇校验 / 偶校验

    stopBitCount

    枚举

    停止位:LPUART_ONE_STOP_BIT(1 位)/2 位

    bitCountPerChar

    枚举

    数据位:LPUART_8_BITS_PER_CHAR(8 位)/9 位 / 10 位

    rxDMAChannel/txDMAChannel

    uint32_t

    DMA 传输的通道号(仅 DMA 模式有效)

    lpuart_state_t

    存储驱动运行时状态

    transferType

    枚举

    当前传输方式(从lpuart_user_config_t复制)

    初始化时传入空实例,驱动内部跟踪传输状态(如是否忙碌、剩余字节数)

    txBuff/rxBuff

    uint8_t*

    发送 / 接收缓冲区指针

    txSize/rxSize

    uint32_t

    剩余待发送 / 待接收字节数

    isTxBusy/isRxBusy

    bool

    发送 / 接收是否忙碌(true= 忙碌)

    transmitStatus

    /receiveStatus

    枚举

    传输状态:STATUS_SUCCESS(成功)/STATUS_TIMEOUT(超时)/ 错误

    rxCallback

    /txCallback

    函数指针

    接收 / 发送回调函数(事件触发时调用)

    rxCallbackParam

    /txCallbackParam

    void*

    回调函数的用户自定义参数

    rxComplete

    /txComplete

    信号量

    阻塞传输时,用于等待传输完成

    rxDMAChannel

    /txDMAChannel

    uint32_t

    DMA 通道号(仅 DMA 模式有效)

    uart_event_t

    定义 UART 事件类型(枚举)

    UART_EVENT_RX_FULL

    枚举值

    接收缓冲区满(单次接收完成,如 1 字节)

    回调函数中判断事件类型,执行对应逻辑(如继续接收 / 处理错误)

    UART_EVENT_TX_EMPTY

    枚举值

    发送缓冲区空(可写入下一字节)

    UART_EVENT_END_TRANSFER

    枚举值

    整个传输完成(所有字节发送 / 接收完毕)

    UART_EVENT_ERROR

    枚举值

    通信错误(校验错 / 帧错误 / 溢出错误)

    uart_callback_t

    定义回调函数签名(函数类型)

    函数原型:void (*)(void* driverState, uart_event_t event, void* userData)

    函数指针类型

    driverStatelpuart_state_t指针;event:事件类型;userData:用户参数

    上层通过LPUART_DRV_InstallRxCallback安装回调,响应传输事件

    二、核心函数功能(按 “功能模块” 分类)

    代码中的函数按 “初始化→配置→发送→接收→中断处理→辅助操作” 划分,以下是各模块的关键函数解析:

    模块 1:初始化与反初始化(驱动 “启动 / 关闭”)

    这是使用 LPUART 的第一步,负责 “硬件初始化、状态复位、中断配置”。

    函数名

    核心功能

    关键逻辑

    LPUART_DRV_GetDefaultConfig

    获取默认配置

    给lpuart_user_config_t填充默认值(波特率 9600、无校验、8 位数据位、1 位停止位、中断传输),避免用户手动填充所有参数。

    LPUART_DRV_Init

    初始化 LPUART

    1. 校验参数合法性(如实例号、状态结构体非空);2. 配置 LPUART 硬件(波特率、校验位、数据位等,调用LPUART_DRV_SetBaudRate);3. 创建同步信号量(rxComplete/txComplete,用于阻塞传输);4. 安装中断处理函数(INT_SYS_InstallHandler)并使能中断;5. 保存状态结构体指针(s_lpuartStatePtr),标记驱动已初始化。

    LPUART_DRV_Deinit

    反初始化 LPUART

    1. 等待发送完成(避免数据残留);2. 销毁同步信号量;3. 禁用中断并恢复默认中断处理函数;4. 清空状态结构体指针,标记驱动未初始化。

    模块 2:通信参数配置(动态调整硬件参数)

    用于初始化后修改 LPUART 的核心通信参数(如波特率)。

    函数名

    核心功能

    关键逻辑

    LPUART_DRV_SetBaudRate

    设置波特率

    1. 校验当前无传输(isTxBusy/isRxBusy为false);2. 计算波特率分频系数(sbr)和过采样率(osr),确保实际波特率与期望偏差最小;3. 配置 LPUART 硬件寄存器(写入osr和sbr)。

    LPUART_DRV_GetBaudRate

    获取当前波特率

    读取硬件寄存器的osr和sbr,结合 LPUART 时钟频率,计算当前实际波特率并返回。

    模块 3:数据发送(三种传输方式:阻塞、轮询、非阻塞)

    驱动提供三种发送接口,适配不同场景(如 “需要等待发送完成”“不允许阻塞”)。

    函数名

    传输方式

    核心功能

    适用场景

    LPUART_DRV_SendDataBlocking

    阻塞

    发送数据后,阻塞等待传输完成(通过osSemWait等待txComplete信号量),函数返回即表示传输结束(成功 / 超时 / 错误)。

    需确保数据发送完成后再执行后续逻辑(如发送指令后等待响应)。

    LPUART_DRV_SendDataPolling

    轮询

    不依赖中断,通过循环查询 “发送缓冲区空” 标志(LPUART_TX_DATA_REG_EMPTY),直到所有数据发送完成。

    不允许使用中断的场景(如裸机、低功耗场景),但会占用 CPU 资源。

    LPUART_DRV_SendData

    非阻塞

    启动发送后立即返回,传输过程由中断 / DMA 完成;上层需通过LPUART_DRV_GetTransmitStatus查询状态,或通过回调函数获取结果。

    不希望阻塞 CPU 的场景(如多任务系统、实时性要求高的应用)。

    LPUART_DRV_GetTransmitStatus

    -

    查询发送状态(成功 / 忙碌 / 错误),并返回剩余待发送字节数。

    非阻塞发送时,上层判断传输是否完成。

    LPUART_DRV_AbortSendingData

    -

    终止正在进行的非阻塞发送,标记状态为STATUS_UART_ABORTED。

    紧急情况下需要停止发送(如超时、错误)。

    模块 4:数据接收(三种传输方式:阻塞、轮询、非阻塞)

    与发送对应,接收也提供三种接口,核心逻辑是 “将硬件接收的数据存入缓冲区”。

    函数名

    传输方式

    核心功能

    适用场景

    LPUART_DRV_ReceiveDataBlocking

    阻塞

    启动接收后,阻塞等待接收完成(通过osSemWait等待rxComplete信号量),函数返回即表示数据接收完毕。

    需等待数据接收后再处理(如接收传感器数据后解析)。

    LPUART_DRV_ReceiveDataPolling

    轮询

    不依赖中断,通过循环查询 “接收缓冲区满” 标志(LPUART_RX_DATA_REG_FULL),直到所有数据接收完成;同时检测接收错误(校验错、帧错误等)。

    不允许使用中断的场景,需手动处理错误。

    LPUART_DRV_ReceiveData

    非阻塞

    启动接收后立即返回,接收过程由中断 / DMA 完成;上层通过LPUART_DRV_GetReceiveStatus查询状态,或通过回调函数获取接收结果。

    不希望阻塞 CPU 的场景(如多任务系统)。

    LPUART_DRV_GetReceiveStatus

    -

    查询接收状态(成功 / 忙碌 / 错误),并返回剩余待接收字节数。

    非阻塞接收时,上层判断接收是否完成。

    LPUART_DRV_AbortReceivingData

    -

    终止正在进行的非阻塞接收,标记状态为STATUS_UART_ABORTED。

    紧急情况下需要停止接收(如超时、错误)。

    模块 5:回调函数管理(上层与驱动的 “事件通知”)

    通过回调函数,驱动可在 “数据接收满、传输完成、出错” 时主动通知上层,无需上层轮询。

    函数名

    核心功能

    关键逻辑

    LPUART_DRV_InstallRxCallback

    安装接收回调

    将用户实现的接收回调函数(uart_callback_t)和参数存入lpuart_state_t,接收事件触发时调用该函数。

    LPUART_DRV_InstallTxCallback

    安装发送回调

    类似接收回调,发送事件(如发送空、发送完成)触发时调用用户函数。

    模块 6:中断处理(驱动的 “核心事件响应”)

    中断是 “非阻塞传输” 的核心,代码中通过中断处理函数实现 “实时响应硬件事件”,所有中断函数均为static(内部调用,不对外暴露)。

    函数名

    核心功能

    关键逻辑

    LPUART_DRV_IRQHandler

    总中断入口

    LPUART 中断触发时,首先调用该函数;它会分类型处理:

    1. 错误中断(调用LPUART_DRV_ErrIrqHandler);

    2. 接收满中断(调用LPUART_DRV_RxIrqHandler);

    3. 发送空中断(调用LPUART_DRV_TxEmptyIrqHandler);

    4. 发送完成中断(调用LPUART_DRV_TxCompleteIrqHandler)。

    LPUART_DRV_RxIrqHandler

    接收满中断处理

    1. 调用LPUART_DRV_GetData,将硬件接收的数据存入rxBuff;

    2. 更新接收进度(rxBuff指针后移,rxSize递减);

    3. 若接收完成(rxSize == 0),调用接收回调(如UART_EVENT_RX_FULL),并终止接收(LPUART_DRV_CompleteReceiveDataUsingInt)。

    LPUART_DRV_TxEmptyIrqHandler

    发送空中断处理

    1. 调用LPUART_DRV_PutData,将txBuff的数据写入硬件发送缓冲区;

    2. 更新发送进度(txBuff指针后移,txSize递减);

    3. 若发送完成(txSize == 0),禁用发送空中断,启用发送完成中断。

    LPUART_DRV_ErrIrqHandler

    错误中断处理

    检测错误类型(溢出错误、帧错误、校验错误、噪声错误),标记接收状态,终止接收,并调用回调(UART_EVENT_ERROR)。

    模块 7:辅助函数(驱动内部工具)

    这些函数是static修饰的内部函数,用于封装重复操作,简化核心逻辑。

    函数名

    核心功能

    LPUART_DRV_SetTxBuffer

    LPUART_DRV_SetRxBuffer

    设置发送 / 接收缓冲区指针和长度,支持 “连续传输”(如接收满后,通过回调调用该函数配置下一个缓冲区)。

    LPUART_DRV_PutData

    根据数据位长度(8/9/10 位),将txBuff的数据写入 LPUART 硬件发送寄存器。

    LPUART_DRV_GetData

    根据数据位长度,从 LPUART 硬件接收寄存器读取数据,存入rxBuff。

    LPUART_DRV_StartSendDataUsingInt

    LPUART_DRV_CompleteSendDataUsingInt

    中断发送的 “启动 / 终止”:启动时初始化发送状态、使能发送中断;终止时禁用中断、更新状态、释放信号量。

    三、驱动整体工作流程(以 “中断接收” 为例)

    结合之前你关注的 “逐字节连续接收”,用一个实际场景串联驱动的核心操作:

  • 初始化:上层调用LPUART_DRV_GetDefaultConfig获取默认配置,修改后调用LPUART_DRV_Init初始化硬件和驱动状态;

  • 安装回调:调用LPUART_DRV_InstallRxCallback,安装自定义的rxCallback(如你之前的 “接收满则配置下一次接收” 函数);

  • 启动接收:调用LPUART_DRV_ReceiveData(非阻塞),传入接收缓冲区buffer和长度(如 1 字节);

  • 中断触发:硬件接收 1 字节后,触发UART_EVENT_RX_FULL中断,调用LPUART_DRV_RxIrqHandler;

  • 回调处理:中断处理函数调用rxCallback,在回调中判断 “是否收到\n或缓冲区满”,若未满足则调用LPUART_DRV_SetRxBuffer配置下一次接收;

  • 接收完成:当收到\n或缓冲区满时,回调中不再配置下一次接收,接收过程终止。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值