【WCH蓝牙系列芯片】-基于CH582开发板-串口中断识别寄存器的中断标志位识别

------------------------------------------------------------------------------------------------------------------------------------

在使用CH582芯片过程中,经常用的是UART串口外设。从芯片手册中可以看到中断识别寄存器(R8_UARTx_IIR)的每一位对应的描述。

 在中断识别寄存器中第0位到第3位是表示是否有串口中断发生,并且触发的中断类型是什么,这从手册中的也可以看出来。

 

    现在可以通过例程的串口中断函数去验证一个问题,在这么多中断类型中,如果同时发生不同的中断类型,产生不同的中断标志时,IIR寄存器的标志位会如何置位,会不会出现丢失标志位情况。比如,当“接收数据可用”和“THR寄存器空”同时发生,会出现什么情况。
    通过程序复现这个问题的思路:
     1、 通过串口发送数据
     2、 串口接收到的字节数发到FIF0的触发点,产生接收数据可用的中断标志位,但是串口不接收数据
     3、 利用GPIO中断,将RB_IER_THR_EMPTY 位从 0 变 1 触发,强制产生THR寄存器空的标志位,
     4、 此时接收串口发送的数据,再看THR寄存器空的标志位是否被触发。

 

    在CH582的EVT例程中进行修改为这个思路,在主函数添加串口1的配置,中断方式的数据接收和发送,GPIO中断引脚的配置参数。

int main()
{
    uint8_t len;
    SetSysClock(CLK_SOURCE_PLL_60MHz);

    /* 配置串口1:先配置IO口模式,再配置串口 */
    GPIOA_SetBits(GPIO_Pin_9);
    GPIOA_ModeCfg(GPIO_Pin_8, GPIO_ModeIN_PU);      // RXD-配置上拉输入
    GPIOA_ModeCfg(GPIO_Pin_9, GPIO_ModeOut_PP_5mA); // TXD-配置推挽输出,注意先让IO口输出高电平
    UART1_DefInit();

    //打印串口初始化
    GPIOB_SetBits(GPIO_Pin_7);
    GPIOB_ModeCfg(GPIO_Pin_4, GPIO_ModeIN_PU);      // RXD-配置上拉输入
    GPIOB_ModeCfg(GPIO_Pin_7, GPIO_ModeOut_PP_5mA); // TXD-配置推挽输出,注意先让IO口输出高电平
    UART0_DefInit();
printf("hello\r\n");

#if 1 // 测试串口发送字符串
    UART1_SendString(TxBuff, sizeof(TxBuff));
#endif

#if 0 // 查询方式:接收数据后发送出去
    while(1)
    {
        len = UART1_RecvString(RxBuff);
        if(len)
        {
            UART1_SendString(RxBuff, len);
        }
    }
#endif

#if 1 // 中断方式:接收数据后发送出去
    UART1_ByteTrigCfg(UART_7BYTE_TRIG);
    trigB = 7;
    UART1_INTCfg(ENABLE, RB_IER_RECV_RDY | RB_IER_LINE_STAT);
    PFIC_EnableIRQ(UART1_IRQn);
#endif

#if 1
    /* 配置唤醒源为 GPIO - PA5 */
    GPIOA_ModeCfg(GPIO_Pin_5, GPIO_ModeIN_PU);
    GPIOA_ITModeCfg(GPIO_Pin_5, GPIO_ITMode_LowLevel); //低电平触发
    PFIC_EnableIRQ(GPIO_A_IRQn);

    GPIOA_ModeCfg(GPIO_Pin_4, GPIO_ModeOut_PP_5mA);  //点灯使用的IO口
    GPIOA_ResetBits(GPIO_Pin_4);
#endif

    while(1);
}

/*********************************************************************
 * @fn      UART1_IRQHandler
 *
 * @brief   UART1中断函数
 *
 * @return  none
 */
__attribute__((interrupt("WCH-Interrupt-fast")))
__attribute__((section(".highcode")))
void UART1_IRQHandler(void)
{
    volatile uint8_t i;

    switch(UART1_GetITFlag())
    {
        case UART_II_LINE_STAT: // 线路状态错误
        {
            UART1_GetLinSTA();
            break;
        }
        case UART_II_RECV_RDY: // 数据达到设置触发点
            if (R8_UART1_IER & RB_IER_THR_EMPTY)  //判断THR寄存器空这个中断是否被设置
            {
                printf("UART_II_RECV_RDY\r\n");
                for(i = 0; i != trigB; i++)
                {
                    RxBuff[i] = UART1_RecvByte();
                    UART1_SendByte(RxBuff[i]);
                }
            }
            else
            {
                return;
            }
            break;

        case UART_II_RECV_TOUT: // 接收超时,暂时一帧数据接收完成
            printf("UART_II_RECV_TOUT\r\n");
//            i = UART1_RecvString(RxBuff);
//            UART1_SendString(RxBuff, i);
            if (R8_UART1_IER & RB_IER_THR_EMPTY)
            {
                i = UART1_RecvString(RxBuff);
                UART1_SendString(RxBuff, i);
            }
            else
            {
                return;
            }
            break;

        case UART_II_THR_EMPTY: // 发送缓存区空,可继续发送
             printf("UART_II_THR_EMPTY\r\n");
            GPIOA_SetBits(GPIO_Pin_4);
            break;

        case UART_II_MODEM_CHG: // 只支持串口0
            break;

        default:
            break;
    }
}

    在GPIO的中断服务函数中,先清标志位,利用UART1_INTCfg(ENABLE, RB_IER_THR_EMPTY);使能发送中断,会置发送缓存空标志,触发中断。

__attribute__((interrupt("WCH-Interrupt-fast")))
__attribute__((section(".highcode")))
void GPIOA_IRQHandler(void)
{
    GPIOA_ClearITFlagBit(GPIO_Pin_5);
//    printf("GPIO_IN*******************\r\n");
    UART1_INTCfg(ENABLE, RB_IER_THR_EMPTY);   //使能发送中断,会置发送缓存空标志,触发中断
}

    在串口服务函数中,串口接收数据可用中断 UART_II_RECV_RDY中,加入判断,如果串口发送的“THR 寄存器空”中断 UART_II_THR_EMPTY被触发中断,才开始接收数据,否则就一直不接收数据。

    在串口接收数据超时中断 UART_II_RECV_TOUT中,也添加相同的程序,这样可以当串口发送超过触发点时,也可以判断串口接收数据超时中断是否被触发。

   在串口发送的“THR 寄存器空”中断 UART_II_THR_EMPTY中,添加一些提示信息,以便触发这个中断标志时,能够做以区别。

    通过串口调试助手,发送数据来观察,先发送七个字节的数据,然后通过按键触发GPIO中断,可以看到串口1作为数据收发口,也接收到全部数据。串口0的打印来看,先触发UART_II_RECV_RDY中断,再触发UART_II_THR_EMPTY中断。这表明当“接收数据可用”和“THR寄存器空”同时发生后,不仅中断标志位没有丢失,还根据中断优先级来先后处理不同的中断标志。

   再次发送八个数据,然后通过按键触发GPIO中断,可以看出串口1能将全部的数据都接收到,串口0那边依次打印UART_II_RECV_RDY中断,再打印UART_II_RECV_TOUT中断,最后是UART_II_THR_EMPTY中断。
   这也表明,同时产生多个中断标志位时,是不会丢失的,并且会根据中断优先级的顺序来触发中断的.

 

posted on 2024-06-06 15:27  凡仕  阅读(148)  评论(0编辑  收藏  举报