打印

485多机通讯问题,望大侠指点

[复制链接]
4437|4
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
jiangyouzhi|  楼主 | 2012-7-25 08:42 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
请教各位关与485多机通讯问题,小弟用PIC单片机进行RS485多机通讯,1主机4从机,单独一对一通讯都是正常的,但是一起一对四通讯从机可以收到数据,但是主机手表到从机返回的数据,我是采用轮询的方式通讯,先对1号机通讯,1号机收到主机发来的数据后判断是否是本机地址,是本机地址后再返回一个数据,这样对1号机的查询结束后,再对2号进行查询,一直到4号。但是主机却收不到从机发来的数据,每个从机都分配步同的地址,不知是什么问题,折腾好几天了,还望各位大侠帮忙解决下,是什么问题引起的,谢谢!

主机通信主程序:
#include<pic.h>
#include"My_Hfile.h"
__CONFIG(0X0864);
__CONFIG(0X18ff);
volatile UCHAR Addr;           //从机地址
volatile UCHAR Recv_Data[5];    //接收数据缓存
UCHAR Recv_idx;                 //接受数据缓存索引
UINT CRC;                       //CRC校验数据
//----LCD封面显示
UCHAR table1[]={"SL1 DATA:"};
UCHAR table2[]={"SL2 DATA:"};
UCHAR table3[]={"SL3 DATA:"};
UCHAR table4[]={"SL3 DATA:"};
//-------------------------------------------------------------------
bit F_T1,Recv_OK;   //相关标识位
//-----------------------------------主程序-------------------------------------
void main()
{
UCHAR i;
        __delay_ms(100);  //等待足够的数据带从机完成初始化
port_init();       //端口初始化
lcd_init();        //LCD初始化
GOTO_XY(0,0);       //显示位置设置,及显示内容
write_lcd(table1);
GOTO_XY(0,1);
write_lcd(table2);
GOTO_XY(0,2);
write_lcd(table3);
GOTO_XY(0,3);
write_lcd(table4);
Per_init();         //外设初始化
while(1)
{
                //循环访问从机
  for(Addr=0x01;Addr<=0X04;Addr++)
  {
   LED_send=0;
   EN_485=1;       //允许485发送(禁止接受)
   __delay_ms(1);
   Send_Byte(Addr);    //发送从机地址
   Send_Byte(COMMAND); //发送操作命令码
   CRC=0XFFFF;         //CRC校验复位
   CRC16(Addr);        //校验从机地址
   CRC16(COMMAND);     //校验操作命令码
   Send_Byte(CRC);     //发送CRC低8位
   Send_Byte(CRC>>8);  //发送CRC高8位
            __delay_ms(1);
   SET_TIMER1(15000); //设置帧间隔时间
   F_T1=0;
   Recv_OK=0;              //接受成功标志先设0
            EN_485=0;           //允许485接受(禁止发送)
   TMR0=5;             //定时器0设定超时时间
   TMR0IF=0;
                      //  while(!Recv_OK);
   while((!Recv_OK)&&(!F_T1)) ;  //如果主机未接收到从机数据且为超时则等待
                         //------------------------------------------------------
                        //如果主机接受从机数据成功,则继续下面的处理
            if(Recv_OK)
   {
    GIE=0;      //关中断
    Recv_OK=0;  //接收成功标志设为0
    CRC=0XFFFF; //CRC校验复位
    for(i=0;i<5;i++)    //对当前接收的数据校验
    {
     CRC16(Recv_Data[i]);
    }
                                //校验成功时显示返回的数据
                if(CRC==0X0000)
    {
     LED_recv=~LED_recv;
     switch(Addr)
     {
      case 0x01:
        {
         GOTO_XY(9,0);
         hex_asc(Recv_Data[2]);
         break;
         }
      case 0x02:
        {
         GOTO_XY(9,1);
         hex_asc(Recv_Data[2]);
         break;
        }
      case 0x03:
        {
         GOTO_XY(9,2);
         hex_asc(Recv_Data[2]);
         break;
         }
      case 0x04:
        {
         GOTO_XY(9,3);
         hex_asc(Recv_Data[2]);
         break;
        }
      default:{
         GOTO_XY(9,0);
         write_data('E');
         write_data('R');
         write_data('R');
         write_data('O');
         write_data('R');
         GOTO_XY(9,1);
         write_data('E');
         write_data('R');
         write_data('R');
         write_data('O');
         write_data('R');
         GOTO_XY(9,2);
         write_data('E');
         write_data('R');
         write_data('R');
         write_data('O');
         write_data('R');
         GOTO_XY(9,3);
         write_data('E');
         write_data('R');
         write_data('R');
         write_data('O');
         write_data('R');
         break;
        }
     }
    }
   }
   //__delay_ms(10); //每完成一个从机数据处理后延时10ms
   GIE=1;          //再开中断
   
  }
  //__delay_ms(15); //每完成一轮扫描后等待10MS
}
}
//定时器中断及485接收中断程序
void interrupt ISR()
{
UCHAR temp;
        //-----------------定时器1溢出中断--------------------------------------
if(TMR1IF)
{
  TMR1IF=0;
        F_T1=1;
}
//-----------------串口接收中断-------------------------------------------------
if(RCIF)
{
  TEST1=~TEST1;
  Recv_OK=0;
  temp=RCREG;
  if(Recv_idx==0)
  {
  
   if(temp==Addr)
   {
    Recv_Data[Recv_idx++]=temp; TEST2=~TEST2;
   }
   else
   {
    Recv_idx=0;
   }
  }
  else if(Recv_idx==5)
  {
   Recv_idx=0;
   Recv_OK=1;
  }
  else
  {
   Recv_Data[Recv_idx++]=temp;
  }
  
}
}

