搜索

GD32F103实现modbus协议

[复制链接]
1180|19
 楼主 | 2020-12-18 17:16 | 显示全部楼层 |阅读模式
一、modbus
Modbus是一种串行通信协议,是Modicon公司(现在的施耐德电气Schneider Electric)于1979年为使用可编程逻辑控制器(PLC)通信而发表。
Modbus已经成为工业领域通信协议的业界标准(De facto),并且现在是工业电子设备之间常用的连接方式。在中国,Modbus 已经成为国家标准。
标准编号:GB/T19582-2008
标准名称:《基于 Modbus 协议的工业自动化网络规范》
分 3 个部分:
《GB/T 19582.1-2008 第 1 部分:Modbus 应用协议》
《GB/T 19582.2-2008 第 2 部分:Modbus 协议在串行链路上的实现指南》
《GB/T 19582.3-2008 第 3 部分: Modbus 协议在 TCP/IP 上的实现指南》


使用特权

评论回复
 楼主 | 2020-12-18 17:18 | 显示全部楼层
二、移植freemodbus

下载:要获取 FreeModbus 源码,我们可以直接从他们的官网:
https://www.embedded-solutions.at/en/freemodbus/获取

freemodbus-v1.6.zip

4.78 MB, 下载次数: 67

源码

使用特权

评论回复
 楼主 | 2020-12-18 17:20 | 显示全部楼层
zeshoufx 发表于 2020-12-18 17:18
二、移植freemodbus

下载:要获取 FreeModbus 源码,我们可以直接从他们的官网:

1、函数注册
  1. BOOL
  2. xMBPortTimersInit( USHORT usTim1Timerout50us )
  3. {
  4.         timer_parameter_struct timer_struct;
  5.         uint16_t  PrescalerValue=0;
  6.        
  7.         rcu_periph_clock_enable(RCU_TIMER3);
  8.         PrescalerValue = (uint16_t) (SystemCoreClock / 20000) - 1;
  9.        
  10.         timer_struct.alignedmode=TIMER_COUNTER_EDGE;
  11.         timer_struct.clockdivision=TIMER_CKDIV_DIV1;
  12.         timer_struct.counterdirection=TIMER_COUNTER_UP;
  13.         timer_struct.period=usTim1Timerout50us;
  14.         timer_struct.prescaler=PrescalerValue;
  15.         timer_struct.repetitioncounter=0;
  16.         timer_init(TIMER3,&timer_struct);
  17.        
  18.         timer_autoreload_value_config(TIMER3,usTim1Timerout50us);
  19.         nvic_irq_enable(TIMER3_IRQn,0,3);
  20.        
  21.         timer_interrupt_flag_clear(TIMER3,TIMER_INT_FLAG_UP);
  22.         timer_interrupt_disable(TIMER3,TIMER_INT_UP);
  23.         timer_disable(TIMER3);
  24.     return TRUE;
  25. }
复制代码


使用特权

评论回复
 楼主 | 2020-12-18 17:21 | 显示全部楼层

2、vMBPortTimersEnable和vMBPortTimersDisable函数注册
  1. void
  2. vMBPortTimersEnable(  )
  3. {
  4.     /* Enable the timer with the timeout passed to xMBPortTimersInit( ) */
  5.         timer_interrupt_flag_clear(TIMER3,TIMER_INT_FLAG_UP);
  6.         timer_interrupt_enable(TIMER3,TIMER_INT_UP);
  7.         timer_counter_value_config(TIMER3,0);
  8.         timer_enable(TIMER3);
  9. }
复制代码
  1. void
  2. vMBPortTimersDisable(  )
  3. {
  4.     /* Disable any pending timers. */
  5.         timer_disable(TIMER3);
  6.         timer_counter_value_config(TIMER3,0);
  7.         timer_interrupt_disable(TIMER3,TIMER_INT_UP);
  8.         timer_interrupt_flag_clear(TIMER3,TIMER_INT_FLAG_UP);
  9. }
复制代码


使用特权

评论回复
 楼主 | 2020-12-18 17:22 | 显示全部楼层
zeshoufx 发表于 2020-12-18 17:21
2、vMBPortTimersEnable和vMBPortTimersDisable函数注册

