求助:移植的论坛某位大侠的MODBUS程序,一直有问题,请...

2020-01-30 13:48发布

本帖最后由 langbaiyue 于 2013-4-15 17:08 编辑

源程序是那位大侠与触摸屏通讯
http://www.amobbs.com/forum.php? ... mp;highlight=modbus
#include "STC51.H"
#include "intrins.h"
#define Uchar unsigned char
#define Uint  unsigned int
sbit RS485E        =        P3^7;   //定义485的使能脚
sbit P20        =        P2^0;
sbit P21        =        P2^1 ;       
sbit P22        =        P2^2 ;       
sbit P23        =        P2^3;
sbit P24        =        P2^4;
sbit P25        =        P2^5;
sbit P26        =        P2^6;
sbit P27        =        P2^7;       
bit SendFlag;
bit Send_Over;                // 数据帧发送完毕
Uint ReData;
Uchar send_num1=0;
Uchar led_test=0;
Uchar idata                Send_Sbuf[30];
Uchar idata                Receive_Sbuf[8];
Uchar idata                Send_Num=0;                    //需要返回数据字节个数
Uchar idata                Receive_Num=0;                // 接受字节个数
Uchar idata                Receive_State;                //接收状态
/******modbus 定义***********************/
#define Local_Addr                        0x01
#define Start_Receive                1        // 数据开始接受
#define Receive_Ing                        2
#define Receive_Done                8        // 与接受字节 共同判断 接受一个帧成功
//=================================================================================================
// CRC 高位字节值表
Uchar code CRC_H[] =
{
        0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81,
        0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
        0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01,
        0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
        0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81,
        0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
        0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01,
        0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
        0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81,
        0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
        0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01,
        0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
        0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81,
        0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
        0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01,
        0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
        0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81,
        0x40
} ;
//=================================================================================================
// CRC低位字节值表
//----------------
Uchar code CRC_L[] =
{
        0x00, 0xC0, 0xC1, 0x01, 0xC3, 0x03, 0x02, 0xC2, 0xC6, 0x06, 0x07, 0xC7, 0x05, 0xC5, 0xC4,
        0x04, 0xCC, 0x0C, 0x0D, 0xCD, 0x0F, 0xCF, 0xCE, 0x0E, 0x0A, 0xCA, 0xCB, 0x0B, 0xC9, 0x09,
        0x08, 0xC8, 0xD8, 0x18, 0x19, 0xD9, 0x1B, 0xDB, 0xDA, 0x1A, 0x1E, 0xDE, 0xDF, 0x1F, 0xDD,
        0x1D, 0x1C, 0xDC, 0x14, 0xD4, 0xD5, 0x15, 0xD7, 0x17, 0x16, 0xD6, 0xD2, 0x12, 0x13, 0xD3,
        0x11, 0xD1, 0xD0, 0x10, 0xF0, 0x30, 0x31, 0xF1, 0x33, 0xF3, 0xF2, 0x32, 0x36, 0xF6, 0xF7,
        0x37, 0xF5, 0x35, 0x34, 0xF4, 0x3C, 0xFC, 0xFD, 0x3D, 0xFF, 0x3F, 0x3E, 0xFE, 0xFA, 0x3A,
        0x3B, 0xFB, 0x39, 0xF9, 0xF8, 0x38, 0x28, 0xE8, 0xE9, 0x29, 0xEB, 0x2B, 0x2A, 0xEA, 0xEE,
        0x2E, 0x2F, 0xEF, 0x2D, 0xED, 0xEC, 0x2C, 0xE4, 0x24, 0x25, 0xE5, 0x27, 0xE7, 0xE6, 0x26,
        0x22, 0xE2, 0xE3, 0x23, 0xE1, 0x21, 0x20, 0xE0, 0xA0, 0x60, 0x61, 0xA1, 0x63, 0xA3, 0xA2,
        0x62, 0x66, 0xA6, 0xA7, 0x67, 0xA5, 0x65, 0x64, 0xA4, 0x6C, 0xAC, 0xAD, 0x6D, 0xAF, 0x6F,
        0x6E, 0xAE, 0xAA, 0x6A, 0x6B, 0xAB, 0x69, 0xA9, 0xA8, 0x68, 0x78, 0xB8, 0xB9, 0x79, 0xBB,
        0x7B, 0x7A, 0xBA, 0xBE, 0x7E, 0x7F, 0xBF, 0x7D, 0xBD, 0xBC, 0x7C, 0xB4, 0x74, 0x75, 0xB5,
        0x77, 0xB7, 0xB6, 0x76, 0x72, 0xB2, 0xB3, 0x73, 0xB1, 0x71, 0x70, 0xB0, 0x50, 0x90, 0x91,
        0x51, 0x93, 0x53, 0x52, 0x92, 0x96, 0x56, 0x57, 0x97, 0x55, 0x95, 0x94, 0x54, 0x9C, 0x5C,
        0x5D, 0x9D, 0x5F, 0x9F, 0x9E, 0x5E, 0x5A, 0x9A, 0x9B, 0x5B, 0x99, 0x59, 0x58, 0x98, 0x88,
        0x48, 0x49, 0x89, 0x4B, 0x8B, 0x8A, 0x4A, 0x4E, 0x8E, 0x8F, 0x4F, 0x8D, 0x4D, 0x4C, 0x8C,
        0x44, 0x84, 0x85, 0x45, 0x87, 0x47, 0x46, 0x86, 0x82, 0x42, 0x43, 0x83, 0x41, 0x81, 0x80,
        0x40
} ;
//=================================================================================================