从机主程序:
#include<pic.h>
#include"My_Hfile.h"
__CONFIG(0X0864);
__CONFIG(0X18ff);
volatile UCHAR Recv_Data[4];    //??????
volatile UCHAR Recv_idx;        //????????
UCHAR Addr;                 //?????
UINT CRC;                   //CRC???
UCHAR return_data;          //????????
bit F_T1,Recv_OK;   //?????
//LCD????
UCHAR table1[]={"RECV BYTE1:"};
UCHAR table2[]={"RECV BYTE2:"};
UCHAR table3[]={"RECV BYTE3:"};
UCHAR table4[]={"RECV BYTE4:"};
//----------------------------???--------------------------------------------
void main()
{
UCHAR i,j;
Recv_OK=0;          //????????0
port_init();        //?????
lcd_init();         //LCD???
        //LCD???????????
GOTO_XY(0,0);
write_lcd(table1);
GOTO_XY(0,1);
write_lcd(table2);
GOTO_XY(0,2);
write_lcd(table3);
GOTO_XY(0,3);
write_lcd(table4);
Per_init();//?????
LED_recv=0;
while(1)
{
                //???????????4???
  if(Recv_OK)
  {
   
   Recv_OK=0;
   GIE=0;      //???
                       // __delay_ms(10);
     //?????????0
   CRC=0XFFFF; //CRC?????
   for(i=0;i<4;i++)    //CRC????????
   {
    CRC16(Recv_Data[i]);
   }
                        //?????????????????5???????????????????2??CRC?
   if(CRC==0X0000)
   {
    LED_recv=1;
    EN_485=1;   //485??????????
                __delay_ms(1);                //?????????????
    GOTO_XY(11,0);
    hex_asc(Recv_Data[0]);
    GOTO_XY(11,1);
    hex_asc(Recv_Data[1]);
    GOTO_XY(11,2);
    hex_asc(Recv_Data[2]);
    GOTO_XY(11,3);
    hex_asc(Recv_Data[3]);
RB5=~RB5;
    if(Recv_Data[0]==Addr)
    {
     return_data=Addr|(0XF0|(j++));//???????
     Send_Byte(Addr);    //??????
     Send_Byte(COMMAND); //?????
     Send_Byte(return_data); //???????
     CRC=0xFFFF; //CRC????
     CRC16(Addr);    //????
     CRC16(COMMAND); //?????
     CRC16(return_data); //???????
     Send_Byte(CRC);     //??CRC?8?
     Send_Byte(CRC>>8);  //??CRC?8?
                    __delay_ms(1);
     EN_485=0;       //????????485??
     LED_recv=0;
    }
   }
   GIE=1;  //???
  }
}
}



void interrupt ISR()
{
UCHAR temp;
        //-----------------定时器1溢出中断--------------------------------------
if(TMR1IF)
{
  TMR1IF=0;
        F_T1=1;
}
//-----------------串口接收中断-------------------------------------------------
if(RCIF)
{
  TEST1=~TEST1;
  Recv_OK=0;
  temp=RCREG;

  if(Recv_idx==0)
  {
  
   if(temp==Addr)
   {
    Recv_Data[Recv_idx++]=temp; TEST2=~TEST2;
   }
   else
   {
    Recv_idx=0;
   }
  }
  else if(Recv_idx==4)
  {
   Recv_idx=0;
   Recv_OK=1;
  }
  else
  {
   Recv_Data[Recv_idx++]=temp;
  }
  
}
}
沙发
兰天白云| | 2012-7-25 11:36 | 只看该作者
从LZ发的问题分析,楼主可能比较粗心(有很多错别字)
1、485是半双工的,从机从接收转为发送需要时间,请问楼主注意时间差了吗
2、单片机是否采用中断工作方式?从机是否收到足够字节数据(重点查)
3、如果从机没有收到足够字节数据,请查主机发送程序
4、如果从机收到足够字节数据,而又有足够的时间把485从接收转变为发送,当然也要保证主机把485从发送转变为接收,是否在从机发送时,主机已完成485状态转换?

使用特权

评论回复
板凳
兰天白云| | 2012-7-25 11:38 | 只看该作者
中断的判断不够严谨

使用特权

评论回复
地板
jiangyouzhi|  楼主 | 2012-7-25 12:14 | 只看该作者
是采用中断的工作方式,在Proteus仿真的时候,4个从机都是接收到完整的数据的,就是主机没有收到从机的数据,不知道是不是总线冲突了,但是我都分配不同的地址,轮询的方式通讯的,怎么会冲突的,请问时间差应该设为多少呢?小弟初次做485多机,还望大侠指教,谢谢

使用特权

评论回复
5
兰天白云| | 2012-7-26 14:12 | 只看该作者
1、当主机发送完数据后,要把485切换成输入接收状态,从你的代码看,数据发送出去后,你是等1毫秒的时间,然后再把485设置为接收,即你的发送不是中断的,也就是说你并不知道发送是什么时候完成的,我不知道Send_Byte()是怎么写的,PIC的硬件是有缓冲的,数据发送完成可以通过标志位查询,当查询到标志位后可立即把485切换到输入,对应的从机接收完数据后应该立即再把485切换成 输出,但要延时一点时间后再发送数据已让主机有完成485切换动作,否则主机无法接收正确数据   
2、程序不够严密
如f(RCIF)
应该写成
if(RCIE&&RCIF)
同时判断两个条件

使用特权

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

本版积分规则

0

主题

2

帖子

1

粉丝