找回密碼
 立即注冊

QQ登錄

只需一步,快速開始

搜索
查看: 15457|回復(fù): 24
打印 上一主題 下一主題
收起左側(cè)

PIC單片機(jī)MODBUS總線通信仿真及程序源碼

  [復(fù)制鏈接]
跳轉(zhuǎn)到指定樓層
樓主
一、MODBUS總線通信仿真(主機(jī)程序)
說明: 本例運(yùn)行時,主機(jī)向各從機(jī)發(fā)送要求返回A/D轉(zhuǎn)換值的命令碼,在主機(jī)
完整接收到從機(jī)A/D數(shù)據(jù)后,在液晶上刷新顯示.
二、MODBUS總線通信仿真(從機(jī)程序)
說明: 本例運(yùn)行時,從機(jī)接收主機(jī)命令,然后將A/D轉(zhuǎn)換值通過485回發(fā)給主機(jī)顯示.


所有資料下載:
PIC單片機(jī)MODBUS總線通信仿真.zip (395.9 KB, 下載次數(shù): 271)

主機(jī)程序部分預(yù)覽:
  1. #define INT8U  unsigned char
  2. #define INT16U unsigned int
  3. #define INT32U unsigned long
  4. #include <pic.h>
  5. #include <stdio.h>
  6. #include "LM041_4BIT.h"
  7. const char* Prompts[17] =
  8. {
  9.   "****************",
  10.   " RS-485  MODBUS ",
  11.   "  TEST PROGRAM  ",
  12.   "****************"
  13. };
  14. volatile INT8U recv_Data[6];           //串口接收數(shù)據(jù)緩沖區(qū)(6字節(jié))
  15. volatile INT8U recv_idx = 0;           //串口接收數(shù)據(jù)緩沖區(qū)索引
  16. volatile INT8U sl_Addr;                //485從機(jī)地址
  17. INT8U  LCD_Buffer[16];                 //LCD顯示緩沖            
  18. INT16U CRC;                            //16位CRC校驗(yàn)結(jié)果
  19. //-----------------------------------------------------------------
  20. #define  LED_Recv  RB6                 //主機(jī)接收指示燈
  21. #define  LED_Send  RB7                 //主機(jī)發(fā)送指示燈
  22. #define  RDE_485   RC5                 //RS485通信控制端
  23. #define  ADC_REQ   65                  //要求從機(jī)返回A/D值的自定義命令碼(范圍65~72)
  24. //19200波特率每字符時間為: 1/19200*(1+8+2) ≈  572us
  25. //幀  間: 3.5個字符時間為: 572 * (3.5 + 1) ≈ 2574us
  26. //字節(jié)間: 1.5個字符時間為: 572 * (1.5 + 1) ≈ 1430us
  27. #define FRAME_SPAN  2574                  //相臨幀之間的間隔時間
  28. #define BYTE_SPAN   1430                  //幀內(nèi)字節(jié)之間的間隔時間
  29. bit     b, F_T1, T_BYTE, T_FRAME, Recv_OK;//相關(guān)標(biāo)識位
  30. //-----------------------------------------------------------------
  31. // 宏定義: 發(fā)送一字節(jié)并等待發(fā)送結(jié)束
  32. //-----------------------------------------------------------------
  33. #define Send_Byte(x)                  \
  34. {                                     \
  35.     LED_Send = 1; RDE_485 = 1;        \
  36.     TXREG = x; while (TRMT == 0);     \
  37.     __delay_us(9); LED_Send = 0;      \
  38. }

  39. //-----------------------------------------------------------------
  40. // 宏定義: 設(shè)置TIMER1的定時初值并設(shè)相關(guān)標(biāo)志位
  41. //-----------------------------------------------------------------
  42. #define Set_TIMER1(x)                \
  43. {                                    \
  44.    TMR1H = (65536 - x) >> 8;         \
  45.    TMR1L = (65536 - x) & 0x0F;       \
  46.    TMR1IF = T_BYTE = T_FRAME = 0;    \
  47.    F_T1 = (x == FRAME_SPAN) ? 1 : 0; \
  48.    if (F_T1) recv_idx = 0;           \
  49. }

  50. //-----------------------------------------------------------------
  51. // 串口初始化
  52. //-----------------------------------------------------------------
  53. void Serial_port_init()
  54. {
  55.     SYNC = 0;                            //選擇異步通信模式
  56.     BRGH = 1;                            //選擇高速波特率發(fā)生模式
  57.     TXEN = 1;                            //允許發(fā)送數(shù)據(jù)
  58.     SPBRG = _XTAL_FREQ/16/19200 - 1;     //設(shè)置波特率為19200  
  59.     SPEN = 1;                            //串行通信端口打開
  60.     CREN = 1;                            //使能連續(xù)接收串行數(shù)據(jù)
  61. }

  62. //-----------------------------------------------------------------
  63. // 外設(shè)初始化(定時器,485等)
  64. //-----------------------------------------------------------------
  65. void Per_Initialize()
  66. {   
  67.     //端口數(shù)據(jù)方向配置
  68.     TRISC7 = TRISC6 = 1; TRISC5 = 0;     //設(shè)置連接485的三只引腳的數(shù)據(jù)方向
  69.     TRISB6 = TRISB7 = 0;                 //主機(jī)收/發(fā)指示燈引腳設(shè)為輸出
  70.     //配置定時器TIMER0
  71.     T0CS = 0;                            //選擇內(nèi)部系統(tǒng)時鐘源
  72.     PSA = 0; PS2 = 1;PS1 = 0; PS0 = 1;   //預(yù)分頻器分配給TIMER0,PS:101->64分頻   
  73.     //配置USART
  74.     Serial_port_init();                  //串口初始化
  75.     RDE_485 = 1;                         //允許485發(fā)送(禁止接收)
  76.     //中斷控制
  77.     RCIE = 1;                            //允許串口接收中斷
  78.     TMR1IE = 1;                          //允許TMR1溢出中斷
  79.     PEIE = 1;                            //允許外設(shè)中斷(TMR1,USART均為PIC外設(shè))
  80.     GIE = 1;                             //開中斷
  81.     TMR1ON = 1;                          //啟動TIMER1(默認(rèn)為1:1分頻)
  82. }

  83. //-----------------------------------------------------------------
  84. // CRC16校驗(yàn)函數(shù) (基于該函數(shù)可得出512字節(jié)的校驗(yàn)碼表,改用查表法進(jìn)行校驗(yàn))
  85. // 多項(xiàng)式: X ^ 16 + X ^ 15 + X ^ 2 + 1, 去高位逆序表示:0xA001
  86. //-----------------------------------------------------------------
  87. void CRC16(INT8U d)
  88. {













  89. }
  90. //-----------------------------------------------------------------
  91. // 主程序     
  92. //-----------------------------------------------------------------
  93. void main()
  94. {
  95.     INT8U i; INT32U  ADC_Result;
  96.     __delay_ms(100);      //等待足夠時間,待從機(jī)完成初始化
  97.     Per_Initialize();     //外設(shè)初始化
  98.     LCD_Initialize();     //LCD初始化
  99.     //輸出系統(tǒng)封面文字(4行)
  100.     for (i = 0; i < 4; i++) LCD_ShowString(i,0,(char*)Prompts[i]);
  101.     //延時10*100ms
  102.     i = 10; while (i--) __delay_ms(100);
  103.     ClearScreen();//清屏
  104.     //顯示液晶上兩行文字
  105.     LCD_ShowString(0,0,(char*)"   A/D Display   ");  
  106.     LCD_ShowString(1,0,(char*)"-----------------");
  107.     while(1)
  108.     {  
  109.         //---------------------------------------------------------
  110.         // 循環(huán)訪問地址為0x01~0x04的4個485從機(jī)
  111.         //---------------------------------------------------------
  112.         for (sl_Addr = 0x01; sl_Addr <= 0x04; sl_Addr++)
  113.         {   
  114.             LED_Send = 0;               //主機(jī)發(fā)送指示燈開
  115.             RDE_485 = 1;                //允許485發(fā)送(禁止接收)
  116.             Send_Byte(sl_Addr);         //(1)發(fā)送從機(jī)地址
  117.             Send_Byte(ADC_REQ);         //(2)發(fā)送操作命令碼(要求從機(jī)返回A/D值)
  118.             CRC = 0xFFFF;               //CRC校驗(yàn)復(fù)位
  119.             CRC16(sl_Addr);             //當(dāng)前從機(jī)地址校驗(yàn)
  120.             CRC16(ADC_REQ);             //當(dāng)前操作命令碼校驗(yàn)
  121.             Send_Byte(CRC);             //(3)發(fā)送校驗(yàn)碼低字節(jié)
  122.             Send_Byte(CRC>>8);          //(4)發(fā)送校驗(yàn)碼高字節(jié)
  123.             Set_TIMER1(FRAME_SPAN);     //用TIMER1控制相鄰幀之間的時間間隔
  124.             Recv_OK = 0;                //先設(shè)接收成功標(biāo)識為假
  125.             RDE_485 = 0;                //允許485接收(禁止發(fā)送)
  126.             //用TIMER0定時器控制接收一部從機(jī)數(shù)據(jù)的超時時間為10ms
  127.             TMR0 = (INT8U)(256 - _XTAL_FREQ / 4 / 64 * 0.01);
  128.             T0IF = 0;                   //清除T0中斷標(biāo)志
  129.             LED_Send = 1;               //主機(jī)發(fā)送指示燈關(guān)
  130.             //如果主機(jī)接收從機(jī)數(shù)據(jù)未完成且未超時(10ms)則等待
  131.             while(!Recv_OK && !T0IF);
  132.             //-----------------------------------------------------
  133.             //如果主機(jī)接收從數(shù)據(jù)成功則繼續(xù)下面的處理
  134.             if (Recv_OK)
  135.             {   GIE = 0;                //關(guān)中斷
  136.                 Recv_OK = 0;            //接收成功標(biāo)志重設(shè)為假
  137.                 CRC = 0xFFFF;           //CRC校驗(yàn)初始化
  138.                 //對來自當(dāng)前從機(jī)的6字節(jié)數(shù)據(jù)進(jìn)行CRC校驗(yàn)
  139.                 for (i = 0; i < 6; i++) CRC16(recv_Data[i]);
  140.                 //校驗(yàn)通過時顯示
  141.                 if (CRC == 0x0000)
  142.                 {
  143.                     LED_Send = 1;            //主機(jī)發(fā)送指示燈關(guān)閉
  144.                     //從機(jī)發(fā)送的6字節(jié)分別是:站號/命令碼/兩字節(jié)數(shù)據(jù)(模數(shù)值)/兩字節(jié)CRC
  145.                     //recv_Data[2],[3]所保存的是從機(jī)返回的模/數(shù)轉(zhuǎn)換值
  146.                     ADC_Result = (recv_Data[2] << 8) + recv_Data[3];
  147.                     //生成待顯示字符串
  148.                     sprintf(LCD_Buffer,
  149.                        "V%d:%4.2f",sl_Addr,(float)(ADC_Result * 5.0 / 1023.0));
  150.                     //發(fā)送到LCD顯示(顯示LCD的下兩行,每行顯示兩組)
  151.                     LCD_ShowString(
  152.                       (INT8U)(sl_Addr-1)/2+2,(sl_Addr&0x01)?0:9, LCD_Buffer);
  153.                 }
  154.             }
  155.             //每完成一個從機(jī)數(shù)據(jù)處理后延時10ms再開中斷
  156.             __delay_ms(10); GIE = 1;
  157.             //-----------------------------------------------------
  158.         }
  159.         __delay_ms(10); //每完成一輪(4個從機(jī))掃描后等待10ms
  160.     }
  161. }

  162. //-----------------------------------------------------------------
  163. // 主機(jī)定時中斷及485接收中斷服務(wù)程序
  164. //-----------------------------------------------------------------
  165. void interrupt ISR()
  166. {  
  167.     INT8U R;
  168.     //----------------------TIMER1定時器溢出中斷--------------------
  169.     if (TMR1IF)
  170.     {   TMR1IF = 0;
  171.         //F_T1: 標(biāo)識TIMER1定時器當(dāng)前用于實(shí)現(xiàn)幀間隔時間定時還時字節(jié)間隔時間定時
  172.         //F_T1 = 0時,將幀間隔時間(3.5字符)到達(dá)設(shè)為假,字節(jié)間隔時間到達(dá)設(shè)為真
  173.         //F_T1 = 1時,將幀間隔時間(3.5字符)到達(dá)設(shè)為真,字節(jié)間隔時間到達(dá)設(shè)為假
  174.         if (F_T1 == 0) { T_FRAME = 0; T_BYTE  = 1; }
  175.         else           { T_FRAME = 1; T_BYTE  = 0; }        
  176.     }
  177.     //-------------------------串口接收中斷-------------------------
  178.     if (RCIF)
  179.     {   
  180.         LED_Recv = ~LED_Recv;                   //主機(jī)接收指示燈閃爍
  181.         R = RCREG;                              //從串口(來自485)讀取一字節(jié)
  182.         RCIF = 0;                               //清標(biāo)志位(此行可省略)
  183.         Recv_OK = 0;                            //先暫時設(shè)接收成功標(biāo)志為假
  184.         //---------------------------------------------------------
  185.         //如果當(dāng)前要接收的是第0字節(jié)
  186.         if (recv_idx == 0)
  187.         {   //如果幀間時間間隔未到,或所收到的字節(jié)與設(shè)備地址不匹配
  188.             //則重新設(shè)TIMER1定時長度為幀間時長FRAME_SPAN
  189.             if (T_FRAME == 0 || R != sl_Addr) { Set_TIMER1(FRAME_SPAN); }
  190.             //否則表示接收的第0個字節(jié)與其設(shè)備地址匹配
  191.             else
  192.             {   recv_Data[recv_idx++] = R;      //字節(jié)R保存到接收緩沖recv_Data
  193.                 Set_TIMER1(BYTE_SPAN);          //重設(shè)T1定時長度為幀內(nèi)字節(jié)間的時長
  194.             }
  195.         }
  196.         //---------------------------------------------------------
  197.         //否則要接收的是第0字節(jié)(即地址字節(jié))之后的數(shù)據(jù)
  198.         else
  199.         {   //如果后續(xù)接收過程中幀內(nèi)字節(jié)時間間隔未超過1.5個字符時間
  200.             if (T_BYTE == 0)
  201.             {   
  202.                 recv_Data[recv_idx++] = R;      //首先將有效字節(jié)保存到接收緩沖
  203.                 //如果接收到的地址字節(jié)(第0字節(jié))后的字節(jié)(即第1字節(jié))不等于操作碼
  204.                 //則將接收緩沖索引歸0,并重設(shè)T1定時長度為幀間隔時長
  205.                 //(注意recv_idx == 2時,剛剛保存R是第1字節(jié))
  206.                 if ( recv_idx == 2 && R != ADC_REQ) { Set_TIMER1(FRAME_SPAN); }
  207.                 //如果接收到來自當(dāng)前從機(jī)的完整的6個字節(jié)數(shù)據(jù)
  208.                 else if (recv_idx == 6)
  209.                 {   
  210.                     Set_TIMER1(FRAME_SPAN);     //重設(shè)T1定時長度為幀間隔時長
  211.                     Recv_OK = 1;                //設(shè)置接收成功標(biāo)識為真
  212.                 }
  213.                 else { Set_TIMER1(BYTE_SPAN); } //重設(shè)T1定時長度為幀內(nèi)字節(jié)間的時長
  214.             }
  215.             //同一幀內(nèi)字符間的時間超時,重設(shè)T1為幀之間的時間間隔
  216.             else  { Set_TIMER1(FRAME_SPAN); }
  217.         }
  218.         //---------------------------------------------------------
  219.     }
  220. }</div><div>從機(jī)程序:</div><div>#define _XTAL_FREQ 4000000UL
  221. #define INT8U  unsigned char
  222. #define INT16U unsigned int
  223. #define INT32U unsigned long
  224. #include <pic.h>
  225. #include <stdio.h>
  226. //配置字,注意禁用MCLR,因?yàn)镽A3/MCLR/VPP引腳用于485從機(jī)地址次高位輸入
  227. __CONFIG(MCLRDIS & WDTDIS & INTIO);
  228. volatile INT8U recv_Data[4];           //串口接收數(shù)據(jù)緩沖區(qū)(4字節(jié))
  229. volatile INT8U recv_idx = 0;           //串口接收數(shù)據(jù)緩沖區(qū)索引
  230. volatile INT8U sl_Addr;                //485從機(jī)地址           
  231. INT16U CRC;                            //16位CRC校驗(yàn)結(jié)果
  232. //-----------------------------------------------------------------
  233. #define  LED_Ptr   RC0                 //本機(jī)收/發(fā)指示燈
  234. #define  RDE_485   RC3                 //RS485通信控制端
  235. #define  ADC_REQ   65                  //要求從機(jī)返回A/D值的自定義命令碼(范圍65~72)
  236. //19200波特率每字符時間為: 1/19200*(1+8+2) ≈  572us
  237. //幀  間: 3.5個字符時間為: 572 * (3.5 + 1) ≈ 2574us
  238. //字節(jié)間: 1.5個字符時間為: 572 * (1.5 + 1) ≈ 1430us
  239. #define FRAME_SPAN  2574                  //相臨幀之間的間隔時間
  240. #define BYTE_SPAN   1430                  //幀內(nèi)字節(jié)之間的間隔時間
  241. bit     b, F_T1, T_BYTE, T_FRAME, Recv_OK;//相關(guān)標(biāo)識位
  242. INT8U   AD_Result[2];                     //2字節(jié)的A/D轉(zhuǎn)換結(jié)果
  243. //-----------------------------------------------------------------
  244. // 宏定義: 發(fā)送一字節(jié)并等待發(fā)送結(jié)束
  245. //-----------------------------------------------------------------
  246. #define Send_Byte(x)                  \
  247. {                                     \
  248.     LED_Ptr = ~LED_Ptr;               \
  249.     RDE_485 = 1;                      \
  250.     TXREG = x; while (TRMT == 0);     \
  251.     __delay_us(9);                    \
  252. }
  253. //-----------------------------------------------------------------
  254. // 宏定義: 設(shè)置TIMER1的定時初值并設(shè)相關(guān)標(biāo)志位
  255. //-----------------------------------------------------------------
  256. #define Set_TIMER1(x)                 \
  257. {                                     \
  258.    TMR1H = (65536 - x) >> 8;          \
  259.    TMR1L = (65536 - x) & 0x0F;        \
  260.    TMR1IF = T_BYTE = T_FRAME = 0;     \
  261.    F_T1 = (x == FRAME_SPAN) ? 1 : 0;  \
  262.    if (F_T1) recv_idx = 0;            \
  263. }
  264. //-----------------------------------------------------------------
  265. // CRC16校驗(yàn)函數(shù) (基于該函數(shù)可得出512字節(jié)的校驗(yàn)碼表,改用查表法進(jìn)行校驗(yàn))
  266. // 多項(xiàng)式: X ^ 16 + X ^ 15 + X ^ 2 + 1, 去高位逆序表示:0xA001
  267. //-----------------------------------------------------------------
  268. void CRC16(INT8U d)
  269. {</div><div>
  270. </div><div>
  271. }
  272. //-----------------------------------------------------------------
  273. // 模/數(shù)轉(zhuǎn)換函數(shù)
  274. //-----------------------------------------------------------------
  275. void AD_Convert()
  276. {
  277.     __delay_us(10);
  278.     GODONE = 1;                          //啟動轉(zhuǎn)換
  279.     while (ADIF == 0);                   //等待轉(zhuǎn)換結(jié)束
  280.     ADIF = 0;                            //AD中斷標(biāo)志清0
  281.     AD_Result[1] = ADRESH;               //保存A/D結(jié)果的高字節(jié)
  282.     AD_Result[0] = ADRESL;               //保存A/D結(jié)果的低字節(jié)
  283. }
  284. //-----------------------------------------------------------------
  285. // 串口初始化
  286. //-----------------------------------------------------------------
  287. void Serial_port_init()
  288. {
  289.     SYNC = 0;                            //選擇異步通信模式
  290.     BRGH = 1;                            //選擇高速波特率發(fā)生模式
  291.     TXEN = 1;                            //允許發(fā)送數(shù)據(jù)
  292.     SPBRG = _XTAL_FREQ/16/19200 - 1;     //設(shè)置波特率為19200  
  293.     SPEN = 1;                            //串行通信端口打開
  294.     CREN = 1;                            //使能連續(xù)接收串行數(shù)據(jù)
  295. }
  296. //-----------------------------------------------------------------
  297. // 外設(shè)初始化(定時器,485等)
  298. //-----------------------------------------------------------------
  299. void Per_Initialize()
  300. {   
  301.     GIE = 0;                             //禁止中斷
  302.     TRISC = 0B00110000;                  //設(shè)置串行通訊端口及LED指示燈端口方向
  303.     LED_Ptr = 0;                         //收/發(fā)指示燈關(guān)閉
  304.     RDE_485 = 1;                         //禁止從機(jī)485接收
  305.     PORTA = 0x00;                        //初始化PORTA
  306.     WPUA = 0xFF;                         //使能PORTA相應(yīng)引腳的弱上拉
  307.     TRISA = 0xFF;                        //PORTA所有引腳全部設(shè)為輸入
  308.     ANSEL = 0x01;                        //PORTA的RA0設(shè)為模擬輸入
  309.     sl_Addr = (PORTA >> 1) & 0x0F;       //獲取所設(shè)置的本機(jī)地址
  310.     Serial_port_init();                  //串口初始化  
  311.     OSCCON = 0B01101000;                 //使用默認(rèn)的4M內(nèi)部振蕩器
  312.     ADCON0 = 0B10000001;                 //選擇0通道,A/D結(jié)果右對齊,使能A/D
  313.     ADCON1 = 0B01010000;                 //AD轉(zhuǎn)換時鐘選擇位ADCS<2:0>=101,選擇FOSC/16   
  314.     RCIE = 1;                            //允許串口接收中斷
  315.     TMR1IE = 1;                          //允許TMR1溢出中斷
  316.     PEIE = 1;                            //允許外設(shè)中斷(TMR1,USART均為PIC外設(shè))
  317.     GIE = 1;                             //開中斷
  318.     RDE_485 = 0;                         //允許從機(jī)485接收(禁止發(fā)送)   
  319.     TMR1ON = 1;                          //啟動TIMER1(默認(rèn)為1:1分頻)
  320.     __delay_us(2);
  321.     Set_TIMER1(FRAME_SPAN);              //用TIMER1控制相鄰幀之間的時間間隔
  322.     Recv_OK = 0;                         //初始時三個標(biāo)識全部設(shè)為0
  323. }
  324. //-----------------------------------------------------------------
  325. // 主程序
  326. //-----------------------------------------------------------------   
  327. void main()
  328. {
  329.     Per_Initialize();                    //外設(shè)初始化
  330.     while(1)
  331.     {
  332.        //如果本從機(jī)已經(jīng)接收到完整的四個字節(jié)數(shù)據(jù)
  333.        if (Recv_OK)
  334.        {
  335.           GIE = 0;                       //關(guān)中斷
  336.           Recv_OK = 0;                   //接收成功標(biāo)志重設(shè)為假
  337.          //對待所接收的來自主機(jī)的4字節(jié)數(shù)據(jù)進(jìn)行CRC校驗(yàn)
  338.           CRC = 0xFFFF;  for(INT8U i = 0; i < 4; i++) CRC16(recv_Data[i]);
  339.           //校驗(yàn)通過后開始向主機(jī)發(fā)送數(shù)據(jù)(6字節(jié):本機(jī)地址,操作碼,兩字節(jié)A/D,兩字節(jié)CRC)
  340.           if (CRC == 0x0000)
  341.           {
  342.              RDE_485 = 1;                //允許發(fā)送,禁止接收
  343.              __delay_ms(1);              //延時1ms
  344.              AD_Convert();               //AN0通道進(jìn)行模/數(shù)轉(zhuǎn)換
  345.              __delay_ms(1);              //延時1ms               
  346.              Send_Byte(sl_Addr);         //回發(fā)本機(jī)地址
  347.              Send_Byte(ADC_REQ);         //回發(fā)A/D請求命令
  348.              Send_Byte(AD_Result[1]);    //回發(fā)A/D轉(zhuǎn)換結(jié)果高字節(jié)
  349.              Send_Byte(AD_Result[0]);    //回發(fā)A/D轉(zhuǎn)換結(jié)果低字節(jié)
  350.              CRC = 0xFFFF;               //先將16位的CRC檢驗(yàn)變量置為全1
  351.              CRC16(sl_Addr);             //校驗(yàn)本機(jī)地址
  352.              CRC16(ADC_REQ);             //校驗(yàn)A/D請求命令
  353.              CRC16(AD_Result[1]);        //校驗(yàn)A/D結(jié)果高字節(jié)
  354.              CRC16(AD_Result[0]);        //校驗(yàn)A/D結(jié)果低字節(jié)
  355.              Send_Byte(CRC);             //最后發(fā)送兩字節(jié)的CRC校驗(yàn)值
  356.              Send_Byte(CRC>>8);
  357.              RDE_485 = 0;                //發(fā)送結(jié)束后,再允許本機(jī)485接收
  358.           }
  359.           GIE = 1;                       //開中斷
  360.        }
  361.     }
  362. }
  363. //-----------------------------------------------------------------
  364. // 485從機(jī)中斷服務(wù)程序
  365. //-----------------------------------------------------------------
  366. void interrupt ISR()
  367. {  
  368.     INT8U R;
  369.     //----------------------TIMER1定時器溢出中斷--------------------
  370.     if (TMR1IF)
  371.     {   TMR1IF = 0;
  372.         //F_T1: 標(biāo)識TIMER1定時器當(dāng)前用于實(shí)現(xiàn)幀間隔時間定時還時字節(jié)間隔時間定時
  373.         //F_T1 = 0時,將幀間隔時間(3.5字符)到達(dá)設(shè)為假,字節(jié)間隔時間到達(dá)設(shè)為真
  374.         //F_T1 = 1時,將幀間隔時間(3.5字符)到達(dá)設(shè)為真,字節(jié)間隔時間到達(dá)設(shè)為假
  375.         if (F_T1 == 0) { T_FRAME = 0; T_BYTE  = 1; }
  376.         else           { T_FRAME = 1; T_BYTE  = 0; }        
  377.     }
  378.     //-------------------------串口接收中斷-------------------------
  379.     if (RCIF)
  380.     {   
  381.         LED_Ptr = ~LED_Ptr;                     //從機(jī)收/發(fā)指示燈閃爍
  382.         R = RCREG;                              //從串口(來自485)讀取一字節(jié)
  383.         RCIF = 0;                               //清標(biāo)志位(此行可省略)
  384.         Recv_OK = 0;                            //先暫時設(shè)接收成功標(biāo)志為假
  385.         //---------------------------------------------------------
  386.         //如果當(dāng)前要接收的是第0字節(jié)
  387.         if (recv_idx == 0)
  388.         {   //如果幀間時間間隔未到,或所收到的字節(jié)與設(shè)備地址不匹配
  389.             //則重新設(shè)TIMER1定時長度為幀間時長FRAME_SPAN
  390.             if (T_FRAME == 0 || R != sl_Addr) { Set_TIMER1(FRAME_SPAN); }
  391.             //否則表示接收的第0個字節(jié)與其設(shè)備地址匹配
  392.             else
  393.             {   recv_Data[recv_idx++] = R;      //字節(jié)R保存到接收緩沖
  394.                 Set_TIMER1(BYTE_SPAN);          //重設(shè)T1為幀內(nèi)字節(jié)間時長
  395.             }
  396.         }
  397.         //---------------------------------------------------------
  398.         //否則要接收的是第0字節(jié)(即地址字節(jié))之后的數(shù)據(jù)
  399.         else
  400.         {   //如果后續(xù)接收過程中幀內(nèi)字節(jié)時間間隔未超過1.5個字符時間
  401.             if (T_BYTE == 0)
  402.             {   
  403.                 recv_Data[recv_idx++] = R;      //首先將有效字節(jié)保存到接收緩沖
  404.                 //如果接收到的地址字節(jié)(第0字節(jié))后的字節(jié)(即第1字節(jié))不等于操作碼
  405.                 //則將接收緩沖索引歸0,并重設(shè)T1定時長度為幀間隔時長
  406.                 //(注意recv_idx == 2時,剛剛保存R是第1字節(jié))
  407.                 if ( recv_idx == 2 && R != ADC_REQ) { Set_TIMER1(FRAME_SPAN); }
  408.                 //如果接收到來自主機(jī)的完整的4個字節(jié)數(shù)據(jù):(本機(jī)地址,命令碼,兩字節(jié)CRC)
  409.                 else if (recv_idx == 4)
  410.                 {   
  411.                     Set_TIMER1(FRAME_SPAN);     //重設(shè)T1定時長度為幀間隔時長
  412.                     Recv_OK = 1;                //設(shè)置接收成功標(biāo)識為真
  413.                 }
  414.                 else { Set_TIMER1(BYTE_SPAN); } //重設(shè)T1定時長度為幀內(nèi)字節(jié)間的時長
  415.             }
  416.             //同一幀內(nèi)字符間的時間超時,重設(shè)T1為幀之間的時間間隔
  417.             else  { Set_TIMER1(FRAME_SPAN); }
  418.         }
  419.         //---------------------------------------------------------
  420.     }
  421. }
