打印

并口主从多机通讯误码挺高,不知道怎么改善

[复制链接]
2366|6
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
电子小生|  楼主 | 2008-10-27 12:10 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
因为要控制多个步进电机(10个以上),开始的时候考虑到电机数量还不是很确定且电机互相间运动较复

杂,所以采取了以下结构,看图:

主机和子机用14线扁平排线连接,还通过其中的两根线给子机供电,连接长度大概在20CM到50CM间。主

从机间通讯口IO都有10K上拉电阻。每个子机再通过光耦控制2片电机控制IC来驱动2个步进电机。
发送大致过程是:首先主机让R/_W=0,D/_A=0,意思是写地址。此时D0~D7广播电机ID,各子机扫描到“写

地址”且地址符合,则等待“写指令”准备接受指令,不符合则跳出。稍后主机让R/_W=0,D/_A=1,意思

是写指令。依次发送指令字节(包括速度,步数,方向等指令参数),各字节间用CLOCK通知子机更新。
在电路装机调试后,发现广播电机ID的时候经常出现子机错误接受的情况,例如本来是2号电机动作的,

结果5号电机也同时以同样的指令参数动作,又或者是通知3号电机动作的,但是却没有任何一个电机动

作。这些错误的情况大概每发送20~30次发生一次。在一开始的构想中,是有指令校验反馈的。主机指令

字节的最后一个字节是其他指令字节(包括地址字节)的1的个数。子机接收后再计算指令字节的1的个数

与指令的最后一个字节对比,符合则D0~D7=子机ID,不符合则D0~D7=0xfe,然后让R/_W=1,D/_A=1,意思

是“子机反馈”,主机判断反馈,是“子机ID”则返回,是“0xfe”则再次重发。在现在的调试中,这

样的指令校验反馈还没有加上。
加上了指令校验反馈相信可以大大改善子机接受错误的情况。但是,现在这样频繁的出现错误,相信我

的电路也是很不好的,为了产品的稳定可靠,咱应该软硬兼施,对吧,所以,想问问该怎么改善电路

相关帖子

沙发
电子小生|  楼主 | 2008-10-27 17:10 | 只看该作者

没人理我?

是什么原因引起的呢?  空间的电磁辐射?  应该把这扁平排线用金属壳包起来?

使用特权

评论回复
板凳
电子小生|  楼主 | 2008-10-29 20:18 | 只看该作者

汗 怎么都没人帮帮我

就算感觉我的问题太小白  也骂我两下当帮顶呀

贴上我加了校验后的程序:
#define Motobus P6 //步进电机指令线数据/地址口

sbit MotoR_W=P0^2;     //步进电机读/写线,=1为主机读,=0为主机写
sbit MotoD_A=P0^3;     //步进电机数据/地址线,=1为数据,=0为地址
sbit MotoClock=P0^4;   //步进电机指令口指令跳变信号

void PORT_Init(void)
{
 XBR2=0x40;
 P1MDOUT=0x00;    
 P0MDOUT=0x00;
 P2MDOUT=0x01;
 P3MDOUT=0xf0;
 P74OUT=0x00; 
}

void Mwait(unsigned int t)
 {
     unsigned int i=0;
     unsigned char n;
     for(i=0;i<t;i++)
     {
      for(n=0;n<50;n++)
      {
       if((MotoR_W==1)&&(MotoD_A==1)) {n=50;i=t;} //子机反馈则跳出等待
       }
     }
 }

Moto(步数、方向、子机ID等参数)
{
   bit iEA;
  iEA=EA;
   EA=0;    //为了防止中断的干扰,禁中断
 .......
 ......
 ......//根据参数赋值给数组计算Cdata[0]~Cdata[5]

       //计算Cdata[0]~Cdata[5]中1的总数,赋值给Cdata[6]
   CUN=0;
   for(i=0;i<=5;i++)
     {
      ACC=Cdata;
      tmp=1;
      for(ii=1;ii<=8;ii++)
      {
       ACC=Cdata;
       CCY=ACC&tmp;if(CCY==1) CUN++;
       tmp*=2;
       }
     }
    Cdata[6]=CUN; //校验字    
    Cdata[7]=0xee;//结束字

          //正式开始发送
    for(CUN=1;CUN<=10;CUN++)  //发送次数计数,最多发送10次,10次仍发送失败返回失败码
    {
                  
        Motobus=Cdata[0];
        _nop_();_nop_();

         //写地址
        MotoR_W=0;
        MotoD_A=0;
        MotoClock=0;
        SmotoDelay(100);


        MotoClock=!MotoClock;
        SmotoDelay(100);
         Motobus=Cdata[1];

        SmotoDelay(100);
             //写数据
       MotoR_W=0;
       MotoD_A=1; 
       for(i=1;i<=7;i++) //持续发送Cdata[1]~Cdata[7]
         {  
          Motobus=Cdata;
           _nop_();_nop_();
          MotoClock=0;
          SmotoDelay(30);
          MotoClock=1;
          SmotoDelay(30);
         }
    Mwait(200);    //等待子机回应,一段时间(Mwait(200))内子机没有回应则不再等待
        tmp=Motobus;    //读子机返回的信息,看是否发送成功
       if(tmp==MotoID) //如果子机返回码正确,跳出发送过程,否则再发送,直到10次
         {RE=1;CUN=11;}
     }//end of for(CUN=1;CUN<=10;CUN++)
       EA=iEA;
       return RE;
}