//=================================================================================================
Uint CRC_Check(Uchar *pack, Uint num);
Uchar Check_CRC(void);
void Read_Reg(void);
void Force_Reg(void);
void Send_CRC(void);
void Function_MODBUS(void);
void delay(Uchar i)
{
        Uchar j;
        for(i; i > 0; i--)
                for(j = 200; j > 0; j--);
}

/**************************************************************************************************
**************************************************************************************************/
Uint CRC_Check(Uchar *pack, Uint num)
{
        unsigned char CRCcode_H = 0XFF;                // 高CRC字节初始化
        unsigned char CRCcode_L = 0XFF;                // 低CRC 字节初始化
        unsigned char index;                        // 数据索引
        while (num--)
        {
                index = CRCcode_L ^ (*pack++);       

                CRCcode_L = CRCcode_H ^ CRC_H[index];

                CRCcode_H = CRC_L[index];
        }
        return (CRCcode_L << 8 | CRCcode_H);        // MODBUS 规定低位在前
}
void Read_Reg(void)
{
        Uchar i,dat_H,dat_L,aaa,bbb;
        Send_Sbuf[2] = Receive_Sbuf[5] * 2;        // 返回 读取的字节个数
        Send_Num = 5 + Send_Sbuf[2];        // 5个固定字节+数据个数 addr1 + fun1 + num1 +【data】+ crc2
        for(i=0; i < Receive_Sbuf[5]; i++)
        {
                dat_H = 0;
                switch(Receive_Sbuf[3] + (i))                // 地址索引递增        //上位机命令地址加上 字节数
                {
                        case 0:                dat_L =0x01;// aaa; //handorautoflag
                                                break; //
                        case 1:         dat_L = 0x02; //trmxnum
                                                break; //
                        case 2:         dat_L = 0x03; //qcmxnum //
                                                break;
                        case 3:         dat_L = 0x04; //trysnum//33  
                                                break;
                        case 4:         dat_L = 0x05; //        qcysnum//
                                                break;
                        case 5:         dat_L = 0x06; //gblsnum
                                                break;//34//
                        case 6:                dat_L = 0x07; //gbbmnum
                                                break;//35  
                       
                }
                Send_Sbuf[i+3] = dat_H;        // 数据高位
                Send_Sbuf[i+4] = dat_L;        // 数据低位
        }
}
/**************************************************************************************************
           6/16号 强置(4x)单个/多个 寄存器
**************************************************************************************************/
void Force_Reg(void)
{
        Uchar i,num,dat,abc,dat_H,dat_L,aaa,bbb;
        Send_Sbuf[2] = Receive_Sbuf[2];        //高地址
        Send_Sbuf[3] = Receive_Sbuf[3];        //低地址
        Send_Sbuf[4] = Receive_Sbuf[4];        //数据个数高位
        Send_Sbuf[5] = Receive_Sbuf[5];        //数据个数低位
        Send_Num = 8;
        if(Receive_Sbuf[1] == 6)                // 强制单个
        {
                num = 1;
                dat = Receive_Sbuf[5];
        }
        else
        {
                num = Receive_Sbuf[5];        // 强制多个
                abc = 8;
                dat = Receive_Sbuf[abc];
        }
        for(i = 0; i < num; i++)
        {
                switch( Receive_Sbuf[3] + i)        // 地址索引
                {
                        case 0:        dat_L = 1; //handorautoflag
                                        break;//
                        case 1: dat_L = aaa; //trmxnum
                                        break; //
                        case 2: dat_L = aaa; //qcmxnum
                                        break; //
                        case 3: dat_L = aaa; //trysnum
                                        break;        //33  
                        case 4: dat_L = aaa; //        qcysnum
                                        break;//
                       
                }
                abc += 2;        // 整形数据 两个字节距离
                dat = Receive_Sbuf[abc];
        }
}
/***************************************
   将CRC加入数据尾部,发送返回数据包
***************************************/
void Send_CRC(void)
{
        Uint send_CRC;
        send_CRC = CRC_Check(&Send_Sbuf, Send_Num-2);
        Send_Sbuf[Send_Num -2] = send_CRC >> 8;
        Send_Sbuf[Send_Num -1] = send_CRC;                // 将校验位加入发送缓冲
        SBUF = Send_Sbuf[0];
}
/*********************************
   校验接收数据包的正确性
**********************************/
Uchar Check_CRC(void)
{
        Uint rec_CRC;
        rec_CRC = CRC_Check(Receive_Sbuf,Receive_Num-2);
        if(rec_CRC == (Receive_Sbuf[Receive_Num-2]<<8)+ Receive_Sbuf[Receive_Num-1])
        {               
                return 1;
        }
        else         
        {       
                return 0;
       
        }  
}

