搜索
bottom↓
回复: 75

C51 modbus 通信协议 可以完成01 03 05 06 功能码

  [复制链接]

出0入0汤圆

发表于 2012-6-15 15:35:04 | 显示全部楼层 |阅读模式
本帖最后由 kaishandage 于 2012-6-15 15:37 编辑

#include "main.h"
sbit SPEAK=P3^4;


/**********************************************************************         
                                欢迎指正,多多交流,只有不断交流才会不断进步,
                本协议内容是根据网络资源修改,网上的MODbus协议大多不能使用,本协议修改后可以完成01 03 05 06
                功能码。10功能码大家完成吧,
本程序已经调试好,直接下载就可以使用,
-----------------------------------------------------------------------
modbus RTU 的C51程序
-----------------------------------------------------------------------
单片机AT89C51          11.0592MHZ
-----------------------------------------------------------------------
通信波特率 9600 8位数据 1位停止位 偶校验 485通位接口
-----------------------------------------------------------------------
单片机控制板地址 localAddr(变量)
通信可设置数据的地址:
字地址 0 - 255 (只取16位的低8位)
**********************************************************************/
uint16  idata D[64] _at_ 0x40;         //10进制地址是64,
/**********************************************************************         
D0 的10进制地址是 64
D1 的10进制地址是 65
该ModBUS支持的功能
01 读线圈 可以读取单个或多个线圈,
上位机发送数据格式  地址,功能码,线圈地址高位,线圈地址低位,读取线圈个数高位,读取线圈个数低位,CRC低位,CRC 高位,
下位机回应数据格式,地址  功能码,数据个数, 数据,CRC低位,CRC  高位,
03 读寄存器,可以读取单个或者多个寄存器
上位机发送数据格式  地址,功能码,寄存器地址高位,寄存器地址低位,数据个数高位,数据个数低位,CRC低位,CRC 高位,
下位机回应数据格式,地址  功能码,数据个数,数据1高位 数据1低位  数据2高位 数据2低位 。。。。,CRC低位,CRC  高位,
05 写单个线圈
上位机发送数据格式  地址,功能码,线圈地址高位,线圈地址低位,数据高位,数据低位,CRC低位,CRC 高位,
下位机回应数据格式,地址,功能码,线圈地址高位,线圈地址低位,数据高位,数据低位,CRC低位,CRC 高位,
06 写单个寄存器
上位机发送数据格式  地址,功能码,数据地址高位,数据地址低位,数据高位,数据低位,CRC低位,CRC 高位,
下位机回应数据格式         地址,功能码,数据地址高位,数据地址低位,数据高位,数据低位,CRC低位,CRC 高位,
0x10 写多个寄存器
上位机发送数据格式  地址,功能码,线圈地址高位,线圈地址低位,读取线圈个数高位,读取线圈个数低位,CRC低位,CRC 高位,
下位机回应数据格式,地址  功能码,数据个数, 数据,CRC低位,CRC  高位,
**********************************************************************/

