51单片机MAX487实现RS485通信程序Proteus仿真

[复制链接]
查看14 | 回复0 | 2021-6-14 02:35:06 | 显示全部楼层 |阅读模式
RS-485总线标准规定了总线接口的电气特性标准即对于2个逻辑状态的定义:正电平在+2V~+6V之间,表示一个逻辑状态;负电平在-2V~-6V之间,则表示另一个逻辑状态;数字信号采用差分传输方式,能够有效减少噪声信号的干扰。RS-485工业总线标准能够有效支持多个分节点和通信距离远,并且对于信息的接收灵敏度较高等特性。在工业通信网络中,RS-485总线一般主要用于与外部各种工业设备进行信息传输和数据交换,所具备的对于噪声的有效抑制能力、高效的数据传输速率与良好的数据传输的可靠性能以及可扩展的通信电缆的长度是其他的许多工业通信标准所无法比拟的。因此,RS-485总线在诸多个领域得到了广泛的应用,比如在工业控制领域、交通的自动化控制领域和现场总线通信网络等。
   RS-485接口的最大传输距离标准值为4000英尺,实际上可达 3000米(理论上的数据,在实际操作中,极限距离仅达1200米左右),另外RS-232-C接口在总线上只允许连接1个收发器,即单站能力。RS485接口在总线上是允许连接多达128个收发器。即具有多站能力,这样用户可以利用单一的RS-485接口方便地建立起设备网络。
本例程为STC89C52+RS485模块组成的“一主两从”模型。从机可拓展多位,修改主、从机地址即可。
本资料包含源文件、仿真程序。实测通过。

