modbus协议-----51端程序的实现【恢复】
//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;
extern unsigned char rx_count,rxbuf;
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++;
}
if(RI)
{
rx_temp=SBUF;
if(rx_ok==FAULT) //已接收到一帧数据,在未处理之前收到的数舍弃
{
if(rx_count
rxbuf=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, rxbuf);
if(wCRC.item != CRC(rxbuf, rx_count-2)) // 判断校验是否正确
return FALSE;
// 正式解析
byAddr = rxbuf; // 地址
byFunCode = rxbuf; // 功能代码
// 如果地址不对
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=byData;
tx_number++;
if(tx_number>30)return FALSE;
return TRUE;
}
// 异常响应 描述 响应解释
// 01 无效功能 变送器不允许执行收到的功能
// 02 无效地址 数据栏中的地址是不允许的
// 03 无效数据 数据栏中的数据是不允许的
// 06 忙 收到的消息没错,但从机正在执行一个长的程序命令
bit ErroRespond(const unsigned char byErroCode)
{
// printf("\nErroRespond%02X \n", byErroCode);
if( !AddSendByte(rxbuf | 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);
} 不错 不错 FreeMODBUS
http://freemodbus.berlios.de/
About
FreeMODBUS is a free implementation of the popular Modbus protocol specially targeted for embedded systems. Modbus is a popular network protocol in the industrial manufacturing environment. A Modbus communication stack requires two layers. The Modbus Application Protocol which defines the data model and functions and a Network layer. In its current version FreeMODBUS provides an implementation of the Modbus Application Protocol v1.1a and supports RTU/ASCII transmission modes defined in the Modbus over serial line specification 1.0. Since version 0.7 FreeModbus also supports Modbus TCP defined in Modbus Messaging on TCP/IP Implementation Guide v1.0a. It is licensed under the BSD which permits its usage in commercial environments. The following Modbus functions are currently supported:
Read Input Register (0x04)
Read Holding Registers (0x03)
Write Single Register (0x06)
Write Multiple Registers (0x10)
Read/Write Multiple Registers (0x17)
Read Coils (0x01)
Write Single Coil (0x05)
Write Multiple Coils (0x0F)
Read Discrete Inputs (0x02)
Report Slave ID (0x11)
The implementation is based upon the most recent standards and should be fully standard compliant. Receiving and transmitting of Modbus RTU/ASCII frames is implemented as a state machines which is driven by callbacks from the hardware abstraction layer. This makes porting to new platforms easy. If a frame is complete it is passed to the Modbus Application Layer where its content is inspected. Hooks are available in the Application Layer to add new Modbus functions.
If Modbus TCP is used the porting layer must send an event to the protocol stack if a new frame is ready for processing. The protocol stack then calls a function which returns the received Modbus TCP frame and processes it. If valid a response is created and the porting layer is supplied with the Modbus response. It should then send the
response back to the client.
--------------------------------------------------------------------------------
- Home
- Examples
- HW/SW requirements
--------------------------------------------------------------------------------
- Ports ASCII/RTU
- FreeRTOS/STR71X
- AVR ATMega8/16/32/128/168/169
- Freescale MCF5235
- TI MSP430
- LPC214X
- Z8 Encore!/Z8F6422
- Win32
- Linux/Cygwin
- FreeRTOS/AT91SAM7X
- Ports TCP
- Win32
- lwIP/MCF5235
- lwIP/STR71X
- Documentation
- API documentation
--------------------------------------------------------------------------------
- Downloads
--------------------------------------------------------------------------------
- Credits
- Contact
- Links
希望对大家用得着! MODBUS协议的M16程序及几篇协议文档 :
http://www.ouravr.com/bbs/bbs_content.jsp?bbs_sn=566107&bbs_page_no=1&bbs_id=2060 MARK ing!! modbus协议-----51端程序的实现 MARK,学习! 留底 good!!! mark mark MARK mark 刚好想弄这个。来看看! mark 学习 学习 MARK MODBUS 学习 标记 mark 好强大 学习学习啦 mark mark 这个以后用的到!MARK! mark 学习了哈,谢谢楼主 MARK 收藏了 mark 好。谢谢。 mark 楼哥,上份教程吧,让大家一步一步跟你上MODBUS, 不错,学习一下! 参考... 标记 mark 标记了谢谢 mark mark mark make modbus 参考 return ,这一堆堆的这些东西是什么???求解 本帖最后由 any_014 于 2013-3-14 09:37 编辑
可能是太早的文章,现在中间加的那些符号使阅读很困难。
------------------------------------------------------------------------------------------------------------------
将其中的符号替换掉后:
//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_RXBUF0x20
extern unsigned char emissivity;
extern unsigned char tx_count,txbuf;
extern unsigned char rx_count,rxbuf;
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++;
}
if(RI)
{
rx_temp=SBUF;
if(rx_ok==FAULT) //已接收到一帧数据,在未处理之前收到的数舍弃
{
if(rx_count
rxbuf=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, rxbuf);
if(wCRC.item != CRC(rxbuf, rx_count-2)) // 判断校验是否正确
return FALSE;
// 正式解析
byAddr = rxbuf; // 地址
byFunCode = rxbuf; // 功能代码
// 如果地址不对
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=byData;
tx_number++;
if(tx_number>30)return FALSE;
return TRUE;
}
// 异常响应 描述 响应解释
// 01 无效功能 变送器不允许执行收到的功能
// 02 无效地址 数据栏中的地址是不允许的
// 03 无效数据 数据栏中的数据是不允许的
// 06 忙 收到的消息没错,但从机正在执行一个长的程序命令
bit ErroRespond(const unsigned char byErroCode)
{
// printf("\nErroRespond%02X \n", byErroCode);
if( !AddSendByte(rxbuf | 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这个位变量貌似没用到。 上PDF吧,这样看代码更舒服点 看了48L才有点头绪! 我是真的一点也看不懂,为什么
来自:amoBBS 阿莫电子论坛 Windows Phone 7 客户端
页:
[1]