[单片机芯片] 【沁恒CH32V307开发板测评】FreeModbus移植

[复制链接]
654|0
星享社 发表于 2025-9-24 12:00 | 显示全部楼层 |阅读模式
本次测评之所以移植FreeModbus,是因为在项目过程使用RS485是比较频繁,而使用开源的FreeModbus,可使设备快速具备Modbus从站或主站功能,降低开发难度,提升项目效率,同时充分利用RISC-V架构的低功耗与高性能特性。
一、FreeModbus简单介绍
1、是什么
FreeMODBUS是一个完全开源(GPLv2许可)的Modbus协议栈,也就是一种modbus库
2、特点
1)轻量级​​
专为​​资源受限的嵌入式系统​​设计,RAM占用通常小于2KB,适合微控制器环境
2)协议支持全面​​
支持​​Modbus RTU​​(二进制编码,高效紧凑)和​​Modbus ASCII​​(文本编码,易于调试)两种串行模式,覆盖了工业应用中最常见的通信方式
3)可移植性与模块化​​
库采用模块化设计,​​核心协议栈与硬件层分离​​。开发者只需实现有限的硬件接口函数(如串口收发、定时器控制),即可轻松移植到不同平台
4)功能码覆盖广泛​​
支持Modbus标准功能码,如读线圈状态(01)、读离散输入(02)、读保持寄存器(03)、读输入寄存器(04)、写单个线圈(05)、写单个寄存器(06)、写多个线圈(15)和写多个寄存器(16)等
5)稳定性
FreeMODBUS拥有​​活跃的社区支持和丰富的实践案例​​,稳定性高,降低了项目风险
二、移植过程
1、在官网的github仓库下载FreeModbus源码
GitHub - cwalter-at/freemodbus: BSD licensed MODBUS RTU/ASCII and TCP slave[url=https://gitee.com/qglh/free-modbus][/url]
下载之后文件
4550168d36b4d87a17.png
2、新建工程,具体工程不赘述
3、复制如下文件到工程目录
1)复制port文件夹到工程目录
9399168d36b5a5bf45.png
2)复制modbus文件到工程目录
5589968d36b6679a3d.png
4、添加modbus相关的头文件目录
8637668d36b765a829.png
5、编译之后报两处错误,暂时不管
2174668d36b825d3dc.png
6、修改portserial.c文件
该文件主要是串口使能、串口初始化、使能串口的发送与接收
根据FreeModbus的接口添加相关的功能接口,如下
  1. /* ----------------------- Start implementation -----------------------------*/
  2. void
  3. vMBPortSerialEnable( BOOL xRxEnable, BOOL xTxEnable )
  4. {
  5.     /* If xRXEnable enable serial receive interrupts. If xTxENable enable
  6.      * transmitter empty interrupts.
  7.      */
  8.    
  9.     if(xRxEnable == TRUE)//串口接收中断使能
  10.     {
  11.         USART_ITConfig(USART2, USART_IT_RXNE, ENABLE);//UART中断使能
  12.     }
  13.     else
  14.     {
  15.         USART_ITConfig(USART2, USART_IT_RXNE, DISABLE);//禁止接收和接收中断
  16.     }

  17.     if(xTxEnable == TRUE)  //串口发送中断使能
  18.     {
  19.         USART_ITConfig(USART2, USART_IT_TC, ENABLE);//使能发送中断
  20.     }
  21.     else
  22.     {
  23.         USART_ITConfig(USART2, USART_IT_TC, DISABLE);//禁止发送中断
  24.     }
  25. }

  26. BOOL xMBPortSerialInit( UCHAR ucPort, ULONG ulBaudRate,UCHAR ucDataBits, eMBParity eParity,UCHAR ucStopBits )
  27. {
  28.     USART2_Init();//初始化串口
  29.     return FALSE;
  30. }

  31. BOOL
  32. xMBPortSerialPutByte( CHAR ucByte )
  33. {
  34.     /* Put a byte in the UARTs transmit buffer. This function is called
  35.      * by the protocol stack if pxMBFrameCBTransmitterEmpty( ) has been
  36.      * called. */
  37.     while(USART_GetFlagStatus(USART2, USART_FLAG_TC) == RESET);
  38.     USART_SendData(USART2, ucByte);
  39.     return TRUE;
  40. }

  41. BOOL
  42. xMBPortSerialGetByte( CHAR * pucByte )
  43. {
  44.     /* Return the byte in the UARTs receive buffer. This function is called
  45.      * by the protocol stack after pxMBFrameCBByteReceived( ) has been called.
  46.      */
  47.     *pucByte = USART_ReceiveData(USART2);
  48.     return TRUE;
  49. }

  50. /* Create an interrupt handler for the transmit buffer empty interrupt
  51. * (or an equivalent) for your target processor. This function should then
  52. * call pxMBFrameCBTransmitterEmpty( ) which tells the protocol stack that
  53. * a new character can be sent. The protocol stack will then call
  54. * xMBPortSerialPutByte( ) to send the character.
  55. */
  56. static void prvvUARTTxReadyISR( void )
  57. {
  58.     pxMBFrameCBTransmitterEmpty(  );
  59. }

  60. /* Create an interrupt handler for the receive interrupt for your target
  61. * processor. This function should then call pxMBFrameCBByteReceived( ). The
  62. * protocol stack will then call xMBPortSerialGetByte( ) to retrieve the
  63. * character.
  64. */
  65. static void prvvUARTRxISR( void )
  66. {
  67.     pxMBFrameCBByteReceived(  );
  68. }

  69. /*********************************************************************
  70. * @fn      USART2_IRQHandler
  71. *
  72. * [url=/u/brief]@brief[/url]   This function handles USART2 global interrupt request.
  73. *
  74. * [url=/u/return]@return[/url]  none
  75. */
  76. void USART2_IRQHandler(void)
  77. {
  78.     if(USART_GetITStatus(USART2, USART_IT_RXNE) != RESET)
  79.     {
  80.         prvvUARTRxISR(); //串口接收中断调用函数
  81.         USART_ClearITPendingBit(USART2,USART_FLAG_RXNE);
  82.     }

  83.     if(USART_GetITStatus(USART2, USART_IT_ORE) != RESET)
  84.     {
  85.         prvvUARTRxISR(); //串口接收中断调用函数
  86.         USART_ClearITPendingBit(USART2,USART_IT_ORE);
  87.     }

  88.     if(USART_GetITStatus(USART2, USART_IT_TC) != RESET)
  89.     {
  90.         prvvUARTTxReadyISR(); //串口接收中断调用函数
  91.         USART_ClearITPendingBit(USART2, USART_IT_TC);
  92.     }
  93. }
