关于CH432中断的问题

我在用中断的方式处理CH432接收数据时,发现一个奇怪的问题,详细如下:

 

CH432初始化:

 

void InitCH432(void)    /* 初始化CH432 */
{
    UINT16 CH432div;
  
   UINT8 DLM;
  UINT8 CH432DLL;
/**************************************************************************
          设置CH432串口0的寄存器

**************************************************************************/
    
    CH432div = ( Fpclk >> 4 ) / CH432_BPS;
    DLM = CH432div >> 8;
    CH432DLL = CH432div & 0xff;
 
    WriteCH432Data( CH432_IER_PORT,  BIT_IER_RESET);  //端口复位//
    WriteCH432Data( CH432_LCR_PORT, BIT_LCR_DLAB );    /* 设置DLAB为1 */
    WriteCH432Data( CH432_DLL_PORT, CH432DLL );    /* 设置波特率 */
    WriteCH432Data( CH432_DLM_PORT, DLM );
    WriteCH432Data( CH432_FCR_PORT,  BIT_FCR_FIFOEN  );    /* 设置FIFO模式,触发点为1 */
    WriteCH432Data( CH432_LCR_PORT, BIT_LCR_WORDSZ1
                                  | BIT_LCR_WORDSZ0 );    /* 字长8位,1位停止位、无校验 */

/**************************************************************************
          设置CH432串口1的寄存器

**************************************************************************/
    CH432div = ( Fpclk >> 4 ) / CH432_BPS1;
    DLM = CH432div >> 8;
    CH432DLL = CH432div & 0xff;
  
  WriteCH432Data( CH432_IER1_PORT,  BIT_IER_RESET);  //端口复位//
    WriteCH432Data( CH432_LCR1_PORT, BIT_LCR_DLAB );    /* 设置DLAB为1 */
    WriteCH432Data( CH432_DLL1_PORT, CH432DLL );    /* 设置波特率 */
    WriteCH432Data( CH432_DLM1_PORT, DLM );
    WriteCH432Data( CH432_FCR1_PORT,  BIT_FCR_RECVTG1 | BIT_FCR_FIFOEN );    /* 设置FIFO模式,触发点为8 bytes */
    WriteCH432Data( CH432_LCR1_PORT,
                                     BIT_LCR_WORDSZ1
                                  | BIT_LCR_WORDSZ0 );    /* 字长8位,1位停止位、无校验 */
    WriteCH432Data( CH432_IER1_PORT,   BIT_IER_IERECV  );    /* 允许接收到数据中断 */
    WriteCH432Data( CH432_MCR1_PORT, BIT_MCR_OUT2  );    /* 允许中断输出,DTR,RTS为1 */
}

 

 

中断处理子程序:

 

