找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 13253|回复: 24
打印 上一主题 下一主题
收起左侧

PIC单片机MODBUS总线通信仿真及程序源码

  [复制链接]
跳转到指定楼层
楼主
一、MODBUS总线通信仿真(主机程序)
说明: 本例运行时,主机向各从机发送要求返回A/D转换值的命令码,在主机
完整接收到从机A/D数据后,在液晶上刷新显示.
二、MODBUS总线通信仿真(从机程序)
说明: 本例运行时,从机接收主机命令,然后将A/D转换值通过485回发给主机显示.


所有资料下载:
PIC单片机MODBUS总线通信仿真.zip (395.9 KB, 下载次数: 266)

主机程序部分预览:
  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];           //串口接收数据缓冲区(6字节)
  15. volatile INT8U recv_idx = 0;           //串口接收数据缓冲区索引
  16. volatile INT8U sl_Addr;                //485从机地址
  17. INT8U  LCD_Buffer[16];                 //LCD显示缓冲            
  18. INT16U CRC;                            //16位CRC校验结果
  19. //-----------------------------------------------------------------
  20. #define  LED_Recv  RB6                 //主机接收指示灯
  21. #define  LED_Send  RB7                 //主机发送指示灯
  22. #define  RDE_485   RC5                 //RS485通信控制端
  23. #define  ADC_REQ   65                  //要求从机返回A/D值的自定义命令码(范围65~72)
  24. //19200波特率每字符时间为: 1/19200*(1+8+2) ≈  572us
  25. //帧  间: 3.5个字符时间为: 572 * (3.5 + 1) ≈ 2574us
  26. //字节间: 1.5个字符时间为: 572 * (1.5 + 1) ≈ 1430us
  27. #define FRAME_SPAN  2574                  //相临帧之间的间隔时间
  28. #define BYTE_SPAN   1430                  //帧内字节之间的间隔时间
  29. bit     b, F_T1, T_BYTE, T_FRAME, Recv_OK;//相关标识位
  30. //-----------------------------------------------------------------
  31. // 宏定义: 发送一字节并等待发送结束
  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. // 宏定义: 设置TIMER1的定时初值并设相关标志位
  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;                            //选择高速波特率发生模式
  57.     TXEN = 1;                            //允许发送数据
  58.     SPBRG = _XTAL_FREQ/16/19200 - 1;     //设置波特率为19200  
  59.     SPEN = 1;                            //串行通信端口打开
  60.     CREN = 1;                            //使能连续接收串行数据
  61. }

  62. //-----------------------------------------------------------------
  63. // 外设初始化(定时器,485等)
  64. //-----------------------------------------------------------------
  65. void Per_Initialize()
  66. {   
  67.     //端口数据方向配置
  68.     TRISC7 = TRISC6 = 1; TRISC5 = 0;     //设置连接485的三只引脚的数据方向
  69.     TRISB6 = TRISB7 = 0;                 //主机收/发指示灯引脚设为输出
  70.     //配置定时器TIMER0
  71.     T0CS = 0;                            //选择内部系统时钟源
  72.     PSA = 0; PS2 = 1;PS1 = 0; PS0 = 1;   //预分频器分配给TIMER0,PS:101->64分频   
  73.     //配置USART
  74.     Serial_port_init();                  //串口初始化
  75.     RDE_485 = 1;                         //允许485发送(禁止接收)
  76.     //中断控制
  77.     RCIE = 1;                            //允许串口接收中断
  78.     TMR1IE = 1;                          //允许TMR1溢出中断
  79.     PEIE = 1;                            //允许外设中断(TMR1,USART均为PIC外设)
  80.     GIE = 1;                             //开中断
  81.     TMR1ON = 1;                          //启动TIMER1(默认为1:1分频)
  82. }

  83. //-----------------------------------------------------------------
  84. // CRC16校验函数 (基于该函数可得出512字节的校验码表,改用查表法进行校验)
  85. // 多项式: 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);      //等待足够时间,待从机完成初始化
  97.     Per_Initialize();     //外设初始化
  98.     LCD_Initialize();     //LCD初始化
  99.     //输出系统封面文字(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.         // 循环访问地址为0x01~0x04的4个485从机
  111.         //---------------------------------------------------------
  112.         for (sl_Addr = 0x01; sl_Addr <= 0x04; sl_Addr++)
  113.         {   
  114.             LED_Send = 0;               //主机发送指示灯开
  115.             RDE_485 = 1;                //允许485发送(禁止接收)
  116.             Send_Byte(sl_Addr);         //(1)发送从机地址
  117.             Send_Byte(ADC_REQ);         //(2)发送操作命令码(要求从机返回A/D值)
  118.             CRC = 0xFFFF;               //CRC校验复位
  119.             CRC16(sl_Addr);             //当前从机地址校验
  120.             CRC16(ADC_REQ);             //当前操作命令码校验
  121.             Send_Byte(CRC);             //(3)发送校验码低字节
  122.             Send_Byte(CRC>>8);          //(4)发送校验码高字节
  123.             Set_TIMER1(FRAME_SPAN);     //用TIMER1控制相邻帧之间的时间间隔
  124.             Recv_OK = 0;                //先设接收成功标识为假
  125.             RDE_485 = 0;                //允许485接收(禁止发送)
  126.             //用TIMER0定时器控制接收一部从机数据的超时时间为10ms
  127.             TMR0 = (INT8U)(256 - _XTAL_FREQ / 4 / 64 * 0.01);
  128.             T0IF = 0;                   //清除T0中断标志
  129.             LED_Send = 1;               //主机发送指示灯关
  130.             //如果主机接收从机数据未完成且未超时(10ms)则等待
  131.             while(!Recv_OK && !T0IF);
  132.             //-----------------------------------------------------
  133.             //如果主机接收从数据成功则继续下面的处理
  134.             if (Recv_OK)
  135.             {   GIE = 0;                //关中断
  136.                 Recv_OK = 0;            //接收成功标志重设为假
  137.                 CRC = 0xFFFF;           //CRC校验初始化
  138.                 //对来自当前从机的6字节数据进行CRC校验
  139.                 for (i = 0; i < 6; i++) CRC16(recv_Data[i]);
  140.                 //校验通过时显示
  141.                 if (CRC == 0x0000)
  142.                 {
  143.                     LED_Send = 1;            //主机发送指示灯关闭
  144.                     //从机发送的6字节分别是:站号/命令码/两字节数据(模数值)/两字节CRC
  145.                     //recv_Data[2],[3]所保存的是从机返回的模/数转换值
  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.                     //发送到LCD显示(显示LCD的下两行,每行显示两组)
  151.                     LCD_ShowString(
  152.                       (INT8U)(sl_Addr-1)/2+2,(sl_Addr&0x01)?0:9, LCD_Buffer);
  153.                 }
  154.             }
  155.             //每完成一个从机数据处理后延时10ms再开中断
  156.             __delay_ms(10); GIE = 1;
  157.             //-----------------------------------------------------
  158.         }
  159.         __delay_ms(10); //每完成一轮(4个从机)扫描后等待10ms
  160.     }
  161. }

  162. //-----------------------------------------------------------------
  163. // 主机定时中断及485接收中断服务程序
  164. //-----------------------------------------------------------------
  165. void interrupt ISR()
  166. {  
  167.     INT8U R;
  168.     //----------------------TIMER1定时器溢出中断--------------------
  169.     if (TMR1IF)
  170.     {   TMR1IF = 0;
  171.         //F_T1: 标识TIMER1定时器当前用于实现帧间隔时间定时还时字节间隔时间定时
  172.         //F_T1 = 0时,将帧间隔时间(3.5字符)到达设为假,字节间隔时间到达设为真
  173.         //F_T1 = 1时,将帧间隔时间(3.5字符)到达设为真,字节间隔时间到达设为假
  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;                   //主机接收指示灯闪烁
  181.         R = RCREG;                              //从串口(来自485)读取一字节
  182.         RCIF = 0;                               //清标志位(此行可省略)
  183.         Recv_OK = 0;                            //先暂时设接收成功标志为假
  184.         //---------------------------------------------------------
  185.         //如果当前要接收的是第0字节
  186.         if (recv_idx == 0)
  187.         {   //如果帧间时间间隔未到,或所收到的字节与设备地址不匹配
  188.             //则重新设TIMER1定时长度为帧间时长FRAME_SPAN
  189.             if (T_FRAME == 0 || R != sl_Addr) { Set_TIMER1(FRAME_SPAN); }
  190.             //否则表示接收的第0个字节与其设备地址匹配
  191.             else
  192.             {   recv_Data[recv_idx++] = R;      //字节R保存到接收缓冲recv_Data
  193.                 Set_TIMER1(BYTE_SPAN);          //重设T1定时长度为帧内字节间的时长
  194.             }
  195.         }
  196.         //---------------------------------------------------------
  197.         //否则要接收的是第0字节(即地址字节)之后的数据
  198.         else
  199.         {   //如果后续接收过程中帧内字节时间间隔未超过1.5个字符时间
  200.             if (T_BYTE == 0)
  201.             {   
  202.                 recv_Data[recv_idx++] = R;      //首先将有效字节保存到接收缓冲
  203.                 //如果接收到的地址字节(第0字节)后的字节(即第1字节)不等于操作码
  204.                 //则将接收缓冲索引归0,并重设T1定时长度为帧间隔时长
  205.                 //(注意recv_idx == 2时,刚刚保存R是第1字节)
  206.                 if ( recv_idx == 2 && R != ADC_REQ) { Set_TIMER1(FRAME_SPAN); }
  207.                 //如果接收到来自当前从机的完整的6个字节数据
  208.                 else if (recv_idx == 6)
  209.                 {   
  210.                     Set_TIMER1(FRAME_SPAN);     //重设T1定时长度为帧间隔时长
  211.                     Recv_OK = 1;                //设置接收成功标识为真
  212.                 }
  213.                 else { Set_TIMER1(BYTE_SPAN); } //重设T1定时长度为帧内字节间的时长
  214.             }
  215.             //同一帧内字符间的时间超时,重设T1为帧之间的时间间隔
  216.             else  { Set_TIMER1(FRAME_SPAN); }
  217.         }
  218.         //---------------------------------------------------------
  219.     }
  220. }</div><div>从机程序:</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,因为RA3/MCLR/VPP引脚用于485从机地址次高位输入
  227. __CONFIG(MCLRDIS & WDTDIS & INTIO);
  228. volatile INT8U recv_Data[4];           //串口接收数据缓冲区(4字节)
  229. volatile INT8U recv_idx = 0;           //串口接收数据缓冲区索引
  230. volatile INT8U sl_Addr;                //485从机地址           
  231. INT16U CRC;                            //16位CRC校验结果
  232. //-----------------------------------------------------------------
  233. #define  LED_Ptr   RC0                 //本机收/发指示灯
  234. #define  RDE_485   RC3                 //RS485通信控制端
  235. #define  ADC_REQ   65                  //要求从机返回A/D值的自定义命令码(范围65~72)
  236. //19200波特率每字符时间为: 1/19200*(1+8+2) ≈  572us
  237. //帧  间: 3.5个字符时间为: 572 * (3.5 + 1) ≈ 2574us
  238. //字节间: 1.5个字符时间为: 572 * (1.5 + 1) ≈ 1430us
  239. #define FRAME_SPAN  2574                  //相临帧之间的间隔时间
  240. #define BYTE_SPAN   1430                  //帧内字节之间的间隔时间
  241. bit     b, F_T1, T_BYTE, T_FRAME, Recv_OK;//相关标识位
  242. INT8U   AD_Result[2];                     //2字节的A/D转换结果
  243. //-----------------------------------------------------------------
  244. // 宏定义: 发送一字节并等待发送结束
  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. // 宏定义: 设置TIMER1的定时初值并设相关标志位
  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校验函数 (基于该函数可得出512字节的校验码表,改用查表法进行校验)
  266. // 多项式: X ^ 16 + X ^ 15 + X ^ 2 + 1, 去高位逆序表示:0xA001
  267. //-----------------------------------------------------------------
  268. void CRC16(INT8U d)
  269. {</div><div>
  270. </div><div>
  271. }
  272. //-----------------------------------------------------------------
  273. // 模/数转换函数
  274. //-----------------------------------------------------------------
  275. void AD_Convert()
  276. {
  277.     __delay_us(10);
  278.     GODONE = 1;                          //启动转换
  279.     while (ADIF == 0);                   //等待转换结束
  280.     ADIF = 0;                            //AD中断标志清0
  281.     AD_Result[1] = ADRESH;               //保存A/D结果的高字节
  282.     AD_Result[0] = ADRESL;               //保存A/D结果的低字节
  283. }
  284. //-----------------------------------------------------------------
  285. // 串口初始化
  286. //-----------------------------------------------------------------
  287. void Serial_port_init()
  288. {
  289.     SYNC = 0;                            //选择异步通信模式
  290.     BRGH = 1;                            //选择高速波特率发生模式
  291.     TXEN = 1;                            //允许发送数据
  292.     SPBRG = _XTAL_FREQ/16/19200 - 1;     //设置波特率为19200  
  293.     SPEN = 1;                            //串行通信端口打开
  294.     CREN = 1;                            //使能连续接收串行数据
  295. }
  296. //-----------------------------------------------------------------
  297. // 外设初始化(定时器,485等)
  298. //-----------------------------------------------------------------
  299. void Per_Initialize()
  300. {   
  301.     GIE = 0;                             //禁止中断
  302.     TRISC = 0B00110000;                  //设置串行通讯端口及LED指示灯端口方向
  303.     LED_Ptr = 0;                         //收/发指示灯关闭
  304.     RDE_485 = 1;                         //禁止从机485接收
  305.     PORTA = 0x00;                        //初始化PORTA
  306.     WPUA = 0xFF;                         //使能PORTA相应引脚的弱上拉
  307.     TRISA = 0xFF;                        //PORTA所有引脚全部设为输入
  308.     ANSEL = 0x01;                        //PORTA的RA0设为模拟输入
  309.     sl_Addr = (PORTA >> 1) & 0x0F;       //获取所设置的本机地址
  310.     Serial_port_init();                  //串口初始化  
  311.     OSCCON = 0B01101000;                 //使用默认的4M内部振荡器
  312.     ADCON0 = 0B10000001;                 //选择0通道,A/D结果右对齐,使能A/D
  313.     ADCON1 = 0B01010000;                 //AD转换时钟选择位ADCS<2:0>=101,选择FOSC/16   
  314.     RCIE = 1;                            //允许串口接收中断
  315.     TMR1IE = 1;                          //允许TMR1溢出中断
  316.     PEIE = 1;                            //允许外设中断(TMR1,USART均为PIC外设)
  317.     GIE = 1;                             //开中断
  318.     RDE_485 = 0;                         //允许从机485接收(禁止发送)   
  319.     TMR1ON = 1;                          //启动TIMER1(默认为1:1分频)
  320.     __delay_us(2);
  321.     Set_TIMER1(FRAME_SPAN);              //用TIMER1控制相邻帧之间的时间间隔
  322.     Recv_OK = 0;                         //初始时三个标识全部设为0
  323. }
  324. //-----------------------------------------------------------------
  325. // 主程序
  326. //-----------------------------------------------------------------   
  327. void main()
  328. {
  329.     Per_Initialize();                    //外设初始化
  330.     while(1)
  331.     {
  332.        //如果本从机已经接收到完整的四个字节数据
  333.        if (Recv_OK)
  334.        {
  335.           GIE = 0;                       //关中断
  336.           Recv_OK = 0;                   //接收成功标志重设为假
  337.          //对待所接收的来自主机的4字节数据进行CRC校验
  338.           CRC = 0xFFFF;  for(INT8U i = 0; i < 4; i++) CRC16(recv_Data[i]);
  339.           //校验通过后开始向主机发送数据(6字节:本机地址,操作码,两字节A/D,两字节CRC)
  340.           if (CRC == 0x0000)
  341.           {
  342.              RDE_485 = 1;                //允许发送,禁止接收
  343.              __delay_ms(1);              //延时1ms
  344.              AD_Convert();               //AN0通道进行模/数转换
  345.              __delay_ms(1);              //延时1ms               
  346.              Send_Byte(sl_Addr);         //回发本机地址
  347.              Send_Byte(ADC_REQ);         //回发A/D请求命令
  348.              Send_Byte(AD_Result[1]);    //回发A/D转换结果高字节
  349.              Send_Byte(AD_Result[0]);    //回发A/D转换结果低字节
  350.              CRC = 0xFFFF;               //先将16位的CRC检验变量置为全1
  351.              CRC16(sl_Addr);             //校验本机地址
  352.              CRC16(ADC_REQ);             //校验A/D请求命令
  353.              CRC16(AD_Result[1]);        //校验A/D结果高字节
  354.              CRC16(AD_Result[0]);        //校验A/D结果低字节
  355.              Send_Byte(CRC);             //最后发送两字节的CRC校验值
  356.              Send_Byte(CRC>>8);
  357.              RDE_485 = 0;                //发送结束后,再允许本机485接收
  358.           }
  359.           GIE = 1;                       //开中断
  360.        }
  361.     }
  362. }
  363. //-----------------------------------------------------------------
  364. // 485从机中断服务程序
  365. //-----------------------------------------------------------------
  366. void interrupt ISR()
  367. {  
  368.     INT8U R;
  369.     //----------------------TIMER1定时器溢出中断--------------------
  370.     if (TMR1IF)
  371.     {   TMR1IF = 0;
  372.         //F_T1: 标识TIMER1定时器当前用于实现帧间隔时间定时还时字节间隔时间定时
  373.         //F_T1 = 0时,将帧间隔时间(3.5字符)到达设为假,字节间隔时间到达设为真
  374.         //F_T1 = 1时,将帧间隔时间(3.5字符)到达设为真,字节间隔时间到达设为假
  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;                     //从机收/发指示灯闪烁
  382.         R = RCREG;                              //从串口(来自485)读取一字节
  383.         RCIF = 0;                               //清标志位(此行可省略)
  384.         Recv_OK = 0;                            //先暂时设接收成功标志为假
  385.         //---------------------------------------------------------
  386.         //如果当前要接收的是第0字节
  387.         if (recv_idx == 0)
  388.         {   //如果帧间时间间隔未到,或所收到的字节与设备地址不匹配
  389.             //则重新设TIMER1定时长度为帧间时长FRAME_SPAN
  390.             if (T_FRAME == 0 || R != sl_Addr) { Set_TIMER1(FRAME_SPAN); }
  391.             //否则表示接收的第0个字节与其设备地址匹配
  392.             else
  393.             {   recv_Data[recv_idx++] = R;      //字节R保存到接收缓冲
  394.                 Set_TIMER1(BYTE_SPAN);          //重设T1为帧内字节间时长
  395.             }
  396.         }
  397.         //---------------------------------------------------------
  398.         //否则要接收的是第0字节(即地址字节)之后的数据
  399.         else
  400.         {   //如果后续接收过程中帧内字节时间间隔未超过1.5个字符时间
  401.             if (T_BYTE == 0)
  402.             {   
  403.                 recv_Data[recv_idx++] = R;      //首先将有效字节保存到接收缓冲
  404.                 //如果接收到的地址字节(第0字节)后的字节(即第1字节)不等于操作码
  405.                 //则将接收缓冲索引归0,并重设T1定时长度为帧间隔时长
  406.                 //(注意recv_idx == 2时,刚刚保存R是第1字节)
  407.                 if ( recv_idx == 2 && R != ADC_REQ) { Set_TIMER1(FRAME_SPAN); }
  408.                 //如果接收到来自主机的完整的4个字节数据:(本机地址,命令码,两字节CRC)
  409.                 else if (recv_idx == 4)
  410.                 {   
  411.                     Set_TIMER1(FRAME_SPAN);     //重设T1定时长度为帧间隔时长
  412.                     Recv_OK = 1;                //设置接收成功标识为真
  413.                 }
  414.                 else { Set_TIMER1(BYTE_SPAN); } //重设T1定时长度为帧内字节间的时长
  415.             }
  416.             //同一帧内字符间的时间超时,重设T1为帧之间的时间间隔
  417.             else  { Set_TIMER1(FRAME_SPAN); }
  418.         }
  419.         //---------------------------------------------------------
  420.     }
  421. }
