kaishandage 发表于 2012-6-15 15:35:04

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

本帖最后由 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位)
**********************************************************************/
uint16idata D _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,receBuf; //发送接收缓冲区
uint8        idata checkoutError;        // ==2 偶校验错
uint8        idata receTimeOut;                //接收超时
bit                idata bt1ms;//100ms,bt100ms;        //定时标志位
uint8 xdata M_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;
                        TB8 = P;        //加上校验位
                        SBUF = sendBuf;
                }
                else
                {
            //发送完后将485置于接收状态
                   b485Send = 1;   
                        receCount = 0;   //清接收地址偏移寄存器
                        checkoutError = 0;
                }
        }
        else if(RI)
        {
                RI = 0;
                receTimeOut = 10;    //通讯超时值这个地方很重要
                //receTimeOut = 50;    //通讯超时值
                receBuf = SBUF;
                ACC = receBuf;
                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=0x11;
                       M=0x22;
                       M=0x33;
                       M=0x44;
                       M=0x55;
                       M=0x66;
                       M=0x77;
                       M=0x88;
                       M=0x99;
                       
                       D=0X1122;
                       D=0x3344;
                       D=0x5566;
                       D=0x7788;
                     D=0X99aa;
        while(1)
        {       
                timeProc();///////////////////////////通讯
                checkComm0Modbus();///////////////////通讯
          /**********************************控制程序*********************************************/
                /*测试程序说明 上位机发送 01 06 00 40 56 78       或者01 05 00 00 00 00 蜂鸣器都应该响*/
                if(M==0X00|D==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 ;
                uchCRCLo = auchCRCLo ;
        }
        return (uchCRCHi << 8 | uchCRCLo) ;
}//uint16 crc16(uint8 *puchMsg, uint16 usDataLen)

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

}

/*读线圈状态能够正确读取一个或者多个线圈状态 OK*/
void readCoil(void)
{
        uint8 *xuwu;
        uint8 i;
        uint8byteCount;
        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; //读取寄存器开始位置       //强制类型转换 值得思考,
        byteCount = receBuf;        //字节个数
                for(i=0;i<byteCount;i++,MADDR++)
        {
                xuwu=(uint8*)MADDR;
                sendBuf =*xuwu;
        }       
//组织发送的数据
        sendBuf = localAddr;           //地址
        sendBuf = 0x01;                   //功能码
        sendBuf = byteCount;           //发送的数据个数
//        sendBuf = *MADDR;           //发送的数据
        byteCount += 3;                           //参加CRC校验计算的数据个数,
        crcData = crc16(sendBuf,byteCount);        //CRC校验
        sendBuf = crcData >> 8;        //应该是低位,怎么成了高位??????
        byteCount++;
        sendBuf = 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;//寄存器地址的低位
        readCount = receBuf;       //要读取的数据个数,
        byteCount = readCount * 2;        //字节数目=数据个数*2
        for(i=0;i<byteCount;i+=2,tempAddr+=2)
        {
                xuwu=(uint8*)tempAddr;
                sendBuf =*xuwu;
                sendBuf =*(xuwu+1);                        
        }
/*组织发送数据*/       
        sendBuf = localAddr;        //地址
        sendBuf = 3;                       //功能码
        sendBuf = byteCount;       //发送字节个数
        byteCount += 3;
        crcData = crc16(sendBuf,byteCount);//CRC校验
        sendBuf = crcData >> 8;
        byteCount++;
        sendBuf = 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;        //强制的地址//强制类型转换 值得思考,
    *MADDR=receBuf;       //强制地址的数据赋值
        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;        //地址码
        *Daddr=receBuf;                //地址的赋值数据
        *(Daddr+1)=receBuf;        //地址的赋值数据
                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;        //地址码
        tempAddr = addr & 0xff;       //        屏蔽高位,
        xxiang=(uint8*)tempAddr+2;
        xxx=tempAddr+2;

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

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

lryxr2507 发表于 2012-6-15 16:27:26

顶一个,支持一下!

Bicycle 发表于 2012-6-15 23:16:39

来支持下楼主

xukai871105 发表于 2012-6-16 08:49:47

感谢楼主的无私分享,支持一下

zcmthr 发表于 2012-6-16 08:57:03

来支持下楼主

xinzhi1986 发表于 2012-6-16 09:33:36

支持一下,51modbus

dengxm2009 发表于 2012-6-16 09:42:09

谢谢楼主无私奉献

saisam 发表于 2012-6-16 14:58:37

下载来学习,多谢了!!!

wkman 发表于 2012-6-16 20:10:38

程序还是

本帖最后由 wkman 于 2012-6-16 20:34 编辑

程序不全,少了    main.h"

支持。争取搞通更多的,。。。学习!{:victory:}

kaishandage 发表于 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,receBuf;
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);

