找回密碼
 立即注冊(cè)

QQ登錄

只需一步,快速開(kāi)始

搜索
查看: 1914|回復(fù): 0
打印 上一主題 下一主題
收起左側(cè)

我的 modbus 從機(jī)板 開(kāi)發(fā)代碼

[復(fù)制鏈接]
跳轉(zhuǎn)到指定樓層
樓主
ID:115923 發(fā)表于 2020-2-21 16:56 | 只看該作者 回帖獎(jiǎng)勵(lì) |倒序?yàn)g覽 |閱讀模式
/***************************Lcd1602.c文件程序源代碼*****************************/

(此處省略,可參考之前章節(jié)的代碼)

/****************************RS485.c文件程序源代碼*****************************/

(此處省略,可參考之前章節(jié)的代碼)

/****************************CRC16.c文件程序源代碼****************************/

/* CRC16計(jì)算函數(shù),ptr-數(shù)據(jù)指針,len-數(shù)據(jù)長(zhǎng)度,返回值-計(jì)算出的CRC16數(shù)值 */

unsigned int GetCRC16(unsigned char *ptr,  unsigned char len)

{

    unsigned int index;

    unsigned char crch = 0xFF;  //高CRC字節(jié)

    unsigned char crcl = 0xFF;  //低CRC字節(jié)

    unsigned char code TabH[] = {  //CRC高位字節(jié)值表

        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  

    } ;  

    unsigned char code TabL[] = {  //CRC低位字節(jié)值表

        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  

    } ;



    while (len--)  //計(jì)算指定長(zhǎng)度的CRC

    {

        index = crch ^ *ptr++;

        crch = crcl ^ TabH[index];

        crcl = TabL[index];

    }



    return ((crch<<8) | crcl);  

}

關(guān)于CRC校驗(yàn)的算法,如果不是專(zhuān)門(mén)學(xué)習(xí)校驗(yàn)算法本身,大家可以不去研究這個(gè)程序的細(xì)節(jié),直接使用現(xiàn)成的函數(shù)即可。

/*****************************main.c文件程序源代碼******************************/

#include
sbit BUZZ = P1^6;
bit flagBuzzOn = 0;   //蜂鳴器啟動(dòng)標(biāo)志
unsigned char T0RH = 0;  //T0重載值的高字節(jié)
unsigned char T0RL = 0;  //T0重載值的低字節(jié)
unsigned char regGroup[5];  //Modbus寄存器組,地址為0x00~0x04
void ConfigTimer0(unsigned int ms);
extern void UartDriver();
extern void ConfigUART(unsigned int baud);
extern void UartRxMonitor(unsigned char ms);
extern void UartWrite(unsigned char *buf, unsigned char len);
extern unsigned int GetCRC16(unsigned char *ptr,  unsigned char len);
extern void InitLcd1602();
extern void LcdShowStr(unsigned char x, unsigned char y, unsigned char *str);


void main()
{

    EA = 1;              //開(kāi)總中斷
    ConfigTimer0(1);   //配置T0定時(shí)1ms
    ConfigUART(9600);  //配置波特率為9600
    InitLcd1602();     //初始化液晶
    while (1)
    {
        UartDriver();  //調(diào)用串口驅(qū)動(dòng)
    }

}

/* 串口動(dòng)作函數(shù),根據(jù)接收到的命令幀執(zhí)行響應(yīng)的動(dòng)作
   buf-接收到的命令幀指針,len-命令幀長(zhǎng)度 */

