1. 声 明
软件著作权登记号:2019SR0183260
Copyright: Wu HaiMeng. All rights reserved.Protected by international copyright laws.
Programmer : Wu YuanFu
Version : V1.10
wModbus is provided in source form for FREE short-term evaluation, for educational use or for peaceful research. If you plan or intend to use wModbus in a commercial application/ product then, you need to contact Wu YuanFu240697738@qq.com to properly license wModbusfor its use in your application/product. The fact that the source is provided does NOT mean that you can use it commercially without paying a licensing fee.
Knowledge of the source code may NOT be used to develop a similar product.
捐助支付宝账号 :240697738@qq.com(吴远福) ,有了你的支持,我才能更好的发展,谢谢!
1. 背景
Modbus是一种串行通信协议,是Modicon公司(现在的施耐德电气 Schneider Electric)于1979年为使用可编程逻辑控制器(PLC)通信而发表。Modbus已经成为工业领域通信协议的业界标准(De facto),并且现在是工业电子设备之间常用的连接方式。
FreeMODBUS 是一个奥地利人写的Modbus协议栈。它是一个针对嵌入式应用的一个免费的通用MODBUS协议的移植。目前免费版本仅有Slave功能,都支持RTU/ASCII模式。
FreeMODBUS网址:https://www.embedded-solutions.at/en/freemodbus/
uC/MODBUS 是由Micrium公司写的Modbus协议栈。它是一个针对嵌入式应用的一个收费的通用MODBUS协议的移植。目前有Slave和Master功能,都支持RTU/ASCII模式。
Micrium公司网址:https://www.micrium.com/
这两个协议栈最大的特点是每发送一个字节或是接收一个字节就需引入相关的中断处理程序,比如说主机发送01 03 00 02 00 01 25 CA,从机回传01 03 02 12 34 B5 33。不管是对于主机还是从机功能,这两个协议栈都至少需要中断15次。经过测试,在单一的串口处理系统中不会有什么问题,但是需多串口进行modbus通信或是其它类型的串口通信功能,就容易造成串口间的中断冲突,使得通信容易出错。经过测试,在单台嵌入式设备里同时实现主机及从机功能时,主机丢包率在30%以上。
2. 特点
- 减少中断次数,同时减少单个中断程序时间,通信测试达到无错误。
- 以一帧完整的报文为中断响应基础。当发送一帧完整的报文完成后响应一次中断,或是接收到到一帧完整的报文后也响应一次中断。
- 在单嵌入式设备硬件允许的情况下,可同时实现任意多个主机与从机功能。
- 进一步减少RAM内存占用,把接收数据串地址与发送数据串进行合并。
- 提高代码利用率,增加代码可读性,尽可能的保持主机与从机风格统一性。
- 更友好支持tcp功能及其它传输类型扩展。
3. 功能
- wMODBUS协议栈 是针对通用的Modbus协议栈在嵌入式系统中应用的一个实现。
- wMODBUS协议栈 在硬件许可的情况下可以挂载任意多个主机与从机。支持多个主机与多个从机同时独立运行。
- wMODBUS协议栈 支持RTU/ASCII模式,支持串串口/网络模式。
- wMODBUS协议栈 支持如下功能码。
读输入寄存器 (0x04)
读保持寄存器 (0x03)
写单个寄存器 (0x06)
写多个寄存器 (0x10)
读/写多个寄存器 (0x17)
读取线圈状态 (0x01)
写单个线圈 (0x05)
写多个线圈 (0x0F)
读输入状态 (0x02) - wMODBUS协议栈 支持实时操作系统及裸机移植。
- wMODBUS协议栈 提供hook回调函数功能。
- wMODBUS协议栈 提供通信统计功能。
- wMODBUS协议栈 主机功能可支持与任意非连续地址的从机里进行通信。
- wMODBUS协议栈 主机功能为应用提供多种请求模式,用户可以选择阻塞还是非阻塞模式,自定义超时时间等,方便应用层灵活调用。
4. 文件结构
- mbconfig.h是wModbus的配置文件,可以对wModbus的功能进行裁减。
- mbevent.c mbevent.h mbtype.h 这三个文件是与嵌入式操作系统相关的代码,针对不同的操作系统,代码需要进行相应的改写,主要是需要实现事件等待函数,事件发送函数等。从而使得中断函数可以对侦听主程序的数据传送功能。
- mbhooks.c 这个文件主要是用户hook函数,针对不同的用户需求而设定,用户可以在这里增加程序来触发其它所需要的功能。
- mb.c mb.h mbdef.h mbcrc.c mbcrc.h mbbuf.c mbbuf.h 这三个文件是主机和从机共用的代码,这些函数已经写好,与嵌入式操作系统以及CPU都无关,用户无需再进行任何修改。主要是实现的了协议栈的创建,使能,接收拆包,发送打包等功能。
- smb.c smbfunc.c smbfunc.h smbport.c smbport.h这五个文件是从机需使用的代码,这些函数已经写好,与嵌入式操作系统以及CPU都无关,用户无需再进行任何修改。主要是实现了从机的侦听与数据处理功能。
- mmb.c mmbfunc.c mmbfunc.h mmbport.c mmbport.h这五个文件是主机需使用的代码,这些函数已经写好,与嵌入式操作系统以及CPU都无关,用户无需再进行任何修改。主要是实现了主机的侦听与数据处理功能。
5. 使用方法
如果需要其它实现方法及商业合作,请与专利人邮件联系240697738@qq.com
发送回调函数
UCHAR PortTransmit (void *Parent, UCHAR *pData, USHORT Size,ULONG lTimeOut)
{
依照lTimeOut时间进行阻塞发送 取0时为永久阻塞,直到发送完成。
……
return MBTRUE;成功发送返回MBTRUE,否则返回MBFALSE
}
接收回调函数
SHORT PortReceive (void *Parent, UCHAR *pData, USHORT Size,ULONG lTimeOut)
{
依照lTimeOut时间进行阻塞接收 取0时为永久阻塞,直到接收完成。
……
Return 接收数据的实际长度,如果未接收到数据返回0,如果接收错误,返回-1。
}
从机任务函数
uint8_t buf[256];//定义操作数据内存
void Task(void *p_arg)
{
wMB mb;//定义wModbus协议栈
int Id;//端口号
//初使化传输路径 - 串口/网口 (依据Id)
//初使化wModbus协议栈
MB_Init( & mb,MB_MODE_RTU,1,& Id); //站号为1的从机
//设置回调函数
MB_PortSet(&mb,PortTransmit,PortReceive);
while(1)
{//轮询接收并处理数据
if(MB_Poll(&mb, buf,0) <=0)
{
printf("MB Port failed!\n");
}
}
}
主机任务函数
uint8_t buf[256];//定义操作数据内存
void Task(void *p_arg)
{
wMB mb;//定义wModbus协议栈
int Id;//端口号
//初使化传输路径 - 串口/网口 (依据Id)
//初使化wModbus协议栈
MB_Init( & mb,MB_MODE_RTU,0,& Id); //站号为0则为主机
//设置回调函数
MB_PortSet(&mb,PortTransmit,PortReceive);
//直接操作功能函数 – 阻塞等待数据返回
mMB_FN01_Read_CoilsRegister()
mMB_FN02_Read_DiscreteRegister()
……
}
对于主机还需实现mmbevent.c文件的接口,mmbevent.c文件对于uCos-III系统的接口如下:
/*
***************************************************************************************
* Init A Mutex RunRes
*
* Description: 此函数用于初使化RunRes互斥资源
* Arguments : p_mb 指向1个wModbus的指针
* Returns : UCHAR 返回处理结果
* MBTRUE 处理
* MBFALSE 出错
* Note(s) : 1) mMB_RunResInit() 在MASTER Modbus中使用
***************************************************************************************
*/
UCHAR mMB_RunResInit( wMB *p_mb )
{
OS_ERR OsErr;
OSMutexCreate(&p_mb->RunGrp, "Master Run Res Sem",&OsErr );
if( OsErr == OS_ERR_NONE) return MBTRUE; else return MBFALSE;
}
/*
***************************************************************************************
* Close A Mutex RunRes
*
* Description: 此函数用于删掉RunRes互斥资源
* Arguments : p_mb 指向1个wModbus的指针
* Note(s) : 1) mMB_RunResClose() 在MASTER Modbus中使用
***************************************************************************************
*/
void mMB_RunResClose( wMB *p_mb )
{
OS_ERR OsErr;
OSMutexDel(&p_mb->RunGrp,OS_OPT_DEL_ALWAYS,&OsErr );
}
/*
***************************************************************************************
* Post A Mutex RunRes
*
* Description: 此函数用于发送RunRes互斥资源
* Arguments : p_mb 指向1个wModbus的指针
* Note(s) : 1) mMB_RunResPost() 在MASTER Modbus中使用
***************************************************************************************
*/
void mMB_RunResPost( wMB *p_mb )
{
OS_ERR OsErr;
OSMutexPost(&p_mb->RunGrp,OS_OPT_POST_NONE, &OsErr);
}
/*
***************************************************************************************
* Pend A Mutex RunRes
*
* Description: 此函数用于请求RunRes互斥资源
* Arguments : p_mb 指向1个wModbus的指针
* Returns : UCHAR 返回处理结果
* MBTRUE 处理
* MBFALSE 出错
* Note(s) : 1) mMB_RunResPend() 在MASTER Modbus中使用
***************************************************************************************
*/
UCHAR mMB_RunResPend( wMB *p_mb,LONG timeout)
{
OS_ERR OsErr;
OSMutexPend(&p_mb->RunGrp, timeout*(OS_CFG_TICK_RATE_HZ/1000), OS_OPT_PEND_BLOCKING, 0, &OsErr);
if(OsErr == OS_ERR_NONE)return MBTRUE;else return MBFALSE;
}
6. 配置定义
mbconfig.h文件配置定义如下:
#define MB_ADDRESS_BROADCAST ( 0 )
#define MB_ADDRESS_MIN ( 1 )
#define MB_ADDRESS_MAX ( 247)
//主从设备使能定义
#define MB_MASTER_ENABLED MBENABLED
#define MB_SLAVE_ENABLED MBENABLED
//模式使能定义
#define MB_TCP_ENABLED MBENABLED
#define MB_RTU_ENABLED MBENABLED
#define MB_ASCII_ENABLED MBENABLED
//功能码使能定义
#define MB_FN01_READ_COILS_ENABLED MBENABLED
#define MB_FN02_READ_DISCRETE_ENABLED MBENABLED
#define MB_FN03_READ_HOLDING_ENABLED MBENABLED
#define MB_FN04_READ_INPUT_ENABLED MBENABLED
#define MB_FN05_WRITE_COIL_ENABLED MBENABLED
#define MB_FN06_WRITE_HOLDING_ENABLED MBENABLED
#define MB_FN15_WRITE_COILS_ENABLED MBENABLED
#define MB_FN16_WRITE_HOLDING_ENABLED MBENABLED
#define MB_FN17_OTHER_REP_SLAVEID_ENABLED MBENABLED
#define MB_FN23_READWRITE_HOLDING_ENABLED MBENABLED
//统计使能定义
#define MB_STAT_ENABLED MBENABLED
//广播地址是否回复
#define MB_BROADCASTRESPOND_ENABLED MBDISABLED
#if (MB_SLAVE_ENABLED == MBENABLED)
//数据寄存器每内部地址定义
#define sMB_HOLDING_START 0x1000 //HOLDING起始地址
#define sMB_HOLDING_NREGS 512
#define sMB_INPUT_START 0x9000 //INPUT起始地址
#define sMB_INPUT_NREGS 16
#define sMB_COILS_START 0x0500 //COILS起始地址
#define sMB_COILS_NREGS 64
#define sMB_DISCRETE_START 0x0400 //DISCRETE起始地址
#define sMB_DISCRETE_NREGS 64
#endif