3、定时器终端函数
  1. void TIMER3_IRQHandler(void)
  2. {
  3.         if(timer_interrupt_flag_get(TIMER3,TIMER_INT_FLAG_UP))
  4.         {
  5.                 prvvTIMERExpiredISR();
  6.                 timer_interrupt_flag_clear(TIMER3,TIMER_INT_FLAG_UP);
  7.         }
  8. }
复制代码


使用特权

评论回复
 楼主 | 2020-12-18 17:23 | 显示全部楼层
zeshoufx 发表于 2020-12-18 17:22
3、定时器终端函数

4、vMBPortSerialEnable函数注册
  1. void
  2. vMBPortSerialEnable( BOOL xRxEnable, BOOL xTxEnable )
  3. {
  4.     /* If xRXEnable enable serial receive interrupts. If xTxENable enable
  5.      * transmitter empty interrupts.
  6.      */
  7.         if(TRUE==xRxEnable)
  8.         {
  9.                 usart_interrupt_enable(USART1,USART_INT_RBNE);
  10.                 gpio_bit_reset(GPIOA,GPIO_PIN_1);
  11.         }
  12.         else
  13.         {
  14.                 usart_interrupt_disable(USART1,USART_INT_RBNE);
  15.                 gpio_bit_set(GPIOA,GPIO_PIN_1);
  16.         }
  17.        
  18.         if(TRUE==xTxEnable)
  19.         {
  20.                 usart_interrupt_enable(USART1,USART_INT_TBE);
  21.         }
  22.         else
  23.         {
  24.                 usart_interrupt_disable(USART1,USART_INT_TBE);
  25.         }
  26.        
  27. }
复制代码


使用特权

评论回复
 楼主 | 2020-12-18 17:24 | 显示全部楼层
zeshoufx 发表于 2020-12-18 17:23
4、vMBPortSerialEnable函数注册

5、xMBPortSerialInit函数注册
  1. BOOL
  2. xMBPortSerialInit( UCHAR ucPORT, ULONG ulBaudRate, UCHAR ucDataBits, eMBParity eParity )
  3. {
  4.         (void)ucPORT;
  5.         (void)ucDataBits;
  6.        
  7.         rcu_periph_clock_enable(RCU_GPIOA);
  8.         rcu_periph_clock_enable(RCU_USART1);
  9.        
  10.         gpio_init(GPIOA,GPIO_MODE_AF_PP,GPIO_OSPEED_50MHZ,GPIO_PIN_2);
  11.         gpio_init(GPIOA,GPIO_MODE_IN_FLOATING,GPIO_OSPEED_50MHZ,GPIO_PIN_3);
  12.        
  13.         gpio_init(GPIOA,GPIO_MODE_OUT_PP,GPIO_OSPEED_50MHZ,GPIO_PIN_1);
  14.        
  15.         usart_baudrate_set(USART1,ulBaudRate);
  16.         usart_stop_bit_set(USART1,USART_STB_1BIT);
  17.         usart_hardware_flow_cts_config(USART1,USART_CTS_DISABLE);
  18.         usart_hardware_flow_rts_config(USART1,USART_RTS_DISABLE);
  19.         usart_transmit_config(USART1,USART_TRANSMIT_ENABLE);
  20.         usart_receive_config(USART1,USART_RECEIVE_ENABLE);
  21.         switch(eParity)
  22.         {
  23.                 case MB_PAR_NONE:
  24.                 {
  25.                         usart_parity_config(USART1,USART_PM_NONE);
  26.                         usart_word_length_set(USART1,USART_WL_8BIT);
  27.                         usart_interrupt_disable(USART1,USART_INT_PERR);
  28.                         break;
  29.                 }
  30.                
  31.                 case MB_PAR_ODD:
  32.                 {
  33.                         usart_parity_config(USART1,USART_PM_ODD);
  34.                         usart_word_length_set(USART1,USART_WL_9BIT);
  35.                         usart_interrupt_enable(USART1,USART_INT_PERR);
  36.                         break;
  37.                 }
  38.                
  39.                 case MB_PAR_EVEN:
  40.                 {
  41.                         usart_parity_config(USART1,USART_PM_EVEN);
  42.                         usart_word_length_set(USART1,USART_WL_9BIT);
  43.                         usart_interrupt_enable(USART1,USART_INT_PERR);
  44.                         break;
  45.                 }
  46.                
  47.                 default :break;
  48.         }
  49.        
  50.         usart_enable(USART1);
  51.         nvic_irq_enable(USART1_IRQn,0,0);
  52.     return TRUE;
  53. }
