第7章        RL-TCPnet网络协议栈移植(裸机)

本章教程为大家讲解RL-TCPnet网络协议栈的裸机移植方式,学习了上个章节讲解的底层驱动接口函数之后,移植就比较容易了,主要是添加库文件、配置文件和驱动文件即可。

本章教程含STM32F407开发板和STM32F429开发板的移植。

7.1  移植前准备工作说明

7.2  STM32F407移植RL-TCPnet协议栈

7.3  STM32F429移植RL-TCPnet协议栈

7.4  总结

7.1  移植前准备工作说明

1、学习本章节前,务必要优先学习第6章的底层驱动讲解。

2、RL-TCPnet只有库,没有源码。库分为两个版本,一个用于调试的版本TCPD_CM3.lib和一个正式版本TCP_CM3.lib,当前的例子统一使用调试版本。另外注意,虽然是CM3版本的,但可同时用于CM3和CM4内核的MCU,因为官方没有专门的CM4内核库。

3、测试时,请将网线接到路由器或者交换机上面测试,因为已经使能了DHCP,可以自动获取IP地址。

而且使能了NetBIOS局域网域名,用户只需在电脑端ping armfly,就可以获得板子的IP地址。

4、如果要使用固定IP进行测试,请看第57章。

5、网口使用的是DM9161/9162(紧挨着9帧串口座的网口),而不是DM9000。

6、找一个简单的工程,最好是跑马灯之类的,越简单越好,我们就在这个简单的工程上面移植即可。

7.2   STM32F407移植RL-TCPnet协议栈

7.2.1      RL-TCPnet网络协议栈移植

首先准备好一个简单的裸机工程模板,工程模板的制作就不做讲解了,这里的重点是教大家移植RL-TCPnet协议栈。准备好的工程模板如下图所示(大家也可以制作其它任意的工程模板,不限制):

准备好工程模板后,就可以开始移植了。首先要做的就是将所有需要的文件放到工程模板里面。下面分三步跟大家进行说明,当然,不限制必须使用下面的方法添加源码到工程,只要将需要的文件添加到工程模板即可。

第1步:将我们裸机模板中制作好的RL-ARM文件夹复制粘贴到大家准备好的工程模板中。

RL-ARM文件夹中有如下七个文件夹:

Config文件夹用于存放RTX及其中间件的配置文件。

Driver文件夹用于存放中间件的驱动文件,也就是底层移植文件。

RL-CAN文件夹用于存放CAN总线的源码文件。

RL-FlashFS文件夹用于存放文件系统RL-FlashFS的库文件。

RL-RTX文件夹用于存放RTX的源码文件。

RL-TCPnet文件夹用于存放网络协议栈RL-TCPnet的库文件。

RL-USB文件夹用于存放USB协议栈RL-USB的库文件。

也许有用户会问:我们不是仅仅需要移植RL-TCPnet的相关文件就行了吗,为什么把RTX及其所有中间件都添加进来了?这样做的目的是为了以后升级的方便,如果需要添加USB、文件系统、CAN等组件,直接添加到工程即可。

这些文件全部来自MDK4.74的安装目录,库文件位于路径:C:\Keil_v474\ARM\RV31下,而驱动和配置文件位于路径:C:\Keil_v474\ARM\RL下。

第2步:添加RL-TCPnet的库文件、配置文件和驱动文件到工程。

添加完毕后的效果如下:

Net_Config.c和NET_Debug.c在RL-ARM文件夹的Config文件里面。

TCPD_CM3.lib在RL-ARM文件夹的RL-TCPnet文件里面。

ETH_STM32F4xx.c和ETH_STM32F4xx.h在RL-ARM文件夹的Driver文件里面。

第3步:也是最后一步,添加相应的头文件路径。

在原来工程模板的基础上面新添加的三个路径:

至此,RL-TCPnet的移植工作就完成了,剩下就是系统配置和应用了。

7.2.2     RL-TCPnet配置说明(Net_Config.c)

RL-TCPnet的配置工作是通过配置文件Net_Config.c实现。在MDK工程中打开文件Net_Config.c,可以看到下图所示的工程配置向导:

RL-TCPnet要配置的选项非常多,我们这里把几个主要的配置选项简单介绍下。

System Definitions

(1)Local Host Name

局域网域名。

这里起名为armfly,使用局域网域名限制为15个字符。

(2)Memory Pool size

参数范围1536-262144字节。

内存池大小配置,单位字节。另外注意一点,配置向导这里显示的单位是字节,如果看原始定义,MDK会做一个自动的4字节倍数转换,比如我们这里配置的是8192字节,那么原始定义是#define MEM_SIZE  2048,也就是8192/4 = 2048。

(3)Tick Timer interval

可取10,20,25,40,50,100,200,单位ms。

系统滴答时钟间隔,也就是网络协议栈的系统时间基准,默认情况下,取值100ms。

Ethernet Network Interface

以太网接口配置,勾选了此选项就可以配置了,如果没有使能DHCP的话,将使用这里配置的固定IP

(1)MAC Address

局域网内可以随意配置,只要不跟局域网内其它设备的MAC地址冲突即可。

(2)IP Address

IP地址。

(3)Subnet mask

子网掩码。

(4)Default Gateway

默认网关。

Ethernet Network Interface

以太网接口配置,这个配置里面还有如下两项比较重要的配置需要说明。

(1)NetBIOS Name Service

NetBIOS局域网域名服务,这里打上对勾就使能了。这样我们就可以通过前面配置的Local Host Name局域网域名进行访问,而不需要通过IP地址访问了。