復(fù)制代碼

評分

參與人數(shù) 3黑幣 +58 收起 理由
1559705228 + 3 回帖助人的獎勵!
chtyise + 5 贊一個!
admin + 50 共享資料的黑幣獎勵!

查看全部評分

分享到:  QQ好友和群QQ好友和群 QQ空間QQ空間 騰訊微博騰訊微博 騰訊朋友騰訊朋友
收藏收藏4 分享淘帖 頂1 踩

相關(guān)帖子

回復(fù)

使用道具 舉報(bào)

沙發(fā)
ID:122531 發(fā)表于 2017-2-19 16:16 | 只看該作者
請問一下樓主,CRC校驗(yàn)是怎么實(shí)現(xiàn)的?
回復(fù)

使用道具 舉報(bào)

板凳
ID:97308 發(fā)表于 2017-4-20 09:26 | 只看該作者
這個不錯,正需要,謝謝
回復(fù)

使用道具 舉報(bào)

地板
ID:97308 發(fā)表于 2017-4-20 09:28 | 只看該作者
void CRC16(INT8U d)
{

}
這段程序是空的,要自己找
回復(fù)

使用道具 舉報(bào)

5#
ID:97308 發(fā)表于 2017-4-20 09:38 | 只看該作者
/*********************************************************************************/  
/*函數(shù)名稱: GetCRC16()                           
*輸入?yún)?shù):  共  個參數(shù);  
*輸出參數(shù):  共  個參數(shù);  
*返回值:   
*需儲存的參數(shù): 共  個參數(shù);      
*功能介紹:   
        (1)CRC16校驗(yàn); 返回校驗(yàn)碼;               
*修改日志:  
*[2005-11-28 16:40]    Ver. 1.00  
        開始編寫;  
        完成;                                      
/*                                      */  
/*********************************************************************************/  
  