void UartAction(unsigned char *buf, unsigned char len)
{
    unsigned char i;
    unsigned char cnt;
    unsigned char str[4];
    unsigned int  crc;
    unsigned char crch, crcl;

    if (buf[0] != 0x01) // 本機(jī)從地址設(shè)定為0x01,
    {                      //如數(shù)據(jù)幀中的地址字節(jié)與本機(jī)地址不符,
        return;           //則直接退出,即丟棄本幀數(shù)據(jù)不做任何處理
    }

    //地址相符時(shí),再對(duì)本幀數(shù)據(jù)進(jìn)行校驗(yàn)

    crc = GetCRC16(buf, len-2);  //計(jì)算CRC校驗(yàn)值
    crch = crc >> 8;
    crcl = crc & 0xFF;

    if ((buf[len-2]!=crch) || (buf[len-1]!=crcl))
    {
        return;   //如CRC校驗(yàn)不符時(shí)直接退出
    }

    //地址和校驗(yàn)字均相符后,解析功能碼,執(zhí)行相關(guān)操作

    switch (buf[1])
    {
        case 0x03:  //讀取一個(gè)或連續(xù)的寄存器
            if ((buf[2]==0x00) && (buf[3]<=0x05)) //只支持0x0000~0x0005
            {
                if (buf[3] <= 0x04)  // 01 03 [ 00  i ]  [ xx cnt ] [ crch crcl ]
                {
                    i = buf[3];      //提取寄存器地址
                    cnt = buf[5];    //提取待讀取的寄存器數(shù)量
                    buf[2] = cnt*2;  //讀取數(shù)據(jù)的字節(jié)數(shù),為寄存器數(shù)*2
                    len = 3;          //幀前部已有地址、功能碼、字節(jié)數(shù)共3個(gè)字節(jié)
                    while (cnt--)
                    {
                        buf[len++] = 0x00;            //寄存器高字節(jié)補(bǔ)0
                        buf[len++] = regGroup[i++]; //寄存器低字節(jié)
                    }
                }

                else  //地址>=0x05為蜂鳴器狀態(tài)
                {
                    buf[2] = 2;  //讀取數(shù)據(jù)的字節(jié)數(shù)
                    buf[3] = 0x00;
                    buf[4] = flagBuzzOn;
                    len = 5;
                }
                break;
            }

            else  //寄存器地址不被支持時(shí),返回錯(cuò)誤碼
            {
                buf[1] = 0x83;  //功能碼最高位置1
                buf[2] = 0x02;  //設(shè)置異常碼為02-無(wú)效地址
                len = 3;
                break;
            }

        case 0x06:  //寫(xiě)入單個(gè)寄存器
            if ((buf[2]==0x00) && (buf[3]<=0x05)) //只支持0x0000~0x0005
            {
                if (buf[3] <= 0x04)  // 01 06 [ 00  i ]  [ xx regG ] [ crch crcl ]
                {
                    i = buf[3];               //提取寄存器地址
                    regGroup = buf[5];   //保存寄存器數(shù)據(jù)
                    cnt = regGroup >> 4; //顯示到液晶上  16進(jìn)制轉(zhuǎn)string
                    if (cnt >= 0xA)
                        str[0] = cnt - 0xA + 'A';
                    else
                        str[0] = cnt + '0';
                    cnt = regGroup & 0x0F;
                    if (cnt >= 0xA)
                        str[1] = cnt - 0xA + 'A';
                    else
                        str[1] = cnt + '0';
                    str[2] = '';
                    LcdShowStr(i*3, 0, str);
                }

                else  //地址0x05為蜂鳴器狀態(tài) // 01 06 [ 00  05 ]  [ xx  on ] [ crch crcl ]
                {
                    flagBuzzOn = (bit)buf[5]; //寄存器值轉(zhuǎn)為蜂鳴器的開(kāi)關(guān)
                }

                len -= 2; //長(zhǎng)度-2以重新計(jì)算CRC并返回原幀
分享到:  QQ好友和群QQ好友和群 QQ空間QQ空間 騰訊微博騰訊微博 騰訊朋友騰訊朋友
收藏收藏1 分享淘帖 頂 踩
回復(fù)

使用道具 舉報(bào)

本版積分規(guī)則

小黑屋|51黑電子論壇 |51黑電子論壇6群 QQ 管理員QQ:125739409;技術(shù)交流QQ群281945664

Powered by 單片機(jī)教程網(wǎng)

快速回復(fù) 返回頂部 返回列表