使用空闲中断可以有效简化串口指令的解析流程,优化代码结构,奈何部分mcu串口不具备空闲中断,使用定时器可以软件实现空闲中断。
主要逻辑就是用定时器判断串口停止接收数据的时间,到达一定程度时就触发串口空闲中断。
首先需要如下几个变量。
u16 uart_idle_flag = 0;//空闲中断标志位
u16 uart_readbuf_count = 0;//空闲计数
u8 uart_buf[8];//缓存寄存器
u8 UART_REG[4];//帧寄存器
然后计算串口传输一个byte所需的时间,确定定时器的定时,通常定时5-10个byte的时间。在定时器中断里,判断uart_idle_flag,为1表示串口已经在空闲状态,将串口数据位计数清零;为0表示串口还在工作状态,拉高空闲标志位。
/*
* 定时器10ms
*/
void timer_intr_hander(void *InstancePtr, u8 TmrCtrNumber) //回调函数
{
//print("clock cnt : 13456\n");
//检测定时器是否满一个计数周期
if (XTmrCtr_IsExpired(&Timer, 0)) {
if (uart_idle_flag == 1) { //持续空闲
uart_readbuf_count = 0;
return;
}
uart_idle_flag = 1;
}
}
最后串口中断里将数据依次写入接收buf,并不断拉低uart_idle_flag。千万不要在中断了做耗时操作。
/*
* 串口中断
*/
void uart_handler(void *CallbackRef) //中断处理函数
{
u8 Read_data;
u32 isr_status;
XUartLite *InstancePtr = (XUartLite *) CallbackRef;
//读取状态寄存器
isr_status = XUartLite_ReadReg(InstancePtr->RegBaseAddress,
XUL_STATUS_REG_OFFSET);
if (isr_status & RX_NOEMPTY) { //接收 FIFO 中有数据
//读取数据
Read_data = XUartLite_ReadReg(InstancePtr->RegBaseAddress,
XUL_RX_FIFO_OFFSET);
uart_buf[uart_readbuf_count] = Read_data;
uart_idle_flag = 0;
if (uart_readbuf_count == 3) {
uart_readbuf_count = 0;
//memcpy(UART_REG, uart_buf, 4);
UART_REG[3] = uart_buf[3];
UART_REG[2] = uart_buf[2];
UART_REG[1] = uart_buf[1];
UART_REG[0] = uart_buf[0];
reg_flag = 1;
} else
uart_readbuf_count++;
}
}
主函数中,轮询串口有效标志位,进行处理(处理过程不应过长),并将标志位复位。
int main(void) {
while (1) {
if (reg_flag == 1) {
/*处理操作
*/
reg_flag = 0;
}
}
}