unsigned short GetCRC16(unsigned char *puchMsg, unsigned short usDataLen)   
{   
    /* CRC 高位字節(jié)值表 */   
    unsigned char auchCRCHi[256] = {  
    0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,   
    0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,   
    0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,   
    0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,   
    0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1,   
    0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,   
    0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1,   
    0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,   
    0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,   
    0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40,   
    0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1,   
    0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,   
    0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,   
    0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40,   
    0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,   
    0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,   
    0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,   
    0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,   
    0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,   
    0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,   
    0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,   
    0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40,   
    0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1,   
    0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,   
    0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,   
    0x80, 0x41, 0x00, 0xC1, 0x81, 0x40  
    };   
      
    unsigned char auchCRCLo[256] = {  
    0x00, 0xC0, 0xC1, 0x01, 0xC3, 0x03, 0x02, 0xC2, 0xC6, 0x06,   
    0x07, 0xC7, 0x05, 0xC5, 0xC4, 0x04, 0xCC, 0x0C, 0x0D, 0xCD,   
    0x0F, 0xCF, 0xCE, 0x0E, 0x0A, 0xCA, 0xCB, 0x0B, 0xC9, 0x09,   
    0x08, 0xC8, 0xD8, 0x18, 0x19, 0xD9, 0x1B, 0xDB, 0xDA, 0x1A,   
    0x1E, 0xDE, 0xDF, 0x1F, 0xDD, 0x1D, 0x1C, 0xDC, 0x14, 0xD4,   
    0xD5, 0x15, 0xD7, 0x17, 0x16, 0xD6, 0xD2, 0x12, 0x13, 0xD3,   
    0x11, 0xD1, 0xD0, 0x10, 0xF0, 0x30, 0x31, 0xF1, 0x33, 0xF3,   
    0xF2, 0x32, 0x36, 0xF6, 0xF7, 0x37, 0xF5, 0x35, 0x34, 0xF4,   
    0x3C, 0xFC, 0xFD, 0x3D, 0xFF, 0x3F, 0x3E, 0xFE, 0xFA, 0x3A,   
    0x3B, 0xFB, 0x39, 0xF9, 0xF8, 0x38, 0x28, 0xE8, 0xE9, 0x29,   
    0xEB, 0x2B, 0x2A, 0xEA, 0xEE, 0x2E, 0x2F, 0xEF, 0x2D, 0xED,   
    0xEC, 0x2C, 0xE4, 0x24, 0x25, 0xE5, 0x27, 0xE7, 0xE6, 0x26,   
    0x22, 0xE2, 0xE3, 0x23, 0xE1, 0x21, 0x20, 0xE0, 0xA0, 0x60,   
    0x61, 0xA1, 0x63, 0xA3, 0xA2, 0x62, 0x66, 0xA6, 0xA7, 0x67,   
    0xA5, 0x65, 0x64, 0xA4, 0x6C, 0xAC, 0xAD, 0x6D, 0xAF, 0x6F,   
    0x6E, 0xAE, 0xAA, 0x6A, 0x6B, 0xAB, 0x69, 0xA9, 0xA8, 0x68,   
    0x78, 0xB8, 0xB9, 0x79, 0xBB, 0x7B, 0x7A, 0xBA, 0xBE, 0x7E,   
    0x7F, 0xBF, 0x7D, 0xBD, 0xBC, 0x7C, 0xB4, 0x74, 0x75, 0xB5,   
    0x77, 0xB7, 0xB6, 0x76, 0x72, 0xB2, 0xB3, 0x73, 0xB1, 0x71,   
    0x70, 0xB0, 0x50, 0x90, 0x91, 0x51, 0x93, 0x53, 0x52, 0x92,   
    0x96, 0x56, 0x57, 0x97, 0x55, 0x95, 0x94, 0x54, 0x9C, 0x5C,   
    0x5D, 0x9D, 0x5F, 0x9F, 0x9E, 0x5E, 0x5A, 0x9A, 0x9B, 0x5B,   
    0x99, 0x59, 0x58, 0x98, 0x88, 0x48, 0x49, 0x89, 0x4B, 0x8B,   
    0x8A, 0x4A, 0x4E, 0x8E, 0x8F, 0x4F, 0x8D, 0x4D, 0x4C, 0x8C,   
    0x44, 0x84, 0x85, 0x45, 0x87, 0x47, 0x46, 0x86, 0x82, 0x42,   
    0x43, 0x83, 0x41, 0x81, 0x80, 0x40  
    };  
      
    unsigned char uchCRCHi = 0xFF ; /* 高CRC字節(jié)初始化 */   
    unsigned char uchCRCLo = 0xFF ; /* 低CRC 字節(jié)初始化 */   
    unsigned uIndex = 0; /* CRC循環(huán)中的索引 */   
      
    while (usDataLen--) /* 傳輸消息緩沖區(qū) */   
    {   
        uIndex = uchCRCHi ^ *puchMsg++ ; /* 計(jì)算CRC */   
        uchCRCHi = uchCRCLo ^ auchCRCHi[uIndex] ;   
        uchCRCLo = auchCRCLo[uIndex] ;   
    }   
    return (unsigned short)((unsigned short)uchCRCHi << 8 | uchCRCLo) ;   
}   
/*****************************************************************************/  
回復(fù)

