OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 3365|回复: 3

编写的Modbus程序,调试的过程中遇到了BUG

[复制链接]

4

主题

24

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
323
金钱
323
注册时间
2016-3-24
在线时间
55 小时
发表于 2018-1-8 19:55:07 | 显示全部楼层 |阅读模式
4金钱
我设置的寄存器地址是0-6,一开始发过去的请求报文是01 04 00 00 00 06 70 08,响应报文是01 04 0c 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 54 2c,能够正常响应
但是我把寄存器的地址改大到8,发过去的报文是01 04 00 00 00 08 f1 cc,但响应报文就很奇怪,有两个不同的响应,一个是01 82 02 c1 61,另一个是01 04 10 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 36 a1,而且两个是交叉响应回来的,但正常的话应该是第一个响应才是正确的,寄存器的地址超出了我设置的范围。以下是源码。
[mw_shl_code=c,true]PARSEERROR ModbusRtu_DatParse(Modbus_ParameterTypeDef* pModbus_Msg)
{
        uchar8_t i;
        MODBUSDAT id = 0,func = 1,Reg = 2;
        volatile uint16_t  regAddr;
        MODBUSDAT crcDataLo,crcDataHi,usDataLen;                                                                                //crc校验低位,高位
        MODBUSDAT dat[30];
       
        if(pModbus_Msg->IsComplete != True)                                                                                                //判断数据是否接收完成
                return PARError_RecErr;                                                                                                                //接收未完成,则返回接收错误
        pModbus_Msg->IsComplete = False;                                                                                                //接收完成,清除标志
       
        if(pModbus_Msg->pRecBuf[id] != ARM_ADDRESS)                                                                                //判断设备地址,非本机地址,则不处理数据
        {
                pModbus_Msg->RxCount = 0;
                return PARError_AddrErr;                                                                                                        //返回错误码
        }       
       
        //CRC校验,检查数据的完整性
        usDataLen = pModbus_Msg->RxCount - 2;                                                                                        //获取数据长度
        pModbus_Msg->crcData = crc16(pModbus_Msg->pRecBuf,usDataLen);                                        //计算CRC
        crcDataHi = pModbus_Msg->crcData / 256;                                                                                        //CRC高位
        crcDataLo = pModbus_Msg->crcData % 256;                                                                                        //CRC低位
        if(!(crcDataHi == pModbus_Msg->pRecBuf[usDataLen] && crcDataLo == pModbus_Msg->pRecBuf[usDataLen + 1]))//CRC校验
        {
                pModbus_Msg->RxCount = 0;                                                                                                        //接收区清空
                return PARError_crcErr;                                                                                                                //如果CRC校验错误,则返回错误码
        }       
       
        regAddr = (pModbus_Msg->pRecBuf[Reg] << 8) + pModbus_Msg->pRecBuf[Reg + 1];                //获取寄存器起始地址
        if( pModbus_Msg->pSendBuf[func] == ModbusFunc_04 || pModbus_Msg->pSendBuf[func] == ModbusFunc_16)//判断是否为读或写多个寄存器
                regAddr = regAddr + ((pModbus_Msg->pRecBuf[Reg + 2] << 8) + pModbus_Msg->pRecBuf[Reg + 3]);
        if(regAddr > REGALL)                                                                                                                        //判断寄存器地址是否超出范围
        {
                pModbus_Msg->RxCount = 0;                                                                                                        //接收区清空
                ModbusRtu_Error(pModbus_Msg->pSendBuf,ErrorFunc_RegAddr);                                        //非法数据地址
                pModbus_Msg->TxCount = 5;
                pModbus_Msg->pSend(pModbus_Msg->pSendBuf,pModbus_Msg->TxCount);
                return PARError_ErrFunc;
        }
       
        //数据解析
        switch(pModbus_Msg->pRecBuf[func])
        {
                case ModbusFunc_04:                                                                                                                        //4号功能码,读输入寄存器
                {
                        //应答报文
                        pModbus_Msg->pSendBuf[id] = ARM_ADDRESS;                                                                //设备地址
                        pModbus_Msg->pSendBuf[func] = ModbusFunc_04;                                                        //功能码
                        usDataLen = pModbus_Msg->pSendBuf[2] = pModbus_Msg->pRecBuf[5] * 2;                //字节数
                        pModbus_Msg->pfunc_04(dat,usDataLen);
                        for(i = 0;i < pModbus_Msg->pRecBuf[5] * 2;i++)
                                pModbus_Msg->pSendBuf[i + 2] = dat;
                        usDataLen += 3;                                                                                                                        //数据长度
                }break;
                case ModbusFunc_06:                                                                                                                        //6号功能码,写单个寄存器
                {
                        pModbus_Msg->pfunc_06((REGAddr)regAddr,((pModbus_Msg->pRecBuf[4] << 8) + pModbus_Msg->pRecBuf[5]));
                        //应答报文
                        usDataLen = 6;                                                                                                                        //数据长度
                        for(i = 0;i < usDataLen;i++)
                                pModbus_Msg->pSendBuf = pModbus_Msg->pRecBuf;
                }break;
                case ModbusFunc_16:                                                                                                                        //16号功能码,写多个寄存器
                {
                        pModbus_Msg->pfunc_16();
                        //应答报文
                        usDataLen = 6;                                                                                                                        //数据长度
                        for(i = 0;i < usDataLen;i++)
                                pModbus_Msg->pSendBuf = pModbus_Msg->pRecBuf;
                }break;
                default :
                {
                        pModbus_Msg->RxCount = 0;                                                                                                //接收区清空
                        ModbusRtu_Error(pModbus_Msg->pSendBuf,ErrorFunc_Func);                                        //不是本设备支持的功能码
                        pModbus_Msg->TxCount = 5;
                        pModbus_Msg->pSend(pModbus_Msg->pSendBuf,pModbus_Msg->TxCount);
                        return PARError_ErrFunc;
                }
        }
       
        pModbus_Msg->crcData = crc16(pModbus_Msg->pSendBuf,usDataLen);                                        //计算CRC
        pModbus_Msg->pSendBuf[usDataLen] = pModbus_Msg->crcData / 256;                                        //CRC高位
        pModbus_Msg->pSendBuf[usDataLen + 1] = pModbus_Msg->crcData % 256;                                //CRC低位
        pModbus_Msg->TxCount = usDataLen + 2;                                                                                        //发送数据长度
        pModbus_Msg->RxCount = 0;                                                                                                                //清除接收缓存
        pModbus_Msg->pSend(pModbus_Msg->pSendBuf,pModbus_Msg->TxCount);
       
        return PARError_OK;                                                                                                                                //如果没有错误,则返回无错误值
}[/mw_shl_code]这一段是判断寄存器范围的(从上面的源码抽出来的)
[mw_shl_code=applescript,true]regAddr = (pModbus_Msg->pRecBuf[Reg] << 8) + pModbus_Msg->pRecBuf[Reg + 1];        //获取寄存器起始地址
if( pModbus_Msg->pSendBuf[func] == ModbusFunc_04 || pModbus_Msg->pSendBuf[func] == ModbusFunc_16)//判断是否为读或写多个寄存器
regAddr = regAddr + ((pModbus_Msg->pRecBuf[Reg + 2] << 8) + pModbus_Msg->pRecBuf[Reg + 3]);
if(regAddr > REGALL)        //判断寄存器地址是否超出范围
{
pModbus_Msg->RxCount = 0;        //接收区清空
ModbusRtu_Error(pModbus_Msg->pSendBuf,ErrorFunc_RegAddr);        //非法数据地址
pModbus_Msg->TxCount = 5;
pModbus_Msg->pSend(pModbus_Msg->pSendBuf,pModbus_Msg->TxCount);
return PARError_ErrFunc;
}[/mw_shl_code]

正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165516
金钱
165516
注册时间
2010-12-1
在线时间
2116 小时
发表于 2018-1-9 00:07:17 | 显示全部楼层
我是开源电子网www.openedv.com站长,有关站务问题请与我联系。
正点原子STM32开发板购买店铺http://openedv.taobao.com
正点原子官方微信公众平台,点击这里关注“正点原子”
回复

使用道具 举报

4

主题

24

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
323
金钱
323
注册时间
2016-3-24
在线时间
55 小时
 楼主| 发表于 2018-1-9 13:35:39 | 显示全部楼层
正点原子 发表于 2018-1-9 00:07
参考我发的代码。

原子哥,你发的代码是在论坛上的吗
回复

使用道具 举报

4

主题

24

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
323
金钱
323
注册时间
2016-3-24
在线时间
55 小时
 楼主| 发表于 2018-1-9 14:02:58 | 显示全部楼层
正点原子 发表于 2018-1-9 00:07
参考我发的代码。

原子哥,找到了
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2025-5-19 22:40

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

快速回复 返回顶部 返回列表