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

2020-01-27 11:19发布

程序如下,单片机是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;
        }
}
友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。