標題: MAX487+51單片機實現(xiàn)RS485通信程序Proteus仿真(實測通過) [打印本頁]

作者: 美琴的備胎    時間: 2021-5-13 12:08
標題: MAX487+51單片機實現(xiàn)RS485通信程序Proteus仿真(實測通過)
   RS-485總線標準規(guī)定了總線接口的電氣特性標準即對于2個邏輯狀態(tài)的定義:正電平在+2V~+6V之間,表示一個邏輯狀態(tài);負電平在-2V~-6V之間,則表示另一個邏輯狀態(tài);數(shù)字信號采用差分傳輸方式,能夠有效減少噪聲信號的干擾。RS-485工業(yè)總線標準能夠有效支持多個分節(jié)點和通信距離遠,并且對于信息的接收靈敏度較高等特性。在工業(yè)通信網(wǎng)絡(luò)中,RS-485總線一般主要用于與外部各種工業(yè)設(shè)備進行信息傳輸和數(shù)據(jù)交換,所具備的對于噪聲的有效抑制能力、高效的數(shù)據(jù)傳輸速率與良好的數(shù)據(jù)傳輸?shù)目煽啃阅芤约翱蓴U展的通信電纜的長度是其他的許多工業(yè)通信標準所無法比擬的。因此,RS-485總線在諸多個領(lǐng)域得到了廣泛的應(yīng)用,比如在工業(yè)控制領(lǐng)域、交通的自動化控制領(lǐng)域和現(xiàn)場總線通信網(wǎng)絡(luò)等。
   RS-485接口的最大傳輸距離標準值為4000英尺,實際上可達 3000米(理論上的數(shù)據(jù),在實際操作中,極限距離僅達1200米左右),另外RS-232-C接口在總線上只允許連接1個收發(fā)器,即單站能力。RS485接口在總線上是允許連接多達128個收發(fā)器。即具有多站能力,這樣用戶可以利用單一的RS-485接口方便地建立起設(shè)備網(wǎng)絡(luò)。
本例程為STC89C52+RS485模塊組成的“一主兩從”模型。從機可拓展多位,修改主、從機地址即可。
本資料包含源文件、仿真程序。實測通過。

MAX487仿真原理圖如下(proteus仿真工程文件可到本帖附件中下載)