uint8        xdata sendBuf[24],receBuf[24]; //发送接收缓冲区
uint8        idata checkoutError;        // ==2 偶校验错  
uint8        idata receTimeOut;                //接收超时
bit                idata bt1ms;//100ms,bt100ms;        //定时标志位
uint8 xdata M[100]  _at_ 0x00;  
//-------------------------------定时器0 1ms 中断 -------------------------
void timer0_IntProc() interrupt 1
{
    TL0 = TIMER_LOW;
    TH0 = TIMER_HIGHT;
        bt1ms = 1;

}   
//--------------------------------串行中断程序---------------------------
void comm_IntProc() interrupt 4
{
        if(TI)
        {
                TI = 0;
                if(sendPosi < sendCount)
                {
                        sendPosi++;
                        ACC = sendBuf[sendPosi];
                        TB8 = P;        //加上校验位
                        SBUF = sendBuf[sendPosi];
                }
                else
                {
            //发送完后将485置于接收状态
                   b485Send = 1;   
                        receCount = 0;   //清接收地址偏移寄存器
                        checkoutError = 0;
                }
        }
        else if(RI)
        {
                RI = 0;
                receTimeOut = 10;    //通讯超时值  这个地方很重要
                //receTimeOut = 50;    //通讯超时值
                receBuf[receCount] = SBUF;
                ACC = receBuf[receCount];
                if(P != RB8)
                        checkoutError = 2;        //偶校验出错
                receCount++;          //接收地址偏移寄存器加1
                receCount &= 0x0f;    //最多一次只能接收16个字节
        }

}   
//------------------------------------定时处理--------------------------------
void timeProc(void)
{
        if(bt1ms)
        {
                bt1ms = 0;
       if(receTimeOut>0)
        {
            receTimeOut--;
            if(receTimeOut==0 && receCount>0)   //判断通讯接收是否超时
            {
              //将485置为接收状态
                           b485Send = 1;                                                                                                                                                                
               receCount = 0;//      //将接收地址偏移寄存器清零
                                checkoutError = 0;
            }
        }
        }
}  
//------------------------------串口初始化------------------------------------
void initUart(void)
{
         //偶校验                                                
        SCON=0xD0;
    PCON=0X80;
    ES = 1;
}
//-----------------------------初始化中断------------------------------------
void initInt(void)
{
        TMOD= 0x21;    //T0用于定时,T1用于波特
        TH0   = TIMER_HIGHT;
        TL0   = TIMER_LOW;
        TR0   = 1;       
    ET0   = 1; //开中断T0
        TH1   = 0xfa;        //晶振为11.0592波特率为9600,SMOD=1,12T,TH1=F6         
        TR1 = 1;                 
        TI  = 1;   //发送允许中断,
        EA=1;       
}   
//--------------------------初始化-----------------------------
void initProg(void)
{       
        initInt(); initUart();  b485Send = 1;
}
//----------------------MAIN_PROG---------------------------------------------
void main(void)
{
initProg();         //初始化

                         M[0]=0x11;
                         M[1]=0x22;
                         M[2]=0x33;
                         M[3]=0x44;
                         M[4]=0x55;
                         M[5]=0x66;
                         M[6]=0x77;
                         M[7]=0x88;
                         M[8]=0x99;
                       
                         D[0]=0X1122;
                         D[1]=0x3344;
                         D[2]=0x5566;
                         D[3]=0x7788;
                     D[4]=0X99aa;
        while(1)
        {         
                timeProc();///////////////////////////通讯
                checkComm0Modbus();///////////////////通讯
            /**********************************控制程序*********************************************/
                /*测试程序说明 上位机发送 01 06 00 40 56 78         或者01 05 00 00 00 00 蜂鸣器都应该响*/
                if(M[0]==0X00|D[0]==0X5678)
                        {
                                SPEAK=0;
                        }
                else
                                SPEAK=1;

/*上位机发送数据说明
                        读取一个线圈
主机器发送                        地址,功能码,寄存器高位,寄存器低位,数据个数高位, 数据个数低位,CRC低位,CRC高位
数组位置                         0                1                        2                        3                        4                                5                6                        7
例如读取MO 发送,        01      01                         00                         00                        00                                 01
主机器返回                        地址,功能码, , 数据个数,         数据1低位                CRC低位,CRC高位
数组位置                         0                1                        2                        3                                                       
例如读取MO 返回,        01      01                         01                         11               
                       
                        读取一个寄存D0 D0 的地址为3F ,D1地址为41 D2地址为43 D3地址为45 D4 地址为47
主机器发送                        地址,功能码,寄存器高位,寄存器低位,数据个数高位, 数据个数低位,CRC低位,CRC高位
数组位置                         0                1                        2                        3                        4                                5                6                        7
例如读取D0 发送,        01      03                         00                         3F                        00                                 01
主机器返回                        地址,功能码, , 数据个数,         数据1低位                CRC低位,CRC高位
数组位置                         0                1                        2                        3                                                       
例如读取D0 返回,        01      01                         01                         11               
        /********************************** END *************************************************/

        }
}