(2)Dynaminc Host Configuration

即DHCP,这里打上对勾就使能了。使能了DHCP后,RL-TCPnet就可以从外接的路由器上获得动态IP地址。

UDP Sockets

UDP Sockets配置,打上对勾就使能了此项功能

(1)Number of UDP Sockets

用于配置可创建的UDP Sockets数量。

范围1 – 20。

TCP Sockets

TCP Sockets配置,打上对勾就使能了此项功能

(1)Number of TCP Sockets

用于配置可创建的TCP Sockets数量。

(2)Number of Retries

范围0-20。

用于配置重试次数,TCP数据传输时,如果在设置的重试时间内得不到应答,算一次重试失败,这里就是配置的最大重试次数。

(3)Retry Timeout in seconds

范围1-10,单位秒。

重试时间。如果发送的数据在重试时间内得不到应答,将重新发送数据。

(4)Default Connect Timeout in seconds

范围1-600,单位秒。

用于配置默认的保持连接时间,即我们常说的Keep Alive时间,如果时间到了将断开连接。常用于HTTP Server,Telnet Server等。

(5)Maximum Segment Size

范围536-1460,单位字节。

MSS定义了TCP数据包能够传输的最大数据分段。

(6)Receive Window Size

范围536-65535,单位字节。

TCP接收窗口大小。

7.2.3     RL-TCPnet调试说明(Net_Debug.c)

(重要说明,RL-TCPnet的调试是通过串口打印出来的)

RL-TCPnet的调试功能是通过配置文件Net_Debug.c实现。在MDK工程中打开文件Net_Debug.c,可以看到下图所示的工程配置向导:

Print Time Stamp

勾选了此选项的话,打印消息时,前面会附带时间信息。

其它所有的选项

默认情况下,所有的调试选项都是关闭的。每个选项有三个调试级别可选择,这里我们以Memory Management Debug为例,点击下拉列表,可以看到里面有Off,Errors only和Full debug三个调试级别可供选择,每个调试选项里面都是这三个级别。

Off:表示关闭此选项的调试功能。

Errors only:表示仅在此选项出错时,将其错误打印出来。

Full debug:表示此选项的全功能调试。

关于调试功能的使用会在第11章详细为大家讲解,移植阶段将其全部关闭即可。

7.2.4     RL-TCPnet应用实例

为了验证移植的RL-TCPnet是否可以使用,需要添加测试代码。下面是编写的测试代码,配套的测试例子完整版是:V5-1000_RL-TCPnet实验_工程移植模板(裸机)。

主函数初始化

在main.c文件实现:

/***********************************************************************************************************    函 数 名: main*    功能说明: 标准c程序入口。*    形    参: 无*    返 回 值: 无**********************************************************************************************************/int main (void){   /* 初始化外设 */bsp_Init();/* 进入RL-TCPnet测试函数 */TCPnetTest();}

硬件外设初始化

硬件外设的初始化是在 bsp.c 文件实现:

/***********************************************************************************************************    函 数 名: bsp_Init*    功能说明: 初始化所有的硬件设备。该函数配置CPU寄存器和外设的寄存器并初始化一些全局变量。只需要调用一次*    形    参:无*    返 回 值: 无**********************************************************************************************************/void bsp_Init(void){/*由于ST固件库的启动文件已经执行了CPU系统时钟的初始化,所以不必再次重复配置系统时钟。启动文件配置了CPU主时钟频率、内部Flash访问速度和可选的外部SRAM FSMC初始化。系统时钟缺省配置为168MHz,如果需要更改,可以修改 system_stm32f4xx.c 文件*//* 优先级分组设置为4,可配置0-15级抢占式优先级,0级子优先级,即不存在子优先级。*/NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);bsp_InitUart();    /* 初始化串口 */bsp_InitKey();     /* 初始化按键变量(必须在 bsp_InitTimer() 之前调用) */bsp_InitLed();     /* 初始LED指示灯端口 */bsp_InitTimer();   /* 初始化滴答定时器 */}

RL-TCPnet功能测试

这里专门创建了一个app_tcpnet_lib.c文件用于RL-TCPnet功能的测试,主要功能是创建了一个TCP Server。