7、修改porttimer.c文件
modbus工作时需要一个定时器来周期工作,定时器时基是50us,周期做为参数输入,去掉前面的inline,具体代码如下:
  1. /* ----------------------- Platform includes --------------------------------*/
  2. #include "port.h"
  3. #include "debug.h"
  4. /* ----------------------- Modbus includes ----------------------------------*/
  5. #include "mb.h"
  6. #include "mbport.h"
  7. void TIM1_UP_IRQHandler(void) __attribute__((interrupt("WCH-Interrupt-fast")));
  8. /* ----------------------- static functions ---------------------------------*/
  9. static void prvvTIMERExpiredISR( void );

  10. /* ----------------------- Start implementation -----------------------------*/
  11. BOOL
  12. xMBPortTimersInit( USHORT usTim1Timerout50us )
  13. {
  14.     TIM1_INT_Init( usTim1Timerout50us);
  15.     return TRUE;
  16. }

  17. void vMBPortTimersEnable(  )
  18. {
  19.     /* Enable the timer with the timeout passed to xMBPortTimersInit( ) */

  20.     TIM_ClearITPendingBit(TIM1, TIM_IT_Update);
  21.     TIM_ITConfig(TIM1, TIM_IT_Update, ENABLE);
  22.     TIM_SetCounter(TIM1,0x0000);
  23.     TIM_Cmd(TIM1, ENABLE);
  24. }

  25. void vMBPortTimersDisable(  )
  26. {
  27.     /* Disable any pending timers. */
  28.     TIM_ClearITPendingBit(TIM1, TIM_IT_Update);
  29.     TIM_ITConfig(TIM1, TIM_IT_Update, DISABLE);
  30.     TIM_SetCounter(TIM1,0x0000);
  31.     TIM_Cmd(TIM1, DISABLE);
  32. }

  33. /* Create an ISR which is called whenever the timer has expired. This function
  34. * must then call pxMBPortCBTimerExpired( ) to notify the protocol stack that
  35. * the timer has expired.
  36. */
  37. static void prvvTIMERExpiredISR( void )
  38. {
  39.     ( void )pxMBPortCBTimerExpired(  );
  40. }

  41. void TIM1_UP_IRQHandler(void)
  42. {
  43.     if(TIM_GetITStatus(TIM1, TIM_IT_Update)==SET)
  44.     {
  45.         prvvTIMERExpiredISR();
  46.         TIM_ClearITPendingBit( TIM1, TIM_IT_Update );
  47.     }
  48. }