复制代码


使用特权

评论回复
 楼主 | 2020-12-18 17:26 | 显示全部楼层
zeshoufx 发表于 2020-12-18 17:24
5、xMBPortSerialInit函数注册

6、发送字节、接收字节、及终端函数
  1. BOOL
  2. xMBPortSerialPutByte( CHAR ucByte )
  3. {
  4.     /* Put a byte in the UARTs transmit buffer. This function is called
  5.      * by the protocol stack if pxMBFrameCBTransmitterEmpty( ) has been
  6.      * called. */
  7.         usart_data_transmit(USART1,ucByte);
  8.         while(usart_flag_get(USART1,USART_FLAG_TC)==RESET){}
  9.     return TRUE;
  10. }
复制代码
  1. BOOL
  2. xMBPortSerialGetByte( CHAR * pucByte )
  3. {
  4.     /* Return the byte in the UARTs receive buffer. This function is called
  5.      * by the protocol stack after pxMBFrameCBByteReceived( ) has been called.
  6.      */
  7.         *pucByte=usart_data_receive(USART1);
  8.     return TRUE;
  9. }
复制代码
  1. void USART1_IRQHandler(void)
  2. {
  3.         if(usart_interrupt_flag_get(USART1,USART_INT_FLAG_PERR))
  4.         {
  5.                 eMBEnable();
  6.                 usart_interrupt_flag_clear(USART1,USART_INT_FLAG_PERR);
  7.         }
  8.         else
  9.         {
  10.                 if(usart_interrupt_flag_get(USART1,USART_INT_FLAG_RBNE))
  11.                 {
  12.                         prvvUARTRxISR();
  13.                         usart_interrupt_flag_clear(USART1,USART_INT_FLAG_RBNE);
  14.                 }
  15.                
  16.                 if(usart_interrupt_flag_get(USART1,USART_INT_FLAG_TBE))
  17.                 {
  18.                         prvvUARTTxReadyISR();
  19.                         usart_interrupt_flag_clear(USART1,USART_INT_FLAG_TBE);
  20.                 }
  21.         }
  22.        
  23.         if(usart_flag_get(USART1,USART_FLAG_ORERR))
  24.         {
  25.                 usart_flag_clear(USART1,USART_FLAG_ORERR);
  26.                 usart_data_receive(USART1);
  27.         }
  28. }
复制代码


使用特权

评论回复
 楼主 | 2020-12-18 17:28 | 显示全部楼层
zeshoufx 发表于 2020-12-18 17:26
6、发送字节、接收字节、及终端函数

7、port.h文件添加内容
  1. #define ENTER_CRITICAL_SECTION( )   INTX_DISABLE()
  2. #define EXIT_CRITICAL_SECTION( )    INTX_ENABLE()
复制代码



使用特权

评论回复

评论

你的灰 2021-2-1 09:01 回复TA
@zeshoufx : __asm void INTX_DISABLE(void) { CPSID I BX LR } __asm void INTX_ENABLE(void) { CPSIE I BX LR } 我指的是这个呢,编译时会报错 
zeshoufx 2021-1-29 20:43 回复TA
@你的灰 :我的bitband.c里没有汇编,, 
你的灰 2021-1-29 16:50 回复TA
楼主大大您好,我想问下这个bitband.c里的汇编部分无法在MDK里编译,您是如何解决这个问题的呢? 
 楼主 | 2020-12-18 17:28 | 显示全部楼层
zeshoufx 发表于 2020-12-18 17:28
7、port.h文件添加内容