mofire 发表于 2012-6-17 18:57:04

好东西必须支持

wtiechen1969 发表于 2012-6-17 21:24:50

modbus通讯协议,谢谢分享!

fangmcu 发表于 2012-6-17 21:29:33

谢谢,分享!!

YUXINFU 发表于 2012-6-18 08:25:37

学习了,谢谢。以前用51也搞了好长时间

gallle 发表于 2012-6-18 08:44:46

谢谢分享

jetli 发表于 2012-6-18 09:02:36

{:sweat:}哎,lz还是rar后,发个工程上来爽利,copy去编译,有错误,不过修正了一下::

void forceSingleCoil(void)

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

void presetSingleRegister(void)

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

hmd420304805 发表于 2012-7-18 10:16:19

楼主 0X01 功能绝对有问题   0x01
          for(i=0;i<byteCount;i++,MADDR++)
         {
               xuwu=(uint8*)MADDR;
               sendBuf =*xuwu;
         }   

pengbo_88 发表于 2012-7-18 11:37:16

{:sad:}感觉很复杂,学习

bfk2003 发表于 2012-7-19 19:37:08

楼主发个工程上来吧!

kms2hh 发表于 2012-7-19 20:15:53

{:handshake:}弓虽贴,楼主钻研辛苦了!

oufuqiang 发表于 2012-7-19 20:43:42

还是希望能有整个工程,用来做总线节点控制还是很方便,通用。目前是自定义协议的。

bfk2003 发表于 2012-7-20 19:10:20

最近也在学习modbus通讯协议,不知道怎么联系。要不楼主搞个群交流一下啊!{:smile:}

dcqq88 发表于 2012-7-20 20:02:44

好好研究啊!!

jetli 发表于 2012-7-21 09:27:35

{:sweat:} 麻烦lz发个keil工程上来吧,自己凑工程很多问题,{:mad:}

2006lc 发表于 2012-7-21 10:26:31

谢谢分享

wuzhujian 发表于 2012-7-21 11:16:41

    代码中有明显错误。
    0x10,可不是15,而是16。
    楼主的代码,没有经过验证就放出来,有点不负责任啊。

yklstudent 发表于 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 ;
                uchCRCHi = auchCRCLo ;
        }
        return (uchCRCHi << 8 | uchCRCLo) ;
}
//uint16 crc16(uint8 *puchMsg, uint16 usDataLen)

yamqqqq 发表于 2012-7-21 13:10:45

谢谢楼主哇,真是一个好人

cqxubo00 发表于 2012-7-21 17:24:13

谢谢楼主,支持

bingtuohun 发表于 2012-7-21 17:46:32

是好东西啊,

hisun 发表于 2012-7-21 18:46:29

将它给马上

cong2010 发表于 2012-8-3 21:34:07

lz不错,程序都差不多,modbus rtu都这样

cqsgcqsg 发表于 2012-8-10 17:55:53

{:smile:}来学习一下

feixue 发表于 2012-8-10 19:47:34

这个资料好啊,最近正在研究这个怎么写呢,谢谢楼主

