找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 2190|回复: 0
打印 上一主题 下一主题
收起左侧

PC和单片机通过MODBUS RTU通信

[复制链接]
跳转到指定楼层
楼主
ID:504942 发表于 2019-4-4 17:21 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
最近研究了一下MODBUS通信,在STC12C5A60S2单片机上实现了MODBUS协议的部分功能,方便上位机从单片机系统上获取数据,比如由单片机获取的温度、湿度、或者控制信号的状态等。有了MODBUS协议后,上位机的开发就很方便了,可以使用C#等高级语言通过串口通信,或者使用组态王直接通过串口通信而不需要写代码,这些都归功于MODBUS协议的开放性,很多的组态软件都能提供对他的支持。甚至通过PLC直接可以和单片机通信,比如在PLC系统上没有AD时,可以使用单片也来进行AD,然后通过MODBUS返回给PLC进行相应的控制。
通过MODBUS协议可以实现主机和多个从机进行通谢,而每个从机有唯一的地址,主机就靠这个地址和从机进行通信。每一帧数据都要通过CRC进行校验,保证通信的正确性。
在进行多机通信时只需要把每个从机的串口并到一起即可,见后面的图。
单片机中3号功能的核心代码如下:
unsigned char createRespond_M(unsigned char *respondMessage,unsigned char* _messageReceived ,unsigned int* _registerData)
{
    unsigned char  i,j;
    unsigned char  numberOfPoints = 0;
    unsigned char_slaveAddress = 0 ;
    unsigned char  bytesToSend = 0;
    unsigned char  startAddress=0;
    unsigned charcrcCalculation[]={0,0,0};
    unsigned int CntHi= _messageReceived[4];  //将其转换为int型,然后放到高8位。
    CntHi = CntHi<<8;                    
    numberOfPoints = CntHi| _messageReceived[5];
    if(numberOfPoints > MaxnumberOfPoints)
    {
        return  0;
    }
   
    bytesToSend = 2 *numberOfPoints +5;
    _slaveAddress = _messageReceived[0];
    respondMessage[0] =_slaveAddress;
    respondMessage[1] = 3;
    respondMessage[2] =2 * numberOfPoints;
    startAddress = (((unsigned int)(_messageReceived[2])) << 8) |_messageReceived[3];
    j= 0;
    for (i = 0; i< numberOfPoints; i++)
    {
        respondMessage[i + j + 3] = ((_registerData[startAddress + i] >> 8)& 0xff);
        respondMessage[i + j + 4] =(_registerData[startAddress + i] & 0xff);
        j++;
    }
    calculateCRC(respondMessage, bytesToSend - 2,crcCalculation);
    respondMessage[bytesToSend - 2] = crcCalculation[0];
    respondMessage[bytesToSend - 1] = crcCalculation[1];
    return bytesToSend;
}
//对接收的数据进行CRC检验,同时判断是否为Address所指定的从机地址和是否为function3功能。
bitCheckRecData(unsigned char * RecData,unsigned charAddress)
{
    if(RecData[0] ==Address && RecData[1] == 3)   //地址为自己的地址,同时功能码为3(function3)
    {
        if(checkCRC(RecData,8))
        {
            return 1;
        }
    }
    return 0;
}
本例中每个从机返回80个字节的数据,1号机返回i+1,  2号机返回2*i+1   ,当然在实际运用中只要自己定义所返回的数据的含义即可。比如1,2字节代表温度,3,4字节代表湿度,接下来的4个字节代表P0,P1,P2,P3端口的状态等。可以自由定义,很方便。
具体效果见下图:
把两块板的串口通过杜绑线连在一起。
在TEXTBOX中输入从机的地址,返回相应的数据
如果输入的地址从机不存在,那么通信将会超时,就会提示通信故障。这个是根据通信超时来判断的。

评分

参与人数 1黑币 +50 收起 理由
admin + 50 共享资料的黑币奖励!

查看全部评分

分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享淘帖 顶 踩
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

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