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<MAX_RXBUF) 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); } |