inovar 发表于 2012-9-12 15:04:25

学习了。。。

liuzhengyaAVR 发表于 2012-9-15 22:24:16

感谢楼主的无私分享,支持一下

zhang8198 发表于 2012-9-20 23:35:47

谢谢楼主{:smile:}{:smile:}{:smile:}

huaidan2088 发表于 2012-9-21 11:11:58

henhao   henqiangda

Making 发表于 2012-10-19 11:01:15

学习了,,,,,,,,,,,

蚂蚁 发表于 2012-10-25 16:25:39

BODBUS,正在学习!!!

plcpro 发表于 2012-11-18 02:28:09

mark   在做MODBUS

waking 发表于 2012-11-18 11:17:13

呵呵 我当初的MODBUS也是根据这个改编的

Tomas_Yung 发表于 2012-12-13 21:37:09

路过。。。。。

lsxiaoma 发表于 2012-12-14 11:25:28

感谢分享,谢谢,{:biggrin:}

langbaiyue 发表于 2012-12-26 10:18:51

下下来验证一下子,感谢楼主!

YOU1 发表于 2012-12-26 17:59:21

路过顶起

机械人 发表于 2012-12-26 20:24:57

先留个脚印

mique 发表于 2013-1-2 13:22:52

mark 一下,正在研究MODBUS

mique 发表于 2013-2-19 16:09:09

mark modbus slave

xccad 发表于 2013-2-22 16:52:59

学习了,,,不错不错。

jhxmzx 发表于 2013-3-2 20:23:54

Mark Modbus,正用着

fayuanye 发表于 2013-3-10 23:19:39

谢谢楼主分享

cvi670 发表于 2013-3-12 16:03:27

做事要严谨啊

fayuanye 发表于 2013-3-28 11:12:39

谢谢楼主分享!!

wzhansen 发表于 2013-3-28 17:31:13

马上要上类似的东东,谢谢

eddia2012 发表于 2013-4-5 12:36:19

modbus标记!

mianchaodahai 发表于 2013-5-16 14:31:00

楼主,请问这一句是什么意思?TB8 = P; 这2个都没定义

mianchaodahai 发表于 2013-5-16 14:54:34

楼主,这一句 TB8 = P; 是什么意思啊?程序里面没有定义这2个变量

himan 发表于 2013-5-28 16:45:33

不错 不错不错

liujing8862770 发表于 2013-7-23 11:55:16

正在学习。。。

a794001114 发表于 2013-7-25 23:20:47

mark,C51 modbus 通信

fish_tian 发表于 2013-7-26 01:08:15

mark modbus

xiefy21 发表于 2013-8-14 20:13:40

mark……
顶一个…

戒魔 发表于 2014-11-5 11:37:54

楼主的程 序没有反馈校验,功能码06 这样PLC会提示通信错误

lingergz 发表于 2014-11-5 11:45:50

强大,刚进论坛就发这么牛的帖子

huangweida 发表于 2014-11-7 14:57:29

得顶啊好东西哦

yao2013lin 发表于 2014-11-12 12:30:57

好东西必须顶

Tonyhai 发表于 2014-11-12 13:26:46

楼主的无私分享,支持一下

zhinengyibiao 发表于 2014-11-12 13:49:07

很好,源程序下载就更好了,呵呵

jetbo 发表于 2020-1-7 11:30:02

modbus mark

zhangfuhg 发表于 2020-1-10 19:30:26

没有一个真正能用的MODBUS RTU程序!

szdy 发表于 2020-1-10 19:46:19

支持一下

lvxinchao-206 发表于 2020-6-27 21:53:38

这个虽然老帖我在学 在做 modbus 做的好 也难啊啊

cheng-8yang 发表于 2020-6-28 05:12:23

STM32F0芯片支持MODBUD

tangguotaizi 发表于 2020-6-28 07:07:36

感谢楼主,标记下
页: [1]
查看完整版本: C51 modbus 通信协议 可以完成01 03 05 06 功能码