找回密码
 立即注册
查看: 984|回复: 2

分享一个关于Modbus的工程【内部还有其他外设部分】

[复制链接]

该用户从未签到

1

主题

2

回帖

44

积分

新手上路

积分
44
发表于 2023-5-6 15:30:25 | 显示全部楼层 |阅读模式
最近接触到了STC32G的单片机,一开始使用寄存器觉得很不习惯,因为以前一直是在使用STM32系列的所以使用库函数习惯,但是当学习了STC32才感慨到这个单片机也是“确实挺不错的”。
下面分享一下我写的关于使用RS485实现modbus的功能,使用的功能码是【03/06】。

先和大家分享一下我对于03和06功能码的理解吧:

/==================================03功能码,一共是8位=============================================/
主机发送:     0             1           2 3            4 5                6 7                03功能码其实就是读多个寄存器里面的数据
                从机地址  功能码    起始地址    数据长度      CRC校验码
从机回复:    0             1              2               34                 56           .....      (n-1)n
                从机地址  功能码   读取字节数  寄存器数据1         寄存器数据2   .....       CRC校验码
/=============================================================================================/
/==================================06功能码,一共是8位 ======================================== =====/
主机发送:    0           1             2 3             4 5               6 7                06功能码其实就是写一个寄存器里面的数据
             从机地址  功能码   寄存器地址    写入的数据         CRC校验码
从机回复:和主机发送的一样
/==============================================================================================/

在这个例程中,我们将使用DMA_I2C或者I2C去读写我们的EEPROM,这里我们使用的型号是AT24C64。

首先是这个项目应该是主要建立在USART和I2C之上的,因此我们应该着重配置这两个部分,我在这里使用的是库函数版本,因为真的很好用!
个人觉得假如学过51系列的单片机的话,使用STC32G的库函数版本,然后哪里不懂得或者忘了再去找其定义的寄存器,这样的过程是很有趣的一件事。
  1. /*                                             USART4的配置函数                                            */
复制代码
  1. /*                                             DMA-I2C配置函数                                            */
复制代码
以上是关于I2C的配置,因为是使用的库函数版本,我也就不过多赘述了,毕竟手册里和例程里面讲的比我还详细!
下面最主要的是来说明一下,modbus——rtu函数是怎么编写的。
我使用了一种比较暴力的编写方式,就是按部就班的编写,modbus规定了什么我们就编写什么。
因为06是写单个寄存器,03是读多个寄存器,因此我们在里面进行相关操作。
  1. void modbus_func(){
  2. <div style="text-align: left;"><p style="line-height: 30px; text-indent: 2em;"></p>
  3. <div><p style="line-height: 30px; text-indent: 2em;"></p>
  4. <div>uint16 addr;                //寄存器地址【03/06】
  5. uint8 addh,addl;        //高地址,低地址【03/06】
  6. uint16 crcData;        //CRC校验码【03/06】
  7. uint16 readCount;        //需要读出的数据的寄存器长度【03】
  8. uint8 byteCount;        //需要读出的数据的字节长度【03】
  9. uint8 sendCount;        //需要发送的数据的字节长度【03】
  10. uint8 status,i;                         //验证位,循环量
  11. addr = 0;
  12. addr=(RX4_Buffer[2]<<8)+RX4_Buffer[3];//读取地址【03/06】
  13. addh=addr>>8;                //高地址【03/06】
  14. addl=addr& 0xff;        //低地址【03/06】
  15. TX4_Buffer[0] = SL_ADDREESS;//返回本机地址【03/06】
  16. if(RX4_Buffer[1]==0x06){
  17. <b><i><u><font color="#800080">//str[0]=RX4_Buffer[4];</font></u></i></b>
  18. <b><i><u><font color="#800080">str[1]=RX4_Buffer[5];</font></u></i></b>
  19. <b><i><u><font color="#800080">I2C_Write_16add(addh,addl,str,1);</font></u></i></b>
  20. TX4_Buffer[1] = 0x06;                                                                //06功能码
  21. TX4_Buffer[2] = RX4_Buffer[2];                                                                //返回高地址
  22. TX4_Buffer[3] = RX4_Buffer[3];                                                                //返回低地址
  23. TX4_Buffer[4] = RX4_Buffer[4];                                        //原样返回数据
  24. TX4_Buffer[5] = RX4_Buffer[5];
  25. crcData = Modbus_Rtu_CRC(TX4_Buffer,6);                //CRC校验部分
  26. TX4_Buffer[6] = crcData & 0xff;
  27. TX4_Buffer[7] = crcData >> 8;
  28. USART4_SendArr(TX4_Buffer,8);
  29. delay_ms(2);
  30. }
  31. else if(RX4_Buffer[1]==0x03){
  32. readCount = (RX4_Buffer[4]<<8) | RX4_Buffer[5];        //要读的寄存器个数
  33. byteCount = readCount * 2;                                                                //要读字节个数
  34. TX4_Buffer[1] = 0x03;                                                                        //03功能码
  35. TX4_Buffer[2] = byteCount&0xff;                                                //读取的字节数
  36. <b><i><u><font color="#ff8c00">I2C_Read_16add(addh,addl,str,byteCount);</font></u></i></b>
  37. <b><i><u><font color="#ff8c00">for(i=0;i<byteCount;i+=2)        //先是34后是56所以i+2</font></u></i></b>
  38. <b><i><u><font color="#ff8c00">{</font></u></i></b>
  39. <b><i><u><font color="#ff8c00">TX4_Buffer[i+3] = str[i];</font></u></i></b>
  40. <b><i><u><font color="#ff8c00">TX4_Buffer[i+4] = str[i+1];</font></u></i></b>
  41. <b><i><u><font color="#ff8c00">}</font></u></i></b>
  42. byteCount=byteCount+3;
  43. crcData = Modbus_Rtu_CRC(TX4_Buffer,byteCount);
  44. TX4_Buffer[byteCount] = crcData & 0xff;
  45. byteCount++;
  46. TX4_Buffer[byteCount] = crcData >> 8;
  47. sendCount = byteCount + 1;
  48. USART4_SendArr(TX4_Buffer,sendCount);
  49. delay_ms(2);
  50. }</div><p></p></div><p></p></div><p style="line-height: 30px; text-indent: 2em;"></p><div style="text-align: left;">}</div>