8、修改mbconfig.h文件
如图修改,主要修改支持RTU形式
3752168d36bb2e1b63.png
9、在主函数初始定时器和串口,代码如下
  1. /*********************************************************************
  2. * @fn      main
  3. *
  4. * @brief   Main program.
  5. *
  6. * @return  none
  7. */
  8. int main(void)
  9. {
  10.     NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
  11.     SystemCoreClockUpdate();
  12.     Delay_Init();
  13.     USART_Printf_Init(115200);  
  14.     printf("SystemClk:%d\r\n",SystemCoreClock);
  15.     printf( "ChipID:%08x\r\n", DBGMCU_GetCHIPID() );
  16.     printf("This is printf example\r\n");

  17.     modbus_task();
  18. }

  19. /*********************************************************************
  20. * @fn      USART2_Init
  21. *
  22. * @brief   Initializes the USART2 peripheral.
  23. *
  24. * @return  none
  25. */
  26. void USART2_Init(void) {
  27.     GPIO_InitTypeDef  GPIO_InitStructure = {0};
  28.     USART_InitTypeDef USART_InitStructure = {0};
  29.     NVIC_InitTypeDef  NVIC_InitStructure = {0};

  30.     RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);
  31.     RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);

  32.     /* USART2 TX-->A.2   RX-->A.3 */
  33.     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
  34.     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  35.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
  36.     GPIO_Init(GPIOA, &GPIO_InitStructure);
  37.     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;
  38.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
  39.     GPIO_Init(GPIOA, &GPIO_InitStructure);

  40.     USART_InitStructure.USART_BaudRate = 115200;
  41.     USART_InitStructure.USART_WordLength = USART_WordLength_8b;
  42.     USART_InitStructure.USART_StopBits = USART_StopBits_1;
  43.     USART_InitStructure.USART_Parity = USART_Parity_No;
  44.     USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
  45.     USART_InitStructure.USART_Mode = USART_Mode_Tx | USART_Mode_Rx;
  46.     USART_Init(USART2, &USART_InitStructure);

  47.     // USART_ITConfig(USART2, USART_IT_RXNE, ENABLE);//UART中断使能
  48.     // USART_ITConfig(USART2, USART_IT_TC, ENABLE);//使能发送中断
  49.     NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn;
  50.     NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
  51.     NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
  52.     NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  53.     NVIC_Init(&NVIC_InitStructure);

  54.     USART_Cmd(USART2, ENABLE);
  55. }

  56. /*********************************************************************
  57. * @fn      TIM1_INT_Init
  58. *
  59. * @brief   Initializes TIM1 output compare.
  60. *
  61. * @param   arr - the period value.
  62. *          psc - the prescaler value.
  63. *
  64. * @return  none
  65. */
  66. void TIM1_INT_Init(u16 psc)
  67. {

  68.     NVIC_InitTypeDef NVIC_InitStructure={0};
  69.     TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure={0};

  70.     RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE );

  71.     TIM_TimeBaseInitStructure.TIM_Period = psc * 50;
  72.     TIM_TimeBaseInitStructure.TIM_Prescaler = 95;
  73.     TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
  74.     TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
  75.     TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;
  76.     TIM_TimeBaseInit( TIM1, &TIM_TimeBaseInitStructure);

  77.     TIM_ClearITPendingBit( TIM1, TIM_IT_Update );

  78.     NVIC_InitStructure.NVIC_IRQChannel =TIM1_UP_IRQn;
  79.     NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority =0;
  80.     NVIC_InitStructure.NVIC_IRQChannelSubPriority =1;
  81.     NVIC_InitStructure.NVIC_IRQChannelCmd =ENABLE;
  82.     NVIC_Init(&NVIC_InitStructure);

  83. }