void CH432Interrupt(void)    /* 中断方式处理 */
{
    UINT8 InterruptStatus;
    UINT8 RcvNum = 0;
   UINT8 i;
//   UINT8 Status;
 
    InterruptStatus = ReadCH432Data( CH432_IIR_PORT ) & ( ~ CH432_IIR_FIFOS_ENABLED );
    if( ( InterruptStatus & 0x01 ) )    /* 没有中断转到串口1 */
    {
        InterruptStatus = ReadCH432Data( CH432_IIR1_PORT ) & ( ~ CH432_IIR_FIFOS_ENABLED );    /* 读串口1的中断状态 */
        if( ( InterruptStatus & 0x01 ) ) return;    /* 没有中断退出 */
        else
        {
            Delay_ms(30);//必须加上
            ReadCH432Data( CH432_FCR1_PORT );  //这句不知什么意思,必须加上才接收正常
            ReadCH432Data( CH432_LSR1_PORT );  //这句不知什么意思,必须加上才接收正常
           ReadCH432Data( CH432_MCR1_PORT );  //这句不知什么意思,必须加上才接收正常
    
            switch( InterruptStatus )
            {
         case INT_MODEM_CHANGE:
           ReadCH432Data(CH432_MSR1_PORT);  //不处理
           break;
                case INT_NOINT:    /* 没有中断 */
                    break;
                case INT_THR_EMPTY:    /* 发送保持寄存器空中断 */
                    ReadCH432Data(CH432_IIR1_PORT);  //不处理
                    break;
                case INT_RCV_SUCCESS:    /* 串口接收可用数据中断 */
        case INT_RCV_OVERTIME:    /* 接收数据超时中断 */ 
                    RcvNum = CH432Seril1Rcv( buf );
          for(i=0;i          {
           if(rb_can_write(&u_ring_buff) > 0)
           {
            rb_write(&u_ring_buff, &buf[i], 1);
           }     
          } 
          print_buf((U8 *)u_ring_buff.rb_buff,RcvNum,"RcvData");
                    break;
                case INT_RCV_LINES:    /* 接收线路状态中断 */
                    ReadCH432Data( CH432_LSR1_PORT);  //不处理
                    break;
              
                default:    /* 不可能发生的中断 */
                    break;
            }
        }
    }
    else
    {
   
        switch( InterruptStatus )
        {
            case INT_MODEM_CHANGE:
                ReadCH432Data( CH432_MSR_PORT );  //不处理
                break;
            case INT_NOINT:    /* 没有中断 */
                    break;
            case INT_THR_EMPTY:    /* 发送保持寄存器空中断 */
                    ReadCH432Data(CH432_IIR_PORT);  //不处理
                    break;
            case INT_RCV_SUCCESS:    /* 串口接收可用数据中断 */
             
                    RcvNum = CH432Seril0Rcv( buf );
          for(i=0;i          {
           if(rb_can_write(&u_ring_buff) > 0)
           {
            rb_write(&u_ring_buff, &buf[i], 1);
           }     
          } 
      
                    break;
            case INT_RCV_LINES:    /* 接收线路状态中断 */
                    ReadCH432Data( CH432_LSR_PORT);  //不处理
                    break;
            case INT_RCV_OVERTIME:    /* 接收数据超时中断 */
                    RcvNum = CH432Seril0Rcv( buf );
          for(i=0;i          {
           if(rb_can_write(&u_ring_buff) > 0)
           {
            rb_write(&u_ring_buff, &buf[i], 1);
           }     
          }  
                    break;
            default:    /* 不可能发生的中断 */
                    break;
        }
    }
}

现在问题就是,在中断子程序里必须加上下面这四个语句,接收数据才正常,不加的话就无法接收到任何数据:

            Delay_ms(30);//必须加上
            ReadCH432Data( CH432_FCR1_PORT );  //这句不知什么意思,必须加上才接收正常
            ReadCH432Data( CH432_LSR1_PORT );  //这句不知什么意思,必须加上才接收正常
           ReadCH432Data( CH432_MCR1_PORT );  //这句不知什么意思,必须加上才接收正常

 

不加上这四句,LSR的数值就一直为0xE3,而且INT中断引脚一直被拉低,无法恢复到高电平,不知是什么原因,有哪位大神知道原因的,麻烦帮解答一下,谢谢了

补充一下,串口第一次接收到数据时的寄存器值:


IER1: 01

IIR1: C4

FCR1: C4

MCR1: 08

LSR1: 63

MSR1: 00


从LSR看,是FIFO溢出了,但官方的示例程序是在没溢出的情况下才会读数据,看来是官方示例代码的问题,FIFO的深度只有14 bytes,如果串口数据多,很容易就溢出了,官方的示例代码就无法正确执行,有什么办法解决这个问题呢?


而且Datasheet里描述的是:

串口接收的数据可用中断(IIR寄存器的低4 位为04H)是指接收FIFO中的已有数据字节数已经

达到或超过由FCR 寄存器的RECVTG1 和RECVTG0选择的FIFO 触发点。当从RBR 读取数据使FIFO 中字

节数低于FIFO 触发点时,该中断被清除。串口接收的数据超时中断(IIR 寄存器的低4 位为0CH)是

指接收FIFO 中至少有一个字节的数据,并且从上一次串口接收到数据和从上一次被单片机取走数据

开始,已经等待了相当于接收4 个数据的时间。当再次接收到一个新的数据后,该中断被清除,或者

当单片机读取一次RBR 寄存器后,该中断也能被清除。当接收FIFO 全空时,LSR 寄存器的DATARDY

位为0,当接收FIFO 中有数据时,DATARDY 位为1 有效。


那么,当FIFO满时,才会触发接收数据中断,但如果串口数据比FIFO大很多,肯定就会溢出,官方的代码并没有考虑这种情况。


再补充一下,第一次收到数据后,LSR的值是0xF3,也就是说出现了break线路间隔错误,不是很理解这个线路间隔是什么意思


你好:


本身CH432内部串口的fifo大小就16个字节,如果数据满了你还没有取走,下一字节数据肯定触发fifo溢出。不管设计多大的fifo空间,如果取数据慢,数据量总会在达到某一数量级时出现溢出现象。所以会设置“fifo触发点”这种中断。

如果你设置触发点为14字节,那么当fifo报出次中断后,要及时取走14字节(不用判断),否则还有2字节当前通讯波特率的数据就会满,这段时间你取数据的速度和串口送进来的数据就是一个速度赛跑。

如果你本身操作慢,那么触发级别可以设低,留有足够的余量。


例程本身只是简单操作演示的例子,里面只有出口收发部分并没有涉及到其他功能,可以说整个程序都在等待收发。而且例程中使用的cpu速度(操作432寄存器)远大于当前串口通讯速度。所以不会出现fifo溢



只有登录才能回复,可以选择微信账号登录