请教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;
}
}
485状态切换时候延时下 饭桶 发表于 2013-9-12 14:29 static/image/common/back.gif
485状态切换时候延时下
谢谢 ! 再请教 : 如果在5米距离内,不加匹配电阻会不会是产生这个问题的原因?我在远端刚加了上下拉(1K)和100欧的电阻,略好,一次通讯成功率高了! 而且加了匹配电阻后,近端的成功率明显提高!
页:
[1]