设为首页收藏本站

新势力科技社区

 找回密码
 申,请,会,员

QQ登录

只需一步,快速开始

搜索
由于某种原因,我们论坛暂时只能转移到美国服务器存放,访问速度将受到一定影响,请大家谅解!
查看: 14103|回复: 8

[推荐分享] modbus RTU 的 AVR 单片机 C程序

[复制链接]

195

主题

0

好友

642

积分

管理员

Rank: 10Rank: 10Rank: 10

金钱
6036 新币
贡献
322 点
威望
129 点
最后登录
2018-8-17
精华
26
积分
642
帖子
320
发表于 2008-3-31 11:14:13 |显示全部楼层
modbus RTU的AVR单片机C程序
通讯协议参考: http://www.xinshili.net/bbs/thread-349-1-1.html

完整程序下载: modbusM16.rar (76.33 KB, 下载次数: 5884)

#include "main.h"

//字地址 0 - 255
//位地址 0 - 255

/* CRC 高位字节值表 */
const uint8 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 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; //用于测试 字地址0

uint8    localAddr = 1;    //地址
uint8    sendCount;        //发送字节个数
uint8    receCount;        //接收字节个数
uint8    sendPosi;        //发送位置
uint8    sendBuf[32],receBuf[32];    //发送,接收缓冲区  
uint8    checkoutError;                //校验结果
uint8    receTimeOut;                //接收超时

uint16 crc16(uint8 *puchMsg, uint16 usDataLen)
{
    uint8 uchCRCHi = 0xFF ; /* 高CRC字节初始化 */
    uint8 uchCRCLo = 0xFF ; /* 低CRC 字节初始化 */
    uint32 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)
{   
    sendEnable();    //设为发送
   
    sendPosi = 0;
    if(sendCount > 1)
        sendCount--;
    UDR = sendBuf[0];
}//void beginSend(void)


//读线圈状态
void readCoil(void)
{
    uint8 addr;
    uint8 tempAddr;
    uint8 byteCount;
    uint8 bitCount;
    uint16 crcData;
    uint8 position;
    uint8 i,k;
    uint8  result;
    uint16 tempData;
    uint8  exit = 0;
   
    //addr = (receBuf[2]<<8) + receBuf[3];   
    //tempAddr = addr & 0xfff;
    addr = receBuf[3];
    tempAddr = addr;

    //bitCount = (receBuf[4]<<8) + receBuf[5];    //读取的位个数
    bitCount = receBuf[5];

    byteCount = bitCount / 8;                    //字节个数
    if(bitCount%8 != 0)
        byteCount++;
                                    
    for(k=0;k<byteCount;k++)
    {//字节位置
        position = k + 3;
        sendBuf[position] = 0;
        for(i=0;i<8;i++)
        {
            getCoilVal(tempAddr,&tempData);
            
            sendBuf[position] |= tempData << i;
            tempAddr++;
            if(tempAddr >= addr+bitCount)
            {    //读完
                exit = 1;
                break;
            }   
        }
        if(exit == 1)
            break;
    }
   
    sendBuf[0] = localAddr;
    sendBuf[1] = 0x01;   
    sendBuf[2] = byteCount;
    byteCount += 3;
    crcData = crc16(sendBuf,byteCount);   
    sendBuf[byteCount] = crcData >> 8;
    byteCount++;
    sendBuf[byteCount] = crcData & 0xff;
    sendCount = byteCount + 1;
   
    beginSend();   
}//void readCoil(void)

//读寄存器
void readRegisters(void)
{
    uint8 addr;
    uint8 tempAddr;
    uint16 result;
    uint16 crcData;
    uint8 readCount;
    uint8 byteCount;
    uint8  finsh;    //1完成  0出错
    uint16 i;
    uint16 tempData = 0;   
   
    //addr = (receBuf[2]<<8) + receBuf[3];
    //tempAddr = addr & 0xfff;   
    addr = receBuf[3];
    tempAddr = addr;

    //readCount = (receBuf[4]<<8) + receBuf[5];    //要读的个数
    readCount = receBuf[5];

    byteCount = readCount * 2;
   
    for(i=0;i<byteCount;i+=2,tempAddr++)
    {
        getRegisterVal(tempAddr,&tempData);               
        sendBuf[i+3] = tempData >> 8;                          
        sendBuf[i+4] = tempData & 0xff;            
    }
   
    sendBuf[0] = localAddr;
    sendBuf[1] = 3;
    sendBuf[2] = byteCount;
    byteCount += 3;
    crcData = crc16(sendBuf,byteCount);
    sendBuf[byteCount] = crcData >> 8;
    byteCount++;
    sendBuf[byteCount] = crcData & 0xff;
   
    sendCount = byteCount + 1;
    beginSend();
}//void readRegisters(void)


