锐单电子商城 , 一站式电子元器件采购平台!
  • 电话:400-990-0325

RS-485总线通信应用

时间:2023-11-28 03:37:02 interface传感器mb

概述:

掌握总线的基础知识

了解Modbus通信协议的基本知识

能够进行基础Modbue串行通信协议软件开发

能够搭建RS-485总线和编程实现了网络通信

一、Modbus概述

1.什么是Modbus通信协议
Modbus通信协议由Modicon(现为施耐德电气公司品牌)1979年开发,是世界上第一个真正用于工业场所的总线协议。为了更好地普及和促进Modbus施耐德将在以太网上分布式应用Modbus交给协议的所有权IDA(InterfaceforDistributedAutomation,组织分布式自动化接口,专门成立Modbus-IDA组织。该组织的成立为Modbus为未来的发展奠定了基础。
Modbus通信协议是应用于电子控制器的通用协议,已成为一般工业标准。通过本协议,控制器或控制器可以通过网络(如以太网)和其他设备通信。Modbus使不同厂家生产的控制设备连接成工业网络进行集中监控。Modbus通信协议定义了信息帧结构,描述了控制器要求访问其他设备的过程,控制器如何响应其他设备的要求,以及如何检测和记录错误。
在Modbus在互联网上通信时,每个控制器必须知道它们的设备地址,识别根据地址发送的信息,并决定做什么。如果需要响应,控制器将按下Modbus产生反馈信息并发送消息帧格式。

2.Modbus通信协议版本
Modbus通信协议有多个版本:基于串行链路的版本TCP/IP网络版本和基于其他互联网协议的网络版本,其中前两个有更多的实际应用场景。
基于串行链路Modbus通信协议有两种传输方式,即ModbusRTU与ModbusASCII,这两种模式在数值数据表示和协议细节上略有不同。ModbusRTU采用二进制数据表示的紧凑方式,ModbusASCII表达方式比较冗长。数据验证.ModbusRTU采用循环冗余校验方式,而ModbusASCII纵向冗余校验。另外,配置为ModbusRTU无法与模式节点相匹配ModbusASCII节点通信模式。
3.5.2Modbus通信请求及响应
Modbus它是一种单主/多从的通信协议,即在同一时间内,总线上只能有一个主设备,但从设备中可以有一个或多个(最多247个)。主要设备是指启动通信的设备,从接收请求并做出响应的设备。Modbus在网络中,通信总是由主设备启动,当设备未收到独立设备的请求时,数据不会主动发送。

二、Modbus寄存器

寄存器是Modbus存储数据是通信协议的重要组成部分。
Modbus寄存器最初借鉴PLC(ProgrammableLogicalController,可编程控制器)。后来随着Modbus随着通信协议的发展,寄存器的概念不再局限于具体的物理寄存器,而是逐渐扩展到内存区域。根据存储的数据类型及其读写特性,Modbus寄存器被分为4种类型。

三、Modbus功能码

1.功能码分类
Modbus功能码是Modbus新闻帧的一部分代表了要执行的动作。RTU以模式为例,见表3-7,RTU消息帧的Modbus功能代码占1~127字节。
Modbus标准规定了三类Modbus功能代码:公共功能代码、用户自定义功能代码和保留功能代码。公共功能代码通过Modbus协会确认的功能代码是独一无二的。

四、实验

(1)485主机每隔0.5S从传感器数据中查询Modbus帧。

(2)在485网络中从机接收通信帧后,分析内容,判断是否发送给自己,然后根据功能码要求向主机收集响应传感数据。

(3)主机收到传感数据后,向网关报告

(4)网关通过TCP上报网关

1.定义Modbus帧与Modbus协议管理结构

在portocol.h中定义:

//类modbus 接收帧定义 __packed typedef struct {      u8 address;      //设备地址:0,广播地址;1~255、设备地址。     u8 function;     //帧功能,0~255 //    u8 count;      //帧编号 //    u8 datalen;     //有效数据长度     u8 *data;      ///数据存储区     u16 chkval;      //校验值 } m_rev_frame_typedef;   //Modbus协议管理结构 typedef  struct {     u8* rxbuf;      //接收缓存区     u16 rxlen;      ///接收数据的长度    u8  frameok;     //一帧数据接收完成标记:0,尚未完成;1.完成一帧数据的接收      u8 checkmode;     //验证模式:0、验证和;1、异或;2CRC8;3,CRC16

2.Modbus通信帧分析函数

///分析一帧数据,存储分析结果fx里面 //注意将使用此函数malloc给fx数据指针申请内存,后续用完fx,一定要释放内存!! //否则会导致内存泄漏!!! //fx:帧指针 //buf:输入数据缓冲区(串口接收到的数据) //len:输入数据长度 //返回值:分析结果,0,OK,另外,代码错误。 m_result mb_unpack_frame(m_send_frame_typedef *tx,m_rev_frame_typedef *rx) {     u16 rxchkval=0;       ///接收到的验证值     u16 calchkval=0;     ////计算获得的     u8 cmd = 0 ;            //计算功能码     u8 datalen=0;       //有效数据长度        u8 address=0;    u8 recbyte=0;     u8 res;     DBG_B_INFO("主机分析包程序 "); //    fx->datalen=0;       ///清零数据长度     if(m_ctrl_dev.rxlen>M_MAX_FRAME_LENGTH||m_ctrl_dev.rxlenaddress) {
			      DBG_R_E("返回地址与发送地址不统一");
            return MR_FRAME_SLAVE_ADDRESS;    //地址错误
        }

        cmd=m_ctrl_dev.rxbuf[1];
 
        if (cmd!=tx->function) {
		       	DBG_R_E("发送命令与返回命令不统一");
            return MR_FRANE_ILLEGAL_FUNCTION; //命令帧错误
        }

		

        switch (cmd) {
        case 0x02:res=unpack_disc_reg(tx,rx);			
            break;
        case 0x03:res=unpack_readhold_reg(tx,rx);
            break;
        case 0x04:res=unpack_readinput_reg(tx,rx);
            break;
        case 0x06:res=unpack_writehold_reg(tx,rx);
            break;
	    default :
	        break;
        }
   
    } else {
        return MR_FRAME_CHECK_ERR;
    }
    return MR_OK;
}