8、demo.c内容
  1. #include "mb.h"
  2. #include "mbport.h"

  3. /* ----------------------- Defines ------------------------------------------*/
  4. #define REG_COILS_START 0x0001
  5. #define REG_COILS_SIZE 16
  6. unsigned char ucRegCoilsBuf[REG_COILS_SIZE / 8]={0X00,0X00};

  7. /* ----------------------- Static variables ---------------------------------*/
  8. #define REG_DISC_START 0x0001
  9. #define REG_DISC_SIZE 16
  10. unsigned char ucRegDiscBuf[REG_DISC_SIZE / 8] = { 0x0F, 0XF0 };

  11. /* ----------------------- Start implementation -----------------------------*/


  12. #define REG_INPUT_START 0x0001
  13. #define REG_INPUT_NREGS 8
  14. static USHORT usRegInputStart = REG_INPUT_START;
  15. static USHORT usRegInputBuf[REG_INPUT_NREGS]=
  16. {0x1111,0x2222,0x3333,0x4444,0x5555,0x6666,0x7777,0x8888};


  17. #define REG_HOLDING_START 0x0001 //保持寄存器起始地址
  18. #define REG_HOLDING_NREGS 8 //保持寄存器数量
  19. USHORT usRegHoldingStart = REG_HOLDING_START;
  20. USHORT usRegHoldingBuf[REG_HOLDING_NREGS]=
  21. {0X1100,0X2200,0X3300,0X4400,0X5500,0X6600,0X7700,0X8800};


  22. eMBErrorCode
  23. eMBRegInputCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNRegs )
  24. {
  25.         eMBErrorCode eStatus = MB_ENOERR;
  26.         int iRegIndex;

  27.         if( ( usAddress >= REG_INPUT_START )
  28.         && ( usAddress + usNRegs <= REG_INPUT_START + REG_INPUT_NREGS ) )
  29.         {
  30.                 iRegIndex = ( int )( usAddress - usRegInputStart );
  31.                 while( usNRegs > 0 )
  32.                 {
  33.                         *pucRegBuffer++ =
  34.                         ( unsigned char )( usRegInputBuf[iRegIndex] >> 8 );
  35.                         *pucRegBuffer++ =
  36.                         ( unsigned char )( usRegInputBuf[iRegIndex] & 0xFF );
  37.                         iRegIndex++;
  38.                         usNRegs--;
  39.                 }
  40.         }
  41.                 else
  42.                 {
  43.                         eStatus = MB_ENOREG;
  44.                 }

  45.                 return eStatus;
  46. }


  47. eMBErrorCode
  48. eMBRegHoldingCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNRegs,
  49. eMBRegisterMode eMode )
  50. {
  51.         eMBErrorCode eStatus = MB_ENOERR;
  52.         int iRegIndex;

  53.         if((usAddress>=REG_HOLDING_START) && (usAddress+usNRegs<=REG_HOLDING_START+REG_HOLDING_NREGS) )
  54.         {
  55.                 iRegIndex = ( int )( usAddress - usRegHoldingStart );
  56.                 switch ( eMode )
  57.                 {
  58.                 case MB_REG_READ:
  59.                                 while( usNRegs > 0 )
  60.                                 {
  61.                                         *pucRegBuffer++ = ( unsigned char )( usRegHoldingBuf[iRegIndex] >> 8 );
  62.                                         *pucRegBuffer++ = ( unsigned char )( usRegHoldingBuf[iRegIndex] & 0xFF );
  63.                                         iRegIndex++;

  64.                                         usNRegs--;
  65.                                 }
  66.                                 break;

  67.                 case MB_REG_WRITE:
  68.                                  while( usNRegs > 0 )
  69.                                  {
  70.                                         usRegHoldingBuf[iRegIndex] = *pucRegBuffer++ << 8;
  71.                                         usRegHoldingBuf[iRegIndex] |= *pucRegBuffer++;
  72.                                         iRegIndex++;
  73.                                         usNRegs--;
  74.                                 }
  75.                                 break;
  76.                 }
  77.         }
  78.         else
  79.         {
  80.                 eStatus = MB_ENOREG;
  81.         }
  82.         return eStatus;
  83. }


  84. eMBErrorCode
  85. eMBRegCoilsCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNCoils,eMBRegisterMode eMode )
  86. {
  87.         eMBErrorCode eStatus = MB_ENOERR;

  88.         int iNCoils = ( int )usNCoils;

  89.         unsigned short usBitOffset;

  90.         if( ( usAddress >= REG_COILS_START ) &&( usAddress + usNCoils <= REG_COILS_START + REG_COILS_SIZE ) )
  91.         {
  92.                 usBitOffset = ( unsigned short )( usAddress - REG_COILS_START );
  93.                 switch ( eMode )
  94.                 {
  95.                         /* Read current values and pass to protocol stack. */
  96.                         case MB_REG_READ:
  97.                         while( iNCoils > 0 )
  98.                         {
  99.                                 *pucRegBuffer++ = xMBUtilGetBits( ucRegCoilsBuf, usBitOffset, ( unsigned char )( iNCoils > 8 ? 8 :iNCoils ) );
  100.                         iNCoils -= 8;
  101.                         usBitOffset += 8;
  102.                         }
  103.                         break;

  104.         /* Update current register values. */
  105.                         case MB_REG_WRITE:
  106.                         while( iNCoils > 0 )
  107.                         {
  108.                                 xMBUtilSetBits( ucRegCoilsBuf, usBitOffset,( unsigned char )( iNCoils >8 ? 8 : iNCoils ), *pucRegBuffer++ );
  109.                                 iNCoils -= 8;
  110.                                 usBitOffset += 8;
  111.                         }
  112.                         break;
  113.                 }
  114.        
  115.         }
  116.         else
  117.         {
  118.                 eStatus = MB_ENOREG;
  119.         }
  120.         return eStatus;
  121. }

  122. eMBErrorCode
  123.         eMBRegDiscreteCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNDiscrete )
  124.         {
  125.                 eMBErrorCode eStatus = MB_ENOERR;
  126.                 short iNDiscrete = ( short )usNDiscrete;
  127.                 unsigned short usBitOffset;
  128.        
  129.                 /* Check if we have registers mapped at this block. */
  130.                 if( (usAddress >= REG_DISC_START) &&( usAddress + usNDiscrete<= REG_DISC_START + REG_DISC_SIZE ))
  131.         {
  132.                 usBitOffset = (unsigned short)( usAddress - REG_DISC_START );
  133.                 while( iNDiscrete > 0 )
  134.         {
  135.                 *pucRegBuffer++ =xMBUtilGetBits(ucRegDiscBuf, usBitOffset, (unsigned char)( iNDiscrete >8?8: iNDiscrete ) );
  136.                 iNDiscrete -= 8;
  137.                 usBitOffset+=8;
  138.         }
  139.         }
  140.         else
  141.         {
  142.                 eStatus = MB_ENOREG;//illegal register address
  143.         }
  144.         return eStatus;
  145. }