MAX487仿真原理图如下(proteus仿真工程文件可到本帖附件中下载)
1.png
部分源码:完整源码见附件
  1. #include<reg51.h>
  2. #include<string.h>
  3. #include "lcd.h"
  4. #define _SUCC_   0x0f//数据传送成功
  5. #define _ERR_    0xf0//数据传送失败
  6. unsigned char aa=0xff;//主机与从机之间通信标志
  7. unsigned char temp=0xff;
  8. unsigned char Buff[20];//数据缓冲区
  9. unsigned char recive[6];     //用于保存从机发送的数据
  10. sbit KEY1=P1^3;
  11. sbit KEY2=P1^2;
  12. sbit KEY3=P1^1;
  13. sbit KEY4=P1^0;
  14. sbit KEY5=P3^2;
  15. sbit KEY6=P3^3;

  16. //sbit KEY5=P1^4;
  17. //sbit KEY6=P1^5;
  18. //延时1ms函数
  19. void delay_1ms(unsigned int i)
  20. {
  21.      unsigned int x,y;
  22.      for(x=i;x>0;x--)
  23.          for(y=110;y>0;y--);
  24. }
  25. //串口初始化函数
  26. void init()
  27. {
  28.      TMOD=0x20; //定时器1工作于方式2
  29.      TH1=0xfd;  
  30.      TL1=0xfd; //波特率为9600
  31.      PCON=0;
  32.      SCON=0xd0;  //串口工作于方式3
  33.      TR1=1;  //开启定时器
  34.      TI=0;
  35.      RI=0;
  36. }


  37. //发送数据函数
  38. void SEND_data(unsigned char *Buff)
  39. {
  40.      unsigned char i,lenth,check;
  41.      lenth=strlen(Buff);      //计算数据长度
  42.      check=lenth;
  43.      TI=0;         //发送数据长度
  44.      TB8=0;       //发送数据帧
  45.      SBUF=lenth;
  46.      while(!TI);
  47.      TI=0;
  48.          
  49.      for(i=0;i<lenth;i++)  //发送数据
  50.     {
  51.         check=check^Buff[i];
  52.         TB8=0;
  53.         SBUF=Buff[i];      
  54.         while(!TI);
  55.         TI=0;
  56.     }
  57.       TB8=0;      //发送校验字节
  58.       SBUF=check;   
  59.       while(!TI);
  60.       TI=0;     
  61. }

  62. //接收数据函数
  63. unsigned char RECE_data(unsigned char *Buff)
  64. {
  65.      unsigned char i;
  66.      unsigned char lenth;
  67.      unsigned char check;
  68.      RI=0;     //接收数据长度
  69.      while(!RI);
  70.      if(RB8==1)
  71.      {
  72.          RI = 0;   
  73.          return 0xfe;  //若接收到地址帧,则返回0xfe
  74.      }
  75.      lenth=SBUF;
  76.      RI=0;     
  77.      check=lenth;
  78.      for(i=0;i<lenth;i++) //接收数据
  79.     {
  80.         while(!RI);
  81.         if(RB8==1)   //若接收到地址帧,则返回0xfe
  82.         return 0xfe;
  83.         Buff[i]=SBUF;   
  84.         check=check^(Buff[i]);
  85.         RI=0;
  86.     }
  87.      while(!RI);    //接收校验字节
  88.      if(RB8==1)    //若接收到地址帧,则返回0xfe
  89.      return 0xfe;
  90.      temp=SBUF;
  91.      RI=0;
  92.      check=temp^check;  //将从主机接收到的校验码与自己计算的校验码比对
  93.      if(check!=0)   //校验码不一致,表明数据接收错误,向主机发送错误信号,函数返回0xff
  94.      {
  95.         TI=0;
  96.         TB8=0;
  97.         SBUF=_ERR_;
  98.         while(!TI);
  99.         TI=0;
  100.         return 0xff;
  101.      }
  102.      TI=0;           //校验码一致,表明数据接收正确,向主机发送成功信号,函数返回0x00
  103.      TB8=0;
  104.      SBUF=_SUCC_;         
  105.      while(!TI);
  106.      TI=0;
  107.      return 0;
  108. }                 

  109. //发送从机地址
  110. void ADDR_data(unsigned addr)
  111. {
  112. while(temp!=addr) //主机等待从机返回其地址作为应答信号
  113. {
  114.   TI=0;    //发送从机地址
  115.   TB8=1;    //发送地址帧
  116.   SBUF=addr;
  117.   while(!TI);
  118.   TI=0;
  119.   
  120.   RI=0;
  121.   while(!RI);
  122.   temp=SBUF;
  123.   RI=0;
  124. }
  125. }

  126. void keyscan()
  127. {
  128.   
  129.   if(KEY1==0)
  130.   {
  131.      LcdWriteCom(0x01);  //清屏
  132.      delay_1ms(5);
  133.      if(KEY1==0)
  134.     {
  135.       while(!KEY1);
  136.       ADDR_data(0x01);//发送从机地址
  137.       temp=_ERR_;   //主机等待从机数据接收成功信号
  138.       while(temp!=_SUCC_)
  139.       {
  140.           unsigned char Buff[]={0xfe};
  141.           SEND_data(Buff);//发送数据
  142.           RI=0;
  143.           while(!RI);
  144.           temp=SBUF;
  145.           RI=0;
  146.       }
  147.       SM2=0;       //接收数据帧
  148.       aa=0xff;    //从机接收数据,并将数据保存到数据缓冲区
  149.       while(aa==0xff)
  150.       {
  151.           aa=RECE_data(Buff);
  152.           P0 = 0xff;
  153.       }
  154.       P0 = 0xfe;
  155.       recive[0] = Buff[0];
  156.       recive[1] = Buff[1];
  157.       recive[2] = Buff[2];
  158.      
  159.     }
  160.   }

  161.   if(KEY2==0)
  162.   {
  163.      LcdWriteCom(0x01);  //清屏
  164.      delay_1ms(5);
  165.      if(KEY2==0)
  166.      {
  167.         while(!KEY2);
  168.         ADDR_data(0x01);
  169.         temp=_ERR_;   //主机等待从机数据接收成功信号
  170.         while(temp!=_SUCC_)
  171.        {
  172.           unsigned char Buff[]={0xff};
  173.           SEND_data(Buff);
  174.           RI=0;
  175.           while(!RI);  
  176.           RI=0;
  177.           temp=SBUF;
  178.        }
  179.      }
  180.   }

  181.   if(KEY3==0)
  182.   {
  183.      LcdWriteCom(0x01);  //清屏
  184.      delay_1ms(5);
  185.      if(KEY3==0)
  186.      {
  187.          while(!KEY3);
  188.          ADDR_data(0x02);
  189.          temp=_ERR_;   //主机等待从机数据接收成功信号
  190.          while(temp!=_SUCC_)
  191.         {
  192.            unsigned char Buff[]={0xfe};
  193.            SEND_data(Buff);
  194.            RI=0;
  195.            while(!RI);
  196.            temp=SBUF;
  197.            RI=0;
  198.         }
  199.         SM2=0;       //接收数据帧
  200.         aa=0xff;    //从机接收数据,并将数据保存到数据缓冲区
  201.         while(aa==0xff)
  202.         {
  203.             aa=RECE_data(Buff);
  204.             P0 = 0xff;
  205.         }
  206.         P0 = 0xfe;
  207.         /*
  208.         recive[3] = Buff[0];
  209.         recive[4] = Buff[1];
  210.         recive[5] = Buff[2];
  211.         */
  212.         recive[0] = Buff[0];
  213.         recive[1] = Buff[1];
  214.         recive[2] = Buff[2];
  215.      }
  216.   }

  217.   if(KEY4==0)
  218.   {
  219.       LcdWriteCom(0x01);  //清屏
  220.       delay_1ms(5);
  221.       if(KEY4==0)
  222.      {
  223.          while(!KEY4);
  224.          ADDR_data(0x02);
  225.           temp=_ERR_;   //主机等待从机数据接收成功信号
  226.          while(temp!=_SUCC_)
  227.         {
  228.              unsigned char Buff[]={0xff};
  229.              SEND_data(Buff);
  230.              RI=0;
  231.              while(!RI);
  232.              temp=SBUF;
  233.              RI=0;
  234.         }
  235.      }
  236.   }
  237.   if(KEY5==0)
  238.   {
  239.       LcdWriteCom(0x01);  //清屏
  240.       delay_1ms(5);
  241.       if(KEY5==0)
  242.      {
  243.          while(!KEY5);
  244.          ADDR_data(0x01);
  245.           temp=_ERR_;   //主机等待从机数据接收成功信号
  246.          while(temp!=_SUCC_)
  247.         {
  248.              unsigned char Buff[]={0xff};
  249.              SEND_data(Buff);
  250.              RI=0;
  251.              while(!RI);
  252.              temp=SBUF;
  253.              RI=0;
  254.         }
  255.          ADDR_data(0x02);
  256.           temp=_ERR_;   //主机等待从机数据接收成功信号
  257.          while(temp!=_SUCC_)
  258.         {
  259.              unsigned char Buff[]={0xff};
  260.              SEND_data(Buff);
  261.              RI=0;
  262.              while(!RI);
  263.              temp=SBUF;
  264.              RI=0;
  265.         }
  266.      }
  267.   }
  268.   if(KEY6==0)
  269.   {
  270.       LcdWriteCom(0x01);  //清屏
  271.       delay_1ms(5);
  272.       if(KEY6==0)
  273.      {
  274.          while(!KEY6);
  275.          ADDR_data(0x01);
  276.           temp=_ERR_;   //主机等待从机数据接收成功信号
  277.          while(temp!=_SUCC_)
  278.         {
  279.              unsigned char Buff[]={0xff};
  280.              SEND_data(Buff);
  281.              RI=0;
  282.              while(!RI);
  283.              temp=SBUF;
  284.              RI=0;
  285.         }
  286.          ADDR_data(0x02);
  287.           temp=_ERR_;   //主机等待从机数据接收成功信号
  288.          while(temp!=_SUCC_)
  289.         {
  290.              unsigned char Buff[]={0xff};
  291.              SEND_data(Buff);
  292.              RI=0;
  293.              while(!RI);
  294.              temp=SBUF;
  295.              RI=0;
  296.         }
  297.      }
  298.   }

  299. }      
  300. void main()
  301. {
  302.      init();
  303.      LcdInit();             //初始化LCD1602
  304.      LcdWriteCom(0x01);
  305.      while(1)
  306.      {
  307.         keyscan();
  308.         LcdWriteData(recive[0]);
  309.         LcdWriteData(recive[1]);
  310.         LcdWriteData(recive[2]);
  311.         /*
  312.         LcdWriteData(recive[3]);
  313.         LcdWriteData(recive[4]);
  314.         LcdWriteData(recive[5]);
  315.         */
  316.         LcdWriteCom(0x80);
  317.      }
  318. }
复制代码
2.png 完整程序代码和proteus仿真文件

RS485多机通信-1602显示从机信息.zip (180.8 KB, 售价: 5 工控币)
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则