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

2020-01-30 14:05发布

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

}
友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。