复制代码


使用特权

评论回复
 楼主 | 2020-12-18 17:30 | 显示全部楼层

9、03功能码验证:可以发现返回8个寄存器值与demo.c的值一样
375fdc768a7edad.png

使用特权

评论回复
 楼主 | 2020-12-18 17:33 | 显示全部楼层
zeshoufx 发表于 2020-12-18 17:30
9、03功能码验证:可以发现返回8个寄存器值与demo.c的值一样

10、需要注意的是,为保证串口不乱码,PLL倍频系数不得大于16,需要修改时钟配置,外部晶振不分频
系统时钟设置为96Mhz
  1. RCU_CFG0 &= ~(RCU_CFG0_PLLSEL | RCU_CFG0_PREDV0);
  2.     RCU_CFG0 |= (RCU_PLLSRC_HXTAL );

  3.     /* CK_PLL = (CK_HXTAL/2) * 24 = 96 MHz */
  4.     RCU_CFG0 &= ~(RCU_CFG0_PLLMF | RCU_CFG0_PLLMF_4);
  5.     RCU_CFG0 |= RCU_PLL_MUL12;
复制代码


使用特权

评论回复
 楼主 | 2020-12-18 17:39 | 显示全部楼层
zeshoufx 发表于 2020-12-18 17:33
10、需要注意的是,为保证串口不乱码,PLL倍频系数不得大于16,需要修改时钟配置,外部晶振不分频
系统时 ...

11、工程demo
串口采用usart1,采用RS485方式,其他功能码也测试通过
354665fdc7873a31af.png

3-freemodbus.zip

7.75 MB, 下载次数: 27

工程文件

使用特权

评论回复
| 2021-1-31 23:52 | 显示全部楼层
工程文件已下载。感谢

使用特权

评论回复
| 2021-1-31 23:52 | 显示全部楼层
测试看看可不可以

使用特权

评论回复
| 2021-1-31 23:53 | 显示全部楼层

使用特权

评论回复
| 2021-2-20 15:46 | 显示全部楼层

工程文件已下载。感谢

使用特权

评论回复
扫描二维码,随时随地手机跟帖
您需要登录后才可以回帖 登录 | 注册

本版积分规则

我要发帖 我要提问 投诉建议 申请版主

快速回复

您需要登录后才可以回帖
登录 | 注册
高级模式

论坛热帖

在线客服 快速回复 返回顶部 返回列表