/***********************************************************************************************************                                      用于本文件的调试**********************************************************************************************************/#if 1#define printf_debug printf#else#define printf_debug(...)#endif/***********************************************************************************************************                                      用于本文件的调试**********************************************************************************************************/#define PORT_NUM       1001    /* TCP服务器监听端口号 *//***********************************************************************************************************                                         变量**********************************************************************************************************/uint8_t socket_tcp;/***********************************************************************************************************    函 数 名: tcp_callback*    功能说明: TCP Socket的回调函数*    形    参: soc  TCP Socket类型*             evt  事件类型*             ptr  事件类型是TCP_EVT_DATA,ptr指向的缓冲区记录着接收到的TCP数据,其余事件记录IP地址*             par  事件类型是TCP_EVT_DATA,记录接收到的数据个数,其余事件记录端口号*    返 回 值:**********************************************************************************************************/U16 tcp_callback (U8 soc, U8 evt, U8 *ptr, U16 par){char buf[50];uint16_t i;/* 确保是socket_tcp的回调 */if (soc != socket_tcp){return (0);}switch (evt){/*远程客户端连接消息1、数组ptr存储远程设备的IP地址,par中存储端口号。2、返回数值1允许连接,返回数值0禁止连接。*/case TCP_EVT_CONREQ:sprintf(buf, "远程客户端请求连接IP: %d.%d.%d.%d", ptr[0], ptr[1], ptr[2], ptr[3]);printf_debug("IP:%s  port:%d\r\n", buf, par);return (1);/* 连接终止 */case TCP_EVT_ABORT:break;/* Socket远程连接已经建立 */case TCP_EVT_CONNECT:printf_debug("Socket is connected to remote peer\r\n");break;/* 连接断开 */case TCP_EVT_CLOSE:printf_debug("Connection has been closed\r\n");break;/* 发送的数据收到远程设备应答 */case TCP_EVT_ACK:break;/* 接收到TCP数据帧,ptr指向数据地址,par记录数据长度,单位字节 */case TCP_EVT_DATA:printf_debug("Data length = %d\r\n", par);for(i = 0; i < par; i++){printf_debug("ptr[%d] = %d\r\n", i, ptr[i]);}break;}return (0);}/***********************************************************************************************************    函 数 名: TCP_StatusCheck*    功能说明: 检测TCP的连接状态,主要用于网线插拔的判断*    形    参: 无*    返 回 值: __TRUE  连接*             __FALSE 断开**********************************************************************************************************/uint8_t TCP_StatusCheck(void){uint8_t res;switch (tcp_get_state(socket_tcp)){case TCP_STATE_FREE:case TCP_STATE_CLOSED:res = tcp_listen (socket_tcp, PORT_NUM);printf_debug("tcp listen res = %d\r\n", res);break;case TCP_STATE_LISTEN:break;case TCP_STATE_CONNECT:return (__TRUE);default: break;}return (__FALSE);}/***********************************************************************************************************    函 数 名: tcpnet_poll*    功能说明: 使用TCPnet必须要一直调用的函数*    形    参: 无*    返 回 值: 无**********************************************************************************************************/void tcpnet_poll(void){if(bsp_CheckTimer(0)){/* 此函数坚决不可以放在中断里面跑 */timer_tick ();}main_TcpNet ();}/***********************************************************************************************************    函 数 名: TCPnetTest*    功能说明: TCPnet应用*    形    参: 无*    返 回 值: 无**********************************************************************************************************/void TCPnetTest(void){ int32_t ulCount;uint8_t *sendbuf;uint8_t tcp_status;uint16_t maxlen;uint8_t res;uint8_t ucKeyCode;/* 初始化网络协议栈 */init_TcpNet ();/*创建TCP Socket并创建监听,客户端连接服务器后,10秒内无数据通信将断开连接。但是由于这里使能了TCP_TYPE_KEEP_ALIVE,会一直保持连接,不受10秒的时间限制。*/socket_tcp = tcp_get_socket (TCP_TYPE_SERVER | TCP_TYPE_KEEP_ALIVE, 0, 10, tcp_callback);if(socket_tcp != 0){res = tcp_listen (socket_tcp, PORT_NUM);printf_debug("tcp listen res = %d\r\n", res);}/* 创建一个周期是100ms的软定时器 */bsp_StartAutoTimer(0, 100);while (1){/* TCP轮询 */tcpnet_poll();/* 用于网线插拔的处理 */tcp_status = TCP_StatusCheck();/* 按键消息的处理 */ucKeyCode = bsp_GetKey();if ((ucKeyCode != KEY_NONE)&&(tcp_status == __TRUE)){switch (ucKeyCode){/* K1键按下,给远程TCP客户端发送8字节数据 */case KEY_DOWN_K1:            printf_debug("tcp_get_state(socket_tcp) = %d\r\n", tcp_get_state(socket_tcp));ulCount = 8;do{tcpnet_poll();if (tcp_check_send (socket_tcp) == __TRUE){maxlen = tcp_max_dsize (socket_tcp);ulCount -= maxlen;if(ulCount < 0){/* 这么计算没问题的 */maxlen = ulCount + maxlen;}sendbuf = tcp_get_buf(maxlen);sendbuf[0] = '1';sendbuf[1] = '2';sendbuf[2] = '3';sendbuf[3] = '4';sendbuf[4] = '5';sendbuf[5] = '6';sendbuf[6] = '7';sendbuf[7] = '8';/* 测试发现只能使用获取的内存 */tcp_send (socket_tcp, sendbuf, maxlen);}}while(ulCount > 0);break;/* K2键按下,给远程TCP客户端发送1024字节的数据 */case KEY_DOWN_K2:     printf_debug("tcp_get_state(socket_tcp) = %d\r\n", tcp_get_state(socket_tcp));ulCount = 1024;do{tcpnet_poll();if (tcp_check_send (socket_tcp) == __TRUE){maxlen = tcp_max_dsize (socket_tcp);ulCount -= maxlen;if(ulCount < 0){/* 这么计算没问题的 */maxlen = ulCount + maxlen;}/* 这里仅初始化了每次所发送数据包的前8个字节 */sendbuf = tcp_get_buf(maxlen);sendbuf[0] = 'a';sendbuf[1] = 'b';sendbuf[2] = 'c';sendbuf[3] = 'd';sendbuf[4] = 'e';sendbuf[5] = 'f';sendbuf[6] = 'g';sendbuf[7] = 'h';/* 测试发现只能使用获取的内存 */tcp_send (socket_tcp, sendbuf, maxlen);}}while(ulCount > 0);                     break;/* K3键按下,给远程TCP客户端发送5MB数据 */case KEY_DOWN_K3:            printf_debug("tcp_get_state(socket_tcp) = %d\r\n", tcp_get_state(socket_tcp));ulCount = 5*1024*1024;do{tcpnet_poll();if (tcp_check_send (socket_tcp) == __TRUE){maxlen = tcp_max_dsize (socket_tcp);ulCount -= maxlen;if(ulCount < 0){/* 这么计算没问题的 */maxlen = ulCount + maxlen;}/* 这里仅初始化了每次所发送数据包的前8个字节 */sendbuf = tcp_get_buf(maxlen);sendbuf[0] = 'a';sendbuf[1] = 'b';sendbuf[2] = 'c';sendbuf[3] = 'd';sendbuf[4] = 'e';sendbuf[5] = 'f';sendbuf[6] = 'g';sendbuf[7] = 'h';/* 测试发现只能使用获取的内存 */tcp_send (socket_tcp, sendbuf, maxlen);}}while(ulCount > 0);break;/* 其他的键值不处理 */default:                    break;}}}}

