您的位置:首页 > 其它

freemodbus 在stm32+W5500平台上的移植

2015-07-20 13:58 141 查看
1、理解freemodbus的运行机制

在W5500平台上移植freemodbus,主要就是要理解eMBpoll()函数的状态机,在理解过程中我主要参考这样几篇文章,甚至可以说是抄袭吧(部分代码),在此表示衷心感谢!http://bbs.eeworld.com.cn/thread-362508-1-1.html,http://bbs.eeworld.com.cn/thread-362508-1-1.html,这两篇文章讲的如如何将freemodbus RTU模式的移植,希望大家能仔细领悟,一篇详细描述了移植过程病给了移植的代码,另一篇对freemodbus的运行机制讲的比较透彻,仔细阅读会对整个移植过程有个比较深刻的理解。

2、理解W5500的运行机制

如果能在理解freemodbus RTU,我们再来看modbus TCP到底在W500平台上如何实现。这里我先首先说明,在此之前还要明白W5500的运行过程,如果这个也不懂请参考http://blog.csdn.net/wiznet2012/article/details/41279113这篇文章,将W5500库函数移植一定要看明白,并且读懂其中int32_t
loopback_tcps这个函数,我们移植的平台就是基于这样一个函数的简单改编而已。

3、移植过程

(1)移植环境搭建

在以上两个前提下我们来移植freemodbus—TCP。首先我们按照http://bbs.eeworld.com.cn/thread-362508-1-1.html这篇博文的要求,建立起freemodbus_RTU环境,这几个回调函数写的很好,既然我人家写好了,我就比较懒没有自己重写,直接抄了过来。

eMBErrorCode eMBRegInputCB(
UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNRegs );

eMBErrorCode eMBRegHoldingCB(
UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNRegs, eMBRegisterMode eMode );

eMBErrorCode eMBRegCoilsCB( UCHAR * pucRegBuffer, USHORT usAddress,USHORT
usNCoils,eMBRegisterMode eMode);

eMBErrorCode eMBRegDiscreteCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT
usNDiscrete);

(2)编写porttcp.c文件

在此我参考这篇博文http://blog.csdn.net/xukai871105/article/details/21652287,这篇博文讲的是采用uIP协议实现移植,对于modbus的移植有着非常好参考意义,移植前请仔细阅读。主要是建立

//modbus 接收发送寄存器,全局变量

#define MB_TCP_BUF_SIZE 2048

uint8_t ucTCPRequestFrame[MB_TCP_BUF_SIZE]; //接收寄存器

uint16_t ucTCPRequestLen;

uint8_t ucTCPResponseFrame[MB_TCP_BUF_SIZE]; //发送寄存器

uint16_t ucTCPResponseLen;

uint8_t bFrameSent = FALSE; //是否进行发送响应判断

建立porttcp.c文件,实现这样几个函数

BOOL
xMBTCPPortInit( USHORT usTCPPort )

{

SOCKET sn;

sn=0;

if(getSn_SR(sn)==SOCK_CLOSED)

{

socket(sn,Sn_MR_TCP,usTCPPort,0x00);
//打开socket

}

if (getSn_SR(sn)==SOCK_INIT)

{

listen(sn); //监听

return TRUE;

}

return FALSE;

}

BOOL
xMBTCPPortGetRequest( UCHAR **ppucMBTCPFrame, USHORT * usTCPLength )

{

*ppucMBTCPFrame = (uint8_t *) &ucTCPRequestFrame[0];

*usTCPLength = ucTCPRequestLen;

/* Reset the buffer. */

ucTCPRequestLen = 0;

return TRUE;

}

BOOL xMBTCPPortSendResponse( const UCHAR *pucMBTCPFrame, USHORT usTCPLength )

{

memcpy(ucTCPResponseFrame,pucMBTCPFrame , usTCPLength);

ucTCPResponseLen = usTCPLength;

bFrameSent = TRUE; // 通过W5500发送数据

return bFrameSent;

}

