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

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

[复制链接]

1

主题

2

回帖

66

积分

注册会员

积分
66
发表于 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, 下载次数: 181

源码

回复

使用道具 举报 送花

1

主题

2

回帖

66

积分

注册会员

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

使用道具 举报 送花

  • 打卡等级:偶尔看看III
  • 打卡总天数:32
  • 最近打卡:2025-04-30 10:59:33

25

主题

1154

回帖

2391

积分

超级版主

积分
2391
发表于 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, 2025-5-3 12:48 , Processed in 0.111180 second(s), 60 queries .

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

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