wModbus协议库V2.5-源码及使用说明

1. 声 明

软件著作权登记号:2019SR0183260
Copyright: Wu HaiMeng. All rights reserved.Protected by international copyright laws.
Programmer : Wu YuanFu
Version : V2.40
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 YuanFu[email protected] 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.
捐助支付宝账号 :[email protected](吴远福) ,有了你的支持,我才能更好的发展,谢谢!

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. 特点

  1. 减少中断次数,同时减少单个中断程序时间,通信测试达到无错误。
  2. 以一帧完整的报文为中断响应基础。当发送一帧完整的报文完成后响应一次中断,或是接收到到一帧完整的报文后也响应一次中断。
  3. 在单嵌入式设备硬件允许的情况下,可同时实现任意多个主机与从机功能。
  4. 进一步减少RAM内存占用,把接收数据串地址与发送数据串进行合并。
  5. 提高代码利用率,增加代码可读性,尽可能的保持主机与从机风格统一性。
  6. 更友好支持tcp功能及其它传输类型扩展。

3. 功能

  1. wMODBUS协议栈 是针对通用的Modbus协议栈在嵌入式系统中应用的一个实现。
  2. wMODBUS协议栈 在硬件许可的情况下可以挂载任意多个主机与从机。支持多个主机与多个从机同时独立运行。
  3. wMODBUS协议栈 支持RTU/ASCII模式,支持串串口/网络模式。
  4. wMODBUS协议栈 支持如下功能码。
    读输入寄存器 (0x04)
    读保持寄存器 (0x03)
    写单个寄存器 (0x06)
    写多个寄存器 (0x10)
    读/写多个寄存器 (0x17)
    读取线圈状态 (0x01)
    写单个线圈 (0x05)
    写多个线圈 (0x0F)
    读输入状态 (0x02)
  5. wMODBUS协议栈 支持实时操作系统及裸机移植。
  6. wMODBUS协议栈 提供hook回调函数功能。
  7. wMODBUS协议栈 提供通信统计功能。
  8. wMODBUS协议栈 主机功能可支持与任意非连续地址的从机里进行通信。
  9. wMODBUS协议栈 主机功能为应用提供多种请求模式,用户可以选择阻塞还是非阻塞模式,自定义超时时间等,方便应用层灵活调用。

4. 文件结构

  1. mbconfig.h是wModbus的配置文件,可以对wModbus的功能进行裁减。
  2. mbevent.c 这个文件是与嵌入式操作系统相关的代码,针对不同的操作系统,代码需要进行相应的改写,主要是需要实现事件等待函数,事件发送函数等。从而使得中断函数可以对侦听主程序的数据传送功能。
  3. mb.c mb.h mbtype.h这两个文件是主机和从机共用的代码,这些函数已经写好,与嵌入式操作系统以及CPU都无关,用户无需再进行任何修改。主要是实现的了协议栈的创建,使能,接收拆包,发送打包等功能。
  4. smb.c smbbuf.c smbbuf.h 这五个文件是从机需使用的代码,这些函数已经写好,与嵌入式操作系统以及CPU都无关,用户无需再进行任何修改。主要是实现了从机的侦听与数据处理功能。
  5. mmb.c 这个文件是主机需使用的代码,这些函数已经写好,与嵌入式操作系统以及CPU都无关,用户无需再进行任何修改。主要是实现了主机的侦听与数据处理功能。

5. 使用方法

如果需要其它实现方法及商业合作,请与专利人邮件联系[email protected] 

发送回调函数

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];//定义操作数据内存
static OS_MUTEX   mutex;

void  Task(void *p_arg)
{
	wMB  mb;//定义wModbus协议栈
	int Id;//端口号

	//初使化传输路径 - 串口/网口 (依据Id)

	//初使化wModbus协议栈
	MB_Init(&mb,MB_MODE_RTU,1,0,&mutex); //站号为1的从机

	//设置回调函数
	MB_PortSet(&mb,PortTransmit,PortReceive); 

	while(1)
	{//轮询接收并处理数据
	     if(MB_Poll(&mb, buf,0) <=0)
	     { 
	      	printf("MB Port failed!\n");
	  	 }
	}
}

主机任务函数

uint8_t  buf[256];//定义操作数据内存
static OS_MUTEX   mutex;
void  Task(void *p_arg)
{
	wMB  mb;//定义wModbus协议栈
	int Id;//端口号

	//初使化传输路径 - 串口/网口 (依据Id)

	//初使化wModbus协议栈
	MB_Init( & mb,MB_MODE_RTU,0,&mutex); //站号为0则为主机

	//设置回调函数
	MB_PortSet(&mb,PortTransmit,PortReceive); 

	//直接操作功能函数 – 阻塞等待数据返回
	mMB_FN01_Read_CoilsRegister()
	mMB_FN02_Read_DiscreteRegister()
	……
}

6. 程序源码

mbconfig.h文件:

/*
********************************************************************************************************
*                                                wModbus
*                                       The Embedded Modbus Stack
*
*               Copyright: Wu HaiMeng. All rights reserved.Protected by international copyright laws.
*

* Programmer  : Wu YuanFu
* Version     : V2.50
* LICENSING TERMS:
* ---------------
*           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 YuanFu<[email protected]> to properly license wModbus
*           for 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.
*               
********************************************************************************************************
*/

/* Filename    : mbconfig.h*/

#ifndef _MB_CONFIG_H
#define _MB_CONFIG_H

#ifdef __cplusplus
PR_BEGIN_EXTERN_C
#endif

#define MBDISABLED                              ( 0 )
#define MBENABLED                               ( 1 )

#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

#ifdef __cplusplus
    PR_END_EXTERN_C
#endif
#endif

mbevent.c文件 - 以ucos系统为例

/*
********************************************************************************************************
*                                                wModbus
*                                 The Embedded Modbus Stack Software
*
*               Copyright: Wu YuanFu. All rights reserved.Protected by international copyright laws.
*
* Programmer  : Wu YuanFu
* Version     : V2.50
* LICENSING TERMS:
* ---------------
*           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 YuanFu<[email protected]> to properly license wModbus
*           for 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.
*               
********************************************************************************************************
*/

/* Filename    : mbevent.c*/

#include "mb.h"
#include "oS.h"   

