📄 modbus_rtu.c
字号:
//****************************************************************************
//Copyright (c) 2007-2008 ABX CO,.LTD
//----------All rights reserved----------
//文件名称: modbusrtu.c
//模块功能: MODBUSRTU通讯协议
//创建日期: 2008.01.2
//创 建 人: 罗德良
//参考文档: LPC2104开发板
//说 明: 参照原modbusrtu.c修改成平台无关性
//修改历史:
//****************************************************************************
#define IN_MODBUS_RTU
#include "config.h"
//寄存器在此定义
//内部寄存器定义
#define AICOUNT 35 //AI路数
#define AOCOUNT 146 //AO路数
#define DOCOUNT 8 //DO路数
#define DICOUNT 8 //DI路数
/******************************************
ui16AiReg[0]-[15] AI量化值
ui16AiReg[16] 内部温度值
ui16AiReg[17]-[32] AI采样值
设备信息
ui16AiReg[33] 设备类型
ui16AiReg[34] 设备版本号
ui16AoReg[0]-[1] AO
ui16AoReg[2]-[17] DI计数值(两寄存器为一路)
以下为配置参数
ui16AoReg[18] 存盘请求寄存器
ui16AoReg[19] 站号
ui16AoReg[20] Uart0波特率
ui16AoReg[21] Uart0数据位(Bit7), 校验位(Bit6,5), 停止位(Bit4)
ui16AoReg[22] Uart0帧间隔时间
ui16AoReg[23] Uart1波特率
ui16AoReg[24] Uart1数据位(Bit7), 校验位(Bit6,5), 停止位(Bit4)
ui16AoReg[25] Uart1帧间隔时间
ui16AoReg[26]-[27] AO零位
ui16AoReg[28]-[29] AO满度
ui16AoReg[30]-[37] AI零位(I)
ui16AoReg[38]-[45] AI满度(I)
ui16AoReg[46]-[53] AI零位(V)
ui16AoReg[54]-[61] AI满度(V)
ui16AoReg[62]-[69] AI显示量程下限
ui16AoReg[70]-[77] AI显示量程上限
ui16AoReg[78]-[85] AI显示小数位数
ui16AoReg[86]-[93] AI报警上限
ui16AoReg[94]-[101] AI报警下限
ui16AoReg[102] 内部温度报警上限
ui16AoReg[103] 内部温度报警下限
ui16AoReg[104]-[111]AI信号类型
ui16AoReg[112]-[119]DI工作模式
ui16AoReg[120]-[127]DO工作模式
ui16AoReg[128]-[135]DO控制源
ui16AoReg[136]-[143]DO点动延时寄存器
ui16AoReg[144]-[145]AO输出寄存器
******************************************/
volatile UINT16 ui16AiReg[AICOUNT]; //AI寄存器
volatile UINT16 ui16AoReg[AOCOUNT]; //AO寄存器
volatile UCHAR ucDoReg[DOCOUNT / 8]; //DO寄存器
volatile UCHAR ucDiReg[DICOUNT / 8]; //DI寄存器
//协议结构
typedef struct
{
UCHAR ucSta; //站号
UCHAR ucFun; //功能码
UCHAR ucMess[256]; //内容
}tagMODBUSREV; //MODBUS接收数据结构
typedef struct
{
UCHAR ucSta; //站号
UCHAR ucFun; //功能码
UCHAR ucStarAdrHi; //起始寄存器地址高字节
UCHAR ucStarAdrLo; //起始寄存器地址低字节
UCHAR ucCntHi; //数量高字节
UCHAR ucCntLo; //数量低字节
UCHAR ucCrcHi; //CRC高字节
UCHAR ucCrcLo; //CRC低字节
}tagMODREAD; //MODBUS读数据结构及多写应答结构
typedef struct
{
UCHAR ucSta; //站号
UCHAR ucFun; //功能码
UCHAR ucByteCnt; //字节数
UCHAR ucMess[256]; //内容
}tagMODREADRESP; //MODBUS读应答数据结构
typedef struct
{
UCHAR ucSta; //站号
UCHAR ucFun; //功能码
UCHAR ucAdrHi; //寄存器地址高字节
UCHAR ucAdrLo; //寄存器地址低字节
UCHAR ucDatHi; //数据高字节
UCHAR ucDatLo; //数据低字节
UCHAR ucCrcHi; //CRC高字节
UCHAR ucCrcLo; //CRC低字节
}tagWRSINGAL; //MODBUS写单个寄存器及应答结构
typedef struct
{
UCHAR ucSta; //站号
UCHAR ucFun; //功能码
UCHAR ucStarAdrHi; //起始寄存器地址高字节
UCHAR ucStarAdrLo; //超始寄存器地址低字节
UCHAR ucCntHi; //数量高字节
UCHAR ucCntLo; //数量低字节
UCHAR ucByteCnt; //字节数
UCHAR ucMess[64]; //内容
}tagWRMULTE; //MODBUS写多个寄存器数据结构
typedef struct
{
UCHAR ucSta; //站号
UCHAR ucFun; //功能码
UCHAR ucLen; //长度
UCHAR ucFunNo; //代号
UCHAR ucMess[128]; //内容
}tagWRCONFIG; //配置结构
//MODBUS异常码
#define NO_ERR 0x00 //无异常
#define FUN_ERR 0x01 //不支持的功能码
#define ADR_ERR 0x02 //地址超出范围
#define VAL_ERR 0x03 //数据超出范围
#define FAIL_ERR 0x04 //执行失败
#define CALL_ERR 0x05 //调用参数错误
//****************************************************************************
//函数名称: Read_MultAI
//函数功能: 读输入寄存器(AI)
//输入参数: UCHAR *ucpRevcBuff 接收缓冲
// UCHAR *ucpSendBuff 发送缓冲
// UCHAR *ucpLen 发送缓冲长度
//输出参数: void
//返 回 值: UCHAR 异常码
//创建日期: 2008.01.02
//创 建 人: 罗德良
//参考文档:
//说 明: Modbus 4号功能码
//修改历史:
//****************************************************************************
UCHAR Read_MultAI(UCHAR *ucpRevcBuff, UCHAR *ucpSendBuff, UCHAR *ucpLen)
{
UINT16 ui16Temp, i, ui16Len;
UCHAR m;
tagMODREAD *tagpModRead;
tagMODREADRESP *tagpModReadResp;
if (ucpRevcBuff == NULL || ucpSendBuff == NULL || ucpLen == NULL)
{
return (CALL_ERR);
}
tagpModRead = (tagMODREAD *)ucpRevcBuff; //接收缓冲区
tagpModReadResp = (tagMODREADRESP *)ucpSendBuff; //应答缓冲区
tagpModReadResp -> ucSta = tagpModRead -> ucSta; //站号
tagpModReadResp -> ucFun = tagpModRead -> ucFun; //功能码
//寄存器起始地址
ui16Temp = tagpModRead -> ucStarAdrHi * 256ul + tagpModRead -> ucStarAdrLo;
if (ui16Temp >= AICOUNT) return (ADR_ERR); //寄存器超出范围
//寄存器数量
ui16Len = tagpModRead -> ucCntHi * 256ul + tagpModRead -> ucCntLo;
if ((ui16Len + ui16Temp) > AICOUNT) return(ADR_ERR); //寄存器超出范围
//返回数据字节数
tagpModReadResp -> ucByteCnt = ui16Len * 2;
//内容处理
m = 0;
for (i = ui16Temp; i < ui16Len + ui16Temp; i++)
{
tagpModReadResp -> ucMess[m++] = ui16AiReg[i] / 256ul;
tagpModReadResp -> ucMess[m++] = ui16AiReg[i];
}
//计算CRC
ui16Temp = CRC16((UCHAR *)tagpModReadResp, 3 + tagpModReadResp -> ucByteCnt);
tagpModReadResp -> ucMess[tagpModReadResp -> ucByteCnt] = ui16Temp / 256;
tagpModReadResp -> ucMess[tagpModReadResp -> ucByteCnt + 1] = ui16Temp;
//发送缓冲长度
*ucpLen = 3 + tagpModReadResp -> ucByteCnt + 2;
return (NO_ERR);
}
//****************************************************************************
//函数名称: Read_MultAO
//函数功能: 读保持寄存器(AO)
//输入参数: UCHAR *ucpRevcBuff 接收缓冲
// UCHAR *ucpSendBuff 发送缓冲
// UCHAR *ucpLen 发送缓冲长度
//输出参数: void
//返 回 值: UCHAR 异常码
//创建日期: 2008.01.02
//创 建 人: 罗德良
//参考文档:
//说 明: Modbus 3号功能码
//修改历史:
//****************************************************************************
UCHAR Read_MultAO(UCHAR *ucpRevcBuff, UCHAR *ucpSendBuff, UCHAR *ucpLen)
{
UINT16 ui16Temp, i, ui16Len;
UCHAR m;
tagMODREAD *tagpModRead;
tagMODREADRESP *tagpModReadResp;
if (ucpRevcBuff == NULL || ucpSendBuff == NULL || ucpLen == NULL)
{
return (CALL_ERR);
}
tagpModRead = (tagMODREAD *)ucpRevcBuff; //接收缓冲区
tagpModReadResp = (tagMODREADRESP *)ucpSendBuff; //应答缓冲区
tagpModReadResp -> ucSta = tagpModRead -> ucSta; //站号
tagpModReadResp -> ucFun = tagpModRead -> ucFun; //功能码
//寄存器起始地址
ui16Temp = tagpModRead -> ucStarAdrHi * 256ul + tagpModRead -> ucStarAdrLo;
if (ui16Temp >= AOCOUNT) return (ADR_ERR); //寄存器超出范围
//寄存器数量
ui16Len = tagpModRead -> ucCntHi * 256ul + tagpModRead -> ucCntLo;
if ((ui16Len + ui16Temp) > AOCOUNT) return(ADR_ERR); //寄存器超出范围
//返回数据字节数
tagpModReadResp -> ucByteCnt = ui16Len * 2;
//内容处理
m = 0;
for (i = ui16Temp; i < ui16Len + ui16Temp; i++)
{
tagpModReadResp -> ucMess[m++] = ui16AoReg[i] / 256ul;
tagpModReadResp -> ucMess[m++] = ui16AoReg[i];
}
//计算CRC
ui16Temp = CRC16((UCHAR *)tagpModReadResp, 3 + tagpModReadResp -> ucByteCnt);
tagpModReadResp -> ucMess[tagpModReadResp -> ucByteCnt] = ui16Temp / 256;
tagpModReadResp -> ucMess[tagpModReadResp -> ucByteCnt + 1] = ui16Temp;
//发送缓冲长度
*ucpLen = 3 + tagpModReadResp -> ucByteCnt + 2;
return (NO_ERR);
}
//****************************************************************************
//函数名称: Read_MultCoil
//函数功能: 读取线圈状态
//输入参数: UCHAR *ucpRevcBuff 接收缓冲
// UCHAR *ucpSendBuff 发送缓冲
// UCHAR *ucpLen 发送缓冲长度
//输出参数: void
//返 回 值: UCHAR 异常码
//创建日期: 2008.01.02
//创 建 人: 罗德良
//参考文档:
//说 明: Modbus 1号功能码
//修改历史:
//****************************************************************************
UCHAR Read_MultCoil(UCHAR *ucpRevcBuff, UCHAR *ucpSendBuff, UCHAR *ucpLen)
{
UINT16 ui16Temp, i, ui16Len;
UCHAR ucTemp, ucByteNo, ucBitNo;
tagMODREAD *tagpModRead;
tagMODREADRESP *tagpModReadResp;
if (ucpRevcBuff == NULL || ucpSendBuff == NULL || ucpLen == NULL)
{
return (CALL_ERR);
}
tagpModRead = (tagMODREAD *)ucpRevcBuff; //接收缓冲区
tagpModReadResp = (tagMODREADRESP *)ucpSendBuff; //应答缓冲区
tagpModReadResp -> ucSta = tagpModRead -> ucSta; //站号
tagpModReadResp -> ucFun = tagpModRead -> ucFun; //功能码
//寄存器起始地址
ui16Temp = tagpModRead -> ucStarAdrHi * 256ul + tagpModRead -> ucStarAdrLo;
if (ui16Temp >= DOCOUNT) return (ADR_ERR); //寄存器超出范围
//寄存器数量
ui16Len = tagpModRead -> ucCntHi * 256ul + tagpModRead -> ucCntLo;
if ((ui16Len + ui16Temp) > DOCOUNT) return(ADR_ERR); //寄存器超出范围
//返回数据字节数
tagpModReadResp -> ucByteCnt = ui16Len / 8;
if ((ui16Len % 8) != 0)
{
tagpModReadResp -> ucByteCnt += 1;
}
//内容处理
i = 0;
while (i < ui16Len)
{
//取寄存器位值
ucByteNo = ui16Temp / 8;
ucBitNo = ui16Temp % 8;
ucTemp = ((ucDoReg[ucByteNo] >> ucBitNo) & 0x01);
if ((i % 8) == 0)
{
tagpModReadResp -> ucMess[i / 8] = 0x00;
}
//填充到发送缓冲
tagpModReadResp -> ucMess[i / 8] |= (ucTemp << (i % 8));
i++;
ui16Temp++;
}
//计算CRC
ui16Temp = CRC16((UCHAR *)tagpModReadResp, 3 + tagpModReadResp -> ucByteCnt);
tagpModReadResp -> ucMess[tagpModReadResp -> ucByteCnt] = ui16Temp / 256;
tagpModReadResp -> ucMess[tagpModReadResp -> ucByteCnt + 1] = ui16Temp;
//发送缓冲长度
*ucpLen = 3 + tagpModReadResp -> ucByteCnt + 2;
return (NO_ERR);
}
//****************************************************************************
//函数名称: Read_MultDI
//函数功能: 读取离输入状态
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -