本帖最后由 garett 于 2014-8-2 17:15 编辑
MODBUS通讯协议。本人写了接收程序。大家一起来验证下。看看有没有什么问题个需要更改的地方。
求交流啊啊啊啊啊。每个功能的具体函数。都暂时控制的。因为还没想清楚用数组还是什么别的方法来控制。
/*获取StartAddr的第i个8位数据 不够补零*/
u8 GetByteData(u16 StartAdd,u16 i);
/*获取StartAddr的第i个数据*/
u16 GetData(u16 StartAdd,u16 i);
/*从StateAddr写入value 8位数据*/
void WriteForceState(u16 StateAddr,u8 value);
/*写寄存器值*/
void WriteRegister(u16 RegAddr,u16 RegData);
工程文件:
MODBUS_VER_1.0.zip
(991.87 KB)
= =大家一起来纠错啊~~还有说说自己的看法啊。。求交流。。
#define SlaveID 0x01 //主机地址
#define ReadCoilState 1 //读取线圈状态
#define ReadInputState 2 //读取输入状态
#define ReadHoldRegister 3 //读取保持寄存器
#define ReadInputRegister 4 //读取输入寄存器
#define ForceSingleCoilOutputState 5 //强制写单线圈输出状态
#define PresetSingleRegister 6 //预设(写)单寄存器
#define CommIndexSlaveID 0 //地址
#define CommIndexFunction 1 //功能码
#define CommIndexStartAddrH 2 //起始地址高位
#define CommIndexStartAddrL 3 //起始地址低位
#define CommIndexForceState 4 //强制状态
#define CommIndexDataH 4 //数据高位
#define CommIndexDataL 5 //数据低位
#define MaxRegisterLen 20 //寄存器最大长度
#define MaxDataLen 30 //数据最大长度
u8 CommIndexLength=0; //通信指针长度 在UART接收时设置
u8 CommIndexEnd=0xff; //通信指针结束 在UART接收时设置
u8 SendBuf[MaxDataLen]=0; //发送缓冲区
u8 ReceiveBuf[MaxDataLen]=0; //接收缓冲区
//接收处理
void DisposeReceive(void)
{
u16 CRC16Temp; //CRC校验临时存储变量
if(ReceiveBuf[CommIndexSlaveID]==SlaveID) //如果接收到的数据地址为从机地址
{
/*计算发送来的数据的CRC校验码*/
CRC16Temp=GetCRC16(ReceiveBuf,CommIndexLength);
/*验证计算出来的CRC校验值是否与缓冲区校验值相等*/
if(CRC16Temp==((u16)ReceiveBuf[CommIndexEnd-1]<<8|(u16)ReceiveBuf[CommIndexEnd]))
{ /*CRC校验正确,数据无误*/
switch(ReceiveBuf[CommIndexFunction])
{
case ReadCoilState: //1:读取线圈状态
ReadCoil();
break;
case ReadInputState: //2:读取输入状态
ReadInput();
break;
case ReadHoldRegister: //3读取保存寄存器
ReadHoldReg();
break;
case ReadInputRegister: //4读取输入寄存器
ReadInputReg();
break;
case ForceSingleCoilOutputState: //5强制写单线圈输出状态
ForceSingleCoil();
break;
case PresetSingleRegister: //6预设(写)单寄存器
PresetSingleReg();
break;
default:
break;
}
}
else //CRC校验错误
{
RequestRetry(); //请求主机重发指令
}
}
}
/*
*功能码:0x01 读取线圈状态
*发送:[硬件地址][01][起始地址高][起始地址低][总位数高][总位数低][CRC低][CRC高]
*返回:[硬件地址][01][ 字节数 ][ 位状态1 ][位状态2 ][位状态n ][CRC低][CRC高]
*/
void ReadCoil(void)
{
u16 StartAdd,BitNum,CRC16Temp,i;
u8 CommIndexNum;
StartAdd=(u16)ReceiveBuf[CommIndexStartAddrH]<<8|(u16)ReceiveBuf[CommIndexStartAddrL];
BitNum=(u16)ReceiveBuf[CommIndexDataH]<<8|(u16)ReceiveBuf[CommIndexDataL];
BitNum=BitNum/8;
if(BitNum%8!=0)
BitNum++;
SendBuf[CommIndexNum++]=SlaveID;
SendBuf[CommIndexNum++]=ReadCoilState;
SendBuf[CommIndexNum++]=(u8)BitNum;
/*获取X位状态*/
for(i=0;i<BitNum;i++)
{
/*获取StartAdd的第i个8位数据 不够补0*/
SendBuf[CommIndexNum++]=GetByteData(StartAdd,i);
}
CRC16Temp=GetCRC16(SendBuf,CommIndexNum-1);
SendBuf[CommIndexNum++]=(u8)CRC16Temp>>8;
SendBuf[CommIndexNum++]=(u8)CRC16Temp;
//从SendBuf发送CommIndexNum个8位的返回数据
Uart1_Send(SendBuf,CommIndexNum);
//结束 清除缓冲区
memset(SendBuf,0,sizeof(SendBuf));
}
/*
*功能码:0x02 读取输入状态
*发送:[硬件地址][02][起始地址高][起始地址低][总位数高][总位数低][CRC低][CRC高]
*返回:[硬件地址][02][ 字节数 ][ 位状态1 ][位状态2 ][位状态n ][CRC低][CRC高]
*/
void ReadInput(void)
{
u16 StartAdd,BitNum,CRC16Temp,i;
u8 CommIndexNum=0;
StartAdd=(u16)ReceiveBuf[CommIndexStartAddrH]<<8|(u16)ReceiveBuf[CommIndexStartAddrL];
BitNum=(u16)ReceiveBuf[CommIndexDataH]<<8|(u16)ReceiveBuf[CommIndexDataL];
BitNum=BitNum/8;
if(BitNum%8!=0)
BitNum++;
SendBuf[CommIndexNum++]=SlaveID;
SendBuf[CommIndexNum++]=ReadInputState;
SendBuf[CommIndexNum++]=(u8)BitNum;
/*获取X位状态*/
for(i=0;i<BitNum;i++)
{
/*获取StartAdd的第i个8位数据 不够补0*/
SendBuf[CommIndexNum++]=GetByteData(StartAdd,i);
}
CRC16Temp=GetCRC16(SendBuf,CommIndexNum-1);
SendBuf[CommIndexNum++]=(u8)CRC16Temp>>8;
SendBuf[CommIndexNum++]=(u8)CRC16Temp;
//从SendBuf发送CommIndexNum个8位的返回数据
Uart1_Send(SendBuf,CommIndexNum);
//结束 清除缓冲区
memset(SendBuf,0,sizeof(SendBuf));
}
/*
*功能码:0x03 读取保持寄存器
*发送:[硬件地址][03][起始地址高][起始地址低][总寄存器数高][总寄存器数低][ CRC低 ][ CRC高 ]
*返回:[硬件地址][03][ 字节数 ][寄存器0高 ][ 寄存器0低 ][ 寄存器1高 ][ 寄存器1低 ][ 寄存器n高 ][ 寄存器n低 ][ CRC低 ][ CRC高 ]
*/
void ReadHoldReg(void)
{
u16 StartAdd,RegLen,i,DataTemp,CRC16Temp;
u8 CommIndexNum=0;
//获取起始地址
StartAdd=(u16)ReceiveBuf[CommIndexStartAddrH]<<8|(u16)ReceiveBuf[CommIndexStartAddrL];
//获取读取长度
RegLen=(u16)ReceiveBuf[CommIndexDataH]<<8|(u16)ReceiveBuf[CommIndexDataL];
SendBuf[CommIndexNum++]=SlaveID;
SendBuf[CommIndexNum++]=ReadHoldRegister;
SendBuf[CommIndexNum++]=(u8)(RegLen*2);
for(i=0;i<RegLen;i++)
{
/*获取16位数据并返回赋给[寄存器n高][寄存器n低]*/
DataTemp=GetData(StartAdd,i);
SendBuf[CommIndexNum++] = (u8)(DataTemp>>8);
SendBuf[CommIndexNum++] = (u8)(DataTemp&0x00ff);
}
CRC16Temp=GetCRC16(SendBuf,CommIndexNum-1);
SendBuf[CommIndexNum++]=(u8)(CRC16Temp>>8);
SendBuf[CommIndexNum++]=(u8)(CRC16Temp&0x00ff);
//从SendBuf发送CommIndexNum个8位的返回数据
Uart1_Send(SendBuf,CommIndexNum);
//结束 清除缓冲区
memset(SendBuf,0,sizeof(SendBuf));
}
/*
*功能码:0x04 读取输入寄存器
*发送:[硬件地址][04][起始地址高][起始地址低][总寄存器数高][总寄存器数低][ CRC低 ][ CRC高 ]
*返回:[硬件地址][04][ 字节数 ][寄存器0高 ][ 寄存器0低 ][ 寄存器1高 ][ 寄存器1低 ][ 寄存器n高 ][ 寄存器n低 ][ CRC低 ][ CRC高 ]
*/
void ReadInputReg(void)
{
u16 StartAdd,RegLen,i,DataTemp,CRC16Temp;
u8 CommIndexNum=0;
//获取起始地址
StartAdd=(u16)ReceiveBuf[CommIndexStartAddrH]<<8|(u16)ReceiveBuf[CommIndexStartAddrL];
//获取读取长度
RegLen=(u16)ReceiveBuf[CommIndexDataH]<<8|(u16)ReceiveBuf[CommIndexDataL];
SendBuf[CommIndexNum++]=SlaveID;
SendBuf[CommIndexNum++]=ReadHoldRegister;
SendBuf[CommIndexNum++]=(u8)(RegLen*2);
for(i=0;i<RegLen;i++)
{
/*获取16位数据并返回赋给[寄存器n高][寄存器n低]*/
DataTemp=GetData(StartAdd,i);
SendBuf[CommIndexNum++] = (u8)(DataTemp>>8);
SendBuf[CommIndexNum++] = (u8)(DataTemp&0x00ff);
}
CRC16Temp=GetCRC16(SendBuf,CommIndexNum-1);
SendBuf[CommIndexNum++]=(u8)(CRC16Temp>>8);
SendBuf[CommIndexNum++]=(u8)(CRC16Temp&0x00ff);
//串口发送返回数据
Uart1_Send(SendBuf,CommIndexNum);
//结束 清除缓冲区
memset(SendBuf,0,sizeof(SendBuf));
}
/*
*功能码:0x05 强制(写)单线圈(输出状态)
*发送:[硬件地址][05][线圈地址高][线圈地址低][ 强制状态 ][ CRC低 ][ CRC高 ]
*返回:[硬件地址][05][线圈地址高][线圈地址低][ 强制状态 ][ CRC低 ][ CRC高 ]
*/
void ForceSingleCoil(void)
{
u16 CoilAddr,CRC16Temp;
u8 ForceState,CommIndexNum=0;
CoilAddr=(u16)ReceiveBuf[CommIndexStartAddrH]<<8|(u16)ReceiveBuf[CommIndexStartAddrL];
ForceState=ReceiveBuf[CommIndexForceState];
//从CoilAddr写入ForceState 8位数据
WriteForceState(CoilAddr,ForceState);
SendBuf[CommIndexNum++]=SlaveID;
SendBuf[CommIndexNum++]=ForceSingleCoilOutputState;
SendBuf[CommIndexNum++]=(u8)CoilAddr>>8;
SendBuf[CommIndexNum++]=(u8)CoilAddr&0x00ff;
SendBuf[CommIndexNum++]=ForceState;
CRC16Temp=GetCRC16(SendBuf,CommIndexNum-1);
SendBuf[CommIndexNum++]=(u8)(CRC16Temp>>8);
SendBuf[CommIndexNum++]=(u8)(CRC16Temp&0x00ff);
//串口发送返回数据
Uart1_Send(SendBuf,CommIndexNum);
//结束 清除缓冲区
memset(SendBuf,0,sizeof(SendBuf));
}
/*
*功能码:0x06 预设(写)单寄存器
*发送:[硬件地址][06][寄存器地址高][寄存器地址低][寄存器值高][寄存器值低][ CRC低 ][ CRC高 ]
*返回:[硬件地址][06][寄存器地址高][寄存器地址低][寄存器值高][寄存器值低][ CRC低 ][ CRC高 ]
*/
void PresetSingleReg(void)
{
u16 RegAddr,RegData,CRC16Temp;
u8 CommIndexNum=0;
RegAddr=(u16)ReceiveBuf[CommIndexStartAddrH]<<8|(u16)ReceiveBuf[CommIndexStartAddrL];
RegData=(u16)ReceiveBuf[CommIndexDataH]<<8|(u16)ReceiveBuf[CommIndexDataL];
/*写寄存器值*/
WriteRegister(RegAddr,RegData);
SendBuf[CommIndexNum++]=SlaveID;
SendBuf[CommIndexNum++]=PresetSingleRegister;
SendBuf[CommIndexNum++]=(u8)RegAddr>>8;
SendBuf[CommIndexNum++]=(u8)RegAddr&0x00ff;
SendBuf[CommIndexNum++]=(u8)RegData>>8;
SendBuf[CommIndexNum++]=(u8)RegData&0x00ff;
CRC16Temp=GetCRC16(SendBuf,CommIndexNum-1);
SendBuf[CommIndexNum++]=(u8)(CRC16Temp>>8);
SendBuf[CommIndexNum++]=(u8)(CRC16Temp&0x00ff);
//串口发送返回数据
Uart1_Send(SendBuf,CommIndexNum);
//结束 清除缓冲区
memset(SendBuf,0,sizeof(SendBuf));
}
/*
*CRC校验错误 请求主机重发指令
*/
void RequestRetry(void)
{
}
|
|