公司动态
中断模式串口
串口数据的发送接收可以藉由串口发送中断、接收中断实现。串口发送中断、接收中断可以同时开启。UART发送中断可以分为两种UART发送缓冲区为空中断数据从UART引脚发送出去中断。串口中断模式参见FM33L023D串口中断例程该例程在初始化阶段开启UART0发送、接收中断串口0收到数据后会进入串口中断服务处理程序。串口发送中断、接收中断共用一个中断服务处理程序发送中断触发需要修改中断服务例程。串口中断操作相对于轮询方式操作更复杂。开发者需要先配置串口功能再开启总中断开启UART发送中断、接收中断。中断使能串口中断例程先设置中断触发模式串口发送中断选择BUFFER空且移位寄存器空相对于串口发送缓冲区为空这种模式触发时机晚以前用STM32系列芯片好像没有注意到这个细节。针对这个问题官方论坛有给出明确解释。请问FM33LC0xx系列LPUART发送中断TXBE和TXSE的区别是什么 - FM33LC0xx系列 - 低功耗嵌入式软件开发者论坛 - Powered by Discuz! Archiverhttps://www.fmdevelopers.com.cn/archiver/?tid-1146.htmldeepseek针对这两种模式给出了使用场景我就直接搬运了。追求最高发送吞吐量使用TXE/THRE如果需要连续、大量地发送数据且对CPU效率要求高通常建议使用仅“发送缓冲区空”中断。因为可以在上一个字节还在“路上”移位发送时CPU就提前把下一个字节填入缓冲区充分利用硬件流水线实现最高效的连续发送中间几乎没有空闲间隔。需要精确控制RS485收发切换或流控使用TC如果涉及RS485通信需要在发送完成后立即释放总线将RE/DE引脚拉低或者在半双工模式下切换方向必须使用“BUFFER空且移位寄存器空”中断即发送完成中断。只有在TC标志置位时才能确保总线上所有数据已发送完毕此时切换收发状态才安全否则会造成数据丢失或总线冲突。接收中断选择接收缓冲区满而不是数据接收完成产生中断。接收缓冲区即RXREG寄存器有效长度1Byte接收1Byte触发一次中断这是最常见的模式。数据接收完成更像是一帧接收完成触发一次中断。前者更常见后者估计还要配置数据帧格式帧头、帧尾、校验和等暂时没看到明确的解释。接着通过FL_NVIC_Init函数设置中断优先级底层实际调用NVIC库函数。接着就是配置UARTIE寄存器使能发送中断、接收中断。FL_UART_SetTxInterruptSelect(UART0, FL_UART_INTSEL_TXBE_TXSE); //发生中断选择BUFFER空且移位寄存器空 FL_UART_SetRxInterruptSelect(UART0, FL_UART_INTSEL_RX_FULL); //接收Buffer满中断 InterruptConfigStruct.preemptPriority 0x02; FL_NVIC_Init(InterruptConfigStruct, UART0_IRQn); FL_UART_ClearFlag_TXIF(UART0); FL_UART_ClearFlag_RXIF(UART0); FL_UART_EnableIT_TXIE(UART0); FL_UART_EnableIT_RXIE(UART0); /** * brief Configure NVIC for specified Interrupt. * param configStruct NVIC configuration. * param irq Interrupt number. * retval None */ void FL_NVIC_Init(FL_NVIC_ConfigTypeDef *configStruct, IRQn_Type irq) { /* Check parameter */ if(configStruct-preemptPriority 3) { configStruct-preemptPriority 3; } NVIC_DisableIRQ(irq); NVIC_ClearPendingIRQ(irq); NVIC_SetPriority(irq, configStruct-preemptPriority); NVIC_EnableIRQ(irq); }中断接收中断接收功能相信使用过串口接收中断的开发人员都有一定的了解。UART0接收到1Byte数据后进入中断接收逻辑。由于串口一直不断的接收到数据程序将不断触发串口接收逻辑。开发者可以将接收到的数据存入数组。然后在主循环中对接收数据进行解析如果符合数据帧格式就执行相应的操作。为了防止数据溢出可以使用环形数组。也就是记录接收数据的开始位置、结束位置数据索引循环处理例如index%arrRecvLen。int indexTx 0; //发送索引 int indexRx 0; void UART0_IRQHandler(void) { if(FL_SET FL_UART_IsEnabledIT_TXIE(UART0) FL_SET FL_UART_IsActiveFlag_TXIF(UART0)) { FL_UART_ClearFlag_TXIF(UART0); /*中断发送测试代码 for(indexTx 0;indexTx 9;indexTx) { UART0-TXREG arrSend[i]; } */ } if(FL_SET FL_UART_IsEnabledIT_RXIE(UART0) FL_SET (FL_UART_IsActiveFlag_RXIF(UART0))) { arrRecv[indexRx] (uint8_t)FL_UART_ReadRXBuff(UART0); if(indexRx 10) { } } }中断发送中断发送功能我了解的不多只能给出自己的见解。我为了验证这个功能就在中断使能函数的末尾添加了“UART4-TXREG S”,这样系统初始化执行到末尾便会主动发送S字符接着进入串口发送中断不断向串口发送缓冲区填充数据直至数组内容发送完毕。至此中断发送功能得到验证。但是真正使用的时候还要检查发送缓冲区是否为空不能直接发送。最后再给出中断发送与轮询发送的对比表格。轮询发送for循环中断发送中断驱动for(i0; i13; i) {UART5-TXBUF commSendBuf[i];while(TXE0);}主程序start_index0 0;end_index 13;UART5-TXBUF commSendBuf[0];开启中断使能;中断服务程序自动触发13次if(start_index0 end_index)UART5-TXBUF commSendBuf[start_index0];else关闭中断使能;维度轮询发送中断发送发送循环位置主程序for循环中断服务程序ISR如何检测TXEwhile(TXE0);主动等待由硬件中断自动触发无需显式等待是否有检测代码有显式while有ISR中的if判断索引及硬件自动触发CPU占用高等待期间100%占用低只在ISR中占用几微秒代码结构简单、直观复杂、需要管理状态和中断使能