代碼片段(主機)
  1. #include<reg51.h>
  2. #include<string.h>
  3. #include "lcd.h"
  4. #define _SUCC_   0x0f//數(shù)據(jù)傳送成功
  5. #define _ERR_    0xf0//數(shù)據(jù)傳送失敗
  6. unsigned char aa=0xff;//主機與從機之間通信標志
  7. unsigned char temp=0xff;
  8. unsigned char Buff[20];//數(shù)據(jù)緩沖區(qū)
  9. unsigned char recive[6];     //用于保存從機發(fā)送的數(shù)據(jù)
  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函數(shù)
  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. //串口初始化函數(shù)
  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. //發(fā)送數(shù)據(jù)函數(shù)
  38. void SEND_data(unsigned char *Buff)
  39. {
  40.      unsigned char i,lenth,check;
  41.      lenth=strlen(Buff);      //計算數(shù)據(jù)長度
  42.      check=lenth;
  43.      TI=0;         //發(fā)送數(shù)據(jù)長度
  44.      TB8=0;       //發(fā)送數(shù)據(jù)幀
  45.      SBUF=lenth;
  46.      while(!TI);
  47.      TI=0;
  48.          
  49.      for(i=0;i<lenth;i++)  //發(fā)送數(shù)據(jù)
  50.     {
  51.         check=check^Buff[i];
  52.         TB8=0;
  53.         SBUF=Buff[i];      
  54.         while(!TI);
  55.         TI=0;
  56.     }
  57.       TB8=0;      //發(fā)送校驗字節(jié)
  58.       SBUF=check;   
  59.       while(!TI);
  60.       TI=0;     
  61. }

  62. //接收數(shù)據(jù)函數(shù)
  63. unsigned char RECE_data(unsigned char *Buff)
  64. {
  65.      unsigned char i;
  66.      unsigned char lenth;
  67.      unsigned char check;
  68.      RI=0;     //接收數(shù)據(jù)長度
  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++) //接收數(shù)據(jù)
  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);    //接收校驗字節(jié)
  88.      if(RB8==1)    //若接收到地址幀,則返回0xfe
  89.      return 0xfe;
  90.      temp=SBUF;
  91.      RI=0;
  92.      check=temp^check;  //將從主機接收到的校驗碼與自己計算的校驗碼比對
  93.      if(check!=0)   //校驗碼不一致,表明數(shù)據(jù)接收錯誤,向主機發(fā)送錯誤信號,函數(shù)返回0xff
  94.      {
  95.         TI=0;
  96.         TB8=0;
  97.         SBUF=_ERR_;
  98.         while(!TI);
  99.         TI=0;
  100.         return 0xff;
  101.      }
  102.      TI=0;           //校驗碼一致,表明數(shù)據(jù)接收正確,向主機發(fā)送成功信號,函數(shù)返回0x00
  103.      TB8=0;
  104.      SBUF=_SUCC_;         
  105.      while(!TI);
  106.      TI=0;
  107.      return 0;
  108. }                 

  109. //發(fā)送從機地址
  110. void ADDR_data(unsigned addr)
  111. {
  112. while(temp!=addr) //主機等待從機返回其地址作為應(yīng)答信號
  113. {
  114.   TI=0;    //發(fā)送從機地址
  115.   TB8=1;    //發(fā)送地址幀
  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);//發(fā)送從機地址
  137.       temp=_ERR_;   //主機等待從機數(shù)據(jù)接收成功信號
  138.       while(temp!=_SUCC_)
  139.       {
  140.           unsigned char Buff[]={0xfe};
  141.           SEND_data(Buff);//發(fā)送數(shù)據(jù)
  142.           RI=0;
  143.           while(!RI);
  144.           temp=SBUF;
  145.           RI=0;
  146.       }
  147.       SM2=0;       //接收數(shù)據(jù)幀
  148.       aa=0xff;    //從機接收數(shù)據(jù),并將數(shù)據(jù)保存到數(shù)據(jù)緩沖區(qū)
  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_;   //主機等待從機數(shù)據(jù)接收成功信號
  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_;   //主機等待從機數(shù)據(jù)接收成功信號
  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;       //接收數(shù)據(jù)幀
  200.         aa=0xff;    //從機接收數(shù)據(jù),并將數(shù)據(jù)保存到數(shù)據(jù)緩沖區(qū)
  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_;   //主機等待從機數(shù)據(jù)接收成功信號
  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_;   //主機等待從機數(shù)據(jù)接收成功信號
  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_;   //主機等待從機數(shù)據(jù)接收成功信號
  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_;   //主機等待從機數(shù)據(jù)接收成功信號
  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_;   //主機等待從機數(shù)據(jù)接收成功信號
  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. }
復(fù)制代碼

51hei.png (6.3 KB, 下載次數(shù): 210)

51hei.png

RS485多機通信-1602顯示從機信息.zip

180.8 KB, 下載次數(shù): 242, 下載積分: 黑幣 -5


作者: bouyei    時間: 2021-6-8 11:48
正在做RS485,希望有幫助。
作者: hbkjdxsh    時間: 2022-6-30 16:13
不明白定時器方式2存在的意義是什么啊

作者: 新昌小徐    時間: 2022-7-1 07:50
hbkjdxsh 發(fā)表于 2022-6-30 16:13
不明白定時器方式2存在的意義是什么啊

自動重載定時器模式,如果是模式0,1溢出后需要在中斷程序中手工添加賦初值語句。如果是模式2,系統(tǒng)直接把THx的值賦給TLx




歡迎光臨 (http://www.torrancerestoration.com/bbs/) Powered by Discuz! X3.1