子机:



void ISR_T0(void)interrupt 1 using 1
{
  ...
  ...//递增步数,发送步进脉冲
}

void ISR_T1(void)interrupt 3 using 2
{
  ...
  ...//递增步数,发送步进脉冲 
}

void main(void)                                                        
{
 ..
 ..//初始化等

   while(1)                                            
    {
         if(ReCON()) {
                      ...
                      ...//如果函数ReCON()返回真,则表明主机发来新指令,处理指令后开启计时
                      ...//器启动步进电机。
                      }
         }
}

bit ReCON(void)
{
      unsigned char i,ii,P1BUS,tmp,CCY,CUN,CData[8],XX;
      bit RR=0;
     
   if((MotoR_W==0)&&(MotoD_A==0)&&(MotoClock==0))
   {  
       LED1=1;
       LED2=1;
       P1BUS=P1;
      if((P1BUS==SLAVE0)||(P1BUS==SLAVE1))
        {
         EA=0;//地址符合,准备接受指令字节,关中断。
             if(P1BUS==SLAVE0) LocalID=0;
            if(P1BUS==SLAVE1) LocalID=1;
            CData[0]=P1BUS;
           while(MotoD_A==0) ;
            for(i=1;i<=7;i++) //接收CData[1]~CData[7]7个字节
                 {
                  while(MotoClock==1) ;//等待指令跳变信号(本字节写定)
                  _nop_();_nop_();
                  P1BUS=P1;
                  CData=P1BUS;
                  while(MotoClock==0) ;//等待指令跳变信号(下一字节开始)
             } //end of for(i=1;i<=7;i++) 
           CUN=0;
           
           for(i=0;i<=5;i++)
                     {
                      XX=CData;
                      tmp=1;
                      for(ii=1;ii<=8;ii++)
                      {
                       XX=CData;
                       CCY=XX&tmp;if(CCY==1) CUN++;
                       tmp*=2;
                       }//end of  for(ii=1;ii<=8;ii++)
                     }//end of for(i=0;i<=5;i++)
                      LED2=0; //测试点2
          if(CData[6]==CUN)              
           {
                  LED1=0; //测试点1
              ConSteps=CData[1];
              ConSteps=ConSteps<<8;
              ConSteps&=0xff00;
              ConSteps+=CData[2];

                  
                  //从特殊控制字判断方向参数,暂时特殊控制字不含其它信息
              if(CData[3]==0xff) 
                 ConDIR=1;
                  else     ConDIR=0;
              ConSpeedH=CData[4]; //接收的速度高字节
                          ConSpeedL=CData[5]; //接收的速度低字节
               RR=1;
                 MotoR_W=1;MotoD_A=1;
             P1=CData[0];
             }//end of     if(CData[6]==CData[0])
          
      }//end of  if((P1BUS==SLAVE0)||(P1BUS==SLAVE1))
     }
     EA=1;
    return RR;
}

当子机程序中有“P1=CData[0];”语句后,上电后主机第一次发指令子机可以进入“if(CData[6]==CUN) ”里的语句,但主机此后再发则子机只执行到“if(CData[6]==CUN)”前。这个情况是通过“LED1=0; //测试点1”及“ LED2=0; //测试点2”确认的。实在晕了,硬件的问题没头绪,软件现在也不知道怎么出来这么个奇怪的问题

使用特权

评论回复
地板
夏虫| | 2008-10-30 10:00 | 只看该作者

没这么用过

主从通讯从来没有这么用过,教科书上也没有见过,帮你顶一个吧

使用特权

评论回复
5
夏虫| | 2008-10-30 10:07 | 只看该作者

是否加大SmotoDelay延时会好一些

使用特权

评论回复
6
gunaaaa| | 2008-10-30 10:11 | 只看该作者

是不是相互干扰

单独用一个电机,其他电机不接看看有没有问题

使用特权

评论回复
7
电子小生|  楼主 | 2008-10-30 11:58 | 只看该作者

谢楼上2位顶贴

夏虫:
之所以采用这样的方式而不用串口是因为其他因素的考虑。确实这样用比较古怪。
加大SmotoDelay延时我试过了  居然子机误认为是呼叫子机的情况几率更高了。
而减短延时又开始出现应该响应的子机不响应的几率增加  汗

gunaaaa:
单独接一个子机的情况下,仍看到子机只在上电后接收了一次指令,电机动作一次,然后就再也不进入不了“if(CData[6]==CUN) ”里的语句了

使用特权

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

本版积分规则

9

主题

30

帖子

0

粉丝