复制代码
然后是CRC校验部分,对于这个函数,建议不研究算法的同学可以直接拿来使用,网上也有很多写的方法,例如查表法,那样更快,但我还是喜欢这个计算的。
  1. u16 Modbus_Rtu_CRC(uint8 *Data,uint16 len){
  2.                                                                                         //我们返回的CRC校验码是两个字节
  3.         uint16 crc_16 = 0xffff;                        //预设CRC寄存器为all_1
  4.         uint16  value = 0xA001;                        //CRC寄存器后面与0XA001进行异或
  5.         char i,j;
  6.         for(i = 0;i< len;i++){
  7.                 crc_16 ^= Data[i];                                 //把第1个8bit B数据(既通讯信息帧的第一个字节)与16位的crc_16寄存器的低8位相异或,把结果放于CRC寄存器;
  8.                 for(j = 0;j < 8;j++){                //因为是8位数据因此需要移动8次
  9.                         if(crc_16&1){                                        //检测移出的数据是否等于1
  10.                                 crc_16>>=1;                                       
  11.                                 crc_16^=value;                                //等于1就去异或0xA001
  12.                         }else{
  13.                                 crc_16>>=1;                                        //不等于1就直接移走
  14.                         }
  15.                 }
  16.         }       
  17.         return crc_16;                                                        //返回校验码
  18. }
复制代码

最后奉上我滴工程。请大家批评指正












modbus_rtu - 副本.rar

562.95 KB, 下载次数: 85

源码

回复 送花

使用道具 举报

该用户从未签到

1

主题

2

回帖

44

积分

新手上路

积分
44
 楼主| 发表于 2023-5-6 15:31:57 | 显示全部楼层
貌似发的时候有点问题,实在是抱歉啊,大家从末尾的文件下载吧
回复 支持 反对 送花

使用道具 举报

  • TA的每日心情
    开心
    2024-1-24 13:08
  • 签到天数: 1 天

    [LV.1]初来乍到

    8

    主题

    647

    回帖

    1088

    积分

    超级版主

    积分
    1088
    发表于 2023-5-6 15:47:18 | 显示全部楼层
    本帖最后由 STCAI-32位8051 于 2023-5-6 15:49 编辑

    收到,学习,感谢,家里就下面这些好东西,
    还是 【免费+包邮】送您全家桶一套
    1, STC32G12K128实验箱
    2, STC8H8K64U实验箱
    3, STC一箭双雕之USB转双串口
    4, 开天斧-STC8H8K64U核心功能实验板
    5, 屠龙刀-STC8H8K64U核心功能实验板
    6, STC-USB Link1D
    ===家里就这些好东西了,各送一套,聊表谢意.
      麻烦楼主加我QQ我来给您安排,QQ号:2593903262
                                               微信也可:18106296598
    STC官网:https://www.stcai.com/
    QQ:2593903262
    微信号:18106296598
    回复 支持 反对 送花

    使用道具 举报

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

    本版积分规则

    QQ|手机版|深圳国芯人工智能有限公司 ( 粤ICP备2022108929号-2 )

    GMT+8, 2024-5-15 05:22 , Processed in 0.060554 second(s), 39 queries .

    Powered by Discuz! X3.5

    © 2001-2024 Discuz! Team.

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