//强制单个线圈
void forceSingleCoil(void)
{
    uint8 addr;
    uint8 tempAddr;
    uint16 tempData;
    uint8  onOff;
    uint8 i;
   
    //addr = (receBuf[2]<<8) + receBuf[3];   
    //tempAddr = addr & 0xfff;
    addr = receBuf[3];
    tempAddr = addr;

    //onOff = (receBuf[4]<<8) + receBuf[5];   
    onOff = receBuf[4];
   
    //if(onOff == 0xff00)
    if(onOff == 0xff)
    {    //设为ON
        tempData = 1;
    }
    //else if(onOff == 0x0000)
    else if(onOff == 0x00)
    {    //设为OFF
        tempData = 0;
    }

    setCoilVal(tempAddr,tempData);   
   
    for(i=0;i<receCount;i++)
    {
        sendBuf = receBuf;
    }
    sendCount = receCount;
    beginSend();   
}//void forceSingleCoil(void)


//设置多个寄存器
void presetMultipleRegisters(void)
{
    uint8 addr;
    uint8 tempAddr;
    uint8 byteCount;
    uint8 setCount;
    uint16 crcData;
    uint16 tempData;
    uint8  finsh;    //为1时完成 为0时出错
    uint8 i;
   
    //addr = (receBuf[2]<<8) + receBuf[3];
    //tempAddr = addr & 0xfff;
    addr = receBuf[3];
    tempAddr = addr;

    //setCount = (receBuf[4]<<8) + receBuf[5];
    setCount = receBuf[5];
    byteCount = receBuf[6];   
   
    for(i=0;i<setCount;i++,tempAddr++)
    {
        tempData = (receBuf[i*2+7]<<8) + receBuf[i*2+8];
   
        setRegisterVal(tempAddr,tempData);            
    }
   
    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();   
}//void presetMultipleRegisters(void)



//检查uart0数据
void checkComm0Modbus(void)
{
    uint16 crcData;
    uint16 tempData;
   
    if(receCount > 4)
    {
        switch(receBuf[1])
        {
            case 1://读取线圈状态(读取点 16位以内)
            case 3://读取保持寄存器(一个或多个)
            case 5://强制单个线圈
            case 6://设置单个寄存器            
                    if(receCount >= 8)
                    {//接收完成一组数据                    
                        //应该关闭接收中断
                        UCSRB &= ~BIT(7);               
                        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;   
                        UCSRB |= BIT(7);                                            
                    }
                    break;
        
            case 15://设置多个线圈
                    tempData = receBuf[6];
                    tempData += 9;    //数据个数
                    if(receCount >= tempData)
                    {//应该关闭接收中断
                        UCSRB &= ~BIT(7);              
                        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;
                        UCSRB |= BIT(7);
                    }
                    break;
            
            case 16://设置多个寄存器
                    tempData = (receBuf[4]<<8) + receBuf[5];
                    tempData = tempData * 2;    //数据个数
                    tempData += 9;
                    if(receCount >= tempData)
                    {//应该关闭接收中断
                        UCSRB &= ~BIT(7);                                 
                        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;
                        UCSRB |= BIT(7);
                    }
                    break;
                                
            default:
                    break;            
        }
    }
}//void checkComm0(void)

//取线圈状态 返回0表示成功
uint16 getCoilVal(uint16 addr,uint16 *tempData)
{
    uint16 result = 0;
   
    switch(addr & 0xff)
    {
        case 0:
                break;
        case 1:   
                *tempData = testCoil;
                break;
        case 2:        
                break;        
        case 3:
                break;        
        case 4:
                break;        
        case 5:
                break;
        case 6:
                break;            
        case 7:
                break;        
        case 8:
                break;        
        case 9:
                break;        
        case 10:
                break;
        case 11:
                break;
        case 12:
                break;
        case 13:
                break;
        case 14:
                break;
        case 15:
                break;
        case 16:
                break;                                                        
        default:
                break;        
    }   
   
    return result;
}//uint16 getCoilVal(uint16 addr,uint16 *data)


//设定线圈状态 返回0表示成功
uint16 setCoilVal(uint16 addr,uint16 tempData)
{
    uint16 result = 0;
        
    switch(addr & 0xff)
    {
        case 0:
                break;
        case 1:   
                testCoil = tempData;
                break;
        case 2:        
                break;        
        case 3:
                break;        
        case 4:
                break;        
        case 5:
                break;
        case 6:
                break;            
        case 7:
                break;        
        case 8:
                break;        
        case 9:
                break;        
        case 10:
                break;
        case 11:
                break;
        case 12:
                break;
        case 13:
                break;
        case 14:
                break;
        case 15:
                break;
        case 16:
                break;                                                        
        default:
                break;        
    }   


    return result;
}//uint16 setCoilVal(uint16 addr,uint16 data)

