搜索
bottom↓
回复: 50

modbus协议-----51端程序的实现【恢复】

[复制链接]

出0入0汤圆

发表于 2008-11-20 15:32:29 | 显示全部楼层 |阅读模式
//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("\nErroRespond%02X \n", 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);

}

阿莫论坛20周年了!感谢大家的支持与爱护!!

一只鸟敢站在脆弱的枝条上歇脚,它依仗的不是枝条不会断,而是自己有翅膀,会飞。

出10入95汤圆

发表于 2008-11-21 22:39:14 | 显示全部楼层
不错

出0入0汤圆

发表于 2008-11-21 11:32:09 | 显示全部楼层
不错

出0入0汤圆

 楼主| 发表于 2008-11-21 10:09:35 | 显示全部楼层
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[1] 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 





希望对大家用得着!

出0入0汤圆

 楼主| 发表于 2008-11-20 15:44:51 | 显示全部楼层
MODBUS协议的M16程序及几篇协议文档 :

http://www.ouravr.com/bbs/bbs_content.jsp?bbs_sn=566107&bbs_page_no=1&bbs_id=2060

出0入0汤圆

发表于 2009-4-10 12:00:26 | 显示全部楼层
MARK

出0入8汤圆

发表于 2009-4-10 14:28:45 | 显示全部楼层
ing!!

出0入0汤圆

发表于 2009-4-11 12:31:44 | 显示全部楼层
modbus协议-----51端程序的实现

出0入0汤圆

发表于 2009-4-20 20:09:37 | 显示全部楼层
MARK,学习!

出0入10汤圆

发表于 2009-4-20 21:11:36 | 显示全部楼层
留底

出0入0汤圆

发表于 2009-9-6 15:35:48 | 显示全部楼层
good!!!

出0入0汤圆

发表于 2009-9-13 21:26:12 | 显示全部楼层
mark

出0入0汤圆

发表于 2009-9-17 23:45:46 | 显示全部楼层
mark

出0入0汤圆

发表于 2009-9-21 12:30:44 | 显示全部楼层
MARK

出0入0汤圆

发表于 2009-9-21 22:28:13 | 显示全部楼层
mark

出0入0汤圆

发表于 2009-9-27 19:26:40 | 显示全部楼层
刚好想弄这个。来看看!

出0入0汤圆

发表于 2009-9-27 20:03:38 | 显示全部楼层
mark

出0入0汤圆

发表于 2009-9-28 11:56:35 | 显示全部楼层
学习

出0入0汤圆

发表于 2009-11-19 23:29:41 | 显示全部楼层
学习

出0入0汤圆

发表于 2009-11-20 02:58:29 | 显示全部楼层
MARK MODBUS

出0入0汤圆

发表于 2010-1-5 10:43:40 | 显示全部楼层
学习

出0入0汤圆

发表于 2010-3-15 22:51:39 | 显示全部楼层
标记

出0入0汤圆

发表于 2010-4-10 01:18:17 | 显示全部楼层
mark

出0入0汤圆

发表于 2010-4-10 21:31:20 | 显示全部楼层
好强大

出0入0汤圆

发表于 2010-4-11 10:37:49 | 显示全部楼层
学习学习啦

出0入0汤圆

发表于 2010-4-12 09:47:35 | 显示全部楼层
mark

出0入0汤圆

发表于 2011-5-22 11:05:30 | 显示全部楼层
mark

出0入0汤圆

发表于 2011-5-22 11:57:14 | 显示全部楼层
这个以后用的到!MARK!

出0入0汤圆

发表于 2011-5-22 12:25:12 | 显示全部楼层
mark

出0入0汤圆

发表于 2011-5-22 13:16:05 | 显示全部楼层
学习了哈,谢谢楼主

出0入8汤圆

发表于 2011-6-3 11:14:15 | 显示全部楼层
MARK

出0入0汤圆

发表于 2011-6-3 12:06:06 | 显示全部楼层
收藏了

出0入0汤圆

发表于 2011-6-3 13:00:28 | 显示全部楼层
mark

出0入0汤圆

发表于 2011-6-3 13:27:04 | 显示全部楼层
好。谢谢。

出0入0汤圆

发表于 2011-6-3 14:47:59 | 显示全部楼层
mark

出0入0汤圆

发表于 2011-6-4 15:17:21 | 显示全部楼层
楼哥,上份教程吧,让大家一步一步跟你上MODBUS,

出0入0汤圆

发表于 2011-6-8 23:11:46 | 显示全部楼层
不错,学习一下!

出0入0汤圆

发表于 2011-7-29 14:26:00 | 显示全部楼层
参考...

出0入0汤圆

发表于 2011-7-29 17:07:54 | 显示全部楼层
标记

出0入0汤圆

发表于 2011-7-31 13:11:54 | 显示全部楼层
mark

出0入0汤圆

发表于 2011-11-5 13:17:15 | 显示全部楼层
标记了  谢谢

出0入0汤圆

发表于 2011-11-5 14:33:00 | 显示全部楼层
mark

出0入0汤圆

发表于 2011-11-5 16:27:09 | 显示全部楼层
mark

出0入0汤圆

发表于 2011-11-5 16:44:24 | 显示全部楼层
mark

出0入0汤圆

发表于 2011-11-5 22:27:56 | 显示全部楼层
make modbus

出0入0汤圆

发表于 2011-11-11 09:44:25 | 显示全部楼层
参考

出0入0汤圆

发表于 2012-5-25 10:59:39 | 显示全部楼层
        return&nbsp,这一堆堆的这些东西是什么???求解

出0入0汤圆

发表于 2013-3-13 14:12:15 | 显示全部楼层
本帖最后由 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_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("\nErroRespond%02X \n", 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这个位变量貌似没用到。

出0入0汤圆

发表于 2013-3-13 19:01:54 | 显示全部楼层
上PDF吧,这样看代码更舒服点

出0入0汤圆

发表于 2013-3-13 23:35:41 | 显示全部楼层
看了48L才有点头绪!

出0入0汤圆

发表于 2013-3-13 23:45:55 来自手机 | 显示全部楼层
我是真的一点也看不懂,为什么
来自:amoBBS 阿莫电子论坛 Windows Phone 7 客户端
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-5-18 10:28

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表