搜索
bottom↓
回复: 3

请教MODBUS通讯,上位机第二次才能读到下位机

[复制链接]

出0入4汤圆

发表于 2013-9-12 13:59:02 | 显示全部楼层 |阅读模式
程序如下,单片机是STC12C5A60S2,目前的程序量是60K,当多个下位机被主机读时,第一个被读到的地址总是一次就能读成功,以后的地址读第二次才能被读到,请教是什么原因?

void Modbus_Comm()
{

        if( (Receive_State == Receive_Done) )
        {         
                if( Modbus_Check_CRC() )
                {
                        Modbus_Function();
                       
                        Modbus_Send_CRC();
                        SendFlag        =         1;
                }  
                if(SendFlag)    // max485(半双工通信) RE/DE定义 RE=0为接受状态  DE=1为发送状态(参考MAX485芯片管脚)
                {       
                        ES=0;
                        while( Send_Num > 0 )
                        {  
                                Send_Num--;       
                                TI=0;
                                SBUF =Send_Sbuf[Send_Num1] ;
                                while(TI==0);
                                Send_Num1++;
                        }        
                        Send_Num1         =        0;
                        SendFlag        =        0;
                        RS485E        =        0;              //接收状态
                        ES=1;
                }
                Receive_State = Start_Receive;
        }
        if(abc_true && (Local_Addr == 0 | Local_Addr == 253) )
        {
                abc_true = 0 ;
                Local_Addr = 253 ;                //临时子机地址
                Send_Sbuf[0] = 0x01 ;        //主机地址
                Send_Sbuf[1] = 0x03 ;        //读命令
                Send_Sbuf[2] = 0x00 ;
                Send_Sbuf[3] = 0xfd ;                //地址
                Send_Sbuf[4] = 0x00 ;
                Send_Sbuf[5] = 0x01 ;        //数量
                Send_Num = 8;
                Modbus_Send_CRC();
                ES=0;
                while( Send_Num > 0 )
                {  
                        Send_Num--;       
                        TI=0;
                        SBUF =Send_Sbuf[Send_Num1] ;
                        while(TI==0);
                        Send_Num1++;
                }        
                Send_Num1         =        0;
                SendFlag        =        0;
                RS485E        =        0;              //接收状态
                ES=1;
        }
        if(abc_true && (Local_Addr != 0 | Local_Addr != 253) )
        {
                abc_true = 0 ;
                Send_Sbuf[0] = 0x01 ;        //主机地址
                Send_Sbuf[1] = 0x03 ;        //读命令
                Send_Sbuf[2] = 0x00 ;
                Send_Sbuf[3] = 0xfe ;                //地址
                Send_Sbuf[4] = 0x00 ;
                Send_Sbuf[5] = 0x01 ;        //数量
                Send_Num = 8;
                Modbus_Send_CRC();
                ES=0;
                while( Send_Num > 0 )
                {  
                        Send_Num--;       
                        TI=0;
                        SBUF =Send_Sbuf[Send_Num1] ;
                        while(TI==0);
                        Send_Num1++;
                }        
                Send_Num1         =        0;
                SendFlag        =        0;
                RS485E        =        0;              //接收状态
                ES=1;
        }

}
void Modbus_Delay(Uchar i)
{
        Uchar j;
        for(i; i > 0; i--)
                for(j = 200; j > 0; j--);
}
Uint Modbus_CRC_Check(Uchar *pack, Uint num)
{
        Uchar CRCcode_H = 0XFF;                        // 高CRC字节初始化
        Uchar CRCcode_L = 0XFF;                        // 低CRC 字节初始化
        Uchar index;                                        // 数据索引
        while (num--)
        {
                index = CRCcode_L ^ (*pack++);       
                CRCcode_L = CRCcode_H ^ CRC_H[index];
                CRCcode_H = CRC_L[index];
        }
        return (CRCcode_L << 8 | CRCcode_H);        // MODBUS 规定低位在前
}
void Modbus_Read_Reg(void)                                 
{       
        Uchar i,dat_H,dat_L;
        Uchar j=3;
        Send_Sbuf[2] = Receive_Sbuf[5] * 2;                                // 返回 读取的字节个数
        Send_Num = 5 + Send_Sbuf[2];                                        // 5个固定字节+数据个数 addr1 + fun1 + num1 +【data】+ crc2
        for(i=0; i<Receive_Sbuf[5]; i++)                                        //i++为连续读
        {       
                dat_H = 0;
                switch(Receive_Sbuf[3] + i)                                                // 地址索引递增        //上位机命令地址加上 字节数
                {                               
                        case 0:           dat_L = Local_Addr; //Local_Addr
                                                break;   //通讯地址
                       
                        case 1:    dat_L = 0; //txslnum
                                                break;//70        通讯速率
                    case 2 :
                                        if(Receive_Sbuf[2]==0xfd )
                                        {
                                                Send_Sbuf[0] = 0xfd ;        //子机地址
                                                Send_Sbuf[1] = 0x06 ;        //写命令
                                                Send_Sbuf[2] = 0x00;
                                                Send_Sbuf[3] = 0x01;
                                                Send_Sbuf[4] = 0x00 ;
                                                Send_Sbuf[5] = Local_Addr*100+ziji_addr ;
                                                ziji_addr++;
                                                Send_Num = 8;
                                        }
                                        break;
                }
                if((Receive_Sbuf[3] + i)!=253)
                {
                        Send_Sbuf[j++] = dat_H;        // 数据高位
                        Send_Sbuf[j++] = dat_L;        // 数据低位       
                }
        }
}
void Modbus_Force_Reg(void)
{
        Send_Sbuf[2] = Receive_Sbuf[2];        //高地址
        Send_Sbuf[3] = Receive_Sbuf[3];        //低地址
        Send_Sbuf[4] = Receive_Sbuf[4];        //数据个数高位
        Send_Sbuf[5] = Receive_Sbuf[5];        //数据个数低位
        Send_Num = 0;
//        tongxun_xie_flag=1;
       
        switch( Receive_Sbuf[3])// + i)        // 地址索引
        {
                case 0: Local_Addr = Receive_Sbuf[5]; //Local_Addr
                             break;;           //通讯地址
               

        }
}
void Modbus_Send_CRC(void)
{
        Uint send_CRC;
        send_CRC = Modbus_CRC_Check(&Send_Sbuf, Send_Num-2);
        Send_Sbuf[Send_Num -2] = send_CRC >> 8;
        Send_Sbuf[Send_Num -1] = send_CRC;                // 将校验位加入发送缓冲
        RS485E=1;
        Modbus_Delay(50);
}
Uchar Modbus_Check_CRC(void)
{
        Uint rec_CRC;
        rec_CRC = Modbus_CRC_Check(Receive_Sbuf,Receive_Num-2);
        if(rec_CRC == (Receive_Sbuf[Receive_Num-2]<<8)+ Receive_Sbuf[Receive_Num-1])
        {               
                return 1;
        }
        else         
        {       
                return 0;
        }  
}
void Modbus_Function(void)
{
        Send_Sbuf[0] = Receive_Sbuf[0];
        Send_Sbuf[1] = Receive_Sbuf[1];
        switch(Receive_Sbuf[1])        // 功能号
        {       
                case 3:                Modbus_Read_Reg();
                                        break;
                case 6:                Modbus_Force_Reg();
                                        break;
        }
}