至此,裸机方式移植的RL-TCPnet就可以运行了。

7.2.5     RL-TCPnet实验测试和实验现象

测试前,先将开发板上面的DM9161/9162网口通过网线接到路由器或者交换机上面。

RJ45网络变压器插座上绿灯和黄灯现象

各种网卡、交换机等网络设备都不一样,一般来讲:绿灯分为亮或不亮(代表网络速度),黄灯分为闪烁或不闪烁(代表是否有数据收发)。

绿灯:长亮代表100M; 不亮代表10M。

黄灯:长亮代表无数据收发; 闪烁代表有数据收发。

也有些千兆网卡的灯以颜色区分,不亮代表10M / 绿色代表100M / 黄色代表1000M。现在10M的网络基本看不到了,如果一个灯长亮,基本可以说明100M网络或更高,而另一个灯时而闪烁,那代表有数据收发,具体要看网络设备了。甚至有些低等网卡如TP-LINK,只有一个灯,亮代表连通,闪烁代表数据收发。

对于STM32F407开发板上面的RJ45网络变压器插座上面的灯而言,绿灯代表数据收发,长亮的话表示无数据收发,闪烁代表有数据收发。黄灯代表网络速度,长亮代表100M,不亮代表10M。

底层驱动执行情况

为了验证RL-TCPnet底层驱动接口函数是否有问题,专门在ETH_STM32F4xx.c文件中配置了串口调试打印函数:

/***********************************************************************************************************                                      用于本文件的调试**********************************************************************************************************/#if 1#define printf_eth printf#else#define printf_eth(...)#endif

如果底层驱动正常执行了,打印的效果如下:

ping是否正确

ping命令的主要作用是通过发送数据包并接收应答信息来检测两台设备之间的网络是否连通。ping命令成功说明当前主机与目的主机之间存在连通的路径。如果不成功,需要查看网线是否连通、网卡设置是否正确、IP地址是否可用等。测试方法如下:

(1)WIN+R组合键打开“运行”窗口,输入cmd。

(2)弹出的命令窗口中,输入ping armfly,因为在前面的配置中我们使能了NetBIOS局域网域名,并将名字设置为armfly,而且使能了DHCP,通过ping命令还可以获得板子自动获取的IP地址。

(3)输入ping armfly后,回车。

收发相同,没有数据丢失,说明ping命令也是成功的。

电脑端创建一个TCP Client与板子上面的TCP Server通信

具体测试方法,查看第13章的13.6小节即可,因为配套例子实现的功能是一样的。

7.3  STM32F429移植RL-TCPnet协议栈

7.3.1     RL-TCPnet网络协议栈移植

首先准备好一个简单的裸机工程模板,工程模板的制作就不做讲解了,这里的重点是教大家移植RL-TCPnet协议栈。准备好的工程模板如下图所示(大家也可以制作其它任意的工程模板,不限制):

准备好工程模板后,就可以开始移植了。首先要做的就是将所有需要的文件放到工程模板里面。下面分三步跟大家进行说明,当然,不限制必须使用下面的方法添加源码到工程,只要将需要的文件添加到工程模板即可。

第1步:将我们裸机模板中制作好的RL-ARM文件夹复制粘贴到大家准备好的工程模板中。

RL-ARM文件夹中有如下七个文件夹:

Config文件夹用于存放RTX及其中间件的配置文件。

Driver文件夹用于存放中间件的驱动文件,也就是底层移植文件。

RL-CAN文件夹用于存放CAN总线的源码文件。

RL-FlashFS文件夹用于存放文件系统RL-FlashFS的库文件。

RL-RTX文件夹用于存放RTX的源码文件。

RL-TCPnet文件夹用于存放网络协议栈RL-TCPnet的库文件。

RL-USB文件夹用于存放USB协议栈RL-USB的库文件。

也许有用户会问:我们不是仅仅需要移植RL-TCPnet的相关文件就行了吗,为什么把RTX及其所有中间件都添加进来了?这样做的目的是为了以后升级的方便,如果需要添加USB、文件系统、CAN等组件,直接添加到工程即可。

这些文件全部来自MDK4.74的安装目录,库文件位于路径:C:\Keil_v474\ARM\RV31下,而驱动和配置文件位于路径:C:\Keil_v474\ARM\RL下。

第2步:添加RL-TCPnet的库文件、配置文件和驱动文件到工程。

添加完毕后的效果如下:

Net_Config.c和NET_Debug.c在RL-ARM文件夹的Config文件里面。

TCPD_CM3.lib在RL-ARM文件夹的RL-TCPnet文件里面。

ETH_STM32F4xx.c和ETH_STM32F4xx.h在RL-ARM文件夹的Driver文件里面。

第3步:也是最后一步,添加相应的头文件路径。

在原来工程模板的基础上面新添加的三个路径:

至此,RL-TCPnet的移植工作就完成了,剩下就是系统配置和应用了。