复制代码

评分

参与人数 3黑币 +58 收起 理由
1559705228 + 3 回帖助人的奖励!
chtyise + 5 赞一个!
admin + 50 共享资料的黑币奖励!

查看全部评分

分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏4 分享淘帖 顶1 踩
回复

使用道具 举报

沙发
ID:122531 发表于 2017-2-19 16:16 | 只看该作者
请问一下楼主,CRC校验是怎么实现的?
回复

使用道具 举报

板凳
ID:97308 发表于 2017-4-20 09:26 | 只看该作者
这个不错,正需要,谢谢
回复

使用道具 举报

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

}
这段程序是空的,要自己找
回复

使用道具 举报

5#
ID:97308 发表于 2017-4-20 09:38 | 只看该作者
/*********************************************************************************/  
/*函数名称: GetCRC16()                           
*输入参数:  共  个参数;  
*输出参数:  共  个参数;  
*返回值:   
*需储存的参数: 共  个参数;      
*功能介绍:   
        (1)CRC16校验; 返回校验码;               
*修改日志:  
*[2005-11-28 16:40]    Ver. 1.00  
        开始编写;  
        完成;                                      
/*                                      */  
/*********************************************************************************/  
  
unsigned short GetCRC16(unsigned char *puchMsg, unsigned short usDataLen)   
{   
    /* CRC 高位字节值表 */   
    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字节初始化 */   
    unsigned char uchCRCLo = 0xFF ; /* 低CRC 字节初始化 */   
    unsigned uIndex = 0; /* CRC循环中的索引 */   
      
    while (usDataLen--) /* 传输消息缓冲区 */   
    {   
        uIndex = uchCRCHi ^ *puchMsg++ ; /* 计算CRC */   
        uchCRCHi = uchCRCLo ^ auchCRCHi[uIndex] ;   
        uchCRCLo = auchCRCLo[uIndex] ;   
    }   
    return (unsigned short)((unsigned short)uchCRCHi << 8 | uchCRCLo) ;   
}   
/*****************************************************************************/  
回复