void Serial() interrupt 4
{
        if(RI)
        {       
                RI=0;
                Redata = SBUF;
                switch(Receive_State) //判断当前接受状态
                {
                        case Start_Receive:                Receive_Num = 0;
                                                                        if(Redata == Local_Addr)//&&(Send_Over = 1))//通讯地址一致          
                                                                        {
                                                                                Receive_Sbuf[Receive_Num++] = SBUF;//接受缓冲区开始接收数据
                                                                                Receive_State = Receive_Ing; //接收状态改为正在接收
                                                                        }
                                                                        break;
                        case Receive_Ing:                Receive_Sbuf[Receive_Num++] = Redata;
                                                                        if(Receive_Num==8)        //全部接受完以后再发送
                                                                        {
                                                                                Receive_State=Receive_Done;         //接收完以后改变接收状态
                                                                        }         
                                                                        break;
                }
        }
        if(TI)
        {
                TI=0;
        }
}

阿莫论坛20周年了!感谢大家的支持与爱护!!

曾经有一段真挚的爱情摆在我的面前,我没有珍惜,现在想起来,还好我没有珍惜……

出10入113汤圆

发表于 2013-9-12 14:29:05 | 显示全部楼层
485状态切换时候延时下

出0入4汤圆

 楼主| 发表于 2013-9-12 14:49:38 | 显示全部楼层
饭桶 发表于 2013-9-12 14:29
485状态切换时候延时下

谢谢 ! 再请教 : 如果在5米距离内,不加匹配电阻会不会是产生这个问题的原因?我在远端刚加了上下拉(1K)和100欧的电阻,略好,一次通讯成功率高了!

出0入4汤圆

 楼主| 发表于 2013-9-12 14:52:47 | 显示全部楼层
而且加了匹配电阻后,近端的成功率明显提高!
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片。注意:要连续压缩2次才能满足要求!!】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-8-26 05:14

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

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