7.3.2     RL-TCPnet配置说明(Net_Config.c)

RL-TCPnet的配置工作是通过配置文件Net_Config.c实现。在MDK工程中打开文件Net_Config.c,可以看到下图所示的工程配置向导:

RL-TCPnet要配置的选项非常多,我们这里把几个主要的配置选项简单介绍下。

System Definitions

(1)Local Host Name

局域网域名。

这里起名为armfly,使用局域网域名限制为15个字符。

(2)Memory Pool size

参数范围1536-262144字节。

内存池大小配置,单位字节。另外注意一点,配置向导这里显示的单位是字节,如果看原始定义,MDK会做一个自动的4字节倍数转换,比如我们这里配置的是8192字节,那么原始定义是#define MEM_SIZE  2048,也就是8192/4 = 2048。

(3)Tick Timer interval

可取10,20,25,40,50,100,200,单位ms。

系统滴答时钟间隔,也就是网络协议栈的系统时间基准,默认情况下,取值100ms。

Ethernet Network Interface

以太网接口配置,勾选了此选项就可以配置了,如果没有使能DHCP的话,将使用这里配置的固定IP

(1)MAC Address

局域网内可以随意配置,只要不跟局域网内其它设备的MAC地址冲突即可。

(2)IP Address

IP地址。

(3)Subnet mask

子网掩码。

(4)Default Gateway

默认网关。

Ethernet Network Interface

以太网接口配置,这个配置里面还有如下两项比较重要的配置需要说明。

(1)NetBIOS Name Service

NetBIOS局域网域名服务,这里打上对勾就使能了。这样我们就可以通过前面配置的Local Host Name局域网域名进行访问,而不需要通过IP地址访问了。

(2)Dynaminc Host Configuration

即DHCP,这里打上对勾就使能了。使能了DHCP后,RL-TCPnet就可以从外接的路由器上获得动态IP地址。

UDP Sockets

UDP Sockets配置,打上对勾就使能了此项功能

(1)Number of UDP Sockets

用于配置可创建的UDP Sockets数量。

范围1 – 20。

TCP Sockets

TCP Sockets配置,打上对勾就使能了此项功能

(1)Number of TCP Sockets

用于配置可创建的TCP Sockets数量。

(2)Number of Retries

范围0-20。

用于配置重试次数,TCP数据传输时,如果在设置的重试时间内得不到应答,算一次重试失败,这里就是配置的最大重试次数。

(3)Retry Timeout in seconds

范围1-10,单位秒。

重试时间。如果发送的数据在重试时间内得不到应答,将重新发送数据。

(4)Default Connect Timeout in seconds

范围1-600,单位秒。

用于配置默认的保持连接时间,即我们常说的Keep Alive时间,如果时间到了将断开连接。常用于HTTP Server,Telnet Server等。

(5)Maximum Segment Size

范围536-1460,单位字节。

MSS定义了TCP数据包能够传输的最大数据分段。

(6)Receive Window Size

范围536-65535,单位字节。

TCP接收窗口大小。

7.3.3     RL-TCPnet调试说明(Net_Debug.c)

重要说明,RL-TCPnet的调试是通过串口打印出来的

RL-TCPnet的调试功能是通过配置文件Net_Debug.c实现。在MDK工程中打开文件Net_Debug.c,可以看到下图所示的工程配置向导:

Print Time Stamp

勾选了此选项的话,打印消息时,前面会附带时间信息。

其它所有的选项

默认情况下,所有的调试选项都是关闭的,每个选项有三个调试级别可选择,这里我们以Memory Management Debug为例,点击下拉列表,可以看到里面有Off,Errors only和Full debug三个调试级别可供选择,每个调试选项里面都是这三个级别。

Off:表示关闭此选项的调试功能。

Errors only:表示仅在此选项出错时,将其错误打印出来。

Full debug:表示此选项的全功能调试。

关于调试功能的使用会在第11章详细为大家讲解,移植阶段将其全部关闭即可。

7.3.4     RL-TCPnet应用实例

为了验证移植的RL-TCPnet是否可以使用,需要添加测试代码。下面是编写的测试代码,配套的测试例子完整版是:V6-1000_RL-TCPnet实验_工程移植模板(裸机)。

主函数初始化

/***********************************************************************************************************    函 数 名: main*    功能说明: 标准c程序入口。*    形    参: 无*    返 回 值: 无**********************************************************************************************************/int main (void){   /* 初始化外设 */bsp_Init();/* 进入RL-TCPnet测试函数 */TCPnetTest();}

硬件外设初始化

硬件外设的初始化是在 bsp.c 文件实现:

/***********************************************************************************************************    函 数 名: bsp_Init*    功能说明: 初始化所有的硬件设备。该函数配置CPU寄存器和外设的寄存器并初始化一些全局变量。只需要调用一次*    形    参:无*    返 回 值: 无**********************************************************************************************************/void bsp_Init(void){/*由于ST固件库的启动文件已经执行了CPU系统时钟的初始化,所以不必再次重复配置系统时钟。启动文件配置了CPU主时钟频率、内部Flash访问速度和可选的外部SRAM FSMC初始化。系统时钟缺省配置为168MHz,如果需要更改,可以修改 system_stm32f4xx.c 文件*//* 优先级分组设置为4,可配置0-15级抢占式优先级,0级子优先级,即不存在子优先级。*/NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);SystemCoreClockUpdate();    /* 根据PLL配置更新系统时钟频率变量 SystemCoreClock */bsp_InitUart();    /* 初始化串口 */bsp_InitKey();     /* 初始化按键变量(必须在 bsp_InitTimer() 之前调用) */bsp_InitTimer();    /* 初始化滴答定时器 */bsp_InitExtIO();    /* FMC总线上扩展了32位输出IO, 操作LED等外设必须初始化 */bsp_InitLed();      /* 初始LED指示灯端口 */}

