打印
[51单片机]

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

[复制链接]
8286|16
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
nickyamw|  楼主 | 2013-10-14 22:33 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
本帖最后由 nickyamw 于 2013-10-17 20:24 编辑

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



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


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

        EA = 0;

        CKCON = 0xc7;                  
        TR2=0;
        
        CKCON = 0xf1;                  
        SCON=0x50;

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



         
    T2CON=0x34;
        //SCON=0xD0;                  
    T2MOD=0x00;
    TR2=1;
        
        RI = 0;

        ES = 1;
        EA = 1;



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

        p_buf = UART_BUF + uart_wrlen;

        if(RI)
        {
                uart_outoftime = 1;
                RI = 0;
                if(uart_wrlen > 39)        return;
                *p_buf = SBUF;
                uart_wrlen ++;

        }

}

串口处理函数:
void uart0_CMDPackage(void)
{      
        uint8 i;
        uint8 xdata *p_Dptr;

        uart_outoftime++;        
        if(!uart_outoftime) uart_outoftime = 255;

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

        //uart_wrlen = 0;        
        uart_outoftime = 255 ;
        p_Dptr = UART_BUF;        
        while(uart_wrlen)        
        {               
                if(*p_Dptr != 0xAA)//帧数据以0XAA开头               
                {                        
                        uart_wrlen--;                        
                        p_Dptr++;               
                }               
                else               
                {                        
                        break;               
                }               
        }        
        uart_wrlen = 0;
                        
//后面接具体的处理过程

        }











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

        i = 10000;
        do
        {
                if(RI)        break;
        }
        while(--i);
        RI = 0;        
        return SBUF;
}

void  uart0_ISR(void) interrupt 4                         //Uart0  interrupt
{
        uint8 xdata *p_buf;        

        //p_buf = SDRAMBUF0_ADDR + 2027;
        p_buf = UART_BUF + uart_wrlen;

        if(RI)
        {
                uart_outoftime = 5;

                //RI = 0;
                //if(uart_wrlen > 39)        return;
                //*p_buf = SBUF;
                //uart_wrlen ++;

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

                *p_buf++ = uart0_RcvChar();
                uart_wrlen ++;

                *p_buf++ = uart0_RcvChar();
                uart_wrlen ++;

                *p_buf++ = uart0_RcvChar();
                uart_wrlen ++;

                *p_buf++ = uart0_RcvChar();
                uart_wrlen ++;

                *p_buf++ = uart0_RcvChar();
                uart_wrlen ++;

                *p_buf++ = uart0_RcvChar();
                uart_wrlen ++;

                *p_buf++ = uart0_RcvChar();
                uart_wrlen ++;

                *p_buf++ = uart0_RcvChar();
                uart_wrlen ++;

                *p_buf++ = uart0_RcvChar();
                uart_wrlen ++;

                *p_buf++ = uart0_RcvChar();
                uart_wrlen ++;
        }

}



相关帖子

沙发
NE5532| | 2013-10-15 07:38 | 只看该作者
“一次大循环至少应该会有几ms”这个测试过没?

使用特权

评论回复
板凳
么么沫沫| | 2013-10-15 09:12 | 只看该作者
串口硬件电路的灵敏度够吗?

使用特权

评论回复
评论
NE5532 2013-10-15 10:49 回复TA
额,这个好像真的没有灵敏度的提法 
地板
zjh6607476| | 2013-10-15 10:12 | 只看该作者
中断函数写的一般啊!建议你在中断里直接用个状态机来接收校验数据!

使用特权

评论回复
5
么么沫沫| | 2013-10-15 15:12 | 只看该作者
我用的硬件电路有的支持不了大的波特率,有的可以,我觉得跟硬件的灵敏度有关系,这种说法可能不专业,大侠见笑了

使用特权

评论回复
6
XZL| | 2013-10-15 15:45 | 只看该作者
1:你的通讯波特率是多少?看程序是115200,有计算过你的中断处理程序最小时间和最大时间了吗?能否在下一个字节来之前处理完当前的数据?中断服务程序尽量精简指令,以防影响下次中断。接收的数据放在BUFFER里,在主程序里进行处理。
2:你是否有更高优先级的中断存在?

使用特权

评论回复
7
ayb_ice| | 2013-10-15 15:54 | 只看该作者
先降低波特率测试

使用特权

评论回复
8
cjseng| | 2013-10-15 16:14 | 只看该作者
将串口中断的优先级提到最高再说。

使用特权

评论回复
9
outstanding| | 2013-10-15 16:27 | 只看该作者
原因太多了,单步调试

使用特权

评论回复
10
nickyamw|  楼主 | 2013-10-16 20:16 | 只看该作者
zjh6607476 发表于 2013-10-15 10:12
中断函数写的一般啊!建议你在中断里直接用个状态机来接收校验数据!

请问串口状态机怎么写?

使用特权

评论回复
11
nickyamw|  楼主 | 2013-10-16 20:21 | 只看该作者
XZL 发表于 2013-10-15 15:45
1:你的通讯波特率是多少?看程序是115200,有计算过你的中断处理程序最小时间和最大时间了吗?能否在下一 ...

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


程序里的I2C驱动有关闭总中断的行为,但我试过把I2C相应关总中断的语句注释掉,串口还是这样。
我试试把中断放到最高优先级

使用特权

评论回复
12
nickyamw|  楼主 | 2013-10-16 20:22 | 只看该作者
ayb_ice 发表于 2013-10-15 15:54
先降低波特率测试

没用,还是这样子。

使用特权

评论回复
13
ayb_ice| | 2013-10-17 08:07 | 只看该作者
波特率误差大不大?

使用特权

评论回复
14
zjh6607476| | 2013-10-28 22:16 | 只看该作者
nickyamw 发表于 2013-10-16 20:16
请问串口状态机怎么写?

以前做过,很好用!!可以提供例程给你参考!!!

使用特权

评论回复
15
nickyamw|  楼主 | 2013-10-30 21:31 | 只看该作者
zjh6607476 发表于 2013-10-28 22:16
以前做过,很好用!!可以提供例程给你参考!!!

:D那麻烦你贴上来看看。还没见过串口用的状态机

使用特权

评论回复
16
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 赞一个!
17
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

粉丝