1.RS485的定义
相信做自动化或者智能设备的朋友都听说过RS485协议,RS485通信协议是一种多点通信协议,它允许多个设备在同一总线上进行通信,且每个设备都可以发送和接收数据。RS485通讯协议采用差分信号传输,具有高速、远距离、可靠性强等特点,可实现长距离的数据传输。
RS485通信协议支持半双工通信模式,在同一总线上可以连接多个驱动器和接收器,方便建立设备网络。此外,RS485通信协议的接口电平低,不易损坏芯片,电平与TTL电平兼容,方便与TTL电路连接。RS485通信协议是一种适用于工业控制系统和智能家居等领域的通信协议,具有高速、远距离、可靠性强等优点,能够满足大量数据传输的需求,并提高数据传输的效率和实时性。
2.RS485与Modbus区别
协议性质:RS485是一种物理层通信标准,主要定义了电气特性、信号传输方式和连接方式等,而Modbus是一种通信协议,定义了一种常用的通信格式和规则,用于在主设备和从设备之间进行数据交换。
应用范围:RS485通常用作物理层协议,支持Modbus协议,而Modbus更常用于工业控制领域,是一种通用的通信数据格式,支持RS485、RS232等串口。
所以,RS485和Modbus在协议性质、应用范围和功能特性方面存在明显的区别。在工业控制和智能设备通信领域,二者常常被结合使用,以实现高效、稳定的数据传输。
在物联网中,RS485协议被广泛应用于各种领域,如工业控制、智能家居、城市管理、智能交通等。在这些领域中,RS485协议可以实现设备之间的快速、稳定、可靠的数据传输,提高设备的智能化程度和用户体验。例如,在智能家居中,RS485协议可以用于家庭内部的各种设备之间的通信,包括智能电视、智能音响、智能照明、智能安防等,实现设备的互联互通和集中控制。
3.MODBUS通讯协议及编程
MODBUS通讯协议大致分为以下几种
Modbus-RTU+Modbus-ASCII
Modbus-TCP
Modbus-Plus
Modbus是主从方式通信,也就是说,不能同步进行通信,总线上每次只有一个数据进行传输,即主机发送,从机应答,主机不发送,总线上就没有数据通信.,本文主要讲解RTU协议
3.1. Modbus-RTU协议
这种协议是基于异步串行通信上,一般的介质有:RS-232,RS485,RS-422上,这也是工业上使用的最多的。
3.1.1. 帧结构
帧结构
= 地址 + 功能吗 + 数据 + 校验
地址: 占用一个字节,范围0-255,其中有效范围是1-247,其他有特殊用途,比如255是广播地址(广播地址就是应答所有地址,正常的需要两个设备的地址一样才能进行查询和回复)
功能码:" 占用一个字节,功能码的意义就是,知道这个指令是干啥的,比如你可以查询从机的数据,也可以修改数据,所以不同功能码对应不同功能.
数据: 根据功能码不同,有不同结构,在后续的实例中有说明;
校验: 为了保证数据不错误,增加这个,然后再把前面的数据进行计算看数据是否一致,如果一致,就说明这帧数据是正确的,我再回复;如果不一样,说明你这个数据在传输的时候出了问题,数据不对的,所以就抛弃了;
字符结构
通讯数据结构
3.1.2.常用功能码
03-主机需要发送起始地址+寄存器数量,从机回复总字节数+数据;
06-主机发送起始地址+数据内容(因为你只需要修改一个,所以起始地址就是所要修改的地址),从机返回起始地址+数据内容(发现居然一样!)
10-主机发送起始地址+寄存器个数+总字节数+数据,从机返回起始地址+寄存器数量
.3常用功能码使用举例分析
1.3.1 功能码-0x03读保持寄存器
测试功能描述
:
现在我是主机,我要查询从机地址为1的数据
主机发送: 01 03 00 00 00 01 84 0A
从机回复: 01 03 02 12 34 B5 33
3.2.C语言实现
mbrtu_master.h
#ifndef MBRTU_MASTER_H_
#define MBRTU_MASTER_H_
#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>
#include "mbrtu_master.h"
#include "usart.h"
#include "tim.h"
#include "main.h"
#include "usart.h"
#include "stdio.h"
///
/// MODBUS RTU 主机控制结构
///
///
typedef struct
{
//
// 收发数据缓存
//
uint8_t ucBuf[8];//读取可能是4个字节
//
// 收发数据状态
//
uint16_t usStatus;
//
// 如果使用了RTOS需要进行互斥,那么需要实现以下两个函数的绑定
//
void (*lock)(void);
void (*unlock)(void);
//
// 微秒延时函数,用于等待超时
//
void (*delayms)(uint32_t nms);
//
// 定时器启动和停止函数
//
void (*timerStop)(void);
void (*timerStart)(void);
//
// 发送数据函数,可以是串口、TCP等
//
uint32_t (*sendData)(const void* buf, uint32_t len);
//把接受的数
uint32_t (*sendDataLog)(const void *buf, uint32_t len);
//
// 以下四个回调函数分别是:读线圈、读离散量输入、读保持寄存器、读输入寄存器
//
void (*readCoilsCallback)(uint16_t usStartAddr, uint16_t usNum, const uint8_t* pucBitsOfCoilsState, uint16_t usLen);
void (*readDiscreteInputsCallback)(uint16_t usStartAddr, uint16_t usNum, const uint8_t* pucBitsOfDiscreteInputsState, uint16_t usLen);
void (*readHoldingRegistersCallback)(uint16_t usStartAddr, uint16_t usNum, const uint8_t* pusHoldingRegistersVal, uint8_t usLen);
void (*readInputRegistersCallback)(uint16_t usStartAddr, uint16_t usNum, const uint16_t* pusInputRegistersVal, uint16_t usLen);
}MBRTUMaterTypeDef;
static void timerStop(void);
static void timerStart(void);
static void delayms(uint32_t nms);
static uint32_t sendData(const void *buf, uint32_t len);
static uint32_t sendDataLog(const void *buf, uint32_t len);
static void readCoilsCallback(uint16_t usStartAddr, uint16_t usNum, const uint8_t *pucBitsOfCoilsState, uint16_t usLen);
static void readDiscreteInputsCallback(uint16_t usStartAddr, uint16_t usNum, const uint8_t *pucBitsOfDiscreteInputsState, uint16_t usLen);
static void readHoldingRegistersCallback(uint16_t usStartAddr, uint16_t usNum, const uint8_t *pusHoldingRegistersVal, uint8_t usLen);
static void readInputRegistersCallback(uint16_t usStartAddr, uint16_t usNum, const uint16_t *pusInputRegistersVal, uint16_t usLen);
///
/// MODBUS RTU 主机 API
///
///
int MBRTUMasterReadCoils(MBRTUMaterTypeDef* psModbus, uint8_t ucSlaveAddress, uint16_t usAddress, uint16_t usNum, uint16_t usTimeout);
int MB