网站颜色:

基于STM32的Modbus RTU 从模式源码 MDK源代码

  • 无参数

本代码包括两部分源代码:

(1)代码1是朋友的一个原创代码,实现了全部的MODBUS SLAVE功能码,完全可以跟主机屏,PLC,Robot通讯使用.

(2)代码2是一个项目(CPU是STM32F103R8T6)当中抽取出来部分,主要移植基于freemodbus Modbus_RTU Slave的代码,这个代码参考了外国的freemodbus代码移植到STM32,已经实现了全部的功能码,内有丰富的中文注释.

注意:这两个代码非本人所写,所以无法提供技术支持,适合有编程基础,对MODBUS熟悉的用户使用,有兴趣的朋友可以拍下进行研读移植,如果对MODBUS不太熟悉的,可以参考我的原创MODBUS Slave代码实例(只实现了读0x03写0x06功能):http://zhuhai.witcp.com/shop/c48/tceca5199c1e.html

进行试验之后,再进行研读移植这两个代码,这两个代码,实现了全部的功能码,可以跟常用的MODBUS主机,例如LCD屏(例如威伦通,昆仑,信捷屏),PLC,Robot连接通讯,然后修改编写你的界面应用程序,即可应用移植到你的项目当中.

程序截图:

以下是MODBUS详细介绍如下:

ModBus协议定义了一个控制器能认识使用的消息结构,而不管它们是通过何种网络进行通信的,它制定了消息域的格局和内容的公共格尸描述了一个控制器请求访问其它设备的过程,回应来自其它设备的请求,以及如何侦测并记录错误信息。

通过此协议,控制器相互之间、控制器经由网络(例如以太网)和其它设备之间可以完成信息和数据的交换与传送,使各种不同的公司和厂家的可编程顺序控制器(PLC)、RTU、SCADA系统、DCS或与兼容ModBus协议的第三方设备之间可以连成工业网络,构建各种复杂的监控系统,并利于系统的维护和扩展,这个通讯协议已广泛被国内外电力行业及工控行业作为系统集成的一种通用工业标准协议。
 
关于MODBUS-RTU协议方面的文档说明资料很多、也很多参考代码,但没能有一个真正能用在产品通信中的参考范例。由于MODBUS-RTU实用性好,实现成本低,在工业通讯、仪器、仪表设备中应用尤为普遍。
       在仪器、仪表、传感器中,如果使用Modbus RTU协议,一般作为从站。主站设备一般由PLC、PC机,HMI,PCI板卡等实现。开发从站Modbus RTU硬件上很简单,一般是RS485接口电平。

        作为MODBUS-RTU从站,在一些规范标准中规定的3.5个字符时间间隔作为报文接收判定条件。这样大大减少了从站的误响应。

代码2是从过去成熟的产品中提取出来,加以更多的注释,有助于理解。代码以3.5个字符为判断接收条件,当主站发出的读写命令帧后,从站判断大于等于3.5个字符的时间间隔为判断接收条件。波特率不同时,判断3.5个字符时间,相应不同。

代码2:驱动RS485部分,可用于自收发控制的RS485芯片。也可用于GPIO控制收发的RS485芯片电路。

      UART串口采用接收中断、发送中断方尸以提高响应速度。提供的软件源代码,以工程文件以形式打包,您可以直接编译使用。目前,提供两种MCU C语言代码,STM32F103R8T6代码功能支持功能码:

 

功能码
定 义
操 作(二进制)
(咨询特价)
读开关量输入
读取一路或多路开关量状态输入数据
(咨询特价)
读开关量输出
读取一路或多路开关量输出状态数据
(咨询特价)
(咨询特价)
读寄存器数据
读取一个或多个寄存器的数据
 
(咨询特价)
0X0F
写开关量输出
写多个开关量
控制一路继电器“合/分”输出
(咨询特价)
写单路寄存器
把一组二进制数据写入单个寄存器
(咨询特价)
写多路寄存器
把多组二进制数据写入多个寄存器
此代码源于国外开源代码,在其基础上进行移植、优化,并用于项目多功能电力仪表、马达保护器、三相电流电压表上应用,稳定可靠。收发采用中断方尸实时更好性好。

使用时,仅仅需要修改宏定义,及全局变量即可。如下面所定义的,修改成自己需要的长度,功能即可。

/*----------------------------------------------------------------
名称:         线圈
存储区标识:   0XXXX
类型:         位
读写:         读/写
存储单地址:(00001~0XXXX).XXXX:与设备相关
功能码:       读取线圈状态 (0x01),写单个线圈 (0x05),写多个线圈 (0x0F)
用途:         DO继电器
//-----------------------------------------------------------------*/
#define REG_COILS_START     0x(咨询特价)
#define REG_COILS_SIZE      16
static  unsigned char       ucRegCoilsBuf[REG_COILS_SIZE / 8]={0XF0,0X0F};

/*----------------------------------------------------------------
名称:         输入线圈
存储区标识:   1XXXX
类型:         位
读写:         只读
存储单地址: (10001~1XXXX).XXXX:与设备相关
功能码:       读输入状态 (0x02)
用途:         DI继电器
//-----------------------------------------------------------------*/
/* ----------------------- Defines ------------------------------------------*/
#define REG_DISC_START     0x(咨询特价)
#define REG_DISC_SIZE      16
static  unsigned char ucRegDiscBuf[REG_DISC_SIZE / 8] = { 0x0F, 0XF0 };

/*----------------------------------------------------------------
名称:         输入寄存器
存储区标识:   3XXXX
类型:         字
读写:         只读
存储单地址:(30001~3XXXX).XXXX:与设备相关
功能码:       读输入寄存器 (0x04)
用途:         模拟量输入
//-----------------------------------------------------------------*/
#define REG_INPUT_START   0x(咨询特价)
#define REG_INPUT_NREGS   10
static  USHORT   usRegInputStart = REG_INPUT_START;
static  USHORT   usRegInputBuf[REG_INPUT_NREGS]=
{0X0011,0X0022,0X0033,0X0044,0X0055,0X0066,0X0077,0X0088,0X0099,0x00aa};
/*----------------------------------------------------------------
名称:         保持/输出寄存器
存储区标识:   4XXXX
类型:         字
读写:         读/写
存储单地址:(40001~4XXXX).XXXX:与设备相关
功能码:       读保持寄存器 (0x03),写单个寄存器 (0x06),写多个寄存器 (0x10)
用途:         模拟量输出
//-----------------------------------------------------------------*/
#define REG_HOLDING_START 0x0001 //保持寄存器起始地址
#define REG_HOLDING_NREGS 10    //保持寄存器数量
static  USHORT   usRegHoldingStart = REG_HOLDING_START;
static  USHORT   usRegHoldingBuf[REG_HOLDING_NREGS]=
{0X1100,0X2200,0X3300,0X4400,0X5500,0X6600,0X7700,0X8800,0X9900,0xaa00};

 只需要在初始化中,改变定义就可以了。如下:

eMBInit(MB_RTU, 0x01, 1, 38400, MB_PAR_NONE);

//modbus功能:RTU模式、表号1、串口1、38400、无校验

 

 

 

热门设计服务