langbaiyue 发表于 2013-9-12 13:59:02

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

程序如下,单片机是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 ;
                                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 = 0x01 ;        //主机地址
                Send_Sbuf = 0x03 ;        //读命令
                Send_Sbuf = 0x00 ;
                Send_Sbuf = 0xfd ;                //地址
                Send_Sbuf = 0x00 ;
                Send_Sbuf = 0x01 ;        //数量
                Send_Num = 8;
                Modbus_Send_CRC();
                ES=0;
                while( Send_Num > 0 )
                {
                        Send_Num--;       
                        TI=0;
                        SBUF =Send_Sbuf ;
                        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 = 0x01 ;        //主机地址
                Send_Sbuf = 0x03 ;        //读命令
                Send_Sbuf = 0x00 ;
                Send_Sbuf = 0xfe ;                //地址
                Send_Sbuf = 0x00 ;
                Send_Sbuf = 0x01 ;        //数量
                Send_Num = 8;
                Modbus_Send_CRC();
                ES=0;
                while( Send_Num > 0 )
                {
                        Send_Num--;       
                        TI=0;
                        SBUF =Send_Sbuf ;
                        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;
                CRCcode_H = CRC_L;
        }
        return (CRCcode_L << 8 | CRCcode_H);        // MODBUS 规定低位在前
}
void Modbus_Read_Reg(void)                                 
{       
        Uchar i,dat_H,dat_L;
        Uchar j=3;
        Send_Sbuf = Receive_Sbuf * 2;                                // 返回 读取的字节个数
        Send_Num = 5 + Send_Sbuf;                                        // 5个固定字节+数据个数 addr1 + fun1 + num1 +【data】+ crc2
        for(i=0; i<Receive_Sbuf; i++)                                        //i++为连续读
        {       
                dat_H = 0;
                switch(Receive_Sbuf + i)                                                // 地址索引递增        //上位机命令地址加上 字节数
                {                               
                        case 0:           dat_L = Local_Addr; //Local_Addr
                                                break;   //通讯地址
                       
                        case 1:    dat_L = 0; //txslnum
                                                break;//70        通讯速率
                  case 2 :
                                        if(Receive_Sbuf==0xfd )
                                        {
                                                Send_Sbuf = 0xfd ;        //子机地址
                                                Send_Sbuf = 0x06 ;        //写命令
                                                Send_Sbuf = 0x00;
                                                Send_Sbuf = 0x01;
                                                Send_Sbuf = 0x00 ;
                                                Send_Sbuf = Local_Addr*100+ziji_addr ;
                                                ziji_addr++;
                                                Send_Num = 8;
                                        }
                                        break;
                }
                if((Receive_Sbuf + i)!=253)
                {
                        Send_Sbuf = dat_H;        // 数据高位
                        Send_Sbuf = dat_L;        // 数据低位       
                }
        }
}
void Modbus_Force_Reg(void)
{
        Send_Sbuf = Receive_Sbuf;        //高地址
        Send_Sbuf = Receive_Sbuf;        //低地址
        Send_Sbuf = Receive_Sbuf;        //数据个数高位
        Send_Sbuf = Receive_Sbuf;        //数据个数低位
        Send_Num = 0;
//        tongxun_xie_flag=1;
       
        switch( Receive_Sbuf)// + i)        // 地址索引
        {
                case 0: Local_Addr = Receive_Sbuf; //Local_Addr
                             break;;           //通讯地址
               

        }
}
void Modbus_Send_CRC(void)
{
        Uint send_CRC;
        send_CRC = Modbus_CRC_Check(&Send_Sbuf, Send_Num-2);
        Send_Sbuf = send_CRC >> 8;
        Send_Sbuf = 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<<8)+ Receive_Sbuf)
        {               
                return 1;
        }
        else       
        {       
                return 0;
        }
}
void Modbus_Function(void)
{
        Send_Sbuf = Receive_Sbuf;
        Send_Sbuf = Receive_Sbuf;
        switch(Receive_Sbuf)        // 功能号
        {       
                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 = SBUF;//接受缓冲区开始接收数据
                                                                                Receive_State = Receive_Ing; //接收状态改为正在接收
                                                                        }
                                                                        break;
                        case Receive_Ing:                Receive_Sbuf = Redata;
                                                                        if(Receive_Num==8)        //全部接受完以后再发送
                                                                        {
                                                                                Receive_State=Receive_Done;       //接收完以后改变接收状态
                                                                        }       
                                                                        break;
                }
        }
        if(TI)
        {
                TI=0;
        }
}

饭桶 发表于 2013-9-12 14:29:05

485状态切换时候延时下

langbaiyue 发表于 2013-9-12 14:49:38

饭桶 发表于 2013-9-12 14:29 static/image/common/back.gif
485状态切换时候延时下

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

langbaiyue 发表于 2013-9-12 14:52:47

而且加了匹配电阻后,近端的成功率明显提高!
页: [1]
查看完整版本: 请教MODBUS通讯,上位机第二次才能读到下位机