RL-TCPnet功能测试

这里专门创建了一个app_tcpnet_lib.c文件用于RL-TCPnet功能的测试,主要功能是创建了一个TCP Server。

/***********************************************************************************************************                                      用于本文件的调试**********************************************************************************************************/#if 1#define printf_debug printf#else#define printf_debug(...)#endif/***********************************************************************************************************                                      用于本文件的调试**********************************************************************************************************/#define PORT_NUM       1001    /* TCP服务器监听端口号 *//***********************************************************************************************************                                         变量**********************************************************************************************************/uint8_t socket_tcp;/***********************************************************************************************************    函 数 名: tcp_callback*    功能说明: TCP Socket的回调函数*    形    参: soc  TCP Socket类型*             evt  事件类型*             ptr  事件类型是TCP_EVT_DATA,ptr指向的缓冲区记录着接收到的TCP数据,其余事件记录IP地址*             par  事件类型是TCP_EVT_DATA,记录接收到的数据个数,其余事件记录端口号*    返 回 值:**********************************************************************************************************/U16 tcp_callback (U8 soc, U8 evt, U8 *ptr, U16 par){char buf[50];uint16_t i;/* 确保是socket_tcp的回调 */if (soc != socket_tcp){return (0);}switch (evt){/*远程客户端连接消息1、数组ptr存储远程设备的IP地址,par中存储端口号。2、返回数值1允许连接,返回数值0禁止连接。*/case TCP_EVT_CONREQ:sprintf(buf, "远程客户端请求连接IP: %d.%d.%d.%d", ptr[0], ptr[1], ptr[2], ptr[3]);printf_debug("IP:%s  port:%d\r\n", buf, par);return (1);/* 连接终止 */case TCP_EVT_ABORT:break;/* Socket远程连接已经建立 */case TCP_EVT_CONNECT:printf_debug("Socket is connected to remote peer\r\n");break;/* 连接断开 */case TCP_EVT_CLOSE:printf_debug("Connection has been closed\r\n");break;/* 发送的数据收到远程设备应答 */case TCP_EVT_ACK:break;/* 接收到TCP数据帧,ptr指向数据地址,par记录数据长度,单位字节 */case TCP_EVT_DATA:printf_debug("Data length = %d\r\n", par);for(i = 0; i < par; i++){printf_debug("ptr[%d] = %d\r\n", i, ptr[i]);}break;}return (0);}/***********************************************************************************************************    函 数 名: TCP_StatusCheck*    功能说明: 检测TCP的连接状态,主要用于网线插拔的判断*    形    参: 无*    返 回 值: __TRUE  连接*             __FALSE 断开**********************************************************************************************************/uint8_t TCP_StatusCheck(void){uint8_t res;switch (tcp_get_state(socket_tcp)){case TCP_STATE_FREE:case TCP_STATE_CLOSED:res = tcp_listen (socket_tcp, PORT_NUM);printf_debug("tcp listen res = %d\r\n", res);break;case TCP_STATE_LISTEN:break;case TCP_STATE_CONNECT:return (__TRUE);default: break;}return (__FALSE);}/***********************************************************************************************************    函 数 名: tcpnet_poll*    功能说明: 使用TCPnet必须要一直调用的函数*    形    参: 无*    返 回 值: 无**********************************************************************************************************/void tcpnet_poll(void){if(bsp_CheckTimer(0)){/* 此函数坚决不可以放在中断里面跑 */timer_tick ();}main_TcpNet ();}/***********************************************************************************************************    函 数 名: TCPnetTest*    功能说明: TCPnet应用*    形    参: 无*    返 回 值: 无**********************************************************************************************************/void TCPnetTest(void){ int32_t ulCount;uint8_t *sendbuf;uint8_t tcp_status;uint16_t maxlen;uint8_t res;uint8_t ucKeyCode;/* 初始化网络协议栈 */init_TcpNet ();/*创建TCP Socket并创建监听,客户端连接服务器后,10秒内无数据通信将断开连接。但是由于这里使能了TCP_TYPE_KEEP_ALIVE,会一直保持连接,不受10秒的时间限制。*/socket_tcp = tcp_get_socket (TCP_TYPE_SERVER | TCP_TYPE_KEEP_ALIVE, 0, 10, tcp_callback);if(socket_tcp != 0){res = tcp_listen (socket_tcp, PORT_NUM);printf_debug("tcp listen res = %d\r\n", res);}/* 创建一个周期是100ms的软定时器 */bsp_StartAutoTimer(0, 100);while (1){/* TCP轮询 */tcpnet_poll();/* 用于网线插拔的处理 */tcp_status = TCP_StatusCheck();/* 按键消息的处理 */ucKeyCode = bsp_GetKey();if ((ucKeyCode != KEY_NONE)&&(tcp_status == __TRUE)){switch (ucKeyCode){/* K1键按下,给远程TCP客户端发送8字节数据 */case KEY_DOWN_K1:            printf_debug("tcp_get_state(socket_tcp) = %d\r\n", tcp_get_state(socket_tcp));ulCount = 8;do{tcpnet_poll();if (tcp_check_send (socket_tcp) == __TRUE){maxlen = tcp_max_dsize (socket_tcp);ulCount -= maxlen;if(ulCount < 0){/* 这么计算没问题的 */maxlen = ulCount + maxlen;}sendbuf = tcp_get_buf(maxlen);sendbuf[0] = '1';sendbuf[1] = '2';sendbuf[2] = '3';sendbuf[3] = '4';sendbuf[4] = '5';sendbuf[5] = '6';sendbuf[6] = '7';sendbuf[7] = '8';/* 测试发现只能使用获取的内存 */tcp_send (socket_tcp, sendbuf, maxlen);}}while(ulCount > 0);break;/* K2键按下,给远程TCP客户端发送1024字节的数据 */case KEY_DOWN_K2:     printf_debug("tcp_get_state(socket_tcp) = %d\r\n", tcp_get_state(socket_tcp));ulCount = 1024;do{tcpnet_poll();if (tcp_check_send (socket_tcp) == __TRUE){maxlen = tcp_max_dsize (socket_tcp);ulCount -= maxlen;if(ulCount < 0){/* 这么计算没问题的 */maxlen = ulCount + maxlen;}/* 这里仅初始化了每次所发送数据包的前8个字节 */sendbuf = tcp_get_buf(maxlen);sendbuf[0] = 'a';sendbuf[1] = 'b';sendbuf[2] = 'c';sendbuf[3] = 'd';sendbuf[4] = 'e';sendbuf[5] = 'f';sendbuf[6] = 'g';sendbuf[7] = 'h';/* 测试发现只能使用获取的内存 */tcp_send (socket_tcp, sendbuf, maxlen);}}while(ulCount > 0);                     break;/* K3键按下,给远程TCP客户端发送5MB数据 */case KEY_DOWN_K3:            printf_debug("tcp_get_state(socket_tcp) = %d\r\n", tcp_get_state(socket_tcp));ulCount = 5*1024*1024;do{tcpnet_poll();if (tcp_check_send (socket_tcp) == __TRUE){maxlen = tcp_max_dsize (socket_tcp);ulCount -= maxlen;if(ulCount < 0){/* 这么计算没问题的 */maxlen = ulCount + maxlen;}/* 这里仅初始化了每次所发送数据包的前8个字节 */sendbuf = tcp_get_buf(maxlen);sendbuf[0] = 'a';sendbuf[1] = 'b';sendbuf[2] = 'c';sendbuf[3] = 'd';sendbuf[4] = 'e';sendbuf[5] = 'f';sendbuf[6] = 'g';sendbuf[7] = 'h';/* 测试发现只能使用获取的内存 */tcp_send (socket_tcp, sendbuf, maxlen);}}while(ulCount > 0);break;/* 其他的键值不处理 */default:                    break;}}}}