void vMBTCPPortClose( void )

{

};

void vMBTCPPortDisable( void )

{

};

这其中 xMBTCPPortInit()函数的内容写不写,貌似影响不大。

(3)编写main.c文件

以上说了半天都是参考别人的,而且和W5500没什么关系。现在是freemodbus 和 w5500 库函数如何结合使用的时候了。看一下main函数

int main(void)

{

uint8_t tmp;

uint8_t sn=0;

uint16_t port=MBTCP_PORT;

eMBErrorCode eStatus;

w5500_SPI_Init();

reg_callback_func();//注册W5500回调函数,移植W5500库函数必须

Socket_buffer_init();//W5500 SOCKET Buffer 初始化

/* PHY link 状态检查*/

if(ctlwizchip(CW_GET_PHYLINK, (void*)&tmp) == -1){

// printf("Unknown PHY Link stauts.\r\n");

}

/* 网络初始化 */

network_init();

//启动FreeModbus

eStatus = eMBTCPInit(port );

eStatus =eMBEnable();

while(1)

{

modbus_tcps(sn,port);

}

}

w5500_SPI_Init();

reg_callback_func();//注册W5500回调函数,移植W5500库函数必须

Socket_buffer_init();//W5500 SOCKET Buffer 初始化

/* PHY link 状态检查*/

if(ctlwizchip(CW_GET_PHYLINK, (void*)&tmp)

}

/* 网络初始化 */

network_init();

等都是W5500初始化的过程,

eStatus = eMBTCPInit(port );

eStatus =eMBEnable();

是freemodbus初始化的过程。

来看一下modbus_tcps(sn,port)函数

//W5500在TCP server模式下,接收、发送modbus-TCP报文

void modbus_tcps(uint8_t sn, uint16_t port)

{

switch(getSn_SR(sn)) //获取socket状态

{

case SOCK_CLOSED: //socket处于关闭状态

socket(sn,Sn_MR_TCP,port,0x00); //打开socket

break;

case SOCK_INIT : //socket处于已经初始化状态

listen(sn); //监听

case SOCK_ESTABLISHED : //socket处于连接状态

if(getSn_IR(sn) & Sn_IR_CON)

{

setSn_IR(sn,Sn_IR_CON);

}

ucTCPRequestLen = getSn_RX_RSR(sn); //获取接收数据长度

if(ucTCPRequestLen>0)

{

recv(sn,ucTCPRequestFrame, ucTCPRequestLen);
//W5500接收数据

xMBPortEventPost(EV_FRAME_RECEIVED); //发送EV_FRAME_RECEIVED事件,以驱动eMBpoll()函数中的状态机

eMBPoll(); //处理EV_FRAME_RECEIVED事件

eMBPoll(); //处理EV_EXECUTE事件

if(bFrameSent)

{

bFrameSent = FALSE;

//W5500发送Modbus应答数据包

send(sn,ucTCPResponseFrame,ucTCPResponseLen);

}

}

break;

case SOCK_CLOSE_WAIT : //socket处于等待关闭状态

disconnect(sn); //关闭连接

break;

default:

break;

}

}

这个函数就是不断检查W5500的状态,如果检查到有收到数据包之后开始接受数据,并启动freemodbus状态机。具体流程是,W5500接受数据包存入ucTCPRequestFrame数组中
→ 发送EV_FRAME_RECEIVED事件
→ 两次调用freemodbus状态机,完成对接受报文的解析,并生成响应的报文存入ucTCPRequestFrame数组中
→ 最后W5500将数组中的报文中发送出去。

即每次收到数据包之后就执行这样一个流程即可。ucTCPRequestFrame,ucTCPResponseFrame正是W5500和freemodbus结合的媒介。

4、测试

利用modsan32客户端测试,如下图


5、多客户端支持

主函数这样修改

while(1)

{

for(sn=1;sn<8;sn++)

modbus_tcps(sn,port);

}

w5500具有8个Socket,TCPserver模式下最多支持8个客户端同时访问。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: