zhangranvs 发表于 2023-8-5 14:09:45

分享modbus-rtu从机0F写多个线圈功能码程序


感谢安富莱提供的modbus教程与程序,最近在搞modbus程序过程中需要用到写多个线圈状态,发现安富莱的modbus协议栈没有,所以自己写了一个,分享给大家。
若有不完善的地方也欢迎指正。

static void MODS_0FH(void)
{
    uint16_t reg_addr;
    uint16_t reg_num;
    uint8_t byte_num;
    uint8_t i;
    uint8_t value;

    g_tModS.RspCode = RSP_OK;

    /** 第1步: 判断接到指定个数数据 ===============================================================*/
    /* 地址(8bit)+指令(8bit)+寄存器起始地址高低字节(16bit)+寄存器个数(16bit)+ 字节数(8bit)+ 数据n(8bit)+ CRC16 */
    if (g_tModS.RxCount < 10)
    {
      g_tModS.RspCode = RSP_ERR_VALUE; /* 数据值域错误 */
      goto err_ret;
    }

    /** 第2步: 数据解析 ===========================================================================*/
    /* 数据是大端,要转换为小端 */
    reg_addr = BEBufToUint16(&g_tModS.RxBuf); /* 寄存器号 */
    reg_num = BEBufToUint16(&g_tModS.RxBuf);/* 寄存器个数 */
    byte_num = g_tModS.RxBuf;               /* 后面的数据体字节数 */
   
    /* 判断寄存器个数和后面数据字节数是否一致 */
    /* 一个寄存器占1bit,不满8个也要占一字节 */
    if (byte_num != reg_num / 8 + (reg_num % 8 != 0))
    {
      g_tModS.RspCode = RSP_ERR_VALUE; /* 数据值域错误 */
      goto err_ret;
    }

    for (i = 0; i < reg_num; i++)
    {
      value = g_tModS.RxBuf;
      
      /* state为当前寄存器数据,0或1 */
      uint8_t state = (value >> (i % 8)) & 0x01;
      
      /* reg_addr + i为当前寄存器地址 */
      /* reg_addr + i - REG_DO1为首寄存器地址偏移量 */
      
      /* OUTPUT_ID_DO1为第一路输出GPIO序号,根据实际情况修改 */
      bsp_output_ctrl_switch(reg_addr + i - REG_DO1 + OUTPUT_ID_DO1, state);
    }

    /** 第3步: 应答回复 =========================================================================*/
err_ret:
    if (g_tModS.RspCode == RSP_OK) /* 正确应答 */
    {
      MODS_SendAckOk();
    }
    else
    {
      MODS_SendAckErr(g_tModS.RspCode); /* 告诉主机命令错误 */
    }
}

eric2013 发表于 2023-8-8 10:04:22

谢谢楼主分享。

当前分享的Modbus框架基本是通用的,大家用来支持其它功能码很方便,大家套一下即可。
页: [1]
查看完整版本: 分享modbus-rtu从机0F写多个线圈功能码程序