10、在新建mbtask.c文件添加modbus相关寄存器和函数
代码如下:


  1. #include "stdio.h"
  2. #include "mbtask.h"
  3. #include "debug.h"

  4. /* ----------------------- Static variables ---------------------------------*/
  5. static USHORT usRegInputStart = REG_INPUT_START;
  6. static USHORT usRegInputBuf[REG_INPUT_NREGS] = {0x1234, 0x5678, 0x9ABC, 0xDEF0};
  7. static USHORT usRegHoldingStart = REG_HOLDING_START;
  8. static USHORT usRegHoldingBuf[REG_HOLDING_NREGS] = {0, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09};

  9. //coils buffer
  10. static UCHAR  ucRegCoilsBuf[REG_COILS_SIZE / 8] = {0x01, 0x02};
  11. //discrete Inputs buffer
  12. static UCHAR  ucRegDiscreteBuf[REG_DISCRETE_SIZE / 8] = {0x80, 0x90};


  13. void modbus_task(void)
  14. {
  15.   eMBErrorCode    eStatus;
  16.   
  17. /* ucPort: select port_uart.
  18.   * this parameter can be one of the following values:
  19.   * 0: USART2: tx--PA2,  rx--PA3,  de--PA1;
  20.   * 1: USART3: tx--PB10, rx--PB11, de--PB14;
  21.   * other: invalid.
  22.   */
  23.   eStatus = eMBInit(MB_RTU, MB_SLAVE_ADDRESS, 0, MB_BAUDRATE, MB_PAR_NONE);
  24.   if(MB_ENOERR == eStatus)
  25.   {
  26.     printf("modbus init ok\r\n");
  27.     eStatus = eMBEnable();
  28.     if(MB_ENOERR == eStatus)
  29.     {
  30.       printf("modbus enable ok\r\n");
  31.     }
  32.     else
  33.     {
  34.       printf("modbus enable fail, error code: %u\r\n", eStatus);
  35.     }
  36.   }
  37.   else
  38.   {
  39.     printf("modbus init fail, error code: %u\r\n", eStatus);
  40.   }
  41.   
  42.   if(MB_ENOERR != eStatus)
  43.   {
  44.     printf("exit modbus task.\r\n");
  45.     return;
  46.   }
  47.    
  48.   printf("start modbus pooling..\r\n");
  49.   for(;;){
  50.     eMBPoll();
  51.   }
  52. }

  53. /****************************************************************************
  54. * brief: read input register;
  55. *        responsive function code:
  56. *        04 (Read Input Register).
  57. * param: pucRegBuffer: data buffer, used for respond master;
  58. *           usAddress: register address;
  59. *             usNRegs: register number.
  60. * retval: eStatus: error code.
  61. ****************************************************************************/
  62. eMBErrorCode
  63. eMBRegInputCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNRegs )
  64. {
  65.     eMBErrorCode    eStatus = MB_ENOERR;
  66.     int             iRegIndex;

  67.     if( ( usAddress >= REG_INPUT_START )
  68.         && ( usAddress + usNRegs <= REG_INPUT_START + REG_INPUT_NREGS ) )
  69.     {
  70.         iRegIndex = ( int )( usAddress - usRegInputStart );
  71.         while( usNRegs > 0 )
  72.         {
  73.             *pucRegBuffer++ =
  74.                 ( unsigned char )( usRegInputBuf[iRegIndex] >> 8 );
  75.             *pucRegBuffer++ =
  76.                 ( unsigned char )( usRegInputBuf[iRegIndex] & 0xFF );
  77.             iRegIndex++;
  78.             usNRegs--;
  79.         }
  80.     }
  81.     else
  82.     {
  83.         eStatus = MB_ENOREG;
  84.     }

  85.     return eStatus;
  86. }

  87. /****************************************************************************
  88. * brief: read/write holding register;
  89. *        responsive function code:
  90. *        06 (Write Holding Register);
  91. *        16 (Write Multiple Holding Register);
  92. *        03 (Read Holding Register);
  93. *        23 (Read/Write Multiple Holding Register).
  94. * param: pucRegBuffer: data buffer, used for respond master;
  95. *           usAddress: register address;
  96. *             usNRegs: register number;
  97. *               eMode: access register mode.
  98. * retval: eStatus: error code.
  99. ****************************************************************************/
  100. eMBErrorCode
  101. eMBRegHoldingCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNRegs, eMBRegisterMode eMode )
  102. {
  103.     eMBErrorCode    eStatus = MB_ENOERR;
  104.     int             iRegIndex;

  105.     if( ( usAddress >= REG_HOLDING_START ) && ( usAddress + usNRegs <= REG_HOLDING_START + REG_HOLDING_NREGS ) )
  106.     {
  107.         iRegIndex = ( int )( usAddress - usRegHoldingStart );
  108.         switch ( eMode )
  109.         {
  110.         case MB_REG_READ:
  111.             while( usNRegs > 0 )
  112.             {
  113.                 *pucRegBuffer++ = ( unsigned char )( usRegHoldingBuf[iRegIndex] >> 8 );
  114.                 *pucRegBuffer++ = ( unsigned char )( usRegHoldingBuf[iRegIndex] & 0xFF );
  115.                 iRegIndex++;
  116.                 usNRegs--;
  117.             }
  118.             break;

  119.         case MB_REG_WRITE:
  120.             while( usNRegs > 0 )
  121.             {
  122.                 usRegHoldingBuf[iRegIndex] = *pucRegBuffer++ << 8;
  123.                 usRegHoldingBuf[iRegIndex] |= *pucRegBuffer++;
  124.                 iRegIndex++;
  125.                 usNRegs--;
  126.             }
  127.         }
  128.     }
  129.     else
  130.     {
  131.         eStatus = MB_ENOREG;
  132.     }
  133.     return eStatus;
  134. }

  135. extern void xMBUtilSetBits( UCHAR * ucByteBuf, USHORT usBitOffset, UCHAR ucNBits, UCHAR ucValue );
  136. extern UCHAR xMBUtilGetBits( UCHAR * ucByteBuf, USHORT usBitOffset, UCHAR ucNBits );

  137. /****************************************************************************
  138. * brief: read/write coils;
  139. *        responsive function code:
  140. *        01 (Read Coils);
  141. *        05 (Write Coil);
  142. *        15 (Write Multiple Coils).
  143. * param: pucRegBuffer: data buffer, used for respond master;
  144. *           usAddress: coils address;
  145. *            usNCoils: coils number;
  146. *               eMode: access register mode.
  147. * retval: eStatus: error code.
  148. ****************************************************************************/
  149. eMBErrorCode
  150. eMBRegCoilsCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNCoils,
  151.                eMBRegisterMode eMode )
  152. {
  153.     eMBErrorCode eStatus = MB_ENOERR;
  154.     int16_t iNCoils = ( int16_t )usNCoils;
  155.     int16_t usBitOffset;
  156.    
  157.     if( ( (int16_t)usAddress >= REG_COILS_START ) &&
  158.        ( usAddress + usNCoils <= REG_COILS_START + REG_COILS_SIZE ) )
  159.     {
  160.       usBitOffset = ( int16_t )( usAddress - REG_COILS_START );
  161.       switch ( eMode )
  162.       {
  163.       case MB_REG_READ:
  164.         while( iNCoils > 0 )
  165.         {
  166.           *pucRegBuffer++ = xMBUtilGetBits( ucRegCoilsBuf, usBitOffset,
  167.                                            ( uint8_t )( iNCoils > 8 ? 8 : iNCoils ) );
  168.           iNCoils -= 8;
  169.           usBitOffset += 8;
  170.         }
  171.         break;
  172.         
  173.       case MB_REG_WRITE:
  174.         while( iNCoils > 0 )
  175.         {
  176.           xMBUtilSetBits( ucRegCoilsBuf, usBitOffset,
  177.                          ( uint8_t )( iNCoils > 8 ? 8 : iNCoils ),
  178.                          *pucRegBuffer++ );
  179.           iNCoils -= 8;
  180.         }
  181.         break;
  182.       }
  183.     }
  184.     else
  185.     {
  186.       eStatus = MB_ENOREG;
  187.     }
  188.     return eStatus;
  189. }

  190. /****************************************************************************
  191. * brief: read discrete inputs;
  192. *        responsive function code:
  193. *        02 (read discrete inputs).
  194. * param: pucRegBuffer: data buffer, used for respond master;
  195. *           usAddress: discrete inputs address;
  196. *         usNDiscrete: discrete inputs number.
  197. * retval: eStatus: error code.
  198. ****************************************************************************/
  199. eMBErrorCode
  200. eMBRegDiscreteCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNDiscrete )
  201. {
  202.     eMBErrorCode eStatus = MB_ENOERR;
  203.     int16_t iNDiscrete = ( int16_t )usNDiscrete;
  204.     uint16_t usBitOffset;
  205.    
  206.     if( ( (int16_t)usAddress >= REG_DISCRETE_START ) &&
  207.        ( usAddress + usNDiscrete <= REG_DISCRETE_START + REG_DISCRETE_SIZE ) )
  208.     {
  209.       usBitOffset = ( uint16_t )( usAddress - REG_DISCRETE_START );
  210.       
  211.       while( iNDiscrete > 0 )
  212.       {
  213.         *pucRegBuffer++ = xMBUtilGetBits( ucRegDiscreteBuf, usBitOffset,
  214.                                          ( uint8_t)( iNDiscrete > 8 ? 8 : iNDiscrete ) );
  215.         iNDiscrete -= 8;
  216.         usBitOffset += 8;
  217.       }
  218.     }
  219.     else
  220.     {
  221.       eStatus = MB_ENOREG;
  222.     }
  223.     return eStatus;
  224. }