至此,裸机方式移植的RL-TCPnet就可以运行了。

7.3.5     RL-TCPnet实验测试和实验现象

测试前,先将开发板上面的DM9161/9162网口通过网线接到路由器或者交换机上面。

RJ45网络变压器插座上绿灯和黄灯现象

各种网卡、交换机等网络设备都不一样,一般来讲:绿灯分为亮或不亮(代表网络速度),黄灯分为闪烁或不闪烁(代表是否有数据收发)。

绿灯:长亮代表100M; 不亮代表10M。

黄灯:长亮代表无数据收发; 闪烁代表有数据收发。

也有些千兆网卡的灯以颜色区分,不亮代表10M / 绿色代表100M / 黄色代表1000M。现在10M的网络基本看不到了,如果一个灯长亮,基本可以说明100M网络或更高,而另一个灯时而闪烁,那代表有数据收发,具体要看网络设备了。甚至有些低等网卡如TP-LINK,只有一个灯,亮代表连通,闪烁代表数据收发。

对于STM32F429开发板上面的RJ45网络变压器插座上面的灯而言,绿灯代表数据收发,长亮的话表示无数据收发,闪烁代表有数据收发。黄灯代表网络速度,长亮代表100M,不亮代表10M。

底层驱动执行情况

为了验证RL-TCPnet底层驱动接口函数是否有问题,专门在ETH_STM32F4xx.c文件中配置了串口调试打印函数:

/***********************************************************************************************************                                      用于本文件的调试**********************************************************************************************************/#if 1#define printf_eth printf#else#define printf_eth(...)#endif

如果底层驱动正常执行了,打印的效果如下:

ping是否正确

ping命令的主要作用是通过发送数据包并接收应答信息来检测两台设备之间的网络是否连通。ping命令成功说明当前主机与目的主机之间存在连通的路径。如果不成功,需要查看网线是否连通、网卡设置是否正确、IP地址是否可用等。测试方法如下:

(1)WIN+R组合键打开“运行”窗口,输入cmd。

(2)弹出的命令窗口中,输入ping armfly,因为在前面的配置中我们使能了NetBIOS局域网域名,并将名字设置为armfly,而且使能了DHCP,通过ping命令还可以获得板子自动获取的IP地址。

(3)输入ping armfly后,回车。

收发相同,没有数据丢失,说明ping命令也是成功的。

电脑端创建一个TCP Client与板子上面的TCP Server通信

具体测试方法,查看第13章的13.6小节即可,因为配套例子实现的功能是一样的。

7.4  总结

本章节为大家讲解了RL-TCPnet网络协议栈的裸机移植方法,移植相对比较简单。另一个重要内容是Net_Config.c配置向导文件的说明,这个比较重要,初学者要好好熟悉下。

