感谢安富莱提供的modbus教程与程序,最近在搞modbus程序过程中需要用到写多个线圈状态,发现安富莱的modbus协议栈没有,所以自己写了一个,分享给大家。
若有不完善的地方也欢迎指正。
[C] 纯文本查看 复制代码 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[2]); /* 寄存器号 */
reg_num = BEBufToUint16(&g_tModS.RxBuf[4]); /* 寄存器个数 */
byte_num = g_tModS.RxBuf[6]; /* 后面的数据体字节数 */
/* 判断寄存器个数和后面数据字节数是否一致 */
/* 一个寄存器占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[7 + i / 8];
/* 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); /* 告诉主机命令错误 */
}
}
|