基于GD32F103VK实现modbus-RTU主站

[复制链接]
6844|20
 楼主| zeshoufx 发表于 2021-7-13 16:45 | 显示全部楼层 |阅读模式
#申请原创#
一、modbus协议
      Modbus是一种串行通信协议,是Modicon公司(现在的施耐德电气 Schneider Electric)于1979年为使用可编程逻辑控制器(PLC)通信而发表。
Modbus已经成为工业领域通信协议的业界标准(De facto),并且现在是工业电子设备之间常用的连接方式。
      对于串行连接,存在两个变种,它们在数值数据表示不同和协议细节上略有不同。Modbus RTU是一种紧凑的,采用二进制表示数据的方式,Modbus ASCII是一种人类可读的,冗长的表示方式。这两个变种都使用串行通信(serial communication)方式。RTU格式后续的命令/数据带有循环冗余校验的校验和,而ASCII格式采用纵向冗余校验的校验和。被配置为RTU变种的节点不会和设置为ASCII变种的节点通信,反之亦然。




 楼主| zeshoufx 发表于 2021-7-13 16:48 | 显示全部楼层
二、常用的开源modbus协议

Modbus作为一种常见的工业通信协议,几乎被所有的设备所支持,如果能在软件或者设备中增强Modbus通信功能,
无疑对于市场应用来说是个很吸引人的卖点。而对 于Modbus开发来说,网络上存在相当多的开源库,
其中libmodbus (http://www. libmodbus. org)和freemo-dbus ( htp://www.freemodbus.org)可以说是其中的翘楚,
值得开发者认真分析和学习。
 楼主| zeshoufx 发表于 2021-7-13 16:51 | 显示全部楼层
zeshoufx 发表于 2021-7-13 16:48
二、常用的开源modbus协议

Modbus作为一种常见的工业通信协议,几乎被所有的设备所支持,如果能在软件或者 ...

三、硬件驱动函数
  1. static void InitHardUsart(void)
  2. {
  3.         /* 第1步:打开GPIO和USART部件的时钟 */
  4.         rcu_periph_clock_enable(RCU_GPIOA);
  5.         rcu_periph_clock_enable(RCU_USART1);

  6.         /* 第2步:将USART Tx的GPIO配置为推挽复用模式 */
  7.         gpio_init(GPIOA,GPIO_MODE_AF_PP,GPIO_OSPEED_50MHZ,GPIO_PIN_2);
  8.        
  9.         /* 第3步:将USART Rx的GPIO配置为浮空输入模式
  10.                 由于CPU复位后,GPIO缺省都是浮空输入模式,因此下面这个步骤不是必须的
  11.                 但是,我还是建议加上便于阅读,并且防止其它地方修改了这个口线的设置参数
  12.         */
  13.         gpio_init(GPIOA,GPIO_MODE_IN_FLOATING,GPIO_OSPEED_50MHZ,GPIO_PIN_3);
  14.        
  15.        
  16.         /* 第4步: 配置串口硬件参数 */
  17.         usart_baudrate_set(USART1,USART1_BAUD);
  18.         usart_parity_config(USART1,USART_PM_NONE);
  19.         usart_stop_bit_set(USART1,USART_STB_1BIT);
  20.         usart_word_length_set(USART1,USART_WL_8BIT);
  21.         usart_transmit_config(USART1,USART_TRANSMIT_ENABLE);
  22.         usart_receive_config(USART1,USART_RECEIVE_ENABLE);
  23.         usart_hardware_flow_cts_config(USART1,USART_CTS_DISABLE);
  24.         usart_hardware_flow_rts_config(USART1,USART_RTS_DISABLE);

  25.         usart_interrupt_enable(USART1,USART_INT_RBNE);        /* 使能接收中断 */
  26.         /*
  27.                 USART_ITConfig(USART1, USART_IT_TXE, ENABLE);
  28.                 注意: 不要在此处打开发送中断
  29.                 发送中断使能在SendUart()函数打开
  30.         */
  31.         usart_enable(USART1);                /* 使能串口 */

  32.         /* CPU的小缺陷:串口配置好,如果直接Send,则第1个字节发送不出去
  33.                 如下语句解决第1个字节无法正确发送出去的问题 */
  34.         usart_interrupt_flag_clear(USART1,USART_INT_FLAG_TC);     /* 清发送完成标志,Transmission Complete flag */
  35. }

  36. /**
  37.   * 函数功能: 配置NVIC,设定USART接收中断优先级.
  38.   * 输入参数: 无
  39.   * 返 回 值: 无
  40.   * 说    明:无
  41.   */
  42. static void NVIC_Configuration_USART(void)
  43. {
  44.        
  45.         /* 使能串口1中断 */
  46.         nvic_irq_enable(USART1_IRQn,2,2);

  47. }

  48. /*
  49. *********************************************************************************************************
  50. *        函 数 名: RS485_InitTXE
  51. *        功能说明: 配置RS485发送使能口线 TXE
  52. *        形    参: 无
  53. *        返 回 值: 无
  54. *********************************************************************************************************
  55. */
  56. static void RS485_InitTXEN(void)
  57. {
  58.         rcu_periph_clock_enable(RCU_GPIOA);
  59.         gpio_init(GPIOA,GPIO_MODE_OUT_PP,GPIO_OSPEED_50MHZ,GPIO_PIN_1);
  60. }

  61. /*
  62. *********************************************************************************************************
  63. *        函 数 名: RS485_SendBefor
  64. *        功能说明: 发送数据前的准备工作。对于RS485通信,请设置RS485芯片为发送状态,
  65. *                          并修改 UartVarInit()中的函数指针等于本函数名,比如 g_tUart2.SendBefor = RS485_SendBefor
  66. *        形    参: 无
  67. *        返 回 值: 无
  68. *********************************************************************************************************
  69. */
  70. void RS485_SendBefor(void)
  71. {
  72.         RS485_TX_EN();        /* 切换RS485收发芯片为发送模式 */
  73. }

  74. /*
  75. *********************************************************************************************************
  76. *        函 数 名: RS485_SendOver
  77. *        功能说明: 发送一串数据结束后的善后处理。对于RS485通信,请设置RS485芯片为接收状态,
  78. *                          并修改 UartVarInit()中的函数指针等于本函数名,比如 g_tUart2.SendOver = RS485_SendOver
  79. *        形    参: 无
  80. *        返 回 值: 无
  81. *********************************************************************************************************
  82. */
  83. void RS485_SendOver(void)
  84. {
  85.         RS485_RX_EN();        /* 切换RS485收发芯片为接收模式 */
  86. }


  87. /*
  88. *********************************************************************************************************
  89. *        函 数 名: RS485_SendBuf
  90. *        功能说明: 通过RS485芯片发送一串数据。注意,本函数不等待发送完毕。
  91. *        形    参: 无
  92. *        返 回 值: 无
  93. *********************************************************************************************************
  94. */
  95. void RS485_SendBuf(uint8_t *_ucaBuf, uint16_t _usLen)
  96. {
  97.         switch(USART_SELECT_NUM)
  98.         {
  99.                 case 1:
  100.                 {
  101.                         comSendBuf(COM1, _ucaBuf, _usLen);
  102.                 }break;
  103.                 case 2:
  104.                 {       
  105.                         comSendBuf(COM2, _ucaBuf, _usLen);
  106.                 }break;
  107.                 case 3:
  108.                 {
  109.                         comSendBuf(COM3, _ucaBuf, _usLen);
  110.                 }break;
  111.                 default:
  112.                 {
  113.                        
  114.                 }break;
  115.         }
  116. }


 楼主| zeshoufx 发表于 2021-7-13 16:52 | 显示全部楼层
zeshoufx 发表于 2021-7-13 16:51
三、硬件驱动函数

四、主站函数
/*
*********************************************************************************************************
*        函 数 名: MODH_Send01H
*        功能说明: 发送01H指令,查询1个或多个保持寄存器
*        形    参: _addr : 从站地址
*                          _reg : 寄存器编号
*                          _num : 寄存器个数
*        返 回 值: 无
*********************************************************************************************************
*/
void MODH_Send01H(uint8_t _addr, uint16_t _reg, uint16_t _num)
{
        g_tModH.TxCount = 0;
        g_tModH.TxBuf[g_tModH.TxCount++] = _addr;                /* 从站地址 */
        g_tModH.TxBuf[g_tModH.TxCount++] = 0x01;                /* 功能码 */       
        g_tModH.TxBuf[g_tModH.TxCount++] = _reg >> 8;        /* 寄存器编号 高字节 */
        g_tModH.TxBuf[g_tModH.TxCount++] = _reg;                /* 寄存器编号 低字节 */
        g_tModH.TxBuf[g_tModH.TxCount++] = _num >> 8;        /* 寄存器个数 高字节 */
        g_tModH.TxBuf[g_tModH.TxCount++] = _num;                /* 寄存器个数 低字节 */
       
        MODH_SendAckWithCRC();                /* 发送数据,自动加CRC */
        g_tModH.fAck01H = 0;                /* 清接收标志 */
        g_tModH.RegNum = _num;                /* 寄存器个数 */
        g_tModH.Reg01H = _reg;                /* 保存03H指令中的寄存器地址,方便对应答数据进行分类 */       
}

/*
*********************************************************************************************************
*        函 数 名: MODH_Send02H
*        功能说明: 发送02H指令,读离散输入寄存器
*        形    参: _addr : 从站地址
*                          _reg : 寄存器编号
*                          _num : 寄存器个数
*        返 回 值: 无
*********************************************************************************************************
*/
void MODH_Send02H(uint8_t _addr, uint16_t _reg, uint16_t _num)
{
        g_tModH.TxCount = 0;
        g_tModH.TxBuf[g_tModH.TxCount++] = _addr;                /* 从站地址 */
        g_tModH.TxBuf[g_tModH.TxCount++] = 0x02;                /* 功能码 */       
        g_tModH.TxBuf[g_tModH.TxCount++] = _reg >> 8;        /* 寄存器编号 高字节 */
        g_tModH.TxBuf[g_tModH.TxCount++] = _reg;                /* 寄存器编号 低字节 */
        g_tModH.TxBuf[g_tModH.TxCount++] = _num >> 8;        /* 寄存器个数 高字节 */
        g_tModH.TxBuf[g_tModH.TxCount++] = _num;                /* 寄存器个数 低字节 */
       
        MODH_SendAckWithCRC();                /* 发送数据,自动加CRC */
        g_tModH.fAck02H = 0;                /* 清接收标志 */
        g_tModH.RegNum = _num;                /* 寄存器个数 */
        g_tModH.Reg02H = _reg;                /* 保存03H指令中的寄存器地址,方便对应答数据进行分类 */       
}

/*
*********************************************************************************************************
*        函 数 名: MODH_Send03H
*        功能说明: 发送03H指令,查询1个或多个保持寄存器
*        形    参: _addr : 从站地址
*                          _reg : 寄存器编号
*                          _num : 寄存器个数
*        返 回 值: 无
*********************************************************************************************************
*/
void MODH_Send03H(uint8_t _addr, uint16_t _reg, uint16_t _num)
{
        g_tModH.TxCount = 0;
        g_tModH.TxBuf[g_tModH.TxCount++] = _addr;                /* 从站地址 */
        g_tModH.TxBuf[g_tModH.TxCount++] = 0x03;                /* 功能码 */       
        g_tModH.TxBuf[g_tModH.TxCount++] = _reg >> 8;        /* 寄存器编号 高字节 */
        g_tModH.TxBuf[g_tModH.TxCount++] = _reg;                /* 寄存器编号 低字节 */
        g_tModH.TxBuf[g_tModH.TxCount++] = _num >> 8;        /* 寄存器个数 高字节 */
        g_tModH.TxBuf[g_tModH.TxCount++] = _num;                /* 寄存器个数 低字节 */
       
        MODH_SendAckWithCRC();                /* 发送数据,自动加CRC */
        g_tModH.fAck03H = 0;                /* 清接收标志 */
        g_tModH.RegNum = _num;                /* 寄存器个数 */
        g_tModH.Reg03H = _reg;                /* 保存03H指令中的寄存器地址,方便对应答数据进行分类 */       
}

/*
*********************************************************************************************************
*        函 数 名: MODH_Send04H
*        功能说明: 发送04H指令,读输入寄存器
*        形    参: _addr : 从站地址
*                          _reg : 寄存器编号
*                          _num : 寄存器个数
*        返 回 值: 无
*********************************************************************************************************
*/
void MODH_Send04H(uint8_t _addr, uint16_t _reg, uint16_t _num)
{
        g_tModH.TxCount = 0;
        g_tModH.TxBuf[g_tModH.TxCount++] = _addr;                /* 从站地址 */
        g_tModH.TxBuf[g_tModH.TxCount++] = 0x04;                /* 功能码 */       
        g_tModH.TxBuf[g_tModH.TxCount++] = _reg >> 8;        /* 寄存器编号 高字节 */
        g_tModH.TxBuf[g_tModH.TxCount++] = _reg;                /* 寄存器编号 低字节 */
        g_tModH.TxBuf[g_tModH.TxCount++] = _num >> 8;        /* 寄存器个数 高字节 */
        g_tModH.TxBuf[g_tModH.TxCount++] = _num;                /* 寄存器个数 低字节 */
       
        MODH_SendAckWithCRC();                /* 发送数据,自动加CRC */
        g_tModH.fAck04H = 0;                /* 清接收标志 */
        g_tModH.RegNum = _num;                /* 寄存器个数 */
        g_tModH.Reg04H = _reg;                /* 保存03H指令中的寄存器地址,方便对应答数据进行分类 */       
}

/*
*********************************************************************************************************
*        函 数 名: MODH_Send05H
*        功能说明: 发送05H指令,写强置单线圈
*        形    参: _addr : 从站地址
*                          _reg : 寄存器编号
*                          _value : 寄存器值,2字节
*        返 回 值: 无
*********************************************************************************************************
*/
void MODH_Send05H(uint8_t _addr, uint16_t _reg, uint16_t _value)
{
        g_tModH.TxCount = 0;
        g_tModH.TxBuf[g_tModH.TxCount++] = _addr;                        /* 从站地址 */
        g_tModH.TxBuf[g_tModH.TxCount++] = 0x05;                        /* 功能码 */       
        g_tModH.TxBuf[g_tModH.TxCount++] = _reg >> 8;                /* 寄存器编号 高字节 */
        g_tModH.TxBuf[g_tModH.TxCount++] = _reg;                        /* 寄存器编号 低字节 */
        g_tModH.TxBuf[g_tModH.TxCount++] = _value >> 8;                /* 寄存器值 高字节 */
        g_tModH.TxBuf[g_tModH.TxCount++] = _value;                        /* 寄存器值 低字节 */
       
        MODH_SendAckWithCRC();                /* 发送数据,自动加CRC */

        g_tModH.fAck05H = 0;                /* 如果收到从机的应答,则这个标志会设为1 */
}

/*
*********************************************************************************************************
*        函 数 名: MODH_Send06H
*        功能说明: 发送06H指令,写1个保持寄存器
*        形    参: _addr : 从站地址
*                          _reg : 寄存器编号
*                          _value : 寄存器值,2字节
*        返 回 值: 无
*********************************************************************************************************
*/
void MODH_Send06H(uint8_t _addr, uint16_t _reg, uint16_t _value)
{
        g_tModH.TxCount = 0;
        g_tModH.TxBuf[g_tModH.TxCount++] = _addr;                        /* 从站地址 */
        g_tModH.TxBuf[g_tModH.TxCount++] = 0x06;                        /* 功能码 */       
        g_tModH.TxBuf[g_tModH.TxCount++] = _reg >> 8;                /* 寄存器编号 高字节 */
        g_tModH.TxBuf[g_tModH.TxCount++] = _reg;                        /* 寄存器编号 低字节 */
        g_tModH.TxBuf[g_tModH.TxCount++] = _value >> 8;                /* 寄存器值 高字节 */
        g_tModH.TxBuf[g_tModH.TxCount++] = _value;                        /* 寄存器值 低字节 */
       
        MODH_SendAckWithCRC();                /* 发送数据,自动加CRC */
       
        g_tModH.fAck06H = 0;                /* 如果收到从机的应答,则这个标志会设为1 */
}

/*
*********************************************************************************************************
*        函 数 名: MODH_Send10H
*        功能说明: 发送10H指令,连续写多个保持寄存器. 最多一次支持23个寄存器。
*        形    参: _addr : 从站地址
*                          _reg : 寄存器编号
*                          _num : 寄存器个数n (每个寄存器2个字节) 值域
*                          _buf : n个寄存器的数据。长度 = 2 * n
*        返 回 值: 无
*********************************************************************************************************
*/
void MODH_Send10H(uint8_t _addr, uint16_t _reg, uint8_t _num, uint8_t *_buf)
{
        uint16_t i;
       
        g_tModH.TxCount = 0;
        g_tModH.TxBuf[g_tModH.TxCount++] = _addr;                /* 从站地址 */
        g_tModH.TxBuf[g_tModH.TxCount++] = 0x10;                /* 从站地址 */       
        g_tModH.TxBuf[g_tModH.TxCount++] = _reg >> 8;        /* 寄存器编号 高字节 */
        g_tModH.TxBuf[g_tModH.TxCount++] = _reg;                /* 寄存器编号 低字节 */
        g_tModH.TxBuf[g_tModH.TxCount++] = _num >> 8;        /* 寄存器个数 高字节 */
        g_tModH.TxBuf[g_tModH.TxCount++] = _num;                /* 寄存器个数 低字节 */
        g_tModH.TxBuf[g_tModH.TxCount++] = 2 * _num;        /* 数据字节数 */
       
        for (i = 0; i < 2 * _num; i++)
        {
                if (g_tModH.TxCount > H_RX_BUF_SIZE - 3)
                {
                        return;                /* 数据超过缓冲区超度,直接丢弃不发送 */
                }
                g_tModH.TxBuf[g_tModH.TxCount++] = _buf;                /* 后面的数据长度 */
        }
       
        MODH_SendAckWithCRC();        /* 发送数据,自动加CRC */
}


/*
*********************************************************************************************************
*        函 数 名: MODH_ReciveNew
*        功能说明: 串口接收中断服务程序会调用本函数。当收到一个字节时,执行一次本函数。
*        形    参:
*        返 回 值: 1 表示有数据
*********************************************************************************************************
*/
void MODH_ReciveNew(uint8_t _data)
{
        /*
                3.5个字符的时间间隔,只是用在RTU模式下面,因为RTU模式没有开始符和结束符,
                两个数据包之间只能靠时间间隔来区分,Modbus定义在不同的波特率下,间隔时间是不一样的,
                所以就是3.5个字符的时间,波特率高,这个时间间隔就小,波特率低,这个时间间隔相应就大

                4800  = 7.297ms
                9600  = 3.646ms
                19200  = 1.771ms
                38400  = 0.885ms
        */
        uint32_t timeout;

        g_modh_timeout = 0;
       
        timeout = 35000000 / HBAUD485;                /* 计算超时时间,单位us 35000000*/
       
        /* 硬件定时中断,定时精度us 硬件定时器2用于MODBUS从机, 定时器3用于MODBUS从机主机*/
        bsp_StartHardTimer(3, timeout, (void *)MODH_RxTimeOut);

        if (g_tModH.RxCount < H_RX_BUF_SIZE)
        {
                g_tModH.RxBuf[g_tModH.RxCount++] = _data;
        }
}

 楼主| zeshoufx 发表于 2021-7-13 16:55 | 显示全部楼层
zeshoufx 发表于 2021-7-13 16:52
四、主站函数
/*
********************************************************************************** ...

五、运行效果
主站发送请求至modbus slave截图如图所示
8298760ed54f740211.png

 楼主| zeshoufx 发表于 2021-7-13 16:58 | 显示全部楼层
zeshoufx 发表于 2021-7-13 16:55
五、运行效果
主站发送请求至modbus slave截图如图所示

六、从站响应主站
173460ed559c2bf4c.png
 楼主| zeshoufx 发表于 2021-7-13 17:01 | 显示全部楼层
zeshoufx 发表于 2021-7-13 16:58
六、从站响应主站

七、运行过程
1556160ed5661e9bc5.png
 楼主| zeshoufx 发表于 2021-7-13 17:02 | 显示全部楼层

八、主函数

  1. #include "bitband.h"
  2. #include "systick.h"
  3. #include "led.h"
  4. #include "key.h"
  5. #include "usart.h"

  6. #include "bsp_SysTick.h"
  7. #include "bsp_usartx_fifo.h"
  8. #include "modbus_host.h"

  9. void TestModbusHost(uint8_t value)
  10. {
  11.         switch(value)
  12.         {
  13.                 case 0:
  14.                         //printf("即将发送命令:【读线圈(继电器)状态】MODH_ReadParam_01H\n");
  15.                         MODH_ReadParam_01H(REG_D01, 4);
  16.                         break;
  17.                 case 1:
  18.                         //printf("即将发送命令:【读多个寄存器(内部寄存器)】MODH_ReadParam_03H\n");
  19.                         MODH_ReadParam_03H(REG_P01, 1);
  20.                         break;
  21.                 case 2:
  22.                         //printf("即将发送命令:【读输入离散量(控制按钮)】MODH_ReadParam_02H\n");
  23.                         MODH_ReadParam_02H(REG_T01, 2);
  24.                         break;
  25.                 case 3:
  26.                         //printf("即将发送命令:【读输入寄存器(模拟量信号)】MODH_ReadParam_04H\n");
  27.                         MODH_ReadParam_04H(REG_A01, 1);
  28.                         break;
  29.                 case 4:
  30.                         //printf("即将发送命令:【写单个寄存器(内部寄存器)】MODH_WriteParam_06H\n");
  31.                         MODH_WriteParam_06H(REG_P01, 1);
  32.                         break;
  33.                 case 5:
  34.                         //printf("即将发送命令:【写单个寄存器(内部寄存器)】MODH_WriteParam_06H\n");
  35.                         MODH_WriteParam_06H(REG_P01, 0);
  36.                         break;        
  37.                 case 6:
  38.                         //printf("即将发送命令:【写单个线圈(继电器)】MODH_WriteParam_05H\n");
  39.                         MODH_WriteParam_05H(REG_D04, 1);
  40.                         break;
  41.                 case 7:
  42.                         //printf("即将发送命令:【写单个线圈(继电器)】MODH_WriteParam_05H\n");
  43.                         MODH_WriteParam_05H(REG_D04, 0);
  44.                         break;         
  45.                 case 8:      
  46.                         //printf("即将发送命令:【写多个保存寄存器(内部寄存器)】MODH_WriteParam_10H\n");
  47.                         {
  48.                                 uint8_t buf[4];
  49.                                
  50.                                 buf[0] = 0x01;
  51.                                 buf[1] = 0x02;
  52.                                 buf[2] = 0x03;
  53.                                 buf[3] = 0x04;
  54.                                 MODH_WriteParam_10H(REG_P01, 2, buf);
  55.                         }
  56.                         break;
  57.                 default:
  58.                 {
  59.                 }break;
  60.         }               
  61. }


  62. int main(void)
  63. {
  64. //        u32 uid[3]={0};
  65. //        enhenced_run(ENABLE);
  66. //        nvic_priority_group_set(NVIC_PRIGROUP_PRE2_SUB2);
  67. //        systick_set(96);
  68. //        led_set();
  69. //        key_set();
  70. //        usart_set(9600);
  71. //       
  72. //        get_uid(uid);
  73. //        printf("sram=%dK bytes,flash=%dK bytes\r\n",get_memsize(mem_type_sram),get_memsize(mem_type_flash));
  74. //        printf("uid=[%x%x%x]\r\n",uid[0],uid[1],uid[2]);
  75. //    while (1)
  76. //        {
  77. //        led1=!led1;
  78. //                delay_ms(200);
  79. //                led2=!led2;
  80. //                delay_ms(200);
  81. //                led3=!led3;
  82. //                delay_ms(200);
  83. //                led4=!led4;
  84. //                delay_ms(200);
  85. //    }

  86.         Usart_FIFO_Init();
  87.         SysTick_Init();
  88.         while ( 1 )
  89.         {                        
  90.                 MODH_Poll();
  91.                 TestModbusHost(1);//用于测试向从机发送数据,正式使用有用户编写
  92.         }
  93. }





 楼主| zeshoufx 发表于 2021-7-13 17:08 | 显示全部楼层

上传工程文件

运行

运行

10-modbus_host.zip

6.21 MB, 下载次数: 117

工程文件

zhitao2072 发表于 2021-7-13 17:40 | 显示全部楼层
谢谢分享,你很牛掰啊
dwdsp 发表于 2021-7-14 08:38 | 显示全部楼层
顶个!很不错了!
90houyidai 发表于 2021-7-14 11:11 | 显示全部楼层
不错的模板工程
勇敢的大白菜 发表于 2021-7-14 16:05 | 显示全部楼层
学习了,好好下载之后,学习一下。
 楼主| zeshoufx 发表于 2021-7-14 16:25 | 显示全部楼层
zhitao2072 发表于 2021-7-13 17:40
谢谢分享,你很牛掰啊

一起学习交流,,
 楼主| zeshoufx 发表于 2021-7-14 16:26 | 显示全部楼层
dwdsp 发表于 2021-7-14 08:38
顶个!很不错了!

谢谢你,,,一起学习交流,,
一路向北lm 发表于 2021-7-14 16:45 | 显示全部楼层
主站用的 libmodbus?
 楼主| zeshoufx 发表于 2021-7-14 17:14 | 显示全部楼层

不是,,,
 楼主| zeshoufx 发表于 2021-7-14 22:02 | 显示全部楼层

一起学习交流,,,,
 楼主| zeshoufx 发表于 2021-7-15 08:38 | 显示全部楼层
勇敢的大白菜 发表于 2021-7-14 16:05
学习了,好好下载之后,学习一下。

可以一起学习交流,,,,,,,,,,
编号10086 发表于 2021-7-19 17:15 | 显示全部楼层
可以,正好要用安富莱的例程,直接抄一下楼主的,就可以不用自己一直了。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

67

主题

1991

帖子

15

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