3.编写读取传感器数据并回复响应帧函数

        主机发送读取传感器数据命令,从机解析完主机请求帧后,编写响应的函数。

u8 ReadInputRegister(void)
{
u16 regaddress;u16 regcount;
u16 *input_value_p;
u16 iregindex;
	//发送缓冲区
u8 sendbuf|20];
u8 send_cnt=0;
//计算得到的校验值

u16 calchkval=0;
//取出主机请求帧中的素统
regaddress=(u16)(m_ctrl_dev.rxbuf|2)<<8);14.
regaddress|=(u16/(m_ctrl_dev.rxbuf|3]);
//取出主机请求帧中的素
regcount=(u16)(m_ctrl_dev.rxbuf(4]<<8);17.
regcount|=(u16)(m_ctrl_dev.rxbuf(5]);

input_value_p=inbuf;
//组建响应帧
if((1<=regcount)&&(regcount<4)){
if((regaddress>=0)&&(regaddress<=3)){
sendbuf[send_cnt]=SLAVE_ADDRESS;
//从机地址
send_cnt++;
sendbuf[send_cnt]=0x04;
//功能码0x04
send_cnt++;
sendbuf[send_cnt]=regcount*2;
//字节长度
send_cnt++;
iregindex=regaddress-0;
//将寄存器内容赋值给响应帧
while(regcount>0){
sendbuf[send_cnt]=(u8)(input_value_pliregindex]>>8);
send_cnt++;
sendbuf[send_cnt]=(u8)(input_value_pliregindex]&0xFF);
send_cnt++;
iregindex++;
regcount--;
}
switch(m_ctrl_dev.checkmode)
{
case M_FRAME_CHECK_SUM:
//校验和

calchkval=mc_check_sum(sendbuf,send_cnt);
break;
calchkval=me_check_xor(sendbuf,send_cnt);
case M_FRAME_CHECK_XOR://异或校验48.49.break;
case M_FRAME_CHECK_CRC8://CRC8校验
calchkval=me_check_crc8(sendbuf,send_cnt);break;
case M_FRAME_CHECK_CRC16:
//CRC16校验
    calchkval=mc_check_crc16(sendbuf,send_cnt);
        break;
    }
  if(m_ctrl_dev.checkmode==M_FRAME_CHECK_CRC16)  //如果是CRC16,则有2个字节的CRC
		{
			 sendbuf[send_cnt]=(calchkval>>8)&0XFF;	//高字节在前
        send_cnt++;
        sendbuf[send_cnt]=calchkval&0XFF;			//低字节在后
		}
		RS4851_Send_Buffer(sendbuf,send_cnt+1); //发送这一帧数据
	}
}
		else
		{
			return 1;
		}
    return 0;
}

4.程序结构框架

 

 

 

锐单商城拥有海量元器件数据手册IC替代型号,打造电子元器件IC百科大全!

相关文章