//modbus协议--51端程序的实现
//RTU需要一个定时器来判断3.5个流逝时间。
#define ENABLE 1
#define DISABLE 0
#define TRUE 1
#define FAULT 0
#define RECEIVE_EN 0
#define TRANSFER_EN 1
#define MAX_RXBUF 0x20
extern unsigned char emissivity;
extern unsigned char tx_count,txbuf[15];
extern unsigned char rx_count,rxbuf[15];
extern unsigned char tx_number,rx_number;
extern bit MODBUS_T35,rx_ok;
unsigned char rx_temp;
void InitTimer1() //针对标准8051
{
TMOD=(TMOD|0xf0)&0x1f; //将T1设为16位定时器
TF1=0;
TH1=0x62; //设T1位3.5位的接收时间35bit/9600bit/s=3.646ms
TL1=0x80;//晶振为11.0592MHz,T=65535-3.646ms*11.0592MHz/12=0x6280
ET1=1; //允许T1中断
TR1=1; //T1开始计数
}
void timer1() interrupt 3 using 2 //定时器中断
{
TH1=0x62; //3.646ms interrupt
TL1=0x80;
MODBUS_T35=ENABLE;
if(rx_count>=5) //超时后,若接收缓冲区有数则判断为收到一帧
{
rx_ok=TRUE;
}
}
void scomm() interrupt 4 using 3 //modbus RTU模式
{
if(TI)
{
TI = 0;
if(tx_count < tx_number) //是否发送结束
{
SBUF = txbuf[tx_count];
}
tx_count++;
}
if(RI)
{
rx_temp=SBUF;
if(rx_ok==FAULT) //已接收到一帧数据,在未处理之前收到的数舍弃
{
if(rx_count
rxbuf[rx_count]=rx_temp;
rx_count++;
}
TH1=0x62; //timer1 reset,count again
TL1=0x80;
RI=0;
}
}
//在主循环中判断标志rx_ok来执行帧处理。
if(rx_ok)
{
ParseFrame();
KB0=1;
REN=0;
tx_count=0;
TI=1; //启动发送响应帧
rx_count=0;
rx_ok=0;
}
WORD MAKEWORD(a, b)
{
int_byte itemp;
itemp.items.high=a;
itemp.items.low=b;
return (itemp.item);
}
// 解析帧并发送响应帧 (在帧完整的前提下调用)
bit ParseFrame()
{
unsigned char byAddr ; // 地址
unsigned char byFunCode ; // 功能代码
int_byte wCRC;
wCRC.item = MAKEWORD(rxbuf[rx_count-1], rxbuf[rx_count-2]);
if(wCRC.item != CRC(rxbuf, rx_count-2)) // 判断校验是否正确
return FALSE;
// 正式解析
byAddr = rxbuf[0]; // 地址
byFunCode = rxbuf[1]; // 功能代码
// 如果地址不对
if( (byAddr != m_byAddress) && (byAddr != 0) )
return FALSE;
if(byAddr == m_byAddress)
{
AddSendByte(m_byAddress) ; // 地址
switch( byFunCode )
{
case 3: // 读保持寄存器
Fun3(3);
break;
....// 添加命令散转
......
default:
ErroRespond(1);
return FALSE;
break;
}
}
wCRC.item = CRC(txbuf,tx_number);
AddSendByte(wCRC.items.low);
AddSendByte(wCRC.items.high);
return TRUE;
}
// 根据接收帧模式发送相应,模式的数据
BOOL AddSendByte(const BYTE byData)
{
txbuf[tx_number]=byData;
tx_number++;
if(tx_number>30)return FALSE;
return TRUE;
}
// 异常响应 描述 响应解释
// 01 无效功能 变送器不允许执行收到的功能
// 02 无效地址 数据栏中的地址是不允许的
// 03 无效数据 数据栏中的数据是不允许的
// 06 忙 收到的消息没错,但从机正在执行一个长的程序命令
bit ErroRespond(const unsigned char byErroCode)
{
// printf("
ErroRespond%02X
", byErroCode);
if( !AddSendByte(rxbuf[1] | 0x80) )
return FALSE;
return AddSendByte(byErroCode);
}
//***CRC Calculation for MODBUS Protocol for VC++***//
//数组snd为地址等传输字节,num为字节数//
unsigned int CRC(unsigned char *snd, unsigned char num)
{
unsigned char i, j;
unsigned int c,crc=0xFFFF;
for(i = 0; i < num; i ++)
{
c = snd & 0x00FF;
crc ^= c;
for(j = 0;j < 8; j ++)
{
if (crc & 0x0001)
{
crc>>=1;
crc^=0xA001;
}
else crc>>=1;
}
}
return(crc);
}
友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。
可能是太早的文章,现在中间加的那些符号使阅读很困难。
------------------------------------------------------------------------------------------------------------------
将其中的符号替换掉后:
//modbus协议--51端程序的实现
//RTU需要一个定时器来判断3.5个流逝时间。
#define ENABLE 1
#define DISABLE 0
#define TRUE 1
#define FAULT 0
#define RECEIVE_EN 0
#define TRANSFER_EN 1
#define MAX_RXBUF 0x20
extern unsigned char emissivity;
extern unsigned char tx_count,txbuf[15];
extern unsigned char rx_count,rxbuf[15];
extern unsigned char tx_number,rx_number;
extern bit MODBUS_T35,rx_ok;
unsigned char rx_temp;
void InitTimer1() //针对标准8051
{
TMOD=(TMOD|0xf0)&0x1f; //将T1设为16位定时器
TF1=0;
TH1=0x62; //设T1位3.5位的接收时间35bit/9600bit/s=3.646ms
TL1=0x80;//晶振为11.0592MHz,T=65535-3.646ms*11.0592MHz/12=0x6280
ET1=1; //允许T1中断
TR1=1; //T1开始计数
}
void timer1() interrupt 3 using 2 //定时器中断
{
TH1=0x62; //3.646ms interrupt
TL1=0x80;
MODBUS_T35=ENABLE;
if(rx_count>=5) //超时后,若接收缓冲区有数则判断为收到一帧
{
rx_ok=TRUE;
}
}
void scomm() interrupt 4 using 3 //modbus RTU模式
{
if(TI)
{
TI = 0;
if(tx_count < tx_number) //是否发送结束
{
SBUF = txbuf[tx_count];
}
tx_count++;
}
if(RI)
{
rx_temp=SBUF;
if(rx_ok==FAULT) //已接收到一帧数据,在未处理之前收到的数舍弃
{
if(rx_count
rxbuf[rx_count]=rx_temp;
rx_count++;
}
TH1=0x62; //timer1 reset,count again
TL1=0x80;
RI=0;
}
}
//在主循环中判断标志rx_ok来执行帧处理。
if(rx_ok)
{
ParseFrame();
KB0=1;
REN=0;
tx_count=0;
TI=1; //启动发送响应帧
rx_count=0;
rx_ok=0;
}
WORD MAKEWORD(a, b)
{
int_byte itemp;
itemp.items.high=a;
itemp.items.low=b;
return (itemp.item);
}
// 解析帧并发送响应帧 (在帧完整的前提下调用)
bit ParseFrame()
{
unsigned char byAddr ; // 地址
unsigned char byFunCode ; // 功能代码
int_byte wCRC;
wCRC.item = MAKEWORD(rxbuf[rx_count-1], rxbuf[rx_count-2]);
if(wCRC.item != CRC(rxbuf, rx_count-2)) // 判断校验是否正确
return FALSE;
// 正式解析
byAddr = rxbuf[0]; // 地址
byFunCode = rxbuf[1]; // 功能代码
// 如果地址不对
if( (byAddr != m_byAddress) && (byAddr != 0) )
return FALSE;
if(byAddr == m_byAddress)
{
AddSendByte(m_byAddress) ; // 地址
switch( byFunCode )
{
case 3: // 读保持寄存器
Fun3(3);
break;
....// 添加命令散转
......
default:
ErroRespond(1);
return FALSE;
break;
}
}
wCRC.item = CRC(txbuf,tx_number);
AddSendByte(wCRC.items.low);
AddSendByte(wCRC.items.high);
return TRUE;
}
// 根据接收帧模式发送相应,模式的数据
BOOL AddSendByte(const BYTE byData)
{
txbuf[tx_number]=byData;
tx_number++;
if(tx_number>30)return FALSE;
return TRUE;
}
// 异常响应 描述 响应解释
// 01 无效功能 变送器不允许执行收到的功能
// 02 无效地址 数据栏中的地址是不允许的
// 03 无效数据 数据栏中的数据是不允许的
// 06 忙 收到的消息没错,但从机正在执行一个长的程序命令
bit ErroRespond(const unsigned char byErroCode)
{
// printf(" ErroRespond%02X ", byErroCode);
if( !AddSendByte(rxbuf[1] | 0x80) )
return FALSE;
return AddSendByte(byErroCode);
}
//***CRC Calculation for MODBUS Protocol for VC++***//
//数组snd为地址等传输字节,num为字节数//
unsigned int CRC(unsigned char *snd, unsigned char num)
{
unsigned char i, j;
unsigned int c,crc=0xFFFF;
for(i = 0; i < num; i ++)
{
c = snd & 0x00FF;
crc ^= c;
for(j = 0;j < 8; j ++)
{
if (crc & 0x0001)
{
crc>>=1;
crc^=0xA001;
}
else crc>>=1;
}
}
return(crc);
}
----------------------------------------------------------------
把接收超时作为一帧数据结尾的标志。
但,怎么判断一帧数据的开头呢?何时开始接受?
串口中断也不太明白。
-----------------------------------------------------------------
MODBUS_T35这个位变量貌似没用到。
一周热门 更多>