mbtask.h文件


  1. #ifndef __MBTASK_H
  2. #define __MBTASK_H

  3. #ifdef __cplusplus
  4. extern "C" {
  5. #endif

  6. /* ----------------------- Modbus includes ----------------------------------*/
  7. #include "mb.h"
  8. #include "mbport.h"

  9. /* ----------------------- Defines ------------------------------------------*/
  10. #define MB_SLAVE_ADDRESS                ( 0x01 )
  11. #define MB_BAUDRATE                     ( 115200 )

  12. //input register start address
  13. #define REG_INPUT_START                 ( 1 )
  14. //input register number
  15. #define REG_INPUT_NREGS                 ( 16 )

  16. //holding register start address
  17. #define REG_HOLDING_START               ( 1 )
  18. //holding register number
  19. #define REG_HOLDING_NREGS               ( 16 )

  20. //coils start address
  21. #define REG_COILS_START                 ( 1 )
  22. //coils number
  23. #define REG_COILS_SIZE                  ( 16 )

  24. //discrete inputs start address
  25. #define REG_DISCRETE_START              ( 1 )
  26. //discrete inputs number
  27. #define REG_DISCRETE_SIZE               ( 16 )

  28. void modbus_task(void);

  29. #ifdef __cplusplus
  30. }
  31. #endif

  32. #endif
11、移植成功后,编译无误,下载验证
日志打印
MODBUS初始化成功
5339068d36c73f2d19.png
读保持寄存器测试
3804168d36c8e6cab9.png
写保持寄存器测试
2533868d36c97ee76d.png
移植modbus-rtu完成


















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

本版积分规则

11

主题

30

帖子

0

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