以下为MODBUS.C 文件

#include "main.h"

//字地址 0 - 255 (只取低8位)
//位地址 0 - 255 (只取低8位)

/* CRC 高位字节值表 */
const uint8 code auchCRCHi[] = {
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低位字节值表*/
const uint8 code auchCRCLo[] = {
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
} ;

uint8    testCoil;                //用于测试 位地址1
uint16   testRegister;        //用于测试 字址址16

uint8        xdata localAddr = 01;        //单片机控制板的地址
uint8        xdata sendCount;                //发送字节个数
uint8        xdata receCount;            //接收到的字节个数
uint8        xdata sendPosi,xxx=0;            //发送位置

uint8 xdata *MADDR;        //M区地址指针
//uint8 xdata *DADDR;        // D区地址指针

uint16 crc16(uint8 *puchMsg, uint16 usDataLen)
{
        uint8 xdata uchCRCHi = 0xFF ; /* 高CRC字节初始化 */
        uint8 xdata uchCRCLo = 0xFF ; /* 低CRC 字节初始化 */
        uint32 xdata uIndex ; /* CRC循环中的索引 */
        while (usDataLen--) /* 传输消息缓冲区 */
        {
                uIndex = uchCRCHi ^ *puchMsg++ ; /* 计算CRC */
                uchCRCHi = uchCRCLo ^ auchCRCHi[uIndex] ;
                uchCRCLo = auchCRCLo[uIndex] ;
        }
        return (uchCRCHi << 8 | uchCRCLo) ;
}//uint16 crc16(uint8 *puchMsg, uint16 usDataLen)

//开始发送
void beginSend(void)
{       
        sendPosi = 0;
        if(sendCount > 1)
                sendCount--;
        ACC = sendBuf[0];
        TB8 = P;
        SBUF = sendBuf[0];
        b485Send =0;   

}

/*读线圈状态能够正确读取一个或者多个线圈状态 OK*/
void readCoil(void)
{
        uint8 *xuwu;
        uint8 i;
        uint8  byteCount;
        uint16 crcData;
//                读取一个线圈
//主机器发送                        地址,功能码,寄存器高位,寄存器低位,数据个数高位, 数据个数低位,CRC低位,CRC高位
//数组位置                         0                1                        2                        3                        4                                5                6                        7
//例如读取MO 发送,        01      01                         00                         00                        00                                 01
//主机器返回                        地址,功能码, , 数据个数,         数据                CRC低位,CRC高位
//数组位置                         0                1                        2                        3                                                       
//例如读取MO 返回,        01      01                         01                         11                */
        MADDR= (uint8*)receBuf[3]; //读取寄存器开始位置         //强制类型转换 值得思考,
        byteCount = receBuf[5];        //字节个数
                for(i=0;i<byteCount;i++,MADDR++)
        {
                xuwu=(uint8*)MADDR;
                sendBuf[i+3] =*xuwu;
        }       
//组织发送的数据
        sendBuf[0] = localAddr;           //地址
        sendBuf[1] = 0x01;                   //功能码
        sendBuf[2] = byteCount;           //发送的数据个数
//        sendBuf[3] = *MADDR;           //发送的数据
        byteCount += 3;                           //参加CRC校验计算的数据个数,
        crcData = crc16(sendBuf,byteCount);        //CRC校验
        sendBuf[byteCount] = crcData >> 8;        //应该是低位,怎么成了高位??????
        byteCount++;
        sendBuf[byteCount] = crcData & 0xff; //应该是高位,怎么成了低位??????
        sendCount = byteCount + 1;
        beginSend();
}

/*读寄存器能够正确读取一个或者多个寄存器的数据 */
void readRegisters(void)
{
        uint8 tempAddr,*xuwu;
        uint16 crcData;
        uint8 readCount;
        uint8 byteCount;
        uint8 i;
/*                        读取一个寄存D0 D0 的地址为3F ,D1地址为41 D2地址为43 D3地址为45 D4 地址为47
主机器发送                        地址,功能码,寄存器高位,寄存器低位,数据个数高位, 数据个数低位,CRC低位,CRC高位
例如读取D0 发送,        01      03                         00                         3F                        00                                 01
主机器返回                        地址,功能码, , 数据个数,         数据1低位                CRC低位,CRC高位
数组位置                         0                1                        2                        3                                                       
例如读取D0 返回,        01      01                         01                         11                  */
        tempAddr = receBuf[3];//寄存器  地址的低位
        readCount = receBuf[5];         //要读取的数据个数,
        byteCount = readCount * 2;        //字节数目=数据个数*2
        for(i=0;i<byteCount;i+=2,tempAddr+=2)
        {
                xuwu=(uint8*)tempAddr;
                sendBuf[i+3] =*xuwu;
                sendBuf[i+4] =*(xuwu+1);                        
        }
/*组织发送数据*/       
        sendBuf[0] = localAddr;        //地址
        sendBuf[1] = 3;                         //功能码
        sendBuf[2] = byteCount;         //发送字节个数
        byteCount += 3;
        crcData = crc16(sendBuf,byteCount);//CRC校验
        sendBuf[byteCount] = crcData >> 8;
        byteCount++;
        sendBuf[byteCount] = crcData & 0xff;
        sendCount = byteCount + 1;
        beginSend();
}
//强制单个线圈
void forceSingleCoil(void)
{

        uint8 i;
        /*                        强制一个线圈。
主机器发送                        地址,功能码,寄存器高位,寄存器低位,数据高位, 数据低位,CRC低位,CRC高位
例如强制MO发送,        01      03                         00                         00                        00                 fa                01
返回数据相同,执行完成后MO=FA         */
           MADDR=(uint8*)receBuf[3];        //强制的地址  //强制类型转换 值得思考,
    *MADDR=receBuf[5];         //强制地址的数据赋值
        for(i=0;i<receCount;i++)
        {
                sendBuf = receBuf;
        }
        sendCount = receCount;
        beginSend();
         
}
/*设置单个寄存器ok*/
void presetSingleRegister(void)
{
        uint8 i;
        uint8 *Daddr;

        /*                        设置寄存器一个寄存D0 D0 的地址为40 ,D1地址为42 D2地址为44 D3地址为46 D4 地址为48
主机器发送                        地址,功能码,寄存器高位,寄存器低位,数据数高位, 数数低位,CRC低位,CRC高位
例如设置D0 发送,        01      06                         00                         3F                00                         01                   */
//设置成功原样返回
        Daddr = (uint8*)receBuf[3];        //地址码
        *Daddr=receBuf[4];                //地址的赋值数据
        *(Daddr+1)=receBuf[5];        //地址的赋值数据
                for(i=0;i<receCount;i++)
        {
                sendBuf = receBuf;
        }
        sendCount = receCount;
        beginSend();
}

//设置多个寄存器  还未调试,
void presetMultipleRegisters(void)
{
        uint8 addr;
        uint8 tempAddr,*xxiang;
        uint8 byteCount;
        uint8 setCount;
        uint16 crcData;
        uint16 tempData;
        uint8 i;

        /*                        设置寄存器一个寄存D0 D0 的地址为3F ,D1地址为41 D2地址为43 D3地址为45 D4 地址为47
主机器发送                        地址,功能码,寄存器高位,寄存器低位,数据数高位, 数数低位,CRC低位,CRC高位
例如设置D0 发送,        01      10                         00                         3F                00                         01                   */
//设置成功原样返回

        addr = receBuf[3];        //地址码
        tempAddr = addr & 0xff;         //        屏蔽高位,
        xxiang=(uint8*)tempAddr+2;
        xxx=tempAddr+2;

        setCount = receBuf[5];
        byteCount = receBuf[6];       
       
        for(i=0;i<setCount;i++,tempAddr++)
        {
                tempData = (receBuf[i*2+7]<<8) + receBuf[i*2+8];
                *xxiang=receBuf[8];
                *(xxiang-1)=receBuf[7];
        }
//组织返回数据,       
        sendBuf[0] = localAddr;
        sendBuf[1] = 16;
        sendBuf[2] = addr >> 8;           //发送地址高位,
        sendBuf[3] = addr & 0xff;        //发送地址低位,
        sendBuf[4] = setCount >> 8;        //发送个数高位
        sendBuf[5] = setCount & 0xff;//发送个数低位,
        crcData = crc16(sendBuf,6);
        sendBuf[6] = crcData >> 8;
        sendBuf[7] = crcData & 0xff;
        sendCount = 8;
        beginSend();
}
//检查uart0数据
checkComm0Modbus()
{
        uint16 crcData;
        uint16 tempData;

        if(receCount > 4)
        {
                switch(receBuf[1])
                {
                        case 1: //读取线圈状态(读取点 16位以内)
                        case 3: //读取保持寄存器(一个或多个)
                        case 5: //强制单个线圈
                        case 6: //设置单个寄存器
                                        if(receCount >= 8)
                                        {//接收完成一组数据
                                                //应该关闭接收中断
                                               
                                                if(receBuf[0]==localAddr && checkoutError==0)
                                                {
                                                        crcData = crc16(receBuf,6);
                                                        if(crcData == receBuf[7]+(receBuf[6]<<8))
                                                        {//校验正确
                                                                if(receBuf[1] == 1)
                                                                {//读取线圈状态(读取点 16位以内)
                                                                        readCoil();                                                               
                                                                }
                                                                else if(receBuf[1] == 3)
                                                                {//读取保持寄存器(一个或多个)
                                                                        readRegisters();
                                                                }
                                                                else if(receBuf[1] == 5)
                                                                {//强制单个线圈
                                                                        forceSingleCoil();                                                               
                                                                }
                                                                else if(receBuf[1] == 6)
                                                                {
                                                                        presetSingleRegister();                                               
                                                                }
                                                        }
                                                }                                               
                                                receCount = 0;       
                                                checkoutError = 0;
                                        }
                                        break;
                       
                        case 15: //设置多个线圈
                                        tempData = receBuf[6];
                                        tempData += 9;        //数据个数
                                        if(receCount >= tempData)
                                        {
                                                if(receBuf[0]==localAddr && checkoutError==0)
                                                {
                                                        crcData = crc16(receBuf,tempData-2);
                                                        if(crcData == (receBuf[tempData-2]<<8)+ receBuf[tempData-1])
                                                        {
                                                                //forceMultipleCoils();                       
                                                        }
                                                }       
                                                receCount = 0;
                                                checkoutError = 0;
                                        }
                                        break;
                       
                        case 16: //设置多个寄存器
                                        tempData = (receBuf[4]<<8) + receBuf[5];
                                        tempData = tempData * 2;        //数据个数
                                        tempData += 9;
                                        if(receCount >= tempData)
                                        {
                                                if(receBuf[0]==localAddr && checkoutError==0)
                                                {
                                                        crcData = crc16(receBuf,tempData-2);
                                                        if(crcData == (receBuf[tempData-2]<<8)+ receBuf[tempData-1])
                                                        {
                                                                presetMultipleRegisters();               
                                                        }
                                                }       
                                                receCount = 0;
                                                checkoutError = 0;
                                        }
                                        break;
                                                               
                        default:
                                        break;
                }
        }
return xxx;
}

出0入0汤圆

发表于 2012-6-15 16:27:26 | 显示全部楼层
顶一个,支持一下!

出0入0汤圆

发表于 2012-6-15 23:16:39 | 显示全部楼层
来支持下楼主

出0入0汤圆

发表于 2012-6-16 08:49:47 | 显示全部楼层
感谢楼主的无私分享,支持一下

出0入0汤圆

发表于 2012-6-16 08:57:03 | 显示全部楼层
来支持下楼主

出0入0汤圆

发表于 2012-6-16 09:33:36 | 显示全部楼层
支持一下,51modbus

出0入0汤圆

发表于 2012-6-16 09:42:09 | 显示全部楼层
谢谢楼主无私奉献

出0入0汤圆

发表于 2012-6-16 14:58:37 | 显示全部楼层
下载来学习,多谢了!!!

出0入0汤圆

发表于 2012-6-16 20:10:38 | 显示全部楼层
本帖最后由 wkman 于 2012-6-16 20:34 编辑

程序不全,少了    main.h"

支持。争取搞通更多的,。。。学习!

出0入0汤圆

 楼主| 发表于 2012-6-17 07:36:22 | 显示全部楼层

以下为main.h
#include "reg52.h"

typedef unsigned char        uint8;
typedef unsigned int        uint16;
typedef unsigned long        uint32;

#define TIMER_HIGHT        0xFc
#define TIMER_LOW        0x66
sbit        b485Send                =         P3^3;

extern uint8        xdata sendBuf[24],receBuf[24];
extern uint8        idata checkoutError;        // ==2 偶校验错
extern uint8        idata receTimeOut;
extern uint32   xdata dwTickCount;
extern uint8    idata V0, VM0;
#include "modbus.h"

以下为modbus.h
extern uint8 xdata        sendCount;       
extern uint8 xdata        receCount;       
extern uint8 xdata        sendPosi;

void beginSend(void);
checkComm0Modbus();
void readCoil(void); //读取线圈,一个或者多个,功能码01
void readRegisters(void);//读取寄存器,一个活多个,功能吗03
void forceSingleCoil(void);         //强制单个线圈,功能吗05
void presetSingleRegister(void); //写单个寄存器功能吗06
void presetMultipleRegisters(void);
void forceMultipleCoils(void);
//uint16 getRegisterVal(uint16 addr,uint16 *tempData);
//uint16 setRegisterVal(uint16 addr,uint16 tempData);
//uint16 getCoilVal(uint16 addr,uint16 *tempData);
//uint16 setCoilVal(uint16 addr,uint16 tempData);

出0入0汤圆

发表于 2012-6-17 18:57:04 来自手机 | 显示全部楼层
好东西必须支持

出0入0汤圆

发表于 2012-6-17 21:24:50 | 显示全部楼层
modbus通讯协议,谢谢分享!

出0入8汤圆

发表于 2012-6-17 21:29:33 | 显示全部楼层
谢谢,分享!!

出0入0汤圆

发表于 2012-6-18 08:25:37 | 显示全部楼层
学习了,谢谢。以前用51也搞了好长时间

出0入96汤圆

发表于 2012-6-18 08:44:46 | 显示全部楼层
谢谢分享

出0入0汤圆

发表于 2012-6-18 09:02:36 | 显示全部楼层
哎,lz还是rar后,发个工程上来爽利,copy去编译,有错误,不过修正了一下::

void forceSingleCoil(void)

        sendBuf[i] = receBuf[i];//原为sendBuf = receBuf编译有错误!

void presetSingleRegister(void)

        sendBuf[i] = receBuf[i];//原为sendBuf = receBuf编译有错误!

出0入0汤圆

发表于 2012-7-18 10:16:19 | 显示全部楼层
楼主 0X01 功能绝对有问题   0x01
          for(i=0;i<byteCount;i++,MADDR++)
         {
                 xuwu=(uint8*)MADDR;
                 sendBuf[i+3] =*xuwu;
         }   

出0入0汤圆

发表于 2012-7-18 11:37:16 | 显示全部楼层
感觉很复杂,学习

出0入0汤圆

发表于 2012-7-19 19:37:08 | 显示全部楼层
楼主发个工程上来吧!

出0入0汤圆

发表于 2012-7-19 20:15:53 | 显示全部楼层
弓虽贴,楼主钻研辛苦了!

出0入0汤圆

发表于 2012-7-19 20:43:42 | 显示全部楼层
还是希望能有整个工程,用来做总线节点控制还是很方便,通用。目前是自定义协议的。

出0入0汤圆

发表于 2012-7-20 19:10:20 | 显示全部楼层
最近也在学习modbus通讯协议,不知道怎么联系。要不楼主搞个群交流一下啊!

出0入0汤圆

发表于 2012-7-20 20:02:44 | 显示全部楼层
好好研究啊!!

出0入0汤圆

发表于 2012-7-21 09:27:35 | 显示全部楼层
麻烦lz发个keil工程上来吧,自己凑工程很多问题,

出0入0汤圆

发表于 2012-7-21 10:26:31 | 显示全部楼层
谢谢分享

出0入0汤圆

发表于 2012-7-21 11:16:41 | 显示全部楼层
    代码中有明显错误。
    0x10,可不是15,而是16。
    楼主的代码,没有经过验证就放出来,有点不负责任啊。

出0入0汤圆

发表于 2012-7-21 12:30:08 | 显示全部楼层
本帖最后由 yklstudent 于 2012-7-21 12:33 编辑

楼主的CRC校验程序部分有问题吧
改为这样就行了,不知道是不是你的CRC表搞反了???????????:
/*************测试CRC校验程序******************/
uint16 crc16(uint8 *puchMsg, uint16 usDataLen)
{
        uint8 uchCRCHi = 0xFF ; /* 高CRC字节初始化 */
    uint8 uchCRCLo = 0xFF ; /* 低CRC 字节初始化 */
    uint32 uIndex ; /* CRC循环中的索引 */
    while (usDataLen--) /* 传输消息缓冲区 */
        {
                uIndex = uchCRCLo ^ *puchMsg++ ; /* 计算CRC */
                uchCRCLo = uchCRCHi ^ auchCRCHi[uIndex] ;
                uchCRCHi = auchCRCLo[uIndex] ;
        }
        return (uchCRCHi << 8 | uchCRCLo) ;
}
//uint16 crc16(uint8 *puchMsg, uint16 usDataLen)

出0入0汤圆

发表于 2012-7-21 13:10:45 | 显示全部楼层
谢谢楼主哇,真是一个好人

出0入0汤圆

发表于 2012-7-21 17:24:13 | 显示全部楼层
谢谢楼主,支持

出0入0汤圆

发表于 2012-7-21 17:46:32 | 显示全部楼层
是好东西啊,

出0入0汤圆

发表于 2012-7-21 18:46:29 | 显示全部楼层
将它给马上

出0入0汤圆

发表于 2012-8-3 21:34:07 | 显示全部楼层
lz不错,程序都差不多,modbus rtu都这样

出0入0汤圆

发表于 2012-8-10 17:55:53 | 显示全部楼层
来学习一下

出0入0汤圆

发表于 2012-8-10 19:47:34 | 显示全部楼层
这个资料好啊,最近正在研究这个怎么写呢,谢谢楼主

出0入0汤圆

发表于 2012-9-12 15:04:25 | 显示全部楼层
学习了。。。

出0入0汤圆

发表于 2012-9-15 22:24:16 | 显示全部楼层
感谢楼主的无私分享,支持一下

出0入0汤圆

发表于 2012-9-20 23:35:47 | 显示全部楼层
谢谢楼主

出0入0汤圆

发表于 2012-9-21 11:11:58 来自手机 | 显示全部楼层
henhao   hen  qiang  da

出0入0汤圆

发表于 2012-10-19 11:01:15 | 显示全部楼层
学习了,,,,,,,,,,,

出0入0汤圆

发表于 2012-10-25 16:25:39 | 显示全部楼层
BODBUS,正在学习!!!

出0入0汤圆

发表于 2012-11-18 02:28:09 | 显示全部楼层
mark   在做MODBUS

出0入0汤圆

发表于 2012-11-18 11:17:13 | 显示全部楼层
呵呵 我当初的MODBUS也是根据这个改编的

出0入0汤圆

发表于 2012-12-13 21:37:09 | 显示全部楼层
路过。。。。。

出0入0汤圆

发表于 2012-12-14 11:25:28 | 显示全部楼层
感谢分享,谢谢,

出0入4汤圆

发表于 2012-12-26 10:18:51 | 显示全部楼层
下下来验证一下子,感谢楼主!

出0入0汤圆

发表于 2012-12-26 17:59:21 | 显示全部楼层
路过顶起

出0入0汤圆

发表于 2012-12-26 20:24:57 来自手机 | 显示全部楼层
先留个脚印

出0入0汤圆

发表于 2013-1-2 13:22:52 | 显示全部楼层
mark 一下,正在研究MODBUS

出0入0汤圆

发表于 2013-2-19 16:09:09 | 显示全部楼层
mark modbus slave

出0入0汤圆

发表于 2013-2-22 16:52:59 | 显示全部楼层
学习了,,,不错不错。

出0入0汤圆

发表于 2013-3-2 20:23:54 | 显示全部楼层
Mark Modbus,正用着

出0入0汤圆

发表于 2013-3-10 23:19:39 | 显示全部楼层
谢谢楼主分享

出0入0汤圆

发表于 2013-3-12 16:03:27 来自手机 | 显示全部楼层
做事要严谨啊

出0入0汤圆

发表于 2013-3-28 11:12:39 | 显示全部楼层
谢谢楼主分享!!

出0入0汤圆

发表于 2013-3-28 17:31:13 | 显示全部楼层
马上要上类似的东东,谢谢

出0入0汤圆

发表于 2013-4-5 12:36:19 | 显示全部楼层
modbus标记!

出0入0汤圆

发表于 2013-5-16 14:31:00 | 显示全部楼层
楼主,请问这一句是什么意思?  TB8 = P; 这2个都没定义

出0入0汤圆

发表于 2013-5-16 14:54:34 | 显示全部楼层
楼主,这一句 TB8 = P; 是什么意思啊?程序里面没有定义这2个变量

出0入18汤圆

发表于 2013-5-28 16:45:33 | 显示全部楼层
不错 不错不错

出0入0汤圆

发表于 2013-7-23 11:55:16 | 显示全部楼层
正在学习。。。

出0入0汤圆

发表于 2013-7-25 23:20:47 | 显示全部楼层
mark,C51 modbus 通信

出0入0汤圆

发表于 2013-7-26 01:08:15 | 显示全部楼层
mark modbus

出0入0汤圆

发表于 2013-8-14 20:13:40 来自手机 | 显示全部楼层
mark……
顶一个…

出0入0汤圆

发表于 2014-11-5 11:37:54 | 显示全部楼层
楼主的程 序没有反馈校验,功能码06 这样PLC会提示通信错误

出0入0汤圆

发表于 2014-11-5 11:45:50 | 显示全部楼层
强大,刚进论坛就发这么牛的帖子

出0入0汤圆

发表于 2014-11-7 14:57:29 | 显示全部楼层
得顶啊  好东西哦

出0入0汤圆

发表于 2014-11-12 12:30:57 | 显示全部楼层
好东西必须顶

出0入0汤圆

发表于 2014-11-12 13:26:46 | 显示全部楼层
楼主的无私分享,支持一下

出0入0汤圆

发表于 2014-11-12 13:49:07 | 显示全部楼层
很好,源程序下载就更好了,呵呵

出0入0汤圆

发表于 2020-1-7 11:30:02 | 显示全部楼层
modbus mark

出0入0汤圆

发表于 2020-1-10 19:30:26 | 显示全部楼层
没有一个真正能用的MODBUS RTU程序!

出0入0汤圆

发表于 2020-1-10 19:46:19 | 显示全部楼层
支持一下

出0入0汤圆

发表于 2020-6-27 21:53:38 | 显示全部楼层
这个虽然老帖  我在学 在做 modbus 做的好 也难啊啊

出130入30汤圆

发表于 2020-6-28 05:12:23 来自手机 | 显示全部楼层
STM32F0芯片支持MODBUD

出0入0汤圆

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

本版积分规则

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

GMT+8, 2024-4-20 21:34

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

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