使用道具 举报

6#
ID:211380 发表于 2017-6-15 02:37 | 只看该作者
谢谢楼主分享
回复

使用道具 举报

7#
ID:48413 发表于 2017-8-7 18:19 | 只看该作者
谢谢共享学习一下
回复

使用道具 举报

8#
ID:240143 发表于 2017-10-17 10:05 | 只看该作者
重新编译后仿真没显示呀。请问程序是不是还有问题?
回复

使用道具 举报

9#
ID:268556 发表于 2018-1-3 15:49 | 只看该作者
太诱人了,可是我没有权限不能下载
回复

使用道具 举报

10#
ID:275802 发表于 2018-1-14 12:58 | 只看该作者
感謝分享
回复

使用道具 举报

11#
ID:292657 发表于 2018-3-16 11:01 | 只看该作者
十分诱人啊!收藏先
回复

使用道具 举报

12#
ID:161634 发表于 2018-4-9 17:32 | 只看该作者
赞!!!!!!
回复

使用道具 举报

13#
ID:302666 发表于 2018-4-11 20:08 | 只看该作者
版主解释的很详细
回复

使用道具 举报

14#
ID:326624 发表于 2018-5-10 11:06 | 只看该作者
感谢分享,很详细
回复

使用道具 举报

15#
ID:335780 发表于 2018-5-22 17:08 | 只看该作者
好资料,51黑有你更精彩!!!
回复