【RL-TCPnet网络教程】第7章 RL-TCPnet网络协议栈移植(裸机)相关推荐

  1. mysql connector安装教程_通过安装MySQL Connector/Net实现VS2017 C#编程连接MySQL数据库-网络教程与技术 -亦是美网络...

    对编程有一定了解的小伙伴都知道,一般情况下使用微软的visual studio进行编程开发都会搭配自家的SQL server.Access数据库,而开发web程序一般情况下PHP搭配MySQL使用,但 ...

  2. 无法建立跟远程计算机的连接,彻底解决win8、win10系统宽带拨号出现“错误720:不能建立到远程计算机的连接”的问题-网络教程与技术 -亦是美网络...

    在网上看到很多小伙伴在使用win8.win10系统后,出现了宽带拨号720错误代码的问题,在winxp.win7时代,一般以7开头的错误代码,都是宽带运营商机房或线路的问题,但是在win8.win10 ...

  3. 开机提示小娜无法在本计算机运行,彻底解决win10系统开机出现关键错误开始菜单和Cortana无法工作的问题-网络教程与技术 -亦是美网络...

    前几天小编发布了一款关于优化win10系统的小工具win10_optimize_tool v1.0,主要作用就是去除win10系统中不必要的服务和启动项以及一些设置的优化,当天就有200个同学进行了下 ...

  4. 计算机网络显示叉叉,解决修复vmware10创建虚拟机本地连接显示叉号无法使用网络的问题-网络教程与技术 -亦是美网络...

    今天使用vmvare10创建了一个虚拟机windows server 2003,但是进去系统后,怎么调试,本地连接都显示红色的叉号,也就是说虚拟机无法使用物理机的网络,刚开始以为是虚拟机本身的问题,结 ...

  5. vmware efi linux,图文详解在vmware11虚拟机上安装以EFI启动模式的win 10 technical preview系统-网络教程与技术 -亦是美网络...

    微软发布win10技术预览版后,很多同学都想尝试win10带来的新体验和新功能,但又苦于win10目前还是测试预览版本,在稳定性.兼容性方面还有待改进,即使我们愿意去当微软的小白鼠,但也不能用测试评估 ...

  6. 虚拟机正在应用计算机设置,vmware虚拟机安装windows 10 technical preview卡在“正在准备设置50%”的解决办法-网络教程与技术 -亦是美网络...

    国庆节刚过,微软如约发布了windows 10 technical preview,俗称windows10技术预览版,这让很多急于尝鲜的同学都跃跃欲试,由于发布的版本为测试评估版本,所以很多同学都采取 ...

  7. tcp 远程服务器,C#编程学习之使用TcpClient / BeginConnect测试远程服务器tcp端口连接-网络教程与技术 -亦是美网络...

    有时候经常需要对一些服务器的端口进行tcp连接测试,通常使用"telnet IP地址 端口号"的方式即可,不能说这种方式不可取,只是使用起来比较麻烦,本着简单好用的目的,不如我们自 ...

  8. 【安富莱】【RL-TCPnet网络教程】第8章 RL-TCPnet网络协议栈移植(RTX)

    第8章        RL-TCPnet网络协议栈移植(RTX) 本章教程为大家讲解RL-TCPnet网络协议栈的RTX操作系统移植方式,学习了第6章讲解的底层驱动接口函数之后,移植就比较容易了,主要 ...

  9. 【RL-TCPnet网络教程】第30章 RL-TCPnet之SNTP网络时间获取

    第30章      RL-TCPnet之SNTP网络时间获取 本章节为大家讲解RL-TCPnet的SNTP应用,学习本章节前,务必要优先学习第29章的NTP基础知识.有了这些基础知识之后,再搞本章节会 ...

最新文章

  1. 手机软件:杀手游戏的法官助手,(人多的时候法官没有辅助,是很难记住各个角色的)...
  2. 我也来说说Dynamic
  3. 批量删除满足指定条件的 SAP CRM One Order 订单
  4. iOS:通过URL构件UIImage
  5. EDA技术使用教程实验
  6. 通俗易懂!视觉slam第九部分——光流(Optical Flow)
  7. 在Unity3D中实现安卓平台的本地通知推送
  8. nyoj936蚂蚁的难题(X)
  9. 更新linux gcc版本到gcc 4.4.2
  10. 数据科学 | Numpy入门教程
  11. batchplot插件用法_Batchplot设置使用指南,实现批量打印CAD图纸
  12. 计算机ps基础知识教案范文,计算机制图软件ps教案内页.doc
  13. ClientToScreen ()与 ScreenToClient()
  14. POI读取doc,docx文档内容
  15. 解决git 提交报fatal: unable to access ' ': The requested URL returned error: 403 错(亲测可行)
  16. POS58票据热敏打印机,怎么用ESC/POS命令控制打印
  17. 2022煤炭生产经营单位(安全生产管理人员)判断题及在线模拟考试
  18. 计算机安全会议2017,科学网-第四届中国密码学与数据安全学术会议(CCDS2017)在衡阳师院召开-李浪的博文...
  19. Weir Flow Control售予First Reserve事宜完成之后更名为Trillium Flow Technologies
  20. LED背光源运用在温控设备上

热门文章

  1. 产品分析报告 | 关于OTA垂直细分市场的情况
  2. MySQL用命令窗口打开
  3. 衡量一款工程监测振弦采集仪是否好用的标准是什么呢?
  4. python+selenium 中input标签 框无法选中和点击、输入等元素操作,如何触发该元素框数据加载
  5. 正则表达式限制用户输入时不能输入空格
  6. el-progress仪表盘进度条底色修改
  7. 入侵检测钻石模型和基于网络的威胁复制
  8. 根据像素和百分比修改图像大小
  9. vue+elementUI实现sku表格自动生成【效果图+源码】
  10. 两款免费好用的手机照片恢复软件