串口中断模式

串口数据的发送接收可以藉由串口发送中断、接收中断实现。串口发送中断、接收中断可以同时开启。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.html

deepseek针对这两种模式给出了使用场景,我就直接搬运了。

  • 追求最高发送吞吐量(使用TXE/THRE):如果需要连续、大量地发送数据,且对CPU效率要求高,通常建议使用仅"发送缓冲区空"中断。因为可以在上一个字节还在"路上"(移位发送)时,CPU就提前把下一个字节填入缓冲区,充分利用硬件流水线,实现最高效的连续发送,中间几乎没有空闲间隔。

  • 需要精确控制RS485收发切换或流控(使用TC) :如果涉及RS485通信,需要在发送完成后立即释放总线(将RE/DE引脚拉低),或者在半双工模式下切换方向,必须使用"BUFFER空且移位寄存器空"中断(即发送完成中断)。只有在TC标志置位时,才能确保总线上所有数据已发送完毕,此时切换收发状态才安全,否则会造成数据丢失或总线冲突。

接收中断选择接收缓冲区满,而不是数据接收完成产生中断。接收缓冲区,即RXREG寄存器有效长度1Byte,接收1Byte触发一次中断,这是最常见的模式。数据接收完成,更像是一帧接收完成触发一次中断。前者更常见,后者估计还要配置数据帧格式(帧头、帧尾、校验和等),暂时没看到明确的解释。接着通过FL_NVIC_Init函数设置中断优先级,底层实际调用NVIC库函数。接着就是配置UARTIE寄存器,使能发送中断、接收中断。

objectivec 复制代码
    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)。

objectivec 复制代码
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(i=0; i<13; i++) { UART5->TXBUF = commSendBufi; while(TXE==0); } | 主程序 : start_index0 = 0; end_index = 13; UART5->TXBUF = commSendBuf0; 开启中断使能; 中断服务程序(自动触发13次) : if(start_index0 < end_index) UART5->TXBUF = commSendBufstart_index0++; else 关闭中断使能; |

|-----------------|---------------------|--------------------------|
| 维度 | 轮询发送 | 中断发送 |
| 发送循环位置 | 主程序(for循环) | 中断服务程序(ISR) |
| 如何检测TXE | while(TXE==0); 主动等待 | 由硬件中断自动触发,无需显式等待 |
| 是否有检测代码 | 有(显式 while) | 有(ISR中的 if 判断索引,及硬件自动触发) |
| CPU占用 | 高(等待期间100%占用) | 低(只在ISR中占用几微秒) |
| 代码结构 | 简单、直观 | 复杂、需要管理状态和中断使能 |

相关推荐
ACP广源盛139246256731 小时前
GSV6155@ACP# Type-C 视频信号转换芯片:技术架构、工程痛点适配与落地场景分析
大数据·c语言·开发语言·人工智能·分布式·嵌入式硬件·架构
光子物联单片机2 小时前
STM32传感器模块编程实践(二十一)DIY语音控制小车套件模型
c语言·stm32·单片机·嵌入式硬件·mcu
csdn杰哥2 小时前
瑞萨单片机开发教程[二十八] DTC 串口传输实验
单片机·嵌入式硬件·瑞萨·ra6m5
义嘉泰2 小时前
【硬核拆解】540×540时代的显示核心:集创北方 CO6300 AMOLED驱动芯片深度解析
嵌入式硬件·芯片
铅笔小新z2 小时前
【stm32】GPIO
stm32·嵌入式硬件·mongodb
csdn杰哥3 小时前
瑞萨单片机开发教程[三十] IIC 触摸驱动实验
单片机·嵌入式硬件·瑞萨·ra6m5
振南的单片机世界3 小时前
高优先级“插队”,低优先级让路:中断嵌套的核心规则
arm开发·stm32·单片机·嵌入式硬件
ahccqw5 小时前
电机入门学习(电机认识,分类)
嵌入式硬件
jianqiang.xue12 小时前
系统服务层设计:沉淀通用能力,让业务层只专注业务
stm32·单片机·嵌入式硬件·mcu·物联网·esp32