[51单片机] (已解决!)求助!串口中断有时接收不到完整的一帧数据

[复制链接]
9071|16
 楼主| nickyamw 发表于 2013-10-14 22:33 | 显示全部楼层 |阅读模式
本帖最后由 nickyamw 于 2013-10-17 20:24 编辑

我用的是华邦的W79E532,时钟频率40MHz,2T模式,用串口中断方式接收一帧数据(每帧11或10个字节),但有时候可以完整接收一帧,有时却只接收到最后一个字节,成功接收一帧的概率大概70%左右,
请问我这程序有什么问题?怎么提高串口接收数据的成功率?



问题已经解决,是程序里SD卡部分还有一个关总中断的行为。


串口初始化函数:
  1. void uart0Init(void)
  2. {

  3.         EA = 0;

  4.         CKCON = 0xc7;                  
  5.         TR2=0;
  6.         
  7.         CKCON = 0xf1;                  
  8.         SCON=0x50;

  9.                         RCAP2H=TH2=0xff;           ////115200 40M                 RCAP2HL=40M/(32*b)
  10.                         RCAP2L=TL2=0xf5;



  11.          
  12.     T2CON=0x34;
  13.         //SCON=0xD0;                  
  14.     T2MOD=0x00;
  15.     TR2=1;
  16.         
  17.         RI = 0;

  18.         ES = 1;
  19.         EA = 1;



串口中断服务函数:
  1. {
  2.         uint8 xdata *p_buf;        

  3.         p_buf = UART_BUF + uart_wrlen;

  4.         if(RI)
  5.         {
  6.                 uart_outoftime = 1;
  7.                 RI = 0;
  8.                 if(uart_wrlen > 39)        return;
  9.                 *p_buf = SBUF;
  10.                 uart_wrlen ++;

  11.         }

  12. }

串口处理函数:
  1. void uart0_CMDPackage(void)
  2. {      
  3.         uint8 i;
  4.         uint8 xdata *p_Dptr;

  5.         uart_outoftime++;        
  6.         if(!uart_outoftime) uart_outoftime = 255;

  7.         if(!uart_wrlen) return;
  8.         if(uart_outoftime <= 240 ) // 整个程序,一次大循环至少应该会有几ms,隔了一段时间没接收到下一个字节的数据,就当作一帧数据接收完        
  9.         {               
  10.                 return;        
  11.         }

  12.         //uart_wrlen = 0;        
  13.         uart_outoftime = 255 ;
  14.         p_Dptr = UART_BUF;        
  15.         while(uart_wrlen)        
  16.         {               
  17.                 if(*p_Dptr != 0xAA)//帧数据以0XAA开头               
  18.                 {                        
  19.                         uart_wrlen--;                        
  20.                         p_Dptr++;               
  21.                 }               
  22.                 else               
  23.                 {                        
  24.                         break;               
  25.                 }               
  26.         }        
  27.         uart_wrlen = 0;
  28.                         
  29. //后面接具体的处理过程

  30.         }











今天下午我也试了另外的方法,就是在串口中断函数里用轮询的方式接收一帧数据,每次固定接收11个字节,中断函数被我改成这样子,但接收一帧的成功率也没怎么改善
  1. uint8 uart0_RcvChar(void)
  2. {
  3.         uint16 i;

  4.         i = 10000;
  5.         do
  6.         {
  7.                 if(RI)        break;
  8.         }
  9.         while(--i);
  10.         RI = 0;        
  11.         return SBUF;
  12. }

  13. void  uart0_ISR(void) interrupt 4                         //Uart0  interrupt
  14. {
  15.         uint8 xdata *p_buf;        

  16.         //p_buf = SDRAMBUF0_ADDR + 2027;
  17.         p_buf = UART_BUF + uart_wrlen;

  18.         if(RI)
  19.         {
  20.                 uart_outoftime = 5;

  21.                 //RI = 0;
  22.                 //if(uart_wrlen > 39)        return;
  23.                 //*p_buf = SBUF;
  24.                 //uart_wrlen ++;

  25.                 *p_buf = uart0_RcvChar();
  26.                 if(*p_buf++ != 0xAA) return; //帧数据以0XAA开头
  27.                 uart_wrlen ++;

  28.                 *p_buf++ = uart0_RcvChar();
  29.                 uart_wrlen ++;

  30.                 *p_buf++ = uart0_RcvChar();
  31.                 uart_wrlen ++;

  32.                 *p_buf++ = uart0_RcvChar();
  33.                 uart_wrlen ++;

  34.                 *p_buf++ = uart0_RcvChar();
  35.                 uart_wrlen ++;

  36.                 *p_buf++ = uart0_RcvChar();
  37.                 uart_wrlen ++;

  38.                 *p_buf++ = uart0_RcvChar();
  39.                 uart_wrlen ++;

  40.                 *p_buf++ = uart0_RcvChar();
  41.                 uart_wrlen ++;

  42.                 *p_buf++ = uart0_RcvChar();
  43.                 uart_wrlen ++;

  44.                 *p_buf++ = uart0_RcvChar();
  45.                 uart_wrlen ++;

  46.                 *p_buf++ = uart0_RcvChar();
  47.                 uart_wrlen ++;
  48.         }

  49. }



NE5532 发表于 2013-10-15 07:38 | 显示全部楼层
“一次大循环至少应该会有几ms”这个测试过没?
么么沫沫 发表于 2013-10-15 09:12 | 显示全部楼层
串口硬件电路的灵敏度够吗?

评论

额,这个好像真的没有灵敏度的提法  发表于 2013-10-15 10:49
zjh6607476 发表于 2013-10-15 10:12 | 显示全部楼层
中断函数写的一般啊!建议你在中断里直接用个状态机来接收校验数据!
么么沫沫 发表于 2013-10-15 15:12 | 显示全部楼层
我用的硬件电路有的支持不了大的波特率,有的可以,我觉得跟硬件的灵敏度有关系,这种说法可能不专业,大侠见笑了
XZL 发表于 2013-10-15 15:45 | 显示全部楼层
1:你的通讯波特率是多少?看程序是115200,有计算过你的中断处理程序最小时间和最大时间了吗?能否在下一个字节来之前处理完当前的数据?中断服务程序尽量精简指令,以防影响下次中断。接收的数据放在BUFFER里,在主程序里进行处理。
2:你是否有更高优先级的中断存在?
ayb_ice 发表于 2013-10-15 15:54 | 显示全部楼层
先降低波特率测试
cjseng 发表于 2013-10-15 16:14 | 显示全部楼层
将串口中断的优先级提到最高再说。
outstanding 发表于 2013-10-15 16:27 | 显示全部楼层
原因太多了,单步调试
 楼主| nickyamw 发表于 2013-10-16 20:16 | 显示全部楼层
zjh6607476 发表于 2013-10-15 10:12
中断函数写的一般啊!建议你在中断里直接用个状态机来接收校验数据!

请问串口状态机怎么写?
 楼主| nickyamw 发表于 2013-10-16 20:21 | 显示全部楼层
XZL 发表于 2013-10-15 15:45
1:你的通讯波特率是多少?看程序是115200,有计算过你的中断处理程序最小时间和最大时间了吗?能否在下一 ...

现在也就只在中断里把接收到的放到一个缓冲区里,整个中断才7个语句,以一个语句3个机器周期,也才21个机器周期,远小于串口发送一个字节的时间啊


程序里的I2C驱动有关闭总中断的行为,但我试过把I2C相应关总中断的语句注释掉,串口还是这样。
我试试把中断放到最高优先级
 楼主| nickyamw 发表于 2013-10-16 20:22 | 显示全部楼层
ayb_ice 发表于 2013-10-15 15:54
先降低波特率测试

没用,还是这样子。
ayb_ice 发表于 2013-10-17 08:07 | 显示全部楼层
波特率误差大不大?
zjh6607476 发表于 2013-10-28 22:16 | 显示全部楼层
nickyamw 发表于 2013-10-16 20:16
请问串口状态机怎么写?

以前做过,很好用!!可以提供例程给你参考!!!
 楼主| nickyamw 发表于 2013-10-30 21:31 | 显示全部楼层
zjh6607476 发表于 2013-10-28 22:16
以前做过,很好用!!可以提供例程给你参考!!!

:D那麻烦你贴上来看看。还没见过串口用的状态机
zjh6607476 发表于 2013-10-31 11:10 | 显示全部楼层
nickyamw 发表于 2013-10-30 21:31
那麻烦你贴上来看看。还没见过串口用的状态机

               Buffer[nPos]=UDR1;
                //Uart0_Send(Buffer[nPos]);
                if(Receive_Flag==0)//nPos<=Length_Max)
                {       
                        switch(Status)
                        {
                                case Ready:
                                        if(Buffer[nPos] == Re_Sync)//(Rev1==Re_Sync)//
                                        {
                                                Status = Re_Sync;
                                                nPos = 1;
                                        }
                                        break;
                       
                                case Re_Sync:
                               switch (Buffer[nPos])
                                                 {
                                                          case IMG:
                                                         {
                                                                 Status = Indata_IMG;
                                                                 nPos++;
                                                         }
                                                         break;
                                                         case SET:
                                                         {
                                                                 Status = Indata_SET;
                                                                 nPos++;
                                                         }
                                                         break;
                                                         case GET:
                                                         {
                                                                 Status = Indata_GET;
                                                                 nPos++;
                                                         }
                                                         break;
                                                         case ESC:
                                                         {
                                                                 Status = Indata_ESC;
                                                                 nPos++;
                                                         }
                                                         break;
                                                         default :
                                                         {
                                                                 Status = Ready;
                                                                  nPos = 0;
                                                         }
                                                         break;
                                                 }
                                        break;
                       
                                case Indata_IMG:  //Image
                                {
                                        if(Length == 0)
                                          Length =Buffer[nPos]; //& 0x3F; Rev1;//
                                        else if(nPos==3)
                                          Rand=Buffer[3]; //Rev1;//
                                        else
                                        {
                                         //在次加验包,把0xFF剔除
                                         
                                                 if(nPos>7)
                                                {
                                                        if(EOP_Flag == 1){
                                                                if(Buffer[nPos] == Rand){
                                                                        Receive_Flag = Succee_IMG;
                                                                        Length_S = Length;//-1;//+5;
                                                                  Status = Ready;
                                                                        Length = 0;
                                                                        EOP_Flag = 0;
                                                                        nPos = 0;
                                                                        break;
                                                                }
                                                                EOP_Flag = 0;
                                                        }
                                                        if(Buffer[nPos] == Re_Sync ){
                                                                //Length=Length+1;
                                                        }else if(Buffer[nPos] == EOP){
                                                                //Length=Length+1;
                                                                EOP_Flag = 1;
                                                        }
                                                }
                                        }
                                        nPos++;
                                }
                                break;
                               
                                case Indata_SET:                               
                                {       
                                        if(Length == 0)
                                          Length =Buffer[nPos]; //& 0x3F; Rev1;//
                                        else if(nPos==3)
                                          Rand=Buffer[3]; //Rev1;//
                                        else
                                        {
                                                if(nPos >= Length+5)//send
                                                {
                                                        if((Buffer[Length+4]==EOP) && (Buffer[Length+5]=Rand))
                                                        {
                                                                Receive_Flag=Succee_SET;
                                                                Length_S=Length;//+5;
                                                                Length = 0;
                                                                 nPos = 0;
                                                          Status = Ready;
                                                                break;
                                                        }
                                                }
                                        }
                                        nPos++;
                                }
                                break;
                                       
                                case Indata_GET:
                                {       
                                        if(Length == 0)
                                          Length =Buffer[nPos]; //& 0x3F; Rev1;//
                                        else if(nPos==3)
                                          Rand=Buffer[3]; //Rev1;//
                                        else
                                        {
                                                if(nPos >= Length+5)//send
                                                {
                                                        if((Buffer[Length+4]==EOP) && (Buffer[Length+5]=Rand))
                                                        {
                                                                Receive_Flag=Succee_GET;
                                                                Length_S=Length;//+5;
                                                                Length = 0;
                                                                 nPos = 0;
                                                          Status = Ready;
                                                                break;
                                                        }
                                                }
                                        }
                                        nPos++;
                                }
                                break;

                                default :
                                {
                                        Status = Ready;
                                        nPos = 0;
                                }
                                break;
                        }          
                }else{
                        Status = Ready;
                        nPos = 0;
                        //return error               
                }


仅供参考,用的AVR的单片机!!

评分

参与人数 1威望 +1 收起 理由
nickyamw + 1 赞一个!

查看全部评分

 楼主| nickyamw 发表于 2014-3-15 08:29 | 显示全部楼层
zjh6607476 发表于 2013-10-31 11:10
Buffer[nPos]=UDR1;
                //Uart0_Send(Buffer[nPos]);
                if(Receive_Flag==0)//nPos7)

我今天看同事的程序,也是有这样的状态机,开眼界了。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

9

主题

252

帖子

0

粉丝
快速回复 在线客服 返回列表 返回顶部