国产免费AV|泡泡玛特欧洲总部将设在伦敦|中文天堂网www新版资源在线|一本久道综合在线中文|国精产品一二三产区的使用方法|香蕉鱼在线观看|www.27eee

 找回密碼
 注冊
搜索

51單片機(jī)RS485通信與Modbus協(xié)議

[復(fù)制鏈接]
樓主
eng 發(fā)表于 2021-7-6 16:26:01 | 只看該作者 |倒序?yàn)g覽 |閱讀模式
  1. #include <reg52.h>

  2. struct sTime {  //日期時間結(jié)構(gòu)體定義
  3.     unsigned int  year;
  4.     unsigned char mon;
  5.     unsigned char day;
  6.     unsigned char hour;
  7.     unsigned char min;
  8.     unsigned char sec;
  9.     unsigned char week;
  10. };

  11. bit flag200ms = 1;  //200ms定時標(biāo)志
  12. bit reqRefresh = 0;  //時間刷新請求
  13. struct sTime bufTime;  //日期時間緩沖區(qū)
  14. unsigned char T0RH = 0;  //T0重載值的高字節(jié)
  15. unsigned char T0RL = 0;  //T0重載值的低字節(jié)

  16. void ConfigTimer0(unsigned int ms);
  17. void RefreshTimeShow();
  18. extern void InitDS1302();
  19. extern void GetRealTime(struct sTime *time);
  20. extern void SetRealTime(struct sTime *time);
  21. extern void UartDriver();
  22. extern void ConfigUART(unsigned int baud);
  23. extern void UartRxMonitor(unsigned char ms);
  24. extern void UartWrite(unsigned char *buf, unsigned char len);
  25. extern unsigned int GetCRC16(unsigned char *ptr,  unsigned char len);
  26. extern void InitLcd1602();
  27. extern void LcdShowStr(unsigned char x, unsigned char y, unsigned char *str);

  28. void main()
  29. {
  30.     unsigned char psec=0xAA;  //秒備份,初值A(chǔ)A確保首次讀取時間后會刷新顯示

  31.     EA = 1;            //開總中斷
  32.     ConfigTimer0(1);   //配置T0定時1ms
  33.     ConfigUART(9600);  //配置波特率為9600
  34.     InitDS1302();      //初始化實(shí)時時鐘
  35.     InitLcd1602();     //初始化液晶

  36.     //初始化屏幕上固定不變的內(nèi)容
  37.     LcdShowStr(3, 0, "20  -  -  ");
  38.     LcdShowStr(4, 1, "  :  :  ");

  39.     while (1)
  40.     {
  41.         UartDriver();  //調(diào)用串口驅(qū)動
  42.         if (flag200ms)
  43.         {
  44.             flag200ms = 0;
  45.             GetRealTime(&bufTime);    //獲取當(dāng)前時間
  46.             if (reqRefresh || (psec!=bufTime.sec))
  47.             {   //檢測到時間刷新請求或時間有變化時刷新顯示
  48.                 RefreshTimeShow();
  49.                 psec = bufTime.sec;   //用當(dāng)前值更新上次秒數(shù)
  50.             }
  51.         }
  52.     }
  53. }
  54. /* 將一個BCD碼字節(jié)顯示到屏幕上,(x,y)-屏幕起始坐標(biāo),bcd-待顯示BCD碼 */
  55. void ShowBcdByte(unsigned char x, unsigned char y, unsigned char bcd)
  56. {
  57.     unsigned char str[4];

  58.     str[0] = (bcd >> 4) + '0';
  59.     str[1] = (bcd&0x0F) + '0';
  60.     str[2] = '\0';
  61.     LcdShowStr(x, y, str);
  62. }
  63. /* 刷新日期時間的顯示 */
  64. void RefreshTimeShow()
  65. {
  66.     ShowBcdByte(5,  0, bufTime.year);
  67.     ShowBcdByte(8,  0, bufTime.mon);
  68.     ShowBcdByte(11, 0, bufTime.day);
  69.     ShowBcdByte(4,  1, bufTime.hour);
  70.     ShowBcdByte(7,  1, bufTime.min);
  71.     ShowBcdByte(10, 1, bufTime.sec);
  72. }
  73. /* 串口動作函數(shù),根據(jù)接收到的命令幀執(zhí)行響應(yīng)的動作
  74.    buf-接收到的命令幀指針,len-命令幀長度 */
  75. void UartAction(unsigned char *buf, unsigned char len)
  76. {
  77.     unsigned int  crc;
  78.     unsigned char crch, crcl;

  79.     if (buf[0] != 0x01) //本例中的本機(jī)地址設(shè)定為0x01,
  80.     {                   //如數(shù)據(jù)幀中的地址字節(jié)與本機(jī)地址不符,
  81.         return;         //則直接退出,即丟棄本幀數(shù)據(jù)不做任何處理
  82.     }
  83.     //地址相符時,再對本幀數(shù)據(jù)進(jìn)行校驗(yàn)
  84.     crc = GetCRC16(buf, len-2);  //計(jì)算CRC校驗(yàn)值
  85.     crch = crc >> 8;
  86.     crcl = crc & 0xFF;
  87.     if ((buf[len-2]!=crch) || (buf[len-1]!=crcl))
  88.     {
  89.         return;   //如CRC校驗(yàn)不符時直接退出
  90.     }
  91.     //地址和校驗(yàn)字均相符后,解析功能碼,執(zhí)行相關(guān)操作
  92.     switch (buf[1])
  93.     {
  94.         case 0x06:  //寫入單個寄存器
  95.             if ((buf[2]==0x00) && (buf[3]<=0x06)) //地址0x0000~0x0006分別對應(yīng)
  96.             {                                     // “年/月/日/時/分/秒/星期”
  97.                 GetRealTime(&bufTime);  //獲取當(dāng)前時間
  98.                 switch (buf[3])  //由寄存器地址決定要修改的時間位
  99.                 {
  100.                     case 0: bufTime.year = 0x2000 + buf[5]; break;
  101.                     case 1: bufTime.mon  = buf[5]; break;
  102.                     case 2: bufTime.day  = buf[5]; break;
  103.                     case 3: bufTime.hour = buf[5]; break;
  104.                     case 4: bufTime.min  = buf[5]; break;
  105.                     case 5: bufTime.sec  = buf[5]; break;
  106.                     case 6: bufTime.week = buf[5]; break;
  107.                     default: break;
  108.                 }
  109.                 SetRealTime(&bufTime);  //寫入新修改后的時間
  110.                 reqRefresh = 1;  //設(shè)置顯示刷新請求
  111.                 len -= 2;  //長度-2以重新計(jì)算CRC并返回原幀
  112.                 break;
  113.             }
  114.             else  //寄存器地址不被支持時,返回錯誤碼
  115.             {
  116.                 buf[1] = 0x86;  //功能碼最高位置1
  117.                 buf[2] = 0x02;  //設(shè)置異常碼為02-無效地址
  118.                 len = 3;
  119.                 break;
  120.             }

  121.         default:  //其它不支持的功能碼
  122.             buf[1] |= 0x80;  //功能碼最高位置1
  123.             buf[2] = 0x01;   //設(shè)置異常碼為01-無效功能
  124.             len = 3;
  125.             break;
  126.     }
  127.     crc = GetCRC16(buf, len); //計(jì)算返回幀的CRC校驗(yàn)值
  128.     buf[len++] = crc >> 8;    //CRC高字節(jié)
  129.     buf[len++] = crc & 0xFF;  //CRC低字節(jié)
  130.     UartWrite(buf, len);      //發(fā)送返回幀
  131. }
  132. /* 配置并啟動T0,ms-T0定時時間 */
  133. void ConfigTimer0(unsigned int ms)
  134. {
  135.     unsigned long tmp;  //臨時變量

  136.     tmp = 11059200 / 12;      //定時器計(jì)數(shù)頻率
  137.     tmp = (tmp * ms) / 1000;  //計(jì)算所需的計(jì)數(shù)值
  138.     tmp = 65536 - tmp;        //計(jì)算定時器重載值
  139.     tmp = tmp + 33;           //補(bǔ)償中斷響應(yīng)延時造成的誤差
  140.     T0RH = (unsigned char)(tmp>>8);  //定時器重載值拆分為高低字節(jié)
  141.     T0RL = (unsigned char)tmp;
  142.     TMOD &= 0xF0;   //清零T0的控制位
  143.     TMOD |= 0x01;   //配置T0為模式1
  144.     TH0 = T0RH;     //加載T0重載值
  145.     TL0 = T0RL;
  146.     ET0 = 1;        //使能T0中斷
  147.     TR0 = 1;        //啟動T0
  148. }
  149. /* T0中斷服務(wù)函數(shù),執(zhí)行按鍵掃描和200ms定時 */
  150. void InterruptTimer0() interrupt 1
  151. {
  152.     static unsigned char tmr200ms = 0;

  153.     TH0 = T0RH;  //重新加載重載值
  154.     TL0 = T0RL;
  155.     UartRxMonitor(1);  //串口接收監(jiān)控
  156.     tmr200ms++;
  157.     if (tmr200ms >= 200)  //定時200ms
  158.     {
  159.         tmr200ms = 0;
  160.         flag200ms = 1;
  161.     }
  162. }
復(fù)制代碼

MAX485.pdf (438.77 KB)
Modbus通信協(xié)議.pdf (156.79 KB)
MODBUS協(xié)議中文版.pdf (1.11 MB)
Modbus注意要項(xiàng).pdf (216.87 KB)

您需要登錄后才可以回帖 登錄 | 注冊

本版積分規(guī)則

手機(jī)版|小黑屋|ELEOK |網(wǎng)站地圖

GMT+8, 2026-5-26 06:06

Powered by Discuz! X5.0

© 2001-2026 Discuz! Team.

快速回復(fù) 返回頂部 返回列表