打印

串口通信数据发快了出错?

[复制链接]
楼主: jin1song
手机看帖
扫描二维码
随时随地手机跟帖
21
luck851| | 2012-7-6 18:10 | 只看该作者 回帖奖励 |倒序浏览
波特率一般设为115200

使用特权

评论回复
22
xoyo| | 2012-7-6 20:05 | 只看该作者
你的程序编写的是书本上给学生讲解用的程序,不是实际应用的程序,如果单片机连个串口都处理不了,那要他还能做什么?

使用特权

评论回复
23
jin1song|  楼主 | 2012-7-6 20:08 | 只看该作者
22# xoyo

请教 实际应该怎么样编写?

使用特权

评论回复
24
xoyo| | 2012-7-6 20:17 | 只看该作者
接收用中断和函数指针处理,发送用查询方式.平常时候485处于接收状态,发送之前把485设置为发送状态,发送完成以后设置为接收状态!
另外尽量用函数处理,在主函数中只是判断标志和调用函数!

使用特权

评论回复
25
ningling_21| | 2012-7-6 20:45 | 只看该作者
延时也太久了...

使用特权

评论回复
26
ningling_21| | 2012-7-6 20:45 | 只看该作者
22# xoyo  

请教 实际应该怎么样编写?
jin1song 发表于 2012-7-6 20:08

用中断接收和发送...

使用特权

评论回复
27
jin1song|  楼主 | 2012-7-6 20:51 | 只看该作者
26# ningling_21
在主程序里查询接收和发送有什么坏处?

使用特权

评论回复
28
7120223| | 2012-7-7 09:42 | 只看该作者
发送在主程序 还好,最多有可能延时了一段时间,但接受放在主函数中,如果你的主函数还有其他函数要处理并且时间大于了串口发送来数据的时间了,有可能会出现漏数据了,第一个数据未存储,第二个数据已经发来了

使用特权

评论回复
29
wukunshan| | 2012-7-7 11:44 | 只看该作者
原因就是PC 端的串口读取接收缓冲区的数据需要时间,特别是使用微软自带的串口通信控件,如果串口中断函数里处理的数据量较大时,每接受一个字节的的间隔时间也相应延长,才能正确通信。
看楼主所说的现象,楼主的PC端的串口程序里应该是设置是收到一个字节就产生中断,读取接受缓冲区的数据,然后再进行数据处理,如果收到某个字节后就向单片机发回信息。这样的过程,如果向PC串口发送的字节间隔越短,通信越容易出错,原因是第一个字节收到后PC进入串口中断处理,还没有处理完,下一个字节就来到了,PC串口还没有时间去读取缓冲区,造成这个字节丢失,就会出现楼主所说的现象。
解决这个问题,只有延长字节发送间隔时间,但通信速度会很慢。所以,建议你采用接收到一定的字节数后再进入中断处理。如PC串口设置为收到512字节后再产生中断,那在你连续发送512个字节时,字节间不需要延时,发完512字节后再延时100ms(让PC串口中断后读取和处理数据),然后再进行下一步通信。这样操作既能保证通信速度又能保证通信正确。

使用特权

评论回复
30
jin1song|  楼主 | 2012-7-7 17:04 | 只看该作者
本帖最后由 jin1song 于 2012-7-7 17:06 编辑

综合大家的意见把程序改了一下,接收用中断,发送在主程序。
自动发送间隔30ms,发一会就收不到数据了,中间如果插入手动发送也会收不到数据。收数失败应该如何处理,这个问题请教?

void interrupt_uart0() interrupt 4
{        
        for(a=0;a<6;a++)
        {
                while(RI0==0);
                RI0=0;
                DE=0;
                recdata[a]=SBUF0;
                flag=1;
        }
}
void main()
{        
        uint i;        
        
        PCA0MD &=~0x40;//*PCA0MD:PCA方式寄存器。关看门狗*//         
        Init_Device();
                        
        while(1)
        {         DE=0;
                if(flag==1)
                {
                        flag=0;
                        
                        if(recdata[4] ==(((recdata[0]^recdata[1])^recdata[2])^recdata[3]))
                                {ES0=0;
                                EA=0;
                                senddata_driver();
                                for(i=0;i<10000;i++);
                                transmit_RS485();
                                ES0=1;
                                EA=1;}
                        else
                        {
                        
                                for(i=0;i<6;i++)
                                {
                                        recdata=0;
                                }
                        }               
                }
               
               
                        
                DE=0;
               
               
          }                 

}