/*
********************************************************************************************************
*                                                Init A Mutex RunRes 
*
* Description: 此函数用于初使化RunRes互斥资源
* Arguments  : p_mb           指向1个wModbus的指针
* Returns    : UCHAR          返回处理结果
*                   MBTRUE              处理
*                   MBFALSE             出错 
* Note(s)    : 1 MB_MutexInit() 在MASTER Modbus中使用
********************************************************************************************************
*/
UCHAR MB_MutexInit( wMB *p_mb , void* mutex)
{
	//根据操作系统不一致会有所区别,此处仅以uCos-III 为例。
    OS_ERR       OsErr;
    
    p_mb->Mutex = mutex;
    
    if( p_mb->Mutex == 0 )
    {
         return MBTRUE; 
    }
    
	OSMutexCreate(p_mb->Mutex, "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的指针
* Returns    : UCHAR          返回处理结果
*                   MBTRUE              处理
*                   MBFALSE             出错 
* Note(s)    : 1) MB_MutexClose()
********************************************************************************************************
*/
UCHAR MB_MutexClose( wMB *p_mb )
{
	//根据操作系统不一致会有所区别,此处仅以uCos-III 为例。
    OS_ERR       OsErr;
    if( p_mb->Mutex == 0 )
    {
         return MBTRUE; 
    }    
    OSMutexDel(p_mb->Mutex,OS_OPT_DEL_ALWAYS,&OsErr );
    return MBTRUE;
} 

/*
********************************************************************************************************
*                                                Post A Mutex RunRes
*
* Description: 此函数用于发送RunRes互斥资源
* Arguments  : p_mb           指向1个wModbus的指针
* Returns    : UCHAR          返回处理结果
*                   MBTRUE              处理
*                   MBFALSE             出错 
* Note(s)    : 1) MB_MutexPost() 在MASTER Modbus中使用
********************************************************************************************************
*/
UCHAR MB_MutexPost( wMB *p_mb )
{
	//根据操作系统不一致会有所区别,此处仅以uCos-III 为例。
    OS_ERR       OsErr;
    if( p_mb->Mutex == 0 )
    {
         return MBTRUE; 
    }    
    OSMutexPost(p_mb->Mutex,OS_OPT_POST_NONE, &OsErr);
    return MBTRUE;
}

/*
********************************************************************************************************
*                                                Pend A Mutex RunRes
*
* Description: 此函数用于请求RunRes互斥资源
* Arguments  : p_mb           指向1个wModbus的指针
* Returns    : UCHAR          返回处理结果
*                   MBTRUE              处理
*                   MBFALSE             出错 
* Note(s)    : 1) MB_MutexPend() 在MASTER Modbus中使用
********************************************************************************************************
*/
UCHAR MB_MutexPend( wMB *p_mb)
{
	//根据操作系统不一致会有所区别,此处仅以uCos-III 为例。
    OS_ERR       OsErr;
    if( p_mb->Mutex == 0 )
    {
         return MBTRUE; 
    }    
    OSMutexPend(p_mb->Mutex, 0, OS_OPT_PEND_BLOCKING, 0, &OsErr);
	if(OsErr == OS_ERR_NONE)return MBTRUE;else return MBFALSE;
}

mb.c文件

/*
********************************************************************************************************
*                                                wModbus
*                          The Embedded Modbus Stack Software
*
*               Copyright: Wu YuanFu. All rights reserved.Protected by international copyright laws.
*
* Programmer  : Wu YuanFu
* Version     : V2.50
* LICENSING TERMS:
* ---------------
*           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 YuanFu<[email protected]> to properly license wModbus
*           for 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.
*               
********************************************************************************************************
*/

/* Filename    : mb.c*/
#include "mb.h"
    
#if ( MB_MASTER_ENABLED == MBENABLED || MB_SLAVE_ENABLED== MBENABLED )

/*
********************************************************************************************************
*                                                LRC
*
* Description: 此函数用于ASCII模式下的LRC校验
* Arguments  : pDataBuf       指向需要校验DataBuf的指针
*              iLen           DataBuf的长度
* Returns    : UCHAR          LRC校验的结果
* Note(s)    : 1) MB_LRC() 
********************************************************************************************************
*/
#if ( MB_ASCII_ENABLED == MBENABLED ) 
static UCHAR MB_LRC( UCHAR* pDataBuf, USHORT iLen)
{
    UCHAR    mLRC = 0x00; 
    while( iLen-- ){mLRC += *pDataBuf++;}
    return ( - mLRC );
}
#endif 

/*
********************************************************************************************************
*                                                CRC
*
* Description: 此函数用于RTU模式下的CRC校验
* Arguments  : pDataBuf       指向需要校验DataBuf的指针
*              iLen           DataBuf的长度
* Returns    : USHORT         CRC校验的结果
* Note(s)    : 1) MB_CRC() 
********************************************************************************************************
*/
#if ( MB_RTU_ENABLED == MBENABLED )

const USHORT MBCRC_table[256] = {
0x0000, 0xC0C1, 0xC181, 0x0140, 0xC301, 0x03C0, 0x0280, 0xC241,
0xC601, 0x06C0, 0x0780, 0xC741, 0x0500, 0xC5C1, 0xC481, 0x0440,
0xCC01, 0x0CC0, 0x0D80, 0xCD41, 0x0F00, 0xCFC1, 0xCE81, 0x0E40,
0x0A00, 0xCAC1, 0xCB81, 0x0B40, 0xC901, 0x09C0, 0x0880, 0xC841,
0xD801, 0x18C0, 0x1980, 0xD941, 0x1B00, 0xDBC1, 0xDA81, 0x1A40,
0x1E00, 0xDEC1, 0xDF81, 0x1F40, 0xDD01, 0x1DC0, 0x1C80, 0xDC41,
0x1400, 0xD4C1, 0xD581, 0x1540, 0xD701, 0x17C0, 0x1680, 0xD641,
0xD201, 0x12C0, 0x1380, 0xD341, 0x1100, 0xD1C1, 0xD081, 0x1040,
0xF001, 0x30C0, 0x3180, 0xF141, 0x3300, 0xF3C1, 0xF281, 0x3240,
0x3600, 0xF6C1, 0xF781, 0x3740, 0xF501, 0x35C0, 0x3480, 0xF441,
0x3C00, 0xFCC1, 0xFD81, 0x3D40, 0xFF01, 0x3FC0, 0x3E80, 0xFE41,
0xFA01, 0x3AC0, 0x3B80, 0xFB41, 0x3900, 0xF9C1, 0xF881, 0x3840,
0x2800, 0xE8C1, 0xE981, 0x2940, 0xEB01, 0x2BC0, 0x2A80, 0xEA41,
0xEE01, 0x2EC0, 0x2F80, 0xEF41, 0x2D00, 0xEDC1, 0xEC81, 0x2C40,
0xE401, 0x24C0, 0x2580, 0xE541, 0x2700, 0xE7C1, 0xE681, 0x2640,
0x2200, 0xE2C1, 0xE381, 0x2340, 0xE101, 0x21C0, 0x2080, 0xE041,
0xA001, 0x60C0, 0x6180, 0xA141, 0x6300, 0xA3C1, 0xA281, 0x6240,
0x6600, 0xA6C1, 0xA781, 0x6740, 0xA501, 0x65C0, 0x6480, 0xA441,
0x6C00, 0xACC1, 0xAD81, 0x6D40, 0xAF01, 0x6FC0, 0x6E80, 0xAE41,
0xAA01, 0x6AC0, 0x6B80, 0xAB41, 0x6900, 0xA9C1, 0xA881, 0x6840,
0x7800, 0xB8C1, 0xB981, 0x7940, 0xBB01, 0x7BC0, 0x7A80, 0xBA41,
0xBE01, 0x7EC0, 0x7F80, 0xBF41, 0x7D00, 0xBDC1, 0xBC81, 0x7C40,
0xB401, 0x74C0, 0x7580, 0xB541, 0x7700, 0xB7C1, 0xB681, 0x7640,
0x7200, 0xB2C1, 0xB381, 0x7340, 0xB101, 0x71C0, 0x7080, 0xB041,
0x5000, 0x90C1, 0x9181, 0x5140, 0x9301, 0x53C0, 0x5280, 0x9241,
0x9601, 0x56C0, 0x5780, 0x9741, 0x5500, 0x95C1, 0x9481, 0x5440,
0x9C01, 0x5CC0, 0x5D80, 0x9D41, 0x5F00, 0x9FC1, 0x9E81, 0x5E40,
0x5A00, 0x9AC1, 0x9B81, 0x5B40, 0x9901, 0x59C0, 0x5880, 0x9841,
0x8801, 0x48C0, 0x4980, 0x8941, 0x4B00, 0x8BC1, 0x8A81, 0x4A40,
0x4E00, 0x8EC1, 0x8F81, 0x4F40, 0x8D01, 0x4DC0, 0x4C80, 0x8C41,
0x4400, 0x84C1, 0x8581, 0x4540, 0x8701, 0x47C0, 0x4680, 0x8641,
0x8201, 0x42C0, 0x4380, 0x8341, 0x4100, 0x81C1, 0x8081, 0x4040
};

static USHORT MB_CRC( UCHAR * pDataBuf, USHORT iLen )
{  
    USHORT mCRC = 0xffff;
    while (iLen-- > 0)
        mCRC = MBCRC_table[(mCRC ^ *pDataBuf++) & 0x00ff] ^ (mCRC >> 8) ;
    return mCRC; 
}
#endif


/*
********************************************************************************************************
*                                                Init A wModbus
*
* Description: 此函数用于创建一个wModbus协议栈
* Arguments  : p_mb           指向1个wModbus的指针
*              Mode           传输模式
*              Address        地址
*              Parent         传输硬件句柄
* Returns    : MBTRUE         创建成功
*              MBFALSE        创建失败
* Note(s)    : 1) MB_Init() 
********************************************************************************************************
*/
UCHAR MB_Init( wMB *p_mb,MB_ModeType Mode,UCHAR Address,void *Parent,void* mutex)
{
    if(p_mb != MBNULL)
    {
        if( Address == MB_ADDRESS_BROADCAST ){p_mb->MasterSlave = MBMASTER;}
        else if(( Address >= MB_ADDRESS_MIN ) && ( Address <= MB_ADDRESS_MAX ))
        {
            p_mb->MasterSlave = MBSLAVE;   
            p_mb->NodeAddr = Address;
        }
        else {return MBFALSE;}
        
        p_mb->Mode = Mode;
        p_mb->Parent = Parent;
        p_mb->ComCnt = 0;
        
        #if (MB_STAT_ENABLED == MBENABLED)
        p_mb->StatSendCtr = 0;
        p_mb->StatReceiveErrCtr = 0;
        p_mb->StatHandlersErrCtr = 0;
        p_mb->StatOKCtr = 0;             
        #endif
        
        return MB_MutexInit(p_mb,mutex);
    }

    return MBFALSE;    
} 

/*
********************************************************************************************************
*                                                Close A wModbus
*
* Description: 此函数用于关闭一个wModbus协议栈
* Arguments  : p_mb           指向1个wModbus的指针
* Returns    : MBTRUE         创建成功
*              MBFALSE        创建失败
* Note(s)    : 1) MB_Close() 
********************************************************************************************************
*/
UCHAR MB_Close( wMB *p_mb)
{
    p_mb->Parent = 0;
    p_mb->ComCnt = 0;
    
#if (MB_STAT_ENABLED == MBENABLED)
    p_mb->StatSendCtr = 0;
    p_mb->StatReceiveErrCtr = 0;
    p_mb->StatHandlersErrCtr = 0;
    p_mb->StatOKCtr = 0;             
#endif  

    p_mb->TxCpltPtr = 0;
    p_mb->RxCpltPtr = 0;
    
    return MB_MutexClose(p_mb);    
} 
/*
********************************************************************************************************
*                                                MB Port Set
*
* Description: 此函数用于初使化硬件端口参数
* Arguments  : p_mb           指向1个wModbus的指针
*              TxCpltPtr      数据发送回调函数
*              RxCpltPtr      数据接收回调函数
* Returns    : No
********************************************************************************************************
*/
void MB_PortSet(wMB *p_mb,MBPortTransmit TxCpltPtr,MBPortReceive RxCpltPtr)
{
    if(p_mb != (wMB *)MBNULL)
    {
        p_mb->TxCpltPtr = TxCpltPtr;
        p_mb->RxCpltPtr = RxCpltPtr;
    }
}


#if ( MB_ASCII_ENABLED == MBENABLED ) 
const UCHAR  MBChar_table[256] ={
'0' ,'1' ,'2' ,'3' ,'4' ,'5' ,'6' ,'7' ,'8' ,'9' ,'A' ,'B' ,'C' ,'D' ,'E' ,'F' ,
'G' ,'H' ,'I' ,'J' ,'K' ,'L' ,'M' ,'N' ,'O' ,'P' ,'Q' ,'R' ,'S' ,'T' ,'U' ,'V' ,
'W' ,'X' ,'Y' ,'Z' ,0x24,0x25,0x26,0x27,0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,
0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,
0x40,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,
0x19,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x5b,0x5c,0x5d,0x5e,0x5f,
0x60,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,
0x19,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x7b,0x7c,0x7d,0x7e,0x7f,
'0' ,'1' ,'2' ,'3' ,'4' ,'5' ,'6' ,'7' ,'8' ,'9' ,'A' ,'B' ,'C' ,'D' ,'E' ,'F' ,
'G' ,'H' ,'I' ,'J' ,'K' ,'L' ,'M' ,'N' ,'O' ,'P' ,'Q' ,'R' ,'S' ,'T' ,'U' ,'V' ,
'W' ,'X' ,'Y' ,'Z' ,0x24,0x25,0x26,0x27,0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,
0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,
0x40,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,
0x19,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x5b,0x5c,0x5d,0x5e,0x5f,
0x60,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,
0x19,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x7b,0x7c,0x7d,0x7e,0x7f
};
#endif 

/*
********************************************************************************************************
*                                                wModbus Receive manage
*
* Description: 此函数用于把一个wModbus协议栈接收到的数据进行接收处理。
* Arguments  : p_mb           指向1个wModbus的指针
* Returns    : UCHAR          返回处理结果
*                   MBTRUE              正确处理
*                   MBFALSE             数据出错    
* Note(s)    : 1) MB_Receive() 
********************************************************************************************************
*/
UCHAR MB_Receive( wMB   *p_mb,UCHAR* pRevBuf,USHORT RecvCnt )
{
    UCHAR   Status= MBFALSE;
    volatile SHORT mi;
    
    switch(p_mb->Mode)
    {
        #if ( MB_RTU_ENABLED == MBENABLED )        
        case MB_MODE_RTU:
            if( MB_CRC( pRevBuf, RecvCnt ) == 0 )
            {
                p_mb->RecvAddr = pRevBuf[0];
                p_mb->BufCnt = RecvCnt - 3 ;
                Status = MBTRUE;
            }       
            break;
        #endif
        #if ( MB_ASCII_ENABLED == MBENABLED )         
        case MB_MODE_ASCII:
            if(pRevBuf[0] == 0x3A )
            {
                p_mb->BufCnt = (RecvCnt - 3) >> 1 ;
                for(mi=0;mi<p_mb->BufCnt;mi++)
                {
                    pRevBuf[ mi ] = ( MBChar_table[(pRevBuf[2 * mi + 1])] << 4) 
                                          | ( MBChar_table[(pRevBuf[2 * mi + 2])]);
                }
                if(MB_LRC(pRevBuf,p_mb->BufCnt) == 0)
                {
                    p_mb->RecvAddr = pRevBuf[0]; 
                    p_mb->BufCnt = p_mb->BufCnt - 2 ;
                    Status = MBTRUE;                
                }         
            }
            break; 
        #endif
        #if ( MB_TCP_ENABLED == MBENABLED )        
        case MB_MODE_TCP:
            p_mb->RecvAddr = pRevBuf[6];
            p_mb->BufCnt = RecvCnt - MB_PDU_TCP_OFF ;
            Status = MBTRUE;     
            break;
        #endif
        default:break;        
    }    
    return Status;
}

/*
********************************************************************************************************
*                                                wModbus Send manage
*
* Description: 此函数用于把一个wModbus协议栈的数据进行发送处理。
* Arguments  : p_mb           指向1个wModbus的指针
* Note(s)    : 1) MB_Send() 
********************************************************************************************************
*/
USHORT MB_Send( wMB   *p_mb ,UCHAR* pSndBuf)
{
    volatile USHORT usCRC16;
    volatile SHORT  mi;
    volatile USHORT SendCnt;
	
    if((p_mb->MasterSlave == MBMASTER) || 
      (MB_BROADCASTRESPOND_ENABLED == MBENABLED)||
      (p_mb->RecvAddr != MB_ADDRESS_BROADCAST))
    {
		SendCnt = p_mb->BufCnt;
		
        switch(p_mb->Mode)
        {
            #if ( MB_RTU_ENABLED == MBENABLED )        
            case MB_MODE_RTU:
                pSndBuf[0] =  p_mb->NodeAddr;
                SendCnt ++;
                usCRC16 = MB_CRC( pSndBuf, SendCnt  );
                pSndBuf[SendCnt ++] = ( UCHAR )( usCRC16 & 0xFF );
                pSndBuf[SendCnt ++] = ( UCHAR )( usCRC16 >> 8 );
                break; 
            #endif  
            #if ( MB_ASCII_ENABLED == MBENABLED )           
            case MB_MODE_ASCII:
                pSndBuf[0] =  p_mb->NodeAddr;
                SendCnt ++;
                pSndBuf[SendCnt] = MB_LRC( pSndBuf, SendCnt );
                for(mi=SendCnt;mi>=0;mi--)
                {
                    pSndBuf[2 * mi + 2] = MBChar_table[( pSndBuf[ mi ] & 0x0F )];
                    pSndBuf[2 * mi + 1] = MBChar_table[( pSndBuf[ mi ] >>   4 )];
                }
                pSndBuf[0] = 0x3A;
                pSndBuf[SendCnt * 2 + 3] = 0x0D;        
                pSndBuf[SendCnt * 2 + 4] = 0x0A;
                SendCnt = SendCnt * 2 + 5;
                break;
            #endif            
            #if ( MB_TCP_ENABLED == MBENABLED )        
            case MB_MODE_TCP:
                pSndBuf[6] =  p_mb->NodeAddr;
                SendCnt ++; 
                pSndBuf[4] = 0;
                pSndBuf[5] = ( UCHAR )( SendCnt );        
                SendCnt += 6;
                break;    
            #endif             
            default:break;
        }
        
        #if (MB_STAT_ENABLED == MBENABLED)
            p_mb->StatSendCtr++;
        #endif
		p_mb->BufCnt = SendCnt;
		return SendCnt;
    }
    return 0;
}

/*
********************************************************************************************************
*                                                MB Poll
*
* Description: 此函数用于端口接收数据
* Arguments  : p_mb           指向1个wModbus的指针
* Note(s)    : 1) MB_Poll()  
********************************************************************************************************
*/
MB_Exception MB_Poll(wMB *p_mb,UCHAR* pBuf,LONG lTimeOut)
{ 	
	#if (MB_MASTER_ENABLED  == MBENABLED)
	if(p_mb->MasterSlave == MBMASTER)
	{
        if((p_mb->TxCpltPtr != MBNULL) && (p_mb->BufCnt > 0))
        {
            p_mb->TxCpltPtr(p_mb->Parent,pBuf,p_mb->BufCnt,0);               
        }
	}	
	#endif	
	
    if(p_mb->RxCpltPtr != MBNULL)
    {
        SHORT length = p_mb->RxCpltPtr(p_mb->Parent,pBuf,MB_PDU_SIZE_MAX,lTimeOut);
        if(length >= MB_PDU_SIZE_MIN)
        {          
            if(p_mb->MasterSlave == MBMASTER)
            {
				#if (MB_MASTER_ENABLED  == MBENABLED)
					return mMB_Deal( p_mb,pBuf,length);
				#endif				
            }
			else
			{
				#if (MB_SLAVE_ENABLED  == MBENABLED)
					USHORT Cnt = sMB_Deal( p_mb,pBuf,length);
					if((p_mb->TxCpltPtr != MBNULL) && (Cnt > 0))
					{
						p_mb->TxCpltPtr(p_mb->Parent,pBuf,Cnt,0);
					}
				#endif	
			}
        }
    }
    return MB_EX_NONE;
}

/*
********************************************************************************************************
*                                                 STAT Get
*
* Description: 此函数用于向获取统计信息
* Arguments  : p_mb           指向1个wModbus的指针
*              StatType       需要获取的数据类型
* Note(s)    : 1) MB_STATGet()
********************************************************************************************************
*/
#if (MB_STAT_ENABLED == MBENABLED)
ULONG MB_STATGet( wMB   *p_mb ,MB_StatType StatType)
{
    ULONG  Res = 0;
    
    switch(StatType)
    {
        case MB_STAT_SEND:
            Res = p_mb->StatSendCtr;break;
        case MB_STAT_RECEIVEERR:
            Res = p_mb->StatReceiveErrCtr;break;        
        case MB_STAT_HANDLERSERR:
            Res = p_mb->StatHandlersErrCtr;break;        
        case MB_STAT_OK:
            Res = p_mb->StatOKCtr;break;        
    }
    return Res;
}          
#endif 


/*
********************************************************************************************************
*                                                Set Bits To WordBuf
*
* Description: 此函数用于向WordBuf的数据表内设置NBits个Bits
* Arguments  : pWordBuf       指向WordBuf的数据指针
*              BitOffset      偏移地址
*              NBits          需要设定的bit个数
*              SetValue       需要设定的值
* Note(s)    : 1) MB_UtilSetBits() 用于Discrete 或是 coils的数据转化
*              2) NBits<=16
********************************************************************************************************
*/
void MB_UtilSetBits( USHORT *pWordBuf, USHORT BitOffset, UCHAR NBits,USHORT SetValue )
{
    ULONG          *pDoubleWordBuf;
    ULONG          Mask,WordOffset,NPreBits;
    ULONG          Value = SetValue;

    WordOffset = ( ULONG )( ( BitOffset ) / MB_BITS );
    NPreBits = ( ULONG )( BitOffset - WordOffset * MB_BITS );
    Mask = ( ULONG )( ( ( ULONG ) 1 << NBits ) - 1 ) << NPreBits;
    
    pDoubleWordBuf = (ULONG *)&pWordBuf[WordOffset];
    *pDoubleWordBuf = (ULONG)(( *pDoubleWordBuf & ( ~ Mask )) | ((Value << NPreBits) & Mask ));
}

/*
********************************************************************************************************
*                                                Get Bits From WordBuf
*
* Description: 此函数用于从WordBuf的数据表内获取NBits个Bits
* Arguments  : pWordBuf       指向WordBuf的数据指针
*              BitOffset      偏移地址
*              NBits          需要设定的bit个数
* Returns    : USHORT         获取到的数据值
* Note(s)    : 1) MB_UtilGetBits() 用于Discrete 或是 coils的数据转化
*              2) NBits<=16
********************************************************************************************************
*/
USHORT MB_UtilGetBits( USHORT *pWordBuf, USHORT BitOffset, UCHAR NBits )
{
    ULONG          *pDoubleWordBuf;
    ULONG          Mask,WordOffset,NPreBits;

    WordOffset = ( ULONG )( ( BitOffset ) / MB_BITS );
    NPreBits = ( ULONG )( BitOffset - WordOffset * MB_BITS );
    Mask = ( ULONG )( ( ( ULONG ) 1 << NBits ) - 1 );

    pDoubleWordBuf = (ULONG *)&pWordBuf[WordOffset];    
    return ((USHORT )((*pDoubleWordBuf >> NPreBits ) & Mask));
}

#endif

mb.h文件

/*
********************************************************************************************************
*                                                wModbus
*                                 The Embedded Modbus Stack Software
*
*               Copyright: Wu YuanFu. All rights reserved.Protected by international copyright laws.
*
* Programmer  : Wu YuanFu
* Version     : V2.50
* LICENSING TERMS:
* ---------------
*           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 YuanFu<[email protected]> to properly license wModbus
*           for 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.
*               
********************************************************************************************************
*/

/* Filename    : mb.h*/

#include "mbtype.h"

#if ( MB_SLAVE_ENABLED  == MBENABLED)
#include "smbbuf.h"
#endif

#ifndef _MB_H
#define _MB_H
#ifdef __cplusplus
PR_BEGIN_EXTERN_C
#endif

#if ( MB_MASTER_ENABLED == MBENABLED || MB_SLAVE_ENABLED== MBENABLED )
void         MB_UtilSetBits( USHORT * pWordBuf, USHORT BitOffset,UCHAR NBits, USHORT SetValue );
USHORT       MB_UtilGetBits( USHORT * pWordBuf, USHORT BitOffset,UCHAR NBits );
UCHAR        MB_Receive(wMB *p_mb,UCHAR* pRevBuf,USHORT RecvCnt);
USHORT       MB_Send(wMB *p_mb,UCHAR* pSndBuf);
UCHAR        MB_MutexInit( wMB *p_mb , void* mutex);
UCHAR        MB_MutexClose( wMB *p_mb );
UCHAR        MB_MutexPend( wMB *p_mb);
UCHAR        MB_MutexPost( wMB *p_mb );

//////////////////////////////////////////////////////////////////////////////////////

UCHAR        MB_Init(wMB *p_mb,MB_ModeType Mode,UCHAR Address,void *Parent,void* mutex);
void         MB_PortSet(wMB *p_mb,MBPortTransmit TxCpltPtr,MBPortReceive RxCpltPtr);
UCHAR        MB_Close( wMB *p_mb);
MB_Exception MB_Poll(wMB *p_mb,UCHAR* pBuf,LONG lTimeOut);

#if (MB_STAT_ENABLED == MBENABLED)
ULONG MB_STATGet(wMB *p_mb,MB_StatType StatType);         
#endif 

#if ( MB_SLAVE_ENABLED  == MBENABLED)
USHORT sMB_Deal(wMB *p_mb,UCHAR* pBuf,USHORT length);
USHORT* sMB_GetpBuf(USHORT addr,USHORT num);
void   sMB_RegHoldingWriteCallback(USHORT addr,USHORT value);
void   sMB_RegCoilsWriteCallback( USHORT addr,UCHAR NBits,USHORT value);
#endif

#if (MB_MASTER_ENABLED  == MBENABLED)
MB_Exception mMB_Deal(wMB *p_mb,UCHAR* pBuf,USHORT length);

#if MB_FN01_READ_COILS_ENABLED == MBENABLED
MB_Exception mMB_FN01_Read_CoilsRegister(wMB *p_mb,UCHAR SlaveAddr,USHORT RegAddr,USHORT RegCnt,USHORT *pRegBuffer,USHORT ReadBitOffset,LONG lTimeOut);
#endif
#if MB_FN02_READ_DISCRETE_ENABLED == MBENABLED
MB_Exception mMB_FN02_Read_DiscreteRegister(wMB *p_mb,UCHAR SlaveAddr,USHORT RegAddr,USHORT RegCnt,USHORT *pRegBuffer,USHORT ReadBitOffset,LONG lTimeOut);
#endif
#if MB_FN03_READ_HOLDING_ENABLED == MBENABLED
MB_Exception mMB_FN03_Read_HoldingRegister(wMB *p_mb,UCHAR SlaveAddr, USHORT RegAddr,USHORT RegCnt, USHORT *pRegBuffer,LONG lTimeOut);
#endif
#if MB_FN04_READ_INPUT_ENABLED == MBENABLED
MB_Exception mMB_FN04_Read_InputRegister(wMB *p_mb,UCHAR SlaveAddr,USHORT  RegAddr,USHORT RegCnt,USHORT *pRegBuffer,LONG lTimeOut);                                             
#endif
#if MB_FN05_WRITE_COIL_ENABLED == MBENABLED
MB_Exception mMB_FN05_Write_CoilsRegister(wMB *p_mb,UCHAR SlaveAddr, USHORT RegAddr,USHORT WriteData,LONG lTimeOut);
#endif
#if MB_FN06_WRITE_HOLDING_ENABLED == MBENABLED
MB_Exception mMB_FN06_Write_HoldingRegister(wMB *p_mb,UCHAR SlaveAddr,USHORT RegAddr,USHORT WriteData,LONG lTimeOut);                                                  
#endif 
#if MB_FN15_WRITE_COILS_ENABLED == MBENABLED
MB_Exception mMB_FN15_Write_CoilsRegister(wMB *p_mb,UCHAR SlaveAddr,USHORT RegAddr,USHORT RegCnt,USHORT *pRegBuffer,USHORT WriteBitOffset,LONG lTimeOut);                                               
#endif
#if MB_FN16_WRITE_HOLDING_ENABLED == MBENABLED
MB_Exception mMB_FN16_Write_HoldingRegister(wMB *p_mb,UCHAR SlaveAddr,USHORT RegAddr,USHORT RegCnt,USHORT *pRegBuffer,LONG lTimeOut );                                                 
#endif
#if MB_FN23_READWRITE_HOLDING_ENABLED == MBENABLED
MB_Exception mMB_FN23_ReadWrite_HoldingRegister(wMB *p_mb,UCHAR SlaveAddr,USHORT ReadRegAddr,USHORT ReadRegCnt,USHORT *pReadRegBuffer,USHORT WriteRegAddr,USHORT WriteRegCnt,USHORT *pWriteRegBuffer,LONG lTimeOut);
#endif

#endif

#endif
#ifdef __cplusplus
PR_END_EXTERN_C
#endif
#endif

mbtype.h文件

/*
********************************************************************************************************
*                                                wModbus
*                                 The Embedded Modbus Stack Software
*
*               Copyright: Wu YuanFu. All rights reserved.Protected by international copyright laws.
*
* Programmer  : Wu YuanFu
* Version     : V2.50
* LICENSING TERMS:
* ---------------
*           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 YuanFu<[email protected]> to properly license wModbus
*           for 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.
*               
********************************************************************************************************
*/

/* Filename    : mbtype.h*/

#include "mbconfig.h" 

#ifndef _MB_TYPE_H
#define _MB_TYPE_H

#ifdef __cplusplus
PR_BEGIN_EXTERN_C
#endif

#define MBNULL        				            ( 0 )
#define MBFALSE        				            ( 0 )
#define MBTRUE       					        ( 1 )
#define MBSLAVE        					        ( 1 )
#define MBMASTER       					        ( 0 )
#define MBREAD                                  ( 0 )
#define MBWRITE                                 ( 1 )

#define MB_FUNC_NONE                          	( 0x00 )
#define MB_FN01_READ_COILS                    	( 0x01 )
#define MB_FN02_READ_DISCRETE_INPUTS          	( 0x02 )
#define MB_FN03_READ_HOLDING_REGISTER         	( 0x03 )
#define MB_FN04_READ_INPUT_REGISTER           	( 0x04 )
#define MB_FN05_WRITE_SINGLE_COIL             	( 0x05 )
#define MB_FN06_WRITE_REGISTER                	( 0x06 )
#define MB_FN11_DIAG_GET_COM_EVENT_CNT        	( 0x0B )
#define MB_FN12_DIAG_GET_COM_EVENT_LOG        	( 0x0C )
#define MB_FN15_WRITE_MULTIPLE_COILS          	( 0x0F )
#define MB_FN16_WRITE_MULTIPLE_REGISTERS      	( 0x10 )
#define MB_FN17_OTHER_REPORT_SLAVEID          	( 0x11 )
#define MB_FN23_READWRITE_MULTIPLE_REGISTERS  	( 0x17 )
#define MB_FUNC_ERROR                         	( 128 )

#define MB_PDU_FN01_READCOUNT_MAX               ( 0x07D0 )
#define MB_PDU_FN02_READCOUNT_MAX            	( 0x07D0 )
#define MB_PDU_FN03_READCOUNT_MAX            	( 0x007D )
#define MB_PDU_FN04_READCOUNT_MAX            	( 0x007D )
#define MB_PDU_FN15_WRITECOUNT_MAX            	( 0x07B0 )
#define MB_PDU_FN16_WRITECOUNT_MAX            	( 0x007B )
#define MB_PDU_FN23_READCOUNT_MAX             	( 0x007D )
#define MB_PDU_FN23_WRITECOUNT_MAX            	( 0x0079 )
#define MB_PDU_FNxx_COUNT_MIN            		( 0x0001 )

#define MB_BITS                                 ( 16 )
#define MB_PDU_SIZE_MIN    					    ( 4  )
#define MB_PDU_SIZE_MAX     				    ( 256)   

#define MB_PDU_RTU_OFF      				    ( 1  )
#define MB_PDU_TCP_OFF      				    ( 7  ) 
#define MB_PDU_FUNC_OFF         				( 0  )    

#define MB_PDU_REQ_ADDR_OFF                		( 1  )
#define MB_PDU_REQ_CNT_OFF             			( 3  )
#define MB_PDU_REQ_2ndADDR_OFF     				( 5  )
#define MB_PDU_REQ_2ndCNT_OFF             	    ( 7  )
#define MB_PDU_FN01_BYTECNT_OFF                 ( 1  )
#define MB_PDU_FN01_VALUE_OFF                   ( 2  )
#define MB_PDU_FN02_BYTECNT_OFF                 ( 1  )
#define MB_PDU_FN02_VALUE_OFF                   ( 2  )
#define MB_PDU_FN03_BYTECNT_OFF                 ( 1  )
#define MB_PDU_FN03_VALUE_OFF                   ( 2  )
#define MB_PDU_FN04_BYTECNT_OFF                 ( 1  )
#define MB_PDU_FN04_VALUE_OFF                   ( 2  )
#define MB_PDU_FN05_VALUE_OFF                   ( 3  )
#define MB_PDU_FN06_VALUE_OFF                   ( 3  )
#define MB_PDU_FN15_BYTECNT_OFF                 ( 5  )
#define MB_PDU_FN15_VALUE_OFF                   ( 6  )
#define MB_PDU_FN16_BYTECNT_OFF                 ( 5  )
#define MB_PDU_FN16_VALUE_OFF                   ( 6  )
#define MB_PDU_FN23_WRITEBYTECNT_OFF            ( 9  )
#define MB_PDU_FN23_WRITEVALUE_OFF              ( 10 )
#define MB_PDU_FN23_READBYTECNT_OFF             ( 1  )
#define MB_PDU_FN23_READVALUE_OFF               ( 2  )

typedef     unsigned  	char            UCHAR;
typedef     signed   	char            CHAR;
typedef     unsigned    short  int      USHORT;
typedef     signed      short  int      SHORT;
typedef     unsigned  	int             ULONG;
typedef     signed  	int             LONG;

typedef enum
{
    MB_MODE_RTU                         =1,				
    MB_MODE_ASCII                       =2,									      
    MB_MODE_TCP                         =3,				     
} MB_ModeType;

typedef enum
{
    MB_STAT_SEND                        =1,
    MB_STAT_RECEIVEERR                  =2,
    MB_STAT_HANDLERSERR                 =3,
    MB_STAT_OK                          =4,    
} MB_StatType;

typedef enum
{
    MB_EX_NONE                          = 0x00,                 /**/
    MB_EX_ILLEGAL_FUNCTION              = 0x01,                 /*不合法的功能代码*/
    MB_EX_ILLEGAL_DATA_ADDRESS          = 0x02,                 /*不合法数据地址*/	
    MB_EX_ILLEGAL_DATA_VALUE            = 0x03,                 /*不合法数据*/	
    MB_EX_SLAVE_DEVICE_FAILURE          = 0x04,                 /*从机设备故障*/	
    MB_EX_ACKNOWLEDGE                   = 0x05,                 /*确认*/	
    MB_EX_SLAVE_BUSY                    = 0x06,                 /*从机设备忙*/
    MB_EX_NEGATIVE                      = 0x07,                 /*否定*/
    MB_EX_MEMORY_PARITY_ERROR           = 0x08,                 /*内存奇偶校验错误*/		
    MB_EX_GATEWAY_PATH_FAILED           = 0x0A,                 /**/		
    MB_EX_GATEWAY_TGT_FAILED            = 0x0B,                 /**/
	
	MB_EX_NO_MEMORY               		= 0x11,					//无可用内存
    MB_EX_REVDATAERR                 	= 0x12,					//数据校验出错
} MB_Exception;

typedef  UCHAR(*MBPortTransmit )(void *Parent, UCHAR *pData, USHORT Size,ULONG lTimeOut);//发送回调函数
typedef  SHORT(*MBPortReceive  )(void *Parent, UCHAR *pData, USHORT Size,ULONG lTimeOut);//接收回调函数

typedef  struct    wmb       wMB;
struct  wmb{
    UCHAR              NodeAddr;								/*node 地址*/
    UCHAR              MasterSlave;								/*主从类型*/
    MB_ModeType        Mode;									/*传输模式*/
    UCHAR              ReadWrite;								/*读写类型*/ 
    UCHAR              Value_off;               
    UCHAR              RecvAddr;                
    UCHAR              BufCnt;        
	USHORT             RegCnt;               
    USHORT             RegAddress;
    USHORT             ComCnt;    
    void               *Parent; 								/*参数*/
    void               *Mutex;    
    MBPortReceive      RxCpltPtr;								/*接收回调函数*/   
    MBPortTransmit     TxCpltPtr;								/*发送回调函数*/  

#if (MB_MASTER_ENABLED  == MBENABLED) 
    USHORT             BitOffset;
    USHORT             *RegDataPtr;          
#endif

#if (MB_STAT_ENABLED == MBENABLED)
	ULONG              StatSendCtr;								/*发送量统计*/
    ULONG              StatReceiveErrCtr;						/*接收错误量统计*/
    ULONG              StatHandlersErrCtr;						/*处理错误量统计*/
    ULONG              StatOKCtr;								/*正确量统计*/             
#endif 
};
 
#ifdef __cplusplus
PR_END_EXTERN_C
#endif
#endif

smb.c文件

/*
********************************************************************************************************
*                                                wModbus
*                                 The Embedded Modbus Stack Software
*
*               Copyright: Wu YuanFu. All rights reserved.Protected by international copyright laws.
*
* Programmer  : Wu YuanFu
* Version     : V2.50
* LICENSING TERMS:
* ---------------
*           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 YuanFu<[email protected]> to properly license wModbus
*           for 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.
*               
********************************************************************************************************
*/

/* Filename    : smb.c*/

#include "mb.h"

#define sMB_PDU_FN01_RcvLen_Min                  ( 5 )
#define sMB_PDU_FN02_RcvLen_Min                  ( 5 )
#define sMB_PDU_FN03_RcvLen_Min                  ( 5 )
#define sMB_PDU_FN04_RcvLen_Min                  ( 5 )
#define sMB_PDU_FN05_RcvLen_Min                  ( 5 )
#define sMB_PDU_FN06_RcvLen_Min                  ( 5 )
#define sMB_PDU_FN15_RcvLen_Min                  ( 7 )
#define sMB_PDU_FN16_RcvLen_Min                  ( 8 )
#define sMB_PDU_FN23_RcvLen_Min                  ( 12 )
#define sMB_GetRegValue( x )    	( USHORT )(( FramePtr[x] << 8 ) | FramePtr[x+ 1])

#if ( MB_SLAVE_ENABLED  == MBENABLED)

/*
********************************************************************************************************
*                                                sMB RegInputCB
*
* Description: 此函数用于从机 RegInput 的数据处理函数
* Arguments  : p_mb           指向1个wModbus的指针
* Returns    : 
* Note(s)    : 1) 用于FN04 命令
********************************************************************************************************
*/
static MB_Exception sMB_RegInputCB( wMB *p_mb ,UCHAR* pBuf)
{
    UCHAR  *pRegFrame;
    USHORT *sMBpBuf = sMB_GetpBuf(p_mb->RegAddress,p_mb->RegCnt);
	if(sMBpBuf != MBNULL)
    {
        if(p_mb->Mode == MB_MODE_TCP)
        {
             pRegFrame= &pBuf[MB_PDU_TCP_OFF + p_mb->Value_off];
        }else
        {pRegFrame = &pBuf[MB_PDU_RTU_OFF + p_mb->Value_off];}         
		
        for(USHORT i = 0;i < p_mb->RegCnt;i++)
        {
            *pRegFrame++ = *sMBpBuf >> 8;
			*pRegFrame++ = *sMBpBuf++ ;  
        }
    }
    else{return  MB_EX_ILLEGAL_DATA_ADDRESS;}
    return  MB_EX_NONE;
}

/*
********************************************************************************************************
*                                                sMB RegHolding
*
* Description: 此函数用于从机 RegHolding 的数据处理函数
* Arguments  : p_mb           指向1个wModbus的指针
* Returns    : 
* Note(s)    : 1) 用于FN03 FN06 FN16 FN23 命令
********************************************************************************************************
*/
static MB_Exception sMB_RegHoldingCB( wMB *p_mb ,UCHAR* pBuf)
{
    UCHAR   *pRegFrame; 
    USHORT *sMBpBuf = sMB_GetpBuf(p_mb->RegAddress,p_mb->RegCnt);
	if(sMBpBuf != MBNULL)
    {
        if(p_mb->Mode == MB_MODE_TCP)
        {
             pRegFrame= &pBuf[MB_PDU_TCP_OFF + p_mb->Value_off];
        }else
        {pRegFrame = &pBuf[MB_PDU_RTU_OFF + p_mb->Value_off];} 
        switch ( p_mb->ReadWrite )
        {          
        case MBREAD:
            for(USHORT i = 0;i < p_mb->RegCnt;i++)
            {
                *pRegFrame++ = *sMBpBuf >> 8;
                *pRegFrame++ = *sMBpBuf++ ;  
            }
            break;
        case MBWRITE:
            for(USHORT i = 0;i < p_mb->RegCnt;i++)
            {
                *sMBpBuf = *pRegFrame++ << 8;
                *sMBpBuf |= *pRegFrame++;
                sMB_RegHoldingWriteCallback(p_mb->RegAddress + i,*sMBpBuf++);
            }
            break;
        }		
    }
	else{return MB_EX_ILLEGAL_DATA_ADDRESS;	}
    return MB_EX_NONE;
}

/*
********************************************************************************************************
*                                                sMB RegCoilsCB
*
* Description: 此函数用于从机 RegCoilsCB 的数据处理函数
* Arguments  : p_mb           指向1个wModbus的指针
* Returns    : 
* Note(s)    : 1) 用于FN01 FN05 FN15命令
********************************************************************************************************
*/
static MB_Exception sMB_RegCoilsCB( wMB *p_mb ,UCHAR* pBuf)
{
    USHORT *pRegFrame;
    USHORT *sMBpBuf = sMB_GetpBuf(p_mb->RegAddress,p_mb->RegCnt);
	if(sMBpBuf != MBNULL)
    {       
        if(p_mb->Mode == MB_MODE_TCP)
        {
             pRegFrame = (USHORT *)&pBuf[MB_PDU_TCP_OFF + p_mb->Value_off];
        }else
        {pRegFrame = (USHORT *)&pBuf[MB_PDU_RTU_OFF + p_mb->Value_off];}          
		USHORT Index = ( p_mb->RegAddress - sMB_COILS_START );        
        SHORT RegCnt = ( SHORT )p_mb->RegCnt;    
        switch ( p_mb->ReadWrite )
        {
        case MBREAD:
            while( RegCnt > 0 )
            {
                UCHAR NBits = ( UCHAR )( RegCnt > MB_BITS ? MB_BITS : RegCnt );
                *pRegFrame++ = MB_UtilGetBits( sMBpBuf, Index,NBits);
                RegCnt -= MB_BITS;
                Index += MB_BITS;
            }
            break;
        
        case MBWRITE:
            while( RegCnt > 0 )
            {
                UCHAR NBits = ( UCHAR )( RegCnt > MB_BITS ? MB_BITS : RegCnt );
                MB_UtilSetBits(sMBpBuf, Index,NBits,*pRegFrame);
                sMB_RegCoilsWriteCallback(Index + sMB_COILS_START,NBits,*pRegFrame);	
                RegCnt -= MB_BITS;
                Index += MB_BITS;
                pRegFrame++;
            }
            break;
        }           
    }        
    else{return MB_EX_ILLEGAL_DATA_ADDRESS;}
    return MB_EX_NONE; 
}

/*
********************************************************************************************************
*                                                sMB RegDiscreteCB
*
* Description: 此函数用于从机 RegDiscreteCB 的数据处理函数
* Arguments  : p_mb           指向1个wModbus的指针
* Returns    : 
* Note(s)    : 1) 用于FN02 命令
********************************************************************************************************
*/
static MB_Exception sMB_RegDiscreteCB(wMB *p_mb,UCHAR* pBuf)
{
    USHORT *pRegFrame;
    USHORT *sMBpBuf = sMB_GetpBuf(p_mb->RegAddress,p_mb->RegCnt);
	if(sMBpBuf != MBNULL)
    {
        if(p_mb->Mode == MB_MODE_TCP)
        {
             pRegFrame = (USHORT *)&pBuf[MB_PDU_TCP_OFF + p_mb->Value_off];
        }else
        {pRegFrame = (USHORT *)&pBuf[MB_PDU_RTU_OFF + p_mb->Value_off];}          
		USHORT Index = ( p_mb->RegAddress - sMB_DISCRETE_START );         
        SHORT RegCnt = ( SHORT )p_mb->RegCnt;            
        while( RegCnt > 0 )
        {
            UCHAR NBits = ( UCHAR )( RegCnt > MB_BITS ? MB_BITS : RegCnt );
            *pRegFrame++ = MB_UtilGetBits( sMBpBuf, Index,NBits );
            RegCnt -= MB_BITS;
            Index += MB_BITS;
        }         
    }    
    else{return MB_EX_ILLEGAL_DATA_ADDRESS;}
    return MB_EX_NONE;     
}

/*
********************************************************************************************************
*                                                sMB FN01 Handler
*
* Description: 此函数用于从机 FN01 号命令的处理函数
* Arguments  : p_mb           指向1个wModbus的指针
* Returns    : 
* Note(s)    : 1) 
********************************************************************************************************
*/
#if MB_FN01_READ_COILS_ENABLED == MBENABLED
static MB_Exception sMB_FN01_Read_CoilsHandler( wMB *p_mb ,UCHAR* pBuf)
{
    UCHAR          *FramePtr;    
    UCHAR           ucNBytes;
    MB_Exception    eStatus = MB_EX_NONE;
    
    if( p_mb->BufCnt == sMB_PDU_FN01_RcvLen_Min )
    {
        if(p_mb->Mode == MB_MODE_TCP)
        {
            FramePtr = &pBuf[MB_PDU_TCP_OFF];
        }else
        {FramePtr = &pBuf[MB_PDU_RTU_OFF];}
        p_mb->RegAddress = sMB_GetRegValue( MB_PDU_REQ_ADDR_OFF );
        p_mb->RegCnt   = sMB_GetRegValue( MB_PDU_REQ_CNT_OFF );       
        if((p_mb->RegCnt >= MB_PDU_FNxx_COUNT_MIN ) && (p_mb->RegCnt< MB_PDU_FN01_READCOUNT_MAX))
        {
            if( ( p_mb->RegCnt & 0x0007 ) != 0 )
            {
                ucNBytes = ( UCHAR )( p_mb->RegCnt / 8 + 1 );
            }
            else
            {
                ucNBytes = ( UCHAR )( p_mb->RegCnt / 8 );
            }
            FramePtr[MB_PDU_FN01_BYTECNT_OFF] = ucNBytes;
            p_mb->BufCnt = 2 + ucNBytes;
            p_mb->Value_off = MB_PDU_FN01_VALUE_OFF;
            p_mb->ReadWrite = MBREAD;
            eStatus = sMB_RegCoilsCB( p_mb,pBuf);
        }
        else{eStatus = MB_EX_ILLEGAL_DATA_VALUE;}
    }
    else{eStatus = MB_EX_ILLEGAL_DATA_VALUE;}
    
    return eStatus;
}
#endif

/*
********************************************************************************************************
*                                                sMB FN02 Handler
*
* Description: 此函数用于从机 FN02 号命令的处理函数
* Arguments  : p_mb           指向1个wModbus的指针
* Returns    : 
* Note(s)    : 1) 
********************************************************************************************************
*/
#if MB_FN02_READ_DISCRETE_ENABLED == MBENABLED
static MB_Exception sMB_FN02_Read_DiscreteHandler( wMB *p_mb,UCHAR* pBuf)
{
    UCHAR          *FramePtr; 
    UCHAR           ucNBytes;
    MB_Exception    eStatus = MB_EX_NONE;
    if( p_mb->BufCnt == sMB_PDU_FN02_RcvLen_Min )
    {
        if(p_mb->Mode == MB_MODE_TCP)
        {
            FramePtr = &pBuf[MB_PDU_TCP_OFF];
        }else
        {FramePtr = &pBuf[MB_PDU_RTU_OFF];}
        p_mb->RegAddress = sMB_GetRegValue( MB_PDU_REQ_ADDR_OFF );
        p_mb->RegCnt   = sMB_GetRegValue( MB_PDU_REQ_CNT_OFF );   
        if((p_mb->RegCnt >= MB_PDU_FNxx_COUNT_MIN) && (p_mb->RegCnt<MB_PDU_FN02_READCOUNT_MAX))
        {
            if( ( p_mb->RegCnt & 0x0007 ) != 0 )
            {
                ucNBytes = ( UCHAR ) ( p_mb->RegCnt / 8 + 1 );
            }
            else
            {
                ucNBytes = ( UCHAR ) ( p_mb->RegCnt / 8 );
            }
            FramePtr[MB_PDU_FN02_BYTECNT_OFF] = ucNBytes;
            p_mb->BufCnt =  2 + ucNBytes;
            p_mb->Value_off = MB_PDU_FN02_VALUE_OFF ;
            eStatus = sMB_RegDiscreteCB( p_mb,pBuf);            
        }
        else{eStatus = MB_EX_ILLEGAL_DATA_VALUE;}
    }
    else{eStatus = MB_EX_ILLEGAL_DATA_VALUE;}
    return eStatus;
}
#endif

/*
********************************************************************************************************
*                                                sMB FN03 Handler
*
* Description: 此函数用于从机 FN03 号命令的处理函数
* Arguments  : p_mb           指向1个wModbus的指针
* Returns    : 
* Note(s)    : 1) 
********************************************************************************************************
*/
#if MB_FN03_READ_HOLDING_ENABLED == MBENABLED
static MB_Exception sMB_FN03_Read_HoldingRegister( wMB *p_mb,UCHAR* pBuf)
{
    UCHAR          *FramePtr; 
    MB_Exception    eStatus = MB_EX_NONE;
    if( p_mb->BufCnt == sMB_PDU_FN03_RcvLen_Min )
    {
        if(p_mb->Mode == MB_MODE_TCP)
        {
            FramePtr = &pBuf[MB_PDU_TCP_OFF];
        }else
        {FramePtr = &pBuf[MB_PDU_RTU_OFF];}
        p_mb->RegAddress = sMB_GetRegValue( MB_PDU_REQ_ADDR_OFF );
        p_mb->RegCnt   = sMB_GetRegValue( MB_PDU_REQ_CNT_OFF );   
        if((p_mb->RegCnt>=MB_PDU_FNxx_COUNT_MIN) && (p_mb->RegCnt<= MB_PDU_FN03_READCOUNT_MAX))
        {
            FramePtr[MB_PDU_FN03_BYTECNT_OFF] =  p_mb->RegCnt * 2;
            p_mb->BufCnt = 2 + p_mb->RegCnt * 2;
            p_mb->Value_off = MB_PDU_FN03_VALUE_OFF ;
            p_mb->ReadWrite = MBREAD;
            eStatus = sMB_RegHoldingCB( p_mb,pBuf);
        }
        else{eStatus = MB_EX_ILLEGAL_DATA_VALUE;}
    }
    else{eStatus = MB_EX_ILLEGAL_DATA_VALUE;}
    return eStatus;
}
#endif

/*
********************************************************************************************************
*                                                sMB FN04 Handler
*
* Description: 此函数用于从机 FN04 号命令的处理函数
* Arguments  : p_mb           指向1个wModbus的指针
* Returns    : 
* Note(s)    : 1) 
********************************************************************************************************
*/
#if MB_FN04_READ_INPUT_ENABLED == MBENABLED
static MB_Exception sMB_FN04_Read_InputHandler( wMB *p_mb,UCHAR* pBuf)
{
    UCHAR          *FramePtr; 
    MB_Exception    eStatus = MB_EX_NONE;
    if( p_mb->BufCnt == sMB_PDU_FN04_RcvLen_Min )
    {
        if(p_mb->Mode == MB_MODE_TCP)
        {
            FramePtr = &pBuf[MB_PDU_TCP_OFF];
        }else
        {FramePtr = &pBuf[MB_PDU_RTU_OFF];}        
        p_mb->RegAddress = sMB_GetRegValue( MB_PDU_REQ_ADDR_OFF );
        p_mb->RegCnt   = sMB_GetRegValue( MB_PDU_REQ_CNT_OFF ); 
        if( ( p_mb->RegCnt >= MB_PDU_FNxx_COUNT_MIN) && (p_mb->RegCnt<MB_PDU_FN04_READCOUNT_MAX))
        {
            FramePtr[MB_PDU_FN04_BYTECNT_OFF] =  p_mb->RegCnt * 2 ;
            p_mb->BufCnt = 2 + p_mb->RegCnt * 2;
            p_mb->Value_off = MB_PDU_FN04_VALUE_OFF ;
            eStatus = sMB_RegInputCB( p_mb,pBuf);
        }
        else{eStatus = MB_EX_ILLEGAL_DATA_VALUE;}
    }
    else{eStatus = MB_EX_ILLEGAL_DATA_VALUE;}
    return eStatus;
}
#endif

/*
********************************************************************************************************
*                                                sMB FN05 Handler
*
* Description: 此函数用于从机 FN05 号命令的处理函数
* Arguments  : p_mb           指向1个wModbus的指针
* Returns    : 
* Note(s)    : 1) 
********************************************************************************************************
*/
#if MB_FN05_WRITE_COIL_ENABLED == MBENABLED
static MB_Exception sMB_FN05_Write_CoilsHandler( wMB *p_mb ,UCHAR* pBuf)
{
    UCHAR          *FramePtr; 
    MB_Exception    eStatus = MB_EX_NONE;
    if( p_mb->BufCnt == sMB_PDU_FN05_RcvLen_Min )
    {
        if(p_mb->Mode == MB_MODE_TCP)
        {
            FramePtr = &pBuf[MB_PDU_TCP_OFF];
        }else
        {FramePtr = &pBuf[MB_PDU_RTU_OFF];}
        p_mb->RegAddress = sMB_GetRegValue( MB_PDU_REQ_ADDR_OFF );
        p_mb->RegCnt   = 1;
        if((FramePtr[MB_PDU_FN05_VALUE_OFF + 1] == 0x00 ) 
            && ((FramePtr[MB_PDU_FN05_VALUE_OFF] == 0xFF ) 
		    || (FramePtr[MB_PDU_FN05_VALUE_OFF] == 0 )))
        {
            if( FramePtr[MB_PDU_FN05_VALUE_OFF] == 0xFF )
            {
                FramePtr[MB_PDU_FN05_VALUE_OFF] = 1;
            }
            p_mb->Value_off = MB_PDU_FN05_VALUE_OFF ;
            p_mb->ReadWrite = MBWRITE;
            eStatus = sMB_RegCoilsCB( p_mb,pBuf);
            if(FramePtr[MB_PDU_FN05_VALUE_OFF] == 1)
            {
                FramePtr[MB_PDU_FN05_VALUE_OFF] = 0xFF;
            }
        }
        else {eStatus = MB_EX_ILLEGAL_DATA_VALUE;}
    }
    else {eStatus = MB_EX_ILLEGAL_DATA_VALUE;}
    return eStatus;
}
#endif

/*
********************************************************************************************************
*                                                sMB FN06 Handler
*
* Description: 此函数用于从机 FN06 号命令的处理函数
* Arguments  : p_mb           指向1个wModbus的指针
* Returns    : 
* Note(s)    : 1) 
********************************************************************************************************
*/
#if MB_FN06_WRITE_HOLDING_ENABLED == MBENABLED
static MB_Exception sMB_FN06_Write_HoldingHandler( wMB *p_mb ,UCHAR* pBuf)
{
    UCHAR          *FramePtr; 
    MB_Exception    eStatus = MB_EX_NONE;
    if( p_mb->BufCnt == sMB_PDU_FN06_RcvLen_Min )
    {
        if(p_mb->Mode == MB_MODE_TCP)
        {
            FramePtr = &pBuf[MB_PDU_TCP_OFF];
        }else
        {FramePtr = &pBuf[MB_PDU_RTU_OFF];}
        p_mb->RegAddress = sMB_GetRegValue( MB_PDU_REQ_ADDR_OFF );
        p_mb->RegCnt   = 1;
        p_mb->Value_off = MB_PDU_FN06_VALUE_OFF ;
        p_mb->ReadWrite = MBWRITE;
        eStatus = sMB_RegHoldingCB( p_mb,pBuf);
    }
    else{eStatus = MB_EX_ILLEGAL_DATA_VALUE;}
    return eStatus;
}
#endif

/*
********************************************************************************************************
*                                                sMB FN15 Handler
*
* Description: 此函数用于从机 FN15 号命令的处理函数
* Arguments  : p_mb           指向1个wModbus的指针
* Returns    : 
* Note(s)    : 1) 
********************************************************************************************************
*/
#if MB_FN15_WRITE_COILS_ENABLED == MBENABLED
static MB_Exception sMB_FN15_Write_CoilsHandler( wMB *p_mb ,UCHAR* pBuf)
{
    UCHAR          *FramePtr; 
    UCHAR           ucNBytes;
    MB_Exception    eStatus = MB_EX_NONE;
    if( p_mb->BufCnt >= sMB_PDU_FN15_RcvLen_Min )
    {
        if(p_mb->Mode == MB_MODE_TCP)
        {
            FramePtr = &pBuf[MB_PDU_TCP_OFF];
        }else
        {FramePtr = &pBuf[MB_PDU_RTU_OFF];}        
        p_mb->RegAddress = sMB_GetRegValue( MB_PDU_REQ_ADDR_OFF );
        p_mb->RegCnt   = sMB_GetRegValue( MB_PDU_REQ_CNT_OFF );     
        if( ( p_mb->RegCnt & 0x0007 ) != 0 )
        {
            ucNBytes = ( UCHAR )( p_mb->RegCnt / 8 + 1 );
        }
        else
        {
            ucNBytes = ( UCHAR )( p_mb->RegCnt / 8 );
        }
        if((p_mb->RegCnt>=MB_PDU_FNxx_COUNT_MIN) && (p_mb->RegCnt<=MB_PDU_FN15_WRITECOUNT_MAX) 
            && ( ucNBytes == FramePtr[MB_PDU_FN15_BYTECNT_OFF] ))
        {
            p_mb->BufCnt = MB_PDU_FN15_BYTECNT_OFF; 
            p_mb->Value_off = MB_PDU_FN15_VALUE_OFF ;
            p_mb->ReadWrite = MBWRITE;            
            eStatus = sMB_RegCoilsCB( p_mb,pBuf);
        }
        else{eStatus = MB_EX_ILLEGAL_DATA_VALUE;}
    }
    else{eStatus = MB_EX_ILLEGAL_DATA_VALUE;}
    return eStatus;
}
#endif

/*
********************************************************************************************************
*                                                sMB FN16 Handler
*
* Description: 此函数用于从机 FN16 号命令的处理函数
* Arguments  : p_mb           指向1个wModbus的指针
* Returns    : 
* Note(s)    : 1) 
********************************************************************************************************
*/
#if MB_FN16_WRITE_HOLDING_ENABLED == MBENABLED
static MB_Exception sMB_FN16_Write_HoldingHandler( wMB *p_mb ,UCHAR* pBuf)
{
    UCHAR          *FramePtr; 
    MB_Exception    eStatus = MB_EX_NONE;
    if( p_mb->BufCnt >= sMB_PDU_FN16_RcvLen_Min )
    {
        if(p_mb->Mode == MB_MODE_TCP)
        {
            FramePtr = &pBuf[MB_PDU_TCP_OFF];
        }else
        {FramePtr = &pBuf[MB_PDU_RTU_OFF];}
        p_mb->RegAddress = sMB_GetRegValue( MB_PDU_REQ_ADDR_OFF );
        p_mb->RegCnt   = sMB_GetRegValue( MB_PDU_REQ_CNT_OFF );   
        if((p_mb->RegCnt>=MB_PDU_FNxx_COUNT_MIN) &&(p_mb->RegCnt <=MB_PDU_FN16_WRITECOUNT_MAX) 
            && ( FramePtr[MB_PDU_FN16_BYTECNT_OFF] == ( 2 * p_mb->RegCnt )))
        {
            p_mb->BufCnt = MB_PDU_FN16_BYTECNT_OFF;
            p_mb->Value_off = MB_PDU_FN16_VALUE_OFF ; 
            p_mb->ReadWrite = MBWRITE;            
            eStatus = sMB_RegHoldingCB( p_mb,pBuf);
        }
        else{eStatus = MB_EX_ILLEGAL_DATA_VALUE;}
    }
    else{eStatus = MB_EX_ILLEGAL_DATA_VALUE;}
    return eStatus;
}
#endif

/*
********************************************************************************************************
*                                                sMB FN23 Handler
*
* Description: 此函数用于从机 FN23 号命令的处理函数
* Arguments  : p_mb           指向1个wModbus的指针
* Returns    : 
* Note(s)    : 1) 
********************************************************************************************************
*/
#if MB_FN23_READWRITE_HOLDING_ENABLED == MBENABLED
static MB_Exception sMB_FN23_ReadWrite_HoldingHandler( wMB *p_mb,UCHAR* pBuf)
{
    UCHAR          *FramePtr; 
    MB_Exception    eStatus = MB_EX_NONE;
    if( p_mb->BufCnt >= sMB_PDU_FN23_RcvLen_Min )
    {
        if(p_mb->Mode == MB_MODE_TCP)
        {
            FramePtr = &pBuf[MB_PDU_TCP_OFF];
        }else
        {FramePtr = &pBuf[MB_PDU_RTU_OFF];}
        p_mb->RegAddress = sMB_GetRegValue( MB_PDU_REQ_2ndADDR_OFF );
        p_mb->RegCnt   = sMB_GetRegValue( MB_PDU_REQ_2ndCNT_OFF );  
        if((p_mb->RegCnt>=MB_PDU_FNxx_COUNT_MIN) && (p_mb->RegCnt <=MB_PDU_FN23_WRITECOUNT_MAX) 
         &&(( 2 * p_mb->RegCnt ) == FramePtr[MB_PDU_FN23_WRITEBYTECNT_OFF] ))
        {
            p_mb->Value_off = MB_PDU_FN23_WRITEVALUE_OFF ;
            p_mb->ReadWrite = MBWRITE;
            eStatus = sMB_RegHoldingCB( p_mb,pBuf);
            p_mb->RegAddress = sMB_GetRegValue( MB_PDU_REQ_ADDR_OFF );
            p_mb->RegCnt   = sMB_GetRegValue( MB_PDU_REQ_CNT_OFF );  
            if((eStatus == MB_EX_NONE ) &&( p_mb->RegCnt >= 1 ) 
				&& ( p_mb->RegCnt <= MB_PDU_FN23_READCOUNT_MAX ))
            {
                FramePtr[MB_PDU_FN23_READBYTECNT_OFF] =  p_mb->RegCnt * 2 ;
                p_mb->BufCnt = 2 + 2 * p_mb->RegCnt;
                p_mb->Value_off = MB_PDU_FN23_READVALUE_OFF ;
                p_mb->ReadWrite = MBREAD;
                eStatus =sMB_RegHoldingCB( p_mb,pBuf);
            }
        }
        else{eStatus = MB_EX_ILLEGAL_DATA_VALUE;}
    }
    return eStatus;
}
#endif

/*
********************************************************************************************************
*                                                Function Handlers
*
* Description: 此函数用于从机wModbus协议栈的功能函数库调用。
* Arguments  : p_mb           指向1个wModbus的指针
* Note(s)    : 1) sMB_FuncHandlers() 自动被 sMB_Poll()调用
********************************************************************************************************
*/
static MB_Exception sMB_FuncHandlers(wMB   *p_mb,UCHAR* pBuf)
{
    UCHAR          *FramePtr;    
    MB_Exception   Exception; 
    if(p_mb->Mode == MB_MODE_TCP)
    {
         FramePtr = &pBuf[MB_PDU_TCP_OFF];
    }else
    {FramePtr = &pBuf[MB_PDU_RTU_OFF];}     
    
    switch (FramePtr[MB_PDU_FUNC_OFF])
    {   
#if MB_FN01_READ_COILS_ENABLED == MBENABLED
        case MB_FN01_READ_COILS:
            #if (MB_BROADCASTRESPOND_ENABLED != MBENABLED)
            if(p_mb->RecvAddr != MB_ADDRESS_BROADCAST ) 
            #endif   
            {Exception = sMB_FN01_Read_CoilsHandler(p_mb,pBuf);}break;
#endif
#if MB_FN02_READ_DISCRETE_ENABLED == MBENABLED       
        case MB_FN02_READ_DISCRETE_INPUTS:
            #if (MB_BROADCASTRESPOND_ENABLED != MBENABLED)
            if(p_mb->RecvAddr != MB_ADDRESS_BROADCAST )
            #endif            
            {Exception = sMB_FN02_Read_DiscreteHandler(p_mb,pBuf);}break;
#endif   
#if MB_FN03_READ_HOLDING_ENABLED == MBENABLED
        case MB_FN03_READ_HOLDING_REGISTER:
            #if (MB_BROADCASTRESPOND_ENABLED != MBENABLED)
            if(p_mb->RecvAddr != MB_ADDRESS_BROADCAST )
            #endif              
            {Exception = sMB_FN03_Read_HoldingRegister(p_mb,pBuf);}break;
#endif    
#if MB_FN04_READ_INPUT_ENABLED == MBENABLED
        case MB_FN04_READ_INPUT_REGISTER:
            #if (MB_BROADCASTRESPOND_ENABLED != MBENABLED)
            if(p_mb->RecvAddr != MB_ADDRESS_BROADCAST )
            #endif              
            {Exception = sMB_FN04_Read_InputHandler(p_mb,pBuf);}break;
#endif 
#if MB_FN05_WRITE_COIL_ENABLED == MBENABLED
        case MB_FN05_WRITE_SINGLE_COIL:
            {Exception = sMB_FN05_Write_CoilsHandler(p_mb,pBuf);}break;
#endif   
#if MB_FN06_WRITE_HOLDING_ENABLED == MBENABLED
        case MB_FN06_WRITE_REGISTER:
            {Exception = sMB_FN06_Write_HoldingHandler(p_mb,pBuf);}break;
#endif  
#if MB_FN15_WRITE_COILS_ENABLED == MBENABLED
        case MB_FN15_WRITE_MULTIPLE_COILS:
            {Exception = sMB_FN15_Write_CoilsHandler(p_mb,pBuf);}break;
#endif  
#if MB_FN16_WRITE_HOLDING_ENABLED == MBENABLED
        case MB_FN16_WRITE_MULTIPLE_REGISTERS:
            {Exception = sMB_FN16_Write_HoldingHandler(p_mb,pBuf);}break;
#endif
#if MB_FN23_READWRITE_HOLDING_ENABLED == MBENABLED
        case MB_FN23_READWRITE_MULTIPLE_REGISTERS:
            {Exception = sMB_FN23_ReadWrite_HoldingHandler(p_mb,pBuf);}break;
#endif
        default:
            {Exception = MB_EX_ILLEGAL_FUNCTION;}break;
    } 
    return Exception;
}

/*
********************************************************************************************************
*                                                Deal A wModbus
*
* Description: 此函数用于从机wModbus协议栈Poll函数,需循环调用。
* Arguments  : p_mb           指向1个wModbus的指针
* Returns    : MB_Exception   返回错误代码。
* Note(s)    : 1) sMB_Deal() 应当创建一个wModbus协议栈并使能后使用
********************************************************************************************************
*/
USHORT sMB_Deal( wMB *p_mb,UCHAR* pBuf,USHORT length )
{
    UCHAR          *FramePtr;      
    MB_Exception   eStatus;  
    USHORT         slen = 0;
    if ( MB_MutexPend( p_mb ) != MBFALSE )
    {
        if(MB_Receive( p_mb,pBuf,length) != MBTRUE)
        {
            #if (MB_STAT_ENABLED == MBENABLED)
            p_mb->StatReceiveErrCtr++;
            #endif 
        }
        else 
        {   
            if(( p_mb->RecvAddr == p_mb->NodeAddr ) || ( p_mb->RecvAddr == MB_ADDRESS_BROADCAST ))
            {
                eStatus = sMB_FuncHandlers(p_mb,pBuf);
                if( eStatus != MB_EX_NONE )
                {
                    p_mb->BufCnt  = 0;
                    if(p_mb->Mode == MB_MODE_TCP)
                    {
                         FramePtr= &pBuf[MB_PDU_TCP_OFF];
                    }else
                    {
                        FramePtr = &pBuf[MB_PDU_RTU_OFF];
                    } 
                    FramePtr[p_mb->BufCnt ++] = FramePtr[MB_PDU_FUNC_OFF] | MB_FUNC_ERROR ;
                    FramePtr[p_mb->BufCnt ++] = eStatus;
                    #if (MB_STAT_ENABLED == MBENABLED)
                    p_mb->StatHandlersErrCtr++;
                    #endif  
                }
                #if (MB_STAT_ENABLED == MBENABLED)                    
                else
                {
                    p_mb->StatOKCtr++;
                }
                #endif                      
                slen = MB_Send(p_mb,pBuf);
            }
        } 
        MB_MutexPost(p_mb);
    }
    return slen;
}
#endif

smbbuf.c文件

/*
********************************************************************************************************
*                                                wModbus
*                                 The Embedded Modbus Stack Software
*
*               Copyright: Wu YuanFu. All rights reserved.Protected by international copyright laws.
*
* Programmer  : Wu YuanFu
* Version     : V2.50
* LICENSING TERMS:
* ---------------
*           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 YuanFu<[email protected]> to properly license wModbus
*           for 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.
*               
********************************************************************************************************
*/

/* Filename    : mbbuf.c*/

#include "smbbuf.h"

#if ( MB_SLAVE_ENABLED== MBENABLED )

	#define sMB_HoldingBuf_Addr 	0                                                       //数量为   sMB_HOLDING_NREGS
	#define sMB_InputBuf_Addr 	    (sMB_HoldingBuf_Addr + sMB_HOLDING_NREGS)               //数量为   sMB_INPUT_NREGS
	#define sMB_CoilsBuf_Addr 	    (sMB_InputBuf_Addr + sMB_INPUT_NREGS)                   //数量为   sMB_COILS_NREGS/MB_BITS + 1
	#define sMB_DiscreteBuf_Addr 	(sMB_CoilsBuf_Addr + sMB_COILS_NREGS/MB_BITS +1)        //数量为   sMB_DISCRETE_NREGS/MB_BITS + 1
    #define sMB_BUF_SIZE            (sMB_DiscreteBuf_Addr + sMB_DISCRETE_NREGS/MB_BITS + 1) //数量为   sMB_DISCRETE_NREGS/MB_BITS + 1
    
    static  USHORT MBBuf[sMB_BUF_SIZE];

/*
********************************************************************************************************
*                                                sMB RegHoldingWrite Callback
*
* Description: 此函数用于RegHoldingWrite回调函数
* Arguments  : addr       RegHolding地址
*            : value      RegHolding地址上的值
* Note(s)    : 1) sMB_RegHoldingCBCallback() 可作为用户hook函数。
********************************************************************************************************
*/
__weak void sMB_RegHoldingWriteCallback(USHORT addr,USHORT value)
{

 
}

/*
********************************************************************************************************
*                                                sMB RegCoilsWrite Callback
*
* Description: 此函数用于RegCoilsWrite回调函数
* Arguments  : addr       RegCoils地址
*            : NBits      写入的位数 <=16
*            : value      RegCoils地址上的值
* Note(s)    : 1) sMB_RegCoilsCBCallback() 可作为用户hook函数。
********************************************************************************************************
*/
__weak void sMB_RegCoilsWriteCallback( USHORT addr,UCHAR NBits,USHORT value)
{


}


USHORT* sMB_GetpBuf(USHORT addr,USHORT num)
{
    USHORT* pBuf;
    
    if((addr >= sMB_HOLDING_START ) && ((addr + num) <= (sMB_HOLDING_START+ sMB_HOLDING_NREGS)))
    {
        pBuf = &MBBuf[addr - sMB_HOLDING_START + sMB_HoldingBuf_Addr];
    }
    else if((addr >= sMB_INPUT_START ) && ((addr + num) <= (sMB_INPUT_START+ sMB_INPUT_NREGS)))
    {
        pBuf = &MBBuf[addr - sMB_INPUT_START + sMB_InputBuf_Addr];
    }
    else if((addr >= sMB_COILS_START ) && ((addr + num) <= (sMB_COILS_START+ sMB_COILS_NREGS)))
    {
        pBuf = &MBBuf[sMB_CoilsBuf_Addr];
    }
    else if((addr >= sMB_DISCRETE_START ) && ((addr + num) <= (sMB_DISCRETE_START+ sMB_DISCRETE_NREGS)))
    {
        pBuf = &MBBuf[sMB_DiscreteBuf_Addr];
    }    
    else{return  MBNULL;}
    
    return pBuf;
}

/*
********************************************************************************************************
*                                                  Set Buf
*
* Description: 此函数用于设置数据
* Arguments  : addr           buf数据偏移地址
*              dst            目标数据地址
*              num            数据个数
* Returns    : MBTRUE         成功
*              MBFALSE        失败
* Note(s)    : 1) MB_GetBuf() 
********************************************************************************************************
*/
MB_Exception MB_SetBufs(USHORT addr,USHORT* dst,USHORT num)
{
    USHORT i;
    USHORT* src;
    
    src = sMB_GetpBuf(addr,num);
    if(src != MBNULL)
    {
        for(i=0;i<num;i++)
        {
            src[i] = dst[i];
        }
        return MB_EX_NONE;
    }
    return  MB_EX_ILLEGAL_DATA_ADDRESS;
}

MB_Exception MB_SetBuf(USHORT addr,USHORT dst)
{
    USHORT* src;
    
    src = sMB_GetpBuf(addr,1);
    if(src != MBNULL)
    {
        *src = dst;
        return MB_EX_NONE;
    }
    return  MB_EX_ILLEGAL_DATA_ADDRESS;    
}
/*
********************************************************************************************************
*                                                  Get Buf
*
* Description: 此函数用于获取数据
* Arguments  : addr           buf数据偏移地址
*              dst            目标数据地址
*              num            数据个数
* Returns    : MBTRUE         成功
*              MBFALSE        失败
* Note(s)    : 1) MB_GetBuf() 
********************************************************************************************************
*/
MB_Exception MB_GetBufs(USHORT addr,USHORT* dst,USHORT num)
{
    USHORT i;    
    USHORT* src;
    
    src = sMB_GetpBuf(addr,num);
    if(src != MBNULL)
    {
        for(i=0;i<num;i++)
        {
            dst[i] = src[i];
        }
        return MB_EX_NONE;
    }
    return  MB_EX_ILLEGAL_DATA_ADDRESS;
}

USHORT MB_GetBuf(USHORT addr)
{
    USHORT* src;
    
    src = sMB_GetpBuf(addr,1);
    if(src != MBNULL)
    {
        return *src;
    }
    return  MBNULL;
}

#endif

smbbuf.h文件



/*
********************************************************************************************************
*                                                wModbus
*                                 The Embedded Modbus Stack Software
*
*               Copyright: Wu YuanFu. All rights reserved.Protected by international copyright laws.
*
* Programmer  : Wu YuanFu
* Version     : V2.50
* LICENSING TERMS:
* ---------------
*           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 YuanFu<[email protected]> to properly license wModbus
*           for 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.
*               
********************************************************************************************************
*/

/* Filename    : mbbuf.h*/

#include "mbtype.h"

#ifndef _MB_BUF_H
#define _MB_BUF_H

#ifdef __cplusplus
PR_BEGIN_EXTERN_C
#endif

#if ( MB_SLAVE_ENABLED== MBENABLED )

MB_Exception MB_SetBufs(USHORT addr,USHORT* dst,USHORT num);
MB_Exception MB_GetBufs(USHORT addr,USHORT* dst,USHORT num);
MB_Exception MB_SetBuf(USHORT addr,USHORT dst);
USHORT MB_GetBuf(USHORT addr);

    #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

#ifdef __cplusplus
PR_END_EXTERN_C
#endif
#endif

mmb.c文件

	暂不提供

猜你喜欢

转载自blog.csdn.net/abc240697738/article/details/107497170
今日推荐