使用道具 舉報(bào)

6#
ID:211380 發(fā)表于 2017-6-15 02:37 | 只看該作者
謝謝樓主分享
回復(fù)

使用道具 舉報(bào)

7#
ID:48413 發(fā)表于 2017-8-7 18:19 | 只看該作者
謝謝共享學(xué)習(xí)一下
回復(fù)

使用道具 舉報(bào)

8#
ID:240143 發(fā)表于 2017-10-17 10:05 | 只看該作者
重新編譯后仿真沒顯示呀。請問程序是不是還有問題?
回復(fù)

使用道具 舉報(bào)

9#
ID:268556 發(fā)表于 2018-1-3 15:49 | 只看該作者
太誘人了,可是我沒有權(quán)限不能下載
回復(fù)

使用道具 舉報(bào)

10#
ID:275802 發(fā)表于 2018-1-14 12:58 | 只看該作者
感謝分享
回復(fù)

使用道具 舉報(bào)

11#
ID:292657 發(fā)表于 2018-3-16 11:01 | 只看該作者
十分誘人啊!收藏先
回復(fù)

使用道具 舉報(bào)

12#
ID:161634 發(fā)表于 2018-4-9 17:32 | 只看該作者
贊。。。。!
回復(fù)

使用道具 舉報(bào)

