打印
[应用相关]

modbus通讯协议-接收部分-求指教

[复制链接]
1362|4
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
garett|  楼主 | 2014-8-2 12:32 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
本帖最后由 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)            
{

}

沙发
garett|  楼主 | 2014-8-2 12:40 | 只看该作者
。。为啥添加附件不能超过1M。。超过了。。怎么上传工程??。。。

使用特权

评论回复
板凳
mmuuss586| | 2014-8-2 15:23 | 只看该作者
garett 发表于 2014-8-2 12:40
。。为啥添加附件不能超过1M。。超过了。。怎么上传工程??。。。

我记得好像是4M;
可能你级别太低,有限制吧;
分卷压缩试下;

使用特权

评论回复
地板
garett|  楼主 | 2014-8-2 17:14 | 只看该作者
mmuuss586 发表于 2014-8-2 15:23
我记得好像是4M;
可能你级别太低,有限制吧;
分卷压缩试下;

MODBUS_VER_1.0.zip (991.87 KB)


= =上传了!!求看!

使用特权

评论回复
5
szjyp226| | 2014-8-4 09:21 | 只看该作者
:lol  虽然不太明白。。但是帮楼主顶一个 希望楼主早点解决问题。

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

7

主题

21

帖子

0

粉丝