在网上看了很多S32K14x串口接收的,基官方SDK的串口接收大部分都是使用中断或者DMA接收定长的数据帧,想要接收不定长的数据帧需要开一个接收超时定时器(需要占用系统资源且效率低下)。
查看手册得之S32K14x的串口带有空闲中断的功能,本文记录下在串口中断接收时使用空闲中断的用法。
官方SDK中没有使用空闲中断,所以需要修改官方SDK程序。
1、空闲间隔
默认是1个字节,手里没有示波器,测不出来,所以先使用默认空闲间隔。
2、主程序中
定义接收数组
static uint8_t rx_buff[200] = {0};
在主循环中调用串口初始化,这里还是用的PE的生成的配置
LPUART_DRV_Init(INST_LPUART0, &lpuart0_State, &lpuart0_InitConfig0);
继续使用SDK使用的获取数据函数,在主循环之前调用一次,将定义的接收数组传递进去,接收长度设为0
LPUART_DRV_ReceiveData(INST_LPUART0, rx_buff, 0);
为了方便测试,在主程序定义一个全局变量,用于在串口空闲中断中设置标志,表示串口空闲生效。
主循环中检测到该标志有效后,打印接收到的数据长度,打印接收到的数据。
重新开启串口接收。
volatile char rx_frame_flag = 0; /* 防止被编译器优化掉 */
int main(void)
{
LPUART_DRV_Init(INST_LPUART0, &lpuart0_State, &lpuart0_InitConfig0);
LPUART_DRV_ReceiveData(INST_LPUART0, rx_buff, 0);
while(1)
{
if (rx_frame_flag)
{
rx_frame_flag = 0;
DEBUG_INFO("\r\nrx len %d", lpuart0_State.rxSize);
LPUART_DRV_SendData(INST_LPUART0, (uint8_t *)rx_buff, lpuart0_State.rxSize);
LPUART_DRV_ReceiveData(INST_LPUART0, rx_buff, 0);
}
}
}
3、修改SDK
主要修改lpuart_driver.c函数中的内容
3.1 修改串口接收中断函数
主要修改:
1、在接收到第一个字节时,打开串口空闲中断。
2、接收长度由递减改为递增。
static void LPUART_DRV_RxIrqHandler(uint32_t instance)
{
lpuart_state_t * lpuartState = (lpuart_state_t *)s_lpuartStatePtr[instance];
LPUART_Type * base = s_lpuartBase[instance];
/* Get data and put in receive buffer */
LPUART_DRV_GetData(instance);
if (lpuartState->rxSize == 0)
{
LPUART_SetIntMode(base, LPUART_INT_IDLE_LINE, true);
}
/* Update the internal state */
if (lpuartState->bitCountPerChar == LPUART_8_BITS_PER_CHAR)
{
++lpuartState->rxBuff;
++lpuartState->rxSize;
}
else
{
lpuartState->rxBuff = &lpuartState->rxBuff[2];
lpuartState->rxSize += 2U;
}
}
3.2 修改串口中断函数
主要修改:
一定要写在错误中断处理函数之前,处理空闲中断,因为在错误处理函数里面会把空闲中断标志位清除,所以写在后面会识别不到空闲中断。
这里为了方便测试,在识别到空闲中断后,将rx_frame_flag变量置1。
识别到空闲中断后,关闭空闲中断和串口接收。
extern char rx_frame_flag;
void LPUART_DRV_IRQHandler(uint32_t instance)
{
DEV_ASSERT(instance < LPUART_INSTANCE_COUNT);
const LPUART_Type * base = s_lpuartBase[instance];
if (LPUART_GetIntMode(base, LPUART_INT_IDLE_LINE))
{
if (LPUART_GetStatusFlag(base, LPUART_IDLE_LINE_DETECT))
{
rx_frame_flag = 1;
LPUART_SetIntMode(base, LPUART_INT_IDLE_LINE, false);
LPUART_DRV_CompleteReceiveDataUsingInt(instance);
}
}
LPUART_DRV_ErrIrqHandler(instance);
/* 后面的程序不需要修改,这里不粘贴过来了 */
}
4、测试效果
结合上面的主循环,使用串口通信助手测试,发送数据,串口助手显示如下所示
[23:31:11.173]发→◇123456□
[23:31:11.195]收←◆
rx len 6
123456
[23:31:11.831]发→◇123456□
[23:31:11.853]收←◆
rx len 6
123456
[23:31:16.970]发→◇qwer1234□
[23:31:16.995]收←◆
rx len 8
qwer1234
[23:31:17.824]发→◇qwer1234□
[23:31:17.849]收←◆
rx len 8
qwer1234
5、后记
本文记录为串口接收中断配合空闲中断使用,基本可以满足大部分使用需求。
如果数据量过大,考虑用DMA接收配置空闲中断。