13#
ID:302666 發(fā)表于 2018-4-11 20:08 | 只看該作者
版主解釋的很詳細(xì)
回復(fù)

使用道具 舉報(bào)

14#
ID:326624 發(fā)表于 2018-5-10 11:06 | 只看該作者
感謝分享,很詳細(xì)
回復(fù)

使用道具 舉報(bào)

15#
ID:335780 發(fā)表于 2018-5-22 17:08 | 只看該作者
好資料,51黑有你更精彩!!!
回復(fù)

使用道具 舉報(bào)

16#
ID:249901 發(fā)表于 2018-5-24 20:47 | 只看該作者
樓主玩的可以的!
回復(fù)

使用道具 舉報(bào)

17#
ID:165117 發(fā)表于 2018-5-27 16:59 | 只看該作者
好資料,51黑有你更精彩!!!
回復(fù)

使用道具 舉報(bào)

18#
ID:86450 發(fā)表于 2018-8-14 22:55 來自手機(jī) | 只看該作者
zhili 發(fā)表于 2017-4-20 09:28
void CRC16(INT8U d)
{


厲害了,謝謝樓主
回復(fù)

使用道具 舉報(bào)

19#
ID:388231 發(fā)表于 2018-8-21 10:53 | 只看該作者
學(xué)習(xí)啦
回復(fù)

使用道具 舉報(bào)

20#
ID:389439 發(fā)表于 2019-6-21 15:41 | 只看該作者
這個可以有,好好消化一下
回復(fù)

使用道具 舉報(bào)

21#
ID:48413 發(fā)表于 2019-8-29 20:27 | 只看該作者

謝謝共享學(xué)習(xí)一下
回復(fù)

使用道具 舉報(bào)

22#
ID:119977 發(fā)表于 2019-9-16 16:20 | 只看該作者
樓主您這是什么開發(fā)環(huán)境    我也想玩PIC
回復(fù)

使用道具 舉報(bào)

23#
ID:592524 發(fā)表于 2019-9-26 21:26 | 只看該作者
這個不錯,謝謝。
另外樓主用的是什么編譯器呢?
回復(fù)

使用道具 舉報(bào)

24#
ID:574127 發(fā)表于 2019-10-8 15:02 | 只看該作者
謝謝共享學(xué)習(xí)一下
回復(fù)

使用道具 舉報(bào)

25#
ID:494559 發(fā)表于 2019-12-7 12:43 | 只看該作者
謝謝共享學(xué)習(xí)一下
回復(fù)

使用道具 舉報(bào)

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

本版積分規(guī)則

手機(jī)版|小黑屋|51黑電子論壇 |51黑電子論壇6群 QQ 管理員QQ:125739409;技術(shù)交流QQ群281945664

Powered by 單片機(jī)教程網(wǎng)

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