/**********************
执行MODBUS功能函数
**********************/
void Function_MODBUS(void)
{
        Send_Sbuf[0] = Receive_Sbuf[0];
        Send_Sbuf[1] = Receive_Sbuf[1];
        switch(Receive_Sbuf[1])        // 功能号
        {       
                case 3:                Read_Reg();
                                        break;
                case 6:                Force_Reg();
                                        break;
                case 16:        Force_Reg();
                                        break;
        }
}
/**************************************
            延时程序
**************************************/
void timer0_10ms() interrupt 1
{
        TMOD        =         0x21;
        TH0         =        0XDC;
        TL0         =        0X00;          //定时10毫秒
        led_test++;
        if(led_test>=100)
        {
                led_test=0;
            P27=!P27;
        }
}
void main (void)
{
    PCON         =         0x00;
        SCON         =         0x50;      //REN=1允许串行接受状态,串口工作模式1                             
    TMOD        =         0x21;      //定时器工作方式2                    
        TH0         =        0XDC;
        TL0         =        0X00;                                                        
        TH1         =        0xFD;     //baud*2  /* reload value 19200、数据位8、停止位1。效验位无 (11.0592)   
        TL1         =         0xFd;      
        TR0          =          1;  
        TR1                =         1;                                                                   
        ES           =          1;        //开串口中断   
        ET0                =         1;
        EA           =          1;        // 开总中断
        Receive_State=Start_Receive;
        RS485E=0;
        while(1)
    {
                 if( (Receive_State == Receive_Done) )//&& Send_Over )
                {       
                        if( Check_CRC() ) //
                        {
                                Function_MODBUS();
                                Send_CRC();
                        }         
                        Receive_State = Start_Receive;
                }
        }
}

/****************************************************
               串口中断程序
******************************************************/
void ser_int (void) interrupt 4 using 1
{
        if(RI == 1)        //RI接受中断标志
        {
                RI = 0;       
                ReData                 =         SBUF;
                switch(Receive_State) //判断当前接受状态
                {
                        case Start_Receive:                Receive_Num = 0;
                                                                        if(ReData == Local_Addr)//&&(Send_Over = 1))//通讯地址一致          
                                                                        {
                                                                                Receive_Sbuf[Receive_Num++] = SBUF;//接受缓冲区开始接收数据
                                                                                Receive_State = Receive_Ing; //接收状态改为正在接收
                                                                        }
                                                                        break;
                        case Receive_Ing:                Receive_Sbuf[Receive_Num++] = ReData;
                                                                        if(Receive_Num==8)        //全部接受完以后再发送
                                                                        {
                                                                                SendFlag        =         1;
                                                                                Receive_State=Receive_Done;         //接收完以后改变接收状态
                                                                        }         
                                                                        break;
                }
        }
        if(TI == 1)
        {
                TI = 0;
        }
        if(SendFlag==1)    // max485(半双工通信) RE/DE定义 RE=0为接受状态  DE=1为发送状态(参考MAX485芯片管脚)
        {
                RS485E=1;           //                                           RS5485E=0为接收状态  RS5485E=1为发送状态
                delay(50);
                if( Send_Num > 1 )
                {         
                        Send_Num--;
                        SBUF =Send_Sbuf[send_num1] ;
                        send_num1++;
                }        
                if( Send_Num== 1 )  
                {
                        send_num1         =        0;
                        Send_Over         =         1;
                        SendFlag        =        0;
                }          
        }
        else
        {
                RS485E        =        0;              //接收状态
        }
}
下面是commix测试指令
01 03 00 00 00 02 C4 0B
(47 ms)
01 01 03 04 00 00 02 00 FB
01 03 00 00 00 02 C4 0B
(62 ms)
01
01 03 00 00 00 02 C4 0B
(47 ms)
01 03 04 00 00 02 00 FB 53
01 03 00 00 00 02 C4 0B
(47 ms)
01
01 03 00 00 00 02 C4 0B
(47 ms)
01 03 04 00 00 02 00 FB 53
01 03 00 00 00 02 C4 0B
(47 ms)
01
01 03 00 00 00 02 C4 0B
(47 ms)
01 03 04 00 00 02 FB 53 53
为什么第一次会返回两个01
为什么后面会01与正常返回轮流出现?
为什么连续读3个以上,最后的数据总是错的?
请大家指教
0条回答

一周热门 更多>