//取寄存器值 返回0表示成功
uint16 getRegisterVal(uint16 addr,uint16 *tempData)
{
    uint16 result = 0;
   
    switch(addr & 0xff)
    {
        case 0:
                *tempData = testRegister;
                break;
        case 1:   
                break;
        case 2:        
                break;        
        case 3:
                break;        
        case 4:
                break;        
        case 5:
                break;
        case 6:
                break;            
        case 7:
                break;        
        case 8:
                break;        
        case 9:
                break;        
        case 10:
                break;
        case 11:
                break;
        case 12:
                break;
        case 13:
                break;
        case 14:
                break;
        case 15:
                break;
        case 16:
                break;                                                        
        default:
                break;        
    }
   
    return result;
}//uint16 getRegisterVal(uint16 addr,uint16 &data)

//设置寄存器值 返回0表示成功
uint16 setRegisterVal(uint16 addr,uint16 tempData)
{
    uint16 result = 0;
   
    switch(addr & 0xff)
    {
        case 0:
                testRegister = tempData;
                break;
        case 1:   
                break;
        case 2:        
                break;        
        case 3:
                break;        
        case 4:
                break;        
        case 5:
                break;
        case 6:
                break;            
        case 7:
                break;        
        case 8:
                break;        
        case 9:
                break;        
        case 10:
                break;
        case 11:
                break;
        case 12:
                break;
        case 13:
                break;
        case 14:
                break;
        case 15:
                break;
        case 16:
                break;                                                        
        default:
                break;        
    }
   
    return result;
}//uint8 setRegisterVal(uint16 addr,uint16 data)
新势力将为您助上一臂之力!

0

主题

0

好友

1

积分

等待验证

Rank: 1

金钱
60 新币
贡献
0 点
威望
0 点
最后登录
2008-5-26
精华
0
积分
1
帖子
1
发表于 2008-5-27 14:16:03 |显示全部楼层

好象有问题吧?CRC的低字节应该在高字节前面发送,和地址、数据相反的呀。

好象有问题吧?CRC的低字节应该在高字节前面发送,和地址、数据相反的呀。
回复

使用道具 举报

63

主题

0

好友

160

积分

版主

Rank: 8Rank: 8

金钱
3931 新币
贡献
0 点
威望
26 点
最后登录
2012-2-23
精华
16
积分
160
帖子
160

资源贡献奖

发表于 2008-5-27 22:38:49 |显示全部楼层
我记得好像也是低字节在前面
回复

使用道具 举报

0

主题

0

好友

15

积分

初级会员

Rank: 2

金钱
195 新币
贡献
0 点
威望
0 点
最后登录
2009-7-10
精华
0
积分
15
帖子
15
发表于 2009-6-14 21:25:38 |显示全部楼层
看看呵呵学学呵呵呵
回复

使用道具 举报

0

主题

0

好友

15

积分

初级会员

Rank: 2

金钱
195 新币
贡献
0 点
威望
0 点
最后登录
2009-7-10
精华
0
积分
15
帖子
15
发表于 2009-6-14 21:25:42 |显示全部楼层
看看呵呵学学呵呵呵
回复

使用道具 举报

1

主题

0

好友

16

积分

初级会员

Rank: 2

金钱
135 新币
贡献
0 点
威望
0 点
最后登录
2010-9-7
精华
0
积分
16
帖子
16
发表于 2010-8-5 16:28:08 |显示全部楼层
看看呵呵学学呵呵呵
回复

使用道具 举报

0

主题

0

好友

4

积分

等待验证

Rank: 1

金钱
68 新币
贡献
0 点
威望
0 点
最后登录
2018-1-18
精华
0
积分
4
帖子
4
发表于 2015-4-20 20:25:00 |显示全部楼层
modbus RTU的AVR单片机C程序
回复

使用道具 举报

0

主题

0

好友

10

积分

初级会员

Rank: 2

金钱
62 新币
贡献
0 点
威望
0 点
最后登录
2017-6-5
精华
0
积分
10
帖子
10
发表于 2017-6-5 14:58:49 |显示全部楼层
佩服   都是大神  膜拜
回复

使用道具 举报

0

主题

0

好友

127

积分

初级会员

Rank: 2

金钱
195 新币
贡献
0 点
威望
0 点
最后登录
2018-7-18
精华
0
积分
127
帖子
127
发表于 2018-6-13 05:07:05 |显示全部楼层

NFL Jerseys Wholesale

PHOENIX (AP) 鈥?Former NFL All-Pro safety Darren Sharper's DNA was found in an examination of one of two women who accuse him of drugging and sexually assaulting them at a Tempe apartment, a detective said Wednesday.
Tempe police Detective Kevin Mace said at a bail hearing in China Jerseys Phoenix that Sharper's DNA was Wholesale China Jerseys recovered Cheap Jerseys China from one of the women's NFL Jerseys Wholesale clothing, NFL Jerseys China but none of his DNA was found during an exam of the other woman.
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 申,请,会,员

手机版|Archiver|新势力科技 ( 鲁ICP备05002753号  

GMT+8, 2018-8-18 01:51

Powered by Discuz! X2.5

© 2001-2012 Comsenz Inc.

回顶部