kms2hh 发表于 2008-11-20 15:32:29

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

}

ddcour 发表于 2008-11-21 22:39:14

不错

halloween 发表于 2008-11-21 11:32:09

不错

kms2hh 发表于 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 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 





希望对大家用得着!

kms2hh 发表于 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

deepin 发表于 2009-4-10 12:00:26

MARK

fangmcu 发表于 2009-4-10 14:28:45

ing!!

wangff2531 发表于 2009-4-11 12:31:44

modbus协议-----51端程序的实现

youpeng 发表于 2009-4-20 20:09:37

MARK,学习!

ylei12 发表于 2009-4-20 21:11:36

留底

51hubao 发表于 2009-9-6 15:35:48

good!!!

ma9801 发表于 2009-9-13 21:26:12

mark

sharehej 发表于 2009-9-17 23:45:46

mark

blue.fox 发表于 2009-9-21 12:30:44

MARK

hailiyidishui 发表于 2009-9-21 22:28:13

mark

kouxiangtang 发表于 2009-9-27 19:26:40

刚好想弄这个。来看看!

nicksean 发表于 2009-9-27 20:03:38

mark

qtds11 发表于 2009-9-28 11:56:35

学习

wxdl 发表于 2009-11-19 23:29:41

学习

eduhf_123 发表于 2009-11-20 02:58:29

MARK MODBUS

xiesx1985 发表于 2010-1-5 10:43:40

学习

win100 发表于 2010-3-15 22:51:39

标记

tingfenghu 发表于 2010-4-10 01:18:17

mark

huihui_lzh 发表于 2010-4-10 21:31:20

好强大

binaimei2007 发表于 2010-4-11 10:37:49

学习学习啦

zj_yang1983 发表于 2010-4-12 09:47:35

mark

cuikai12345 发表于 2011-5-22 11:05:30

mark

wukaka 发表于 2011-5-22 11:57:14

这个以后用的到!MARK!

muzheyun 发表于 2011-5-22 12:25:12

mark

wxw123321 发表于 2011-5-22 13:16:05

学习了哈,谢谢楼主

syauxwm 发表于 2011-6-3 11:14:15

MARK

shunda 发表于 2011-6-3 12:06:06

收藏了

power_check 发表于 2011-6-3 13:00:28

mark

Excellence 发表于 2011-6-3 13:27:04

好。谢谢。

leang521 发表于 2011-6-3 14:47:59

mark

zouge888 发表于 2011-6-4 15:17:21

楼哥,上份教程吧,让大家一步一步跟你上MODBUS,

me_xj 发表于 2011-6-8 23:11:46

不错,学习一下!

guoermvp 发表于 2011-7-29 14:26:00

参考...

xdco 发表于 2011-7-29 17:07:54

标记

aspenlin 发表于 2011-7-31 13:11:54

mark

417400765 发表于 2011-11-5 13:17:15

标记了谢谢

cqxubo01 发表于 2011-11-5 14:33:00

mark

lbjhdu 发表于 2011-11-5 16:27:09

mark

fzkqi 发表于 2011-11-5 16:44:24

mark

love_zjb 发表于 2011-11-5 22:27:56

make modbus

T_gourd 发表于 2011-11-11 09:44:25

参考

lhcyy 发表于 2012-5-25 10:59:39

        return&nbsp,这一堆堆的这些东西是什么???求解

any_014 发表于 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_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这个位变量貌似没用到。

Baldwin 发表于 2013-3-13 19:01:54

上PDF吧,这样看代码更舒服点

Bicycle 发表于 2013-3-13 23:35:41

看了48L才有点头绪!

yang476905763 发表于 2013-3-13 23:45:55

我是真的一点也看不懂,为什么
来自:amoBBS 阿莫电子论坛 Windows Phone 7 客户端
页: [1]
查看完整版本: modbus协议-----51端程序的实现【恢复】