使用道具 举报

16#
ID:249901 发表于 2018-5-24 20:47 | 只看该作者
楼主玩的可以的!
回复

使用道具 举报

17#
ID:165117 发表于 2018-5-27 16:59 | 只看该作者
好资料,51黑有你更精彩!!!
回复

使用道具 举报

18#
ID:86450 发表于 2018-8-14 22:55 来自手机 | 只看该作者
zhili 发表于 2017-4-20 09:28
void CRC16(INT8U d)
{


厉害了,谢谢楼主
回复

使用道具 举报

19#
ID:388231 发表于 2018-8-21 10:53 | 只看该作者
学习啦
回复

使用道具 举报

20#
ID:389439 发表于 2019-6-21 15:41 | 只看该作者
这个可以有,好好消化一下
回复

使用道具 举报

21#
ID:48413 发表于 2019-8-29 20:27 | 只看该作者

谢谢共享学习一下
回复

使用道具 举报

22#
ID:119977 发表于 2019-9-16 16:20 | 只看该作者
楼主您这是什么开发环境    我也想玩PIC
回复

使用道具 举报

23#
ID:592524 发表于 2019-9-26 21:26 | 只看该作者
这个不错,谢谢。
另外楼主用的是什么编译器呢?
回复

使用道具 举报

24#
ID:574127 发表于 2019-10-8 15:02 | 只看该作者
谢谢共享学习一下
回复

使用道具 举报

25#
ID:494559 发表于 2019-12-7 12:43 | 只看该作者
谢谢共享学习一下
回复

使用道具 举报

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

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表