搜索
bottom↓
回复: 0

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

[复制链接]

出0入4汤圆

发表于 2013-4-15 17:05:49 | 显示全部楼层 |阅读模式
本帖最后由 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个以上,最后的数据总是错的?
请大家指教

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

一只鸟敢站在脆弱的枝条上歇脚,它依仗的不是枝条不会断,而是自己有翅膀,会飞。
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

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

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

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

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