使用特权

评论回复
31
ningling_21| | 2012-7-7 17:11 | 只看该作者
30# jin1song

中断需改下:
  • void interrupt_uart0() interrupt 4
  • {
  •                        while(RI0==0);
  •                 RI0=0;
  •                 DE=0;
  •                 recdata[a]=SBUF0;
  •                 a++;
  •                 flag=1;
           }

使用特权

评论回复
32
jin1song|  楼主 | 2012-7-7 17:24 | 只看该作者
31# ningling_21

试了一下,改成这样,返回的数据全乱了。

使用特权

评论回复
33
jin1song|  楼主 | 2012-7-8 14:32 | 只看该作者
收数失败应该如何处理,这个问题一直很纠结?

使用特权

评论回复
34
ningling_21| | 2012-7-8 14:39 | 只看该作者
收数失败应该如何处理,这个问题一直很纠结?
jin1song 发表于 2012-7-8 14:32

很简单,接收以后判断数据错误,直接抛弃,继续接收下一批数据...

使用特权

评论回复
35
jin1song|  楼主 | 2012-7-8 14:54 | 只看该作者
34# ningling_21
具体反映到我的程序上,应该怎么样改呢,谢谢。

使用特权

评论回复
36
jin1song|  楼主 | 2012-7-9 09:51 | 只看该作者
哪位大虾讲一下。

使用特权

评论回复
37
bjc125| | 2012-7-9 10:54 | 只看该作者
本帖最后由 bjc125 于 2012-7-9 11:01 编辑

..应该尽量养成思考的习惯,即使是COPY过来的也要弄清楚为什么这样。
对于31# ningling_21 的程序,跟你的程序对照对照后不难发现a的清零问题和Flag条件问题。
34# 的建议,你应该知道你的数据有效性判定在主循环里面,应想如何将这段判断程序移植到中断里面,希望下次你能根据别人的建议自己修改程序

void interrupt_uart0() interrupt 4
{        
while(RI0==0);
{
  RI0=0;
  DE=0;
  recdata[a]=SBUF0;
        if(a>4)
        {
            a=0 ;
            if(recdata[4] ==(((recdata[0]^recdata[1])^recdata[2])^recdata[3]))
           {
                flag=1;
           }
       }
  else
  {
        a++;
   }
}
}
void main()
{        
        uint i;        
        
        PCA0MD &=~0x40;//*PCA0MD:PCA方式寄存器。关看门狗*//         
        Init_Device();
                        
        while(1)
        {         DE=0;
                if(flag==1)
                {
     flag=0;
     ES0=0;
     EA=0;
     senddata_driver();
     for(i=0;i<10000;i++);
     transmit_RS485();
     ES0=1;
     EA=1;
    }
    else
    {
     for(i=0;i<6;i++)
     {
      recdata=0;
     }              
                }   
                DE=0;
          }                 
}
即使是上面这段程序,也存在致命问题,如a0 a1 a2 a3 a4 a5  和b0 b1 b2 b3 b4 b5 都是有效数组
a0 a1 a2 a3 a4 a5 b0 b1 b2 b3 b4 b5 发送本没问题,如在a 和b间存在一个干扰数C0 即a0 a1 a2 a3 a4 a5 C0 b0 b1 b2 b3 b4 b5 发送给单片机,此后单片机很难形成有效的数组,总之存在很大的抗干扰问题。楼主可以试着修改程序去掉这种干扰。

使用特权

评论回复
38
jin1song|  楼主 | 2012-7-9 13:38 | 只看该作者
第一个第二个第六个字节是固定数,我能不能判断这三个数来排除干扰?

使用特权

评论回复
39
xoyo| | 2012-7-9 15:58 | 只看该作者
搞一个起始识别字,最后再加一个效验码,把你要发送的数据放在这两个中间。识别字,效验码不对的直接舍弃!

使用特权

评论回复
40
jin1song|  楼主 | 2012-7-9 16:15 | 只看该作者
已经按照38楼的改了,间隔30ms自动发送没有问题,也没用误码,但是在自动发送中间手动发送一次,就没有返回数据了,怎么回事?

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则