单芯片解决方案,开启全新体验——W55MH32 高性能以太网单片机
W55MH32是WIZnet重磅推出的高性能以太网单片机,它为用户带来前所未有的集成化体验。这颗芯片将强大的组件集于一身,具体来说,一颗W55MH32内置高性能Arm? Cortex-M3核心,其主频最高可达216MHz;配备1024KB FLASH与96KB SRAM,满足存储与数据处理需求;集成TOE引擎,包含WIZnet全硬件TCP/IP协议栈、内置MAC以及PHY,拥有独立的32KB以太网收发缓存,可供8个独立硬件socket使用。如此配置,真正实现了All-in-One解决方案,为开发者提供极大便利。
在封装规格上,W55MH32提供了两种选择:QFN100和QFN68。
W55MH32L采用QFN100封装版本,尺寸为12x12mm,其资源丰富,专为各种复杂工控场景设计。它拥有66个GPIO、3个ADC、12通道DMA、17个定时器、2个I2C、5个串口、2个SPI接口(其中1个带I2S接口复用)、1个CAN、1个USB2.0以及1个SDIO接口。如此丰富的外设资源,能够轻松应对工业控制中多样化的连接需求,无论是与各类传感器、执行器的通信,还是对复杂工业协议的支持,都能游刃有余,成为复杂工控领域的理想选择。同系列还有QFN68封装的W55MH32Q版本,该版本体积更小,仅为8x8mm,成本低,适合集成度高的网关模组等场景,软件使用方法一致。更多信息和资料请进入http://www.w5500.com/网站或者私信获取。
此外,本W55MH32支持硬件加密算法单元,WIZnet还推出TOE+SSL应用,涵盖TCP SSL、HTTP SSL以及 MQTT SSL等,为网络通信安全再添保障。
为助力开发者快速上手与深入开发,基于W55MH32L这颗芯片,WIZnet精心打造了配套开发板。开发板集成WIZ-Link芯片,借助一根USB C口数据线,就能轻松实现调试、下载以及串口打印日志等功能。开发板将所有外设全部引出,拓展功能也大幅提升,便于开发者全面评估芯片性能。
若您想获取芯片和开发板的更多详细信息,包括产品特性、技术参数以及价格等,欢迎访问官方网页:http://www.w5500.com/,我们期待与您共同探索W55MH32的无限可能。
第十六章 W55MH32 PING示例
本篇文章,我们将详细介绍如何在W55MH32芯片上面实现IPRAW功能,并通过实战例程,为大家讲解如何使用IPRAW模式实现ICMP协议中的PING命令进行网络连通性测试。
该例程用到的其他网络协议,例如DHCP请参考相关章节。有关W55MH32的初始化过程,请参考Network Install章节,这里将不再赘述。
1 IPRAW模式简介
IPRAW模式是W55MH32 TOE提供的一种网络通信模式。在这种模式下,用户可以直接操作IP层数据包,对其进行底层细节的处理,从而支持IP层协议的实现,例如ICMP、IGMP等。
2 PING简介
PING是一个用于测试网络连接性和诊断网络问题的命令。它通过使用ICMP即因特网控制报文协议(Internet Control Message Protocol)发送“回显请求”消息(Echo Request)并等待“回显应答”消息(Echo Reply),来检查目标主机是否可达以及网络的响应时间。PING命令是网络诊断工具中最常见的工具之一,通常用于验证网络连通性、检测网络延迟、排查网络故障等。
3 PING命令特点
1.简单性:PING设计非常简单,通常是基于请求-响应的模式。一个设备发送 PING请求包,另一个设备回应PING响应包。它的开销较小,适合嵌入式设备的网络通信需求。
2.低延迟:由于PING本身非常简洁,因此网络延迟很低,适用于需要实时检测设备状态或维持心跳的场景。
3.状态监测与心跳:PING常用于设备间的心跳检测。
4.无负载数据:PING传输的数据通常没有负载或附加的数据,只有简单的请求和响应字段,因此网络负载非常小。
5.容错性与重试机制:一些实现可能会有超时和重试机制,以确保 PING响应的可靠性。
4 PING应用场景
接下来,我们了解下在W55MH32上,可以使用PING完成哪些操作及应用呢?
网络连通性测试:可以用于测试本地设备与目标设备之间的网络是否连通。
网络故障排查:当网络出现问题,如无法访问某个网站或无法与特定设备进行通信时,可以使用 PING命令来逐步定位问题所在。如果对目标设备的 PING请求超时或丢包严重,说明可能存在网络连接中断、路由器配置错误、防火墙阻挡等问题。
网络设备状态监测:在网络管理中,需要实时监测网络中各种设备(如服务器、路由器、交换机等)的状态。可以定期使用 PING命令对这些设备进行检测,根据是否能够收到回复来判断设备是否正常运行。
5 PING命令基本工作流程
1.发送请求
用户在命令行输入 PING命令及目标主机的 IP地址或域名后,系统开始构建 ICMP回显请求数据包。此数据包包含 ICMP协议头部和一定数据,默认 32字节。随后,该数据包被交给 IP层。
IP层在数据包中添加源 IP地址和目标 IP地址等控制信息,组装成完整的 IP数据包。接着,需获取目标主机的 MAC地址。若目标主机与源主机在同一网段,IP层会查询本地 ARP缓存表,若有对应映射则直接获取 MAC地址;若没有,则发送 ARP请求广播来获取。若目标主机与源主机不在同一网段,IP层会将数据包交给路由处理,由路由器依据路由表转发,路由器同样需获取下一跳的 MAC地址。
数据链路层获取目标 MAC地址后,构建数据帧,将 IP 数据包封装其中,附上源和目的 MAC地址及控制信息,再将数据帧发送出去。
2.接收响应
目标主机接收到数据帧后,检查目的 MAC地址,若相符则接收并提取 IP数据包,交给 IP层。IP层检查无误后,将其交给 ICMP协议。
ICMP协议构建 ICMP回显应答数据包,把请求包中的数据复制过来,再交给 IP层。IP层封装成 IP数据包,数据链路层构建新的数据帧,以源主机为目的地址发送出去。
3.结果处理
源主机收到应答数据包后,数据链路层和 IP层依次处理,将 ICMP应答包交给 ICMP协议。ICMP协议记录当前时间,结合请求时的时间戳计算往返时间。若发送多个请求包,系统会统计未收到应答的数据包数量,计算丢包率。通过往返时间和丢包率,用户可判断网络的连通性和质量。
6报文解析
ICMP(Internet Control Message Protocol,互联网控制消息协议)是用于网络设备间传递控制消息的协议,通常用于网络诊断与错误报告。ICMP报文由类型字段、代码字段、校验和及数据部分构成。常见的 ICMP报文类型包括回显请求(ping)和回显应答、目的不可达、超时等。
以下是 ICMP回显请求和应答报文的基本格式:
字段名称 | 长度(字节) | 回显请求值 | 回显应答值 | 描述 |
类型(Type) | 1 | 8 | 0 | 标识ICMP报文的类型 |
代码(Code) | 1 | 0 | 0 | 与类型字段一起决定ICMP报文具体种类 |
检验和(Checksum) | 2 | 计算得出 | 计算得出 | 用于校验整个ICMP数据包的完整性 |
标识符(Identifier) | 2 | 发送进程ID | 与请求相同 | 用于标识发送端发送的报文 |
序列号 (Sequence Number) |
2 | 递增序号 | 与请求相同 | 用于标识发送端发送的报文的顺序号 |
数据(Data) | 可变 | 用户定义 | 与请求相同 | 包含要返回给发送者的数据 |
|报文解析| Internet Control Message Protocol Type: 8 (Echo (ping) request) (ICMP类型字段为8,表示这是一个回显请求(Ping请求)) Code: 0 (ICMP代码字段为 0,表示回显请求的正常类型) Checksum: 0xe1a7 [correct] (0xe1a7是校验和值,状态为 Good,表示报文有效) [Checksum Status: Good] Identifier (BE): 4661 (0x1235) (表示标识符以大端格式存储,值为 4661(十进制)) Identifier (LE): 13586 (0x3512) (LE表示标识符以小端格式存储,值为 13586) Sequence Number (BE): 17186 (0x4322) (序列号字段,用于标识回显请求的序列) Sequence Number (LE): 8771 (0x2243) (序列号帮助配对请求与响应) [Response frame: 15] (此字段表示接收到的响应帧数量,通常用于指示响应的顺序或超时) Data (128 bytes) (包括用于测试的实际数据或填充数据) |报文原文| 08 00 e1 a7 12 35 43 22
7实现过程
接下来,我们在W55MH32上实现PING命令。
注意:测试实例需要PC端和W55MH32处于同一网段。
do_ping()函数起到了控制PING操作流程的作用,它决定了是否继续进行PING操作,以及在操作完成后关闭Socket连接。
这个函数需要主循环中调用,如下图所示:
while (1) { do_ping(SOCKET_ID, dest_ip, ping_num); } void do_ping(uint8_t sn, uint8_t *remote_ip, uint8_t req_num) { if (req >= req_num) { close(sn); return; } else { ping_count(sn, req_num, remote_ip); } }
do_ping()函数需要传入3个参数,分别是spcket号,目标主机IP,PING请求次数。
如果req大于req_num,说明已经达到了指定的 PING请求次数,此时调用close()函数关闭指定的 Socket连接,然后函数返回,结束本次 PING操作。
如果req小于req_num,则调用ping_count()函数。PING操作主要在ping_count()函数内进行,进入该函数之后会执行以下步骤。
ping_count()函数如下:
void ping_count(uint8_t s, uint16_t pCount, uint8_t *addr) { uint16_t rlen, cnt, i; cnt = 0; for (i = 0; i < pCount + 1; i++) { if (i != 0) { // 输出计数编号 printf("No.%d ", i); } switch (getSn_SR(s)) { case SOCK_CLOSED: close(s); // 创建Socket IINCHIP_WRITE(WZTOE_Sn_PROTO(s), IPPROTO_ICMP); if (Socket(s, Sn_MR_IPRAW, 3000, 0) != 0) { // Socket创建失败(此处可添加错误处理) } // 等待Socket注册完成 while (getSn_SR(s) != SOCK_IPRAW); break; case SOCK_IPRAW: // 发送Ping请求 ping_request(s, addr); req++; // 请求计数递增 // 等待Ping响应 while (1) { // 检查是否有接收数据 if ((rlen = getSn_RX_RSR(s)) > 0) { // 处理Ping响应 ping_reply(s, addr, rlen); rep++; // 响应计数递增 if (ping_reply_received) { break; // 收到响应后退出等待 } } // 超时判断(cnt*5ms >= 5000ms时超时) if (cnt > 1000) { printf("Request Time outrnrn"); cnt = 0; break; } else { cnt++; delay_ms(5); // 5ms延迟 } } break; default: break; } // 当请求数达到设定值时,输出统计结果 if (req >= pCount) { printf("Ping Request = %d, Ping Reply = %d, Lost = %drn", req, rep, req - rep); } } }
进入该函数后,程序会执行一个状态机,首先初始化 cnt为 0并开启 for循环。根据Socket的状态进行不同操作,当Socket为 SOCK_CLOSED时,Socket关闭,设置协议,创建 Sn_MR_IPRAW模式的 Socket,并等待 Socket状态变为 SOCK_IPRAW;当Socket为 SOCK_IPRAW时,发送 ping请求,进入内层 while循环,若接收长度大于 0则处理 ping回复,超过一定时间无回复则输出超时信息,同时会根据 cnt进行计数和延迟处理;默认情况不做处理,满足条件时输出 ping请求、回复和丢失的统计信息。
步骤一:发送 PING请求
ping_request()函数在ping_count()函数中,当Socket状态为SOCK_IPRAW时被调用,从而实现按照设定的次数发送 PING请求。
ping_request()函数如下:
void ping_request(uint8_t s, uint8_t *addr) { uint16_t i; ping_reply_received = 0; // 重置响应接收标志 // 初始化Ping请求包数据 PingRequest.Type = PING_REQUEST; // 设置类型为Ping请求 PingRequest.Code = CODE_ZERO; // 代码字段置0 PingRequest.ID = htons(RandomID++); // 设置ID(网络字节序),ID自增 PingRequest.SeqNum = htons(RandomSeqNum++); // 设置序列号(网络字节序),序列号自增 // 填充数据区(简单填充0-7循环值) for (i = 0; i < BUF_LEN; i++) { PingRequest.Data[i] = (i) % 8; } // 计算校验和 PingRequest.CheckSum = 0; // 先清零校验和字段 PingRequest.CheckSum = htons(checksum((uint8_t *)&PingRequest, sizeof(PingRequest))); // 计算并设置校验和(网络字节序) // 发送Ping请求 if (sendto(s, (uint8_t *)&PingRequest, sizeof(PingRequest), addr, 3000) == 0) { printf("Fail to send ping-reply packetrn"); // 发送失败提示 } else { // 发送成功,输出目标IP printf("Ping:%d.%d.%d.%drn", (addr[0]), (addr[1]), (addr[2]), (addr[3])); } }
该函数ping_request的主要作用是发送一个Ping请求。首先初始化一些请求参数,包括请求类型、代码、随机生成的 ID和序列号,填充数据并计算校验和。接着尝试使用sendto()函数发送请求,根据发送结果输出相应信息,包括失败提示和请求目标的地址信息。
步骤二:接收并解析 PING回复:
ping_reply()函数在ping_count()函数中,当检测到Socket收缓冲区有数据(rlen>0)时被调用,从而实现对接收到的 PING回复进行解析处理。ping_reply()函数负责接收和解析PING回复数据包,根据不同的数据包类型进行相应的处理,并在解析成功后打印相关信息。
ping_reply()函数如下:
void ping_reply(uint8_t s, uint8_t *addr, uint16_t rlen) { uint16_t tmp_checksum; uint16_t len; uint16_t i; uint8_t data_buf[136]; uint16_t port = 3000; PINGMSGR PingReply; // 接收数据 len = recvfrom(s, data_buf, rlen, addr, &port); // 处理Ping响应包(ICMP Echo Reply) if (data_buf[0] == PING_REPLY) { // 解析Ping响应包数据 PingReply.Type = data_buf[0]; PingReply.Code = data_buf[1]; PingReply.CheckSum = (data_buf[3] < 8) + data_buf[2]; // 组合校验和(高位+低位) PingReply.ID = (data_buf[5] < 8) + data_buf[4]; // 组合ID(高位+低位) PingReply.SeqNum = (data_buf[7] < 8) + data_buf[6]; // 组合序列号(高位+低位) // 复制数据部分 for (i = 0; i < len - 8; i++) { PingReply.Data[i] = data_buf[8 + i]; } // 校验和验证 tmp_checksum = ~checksum(data_buf, len); if (tmp_checksum != 0xffff) { printf("tmp_checksum = %xrn", tmp_checksum); // 校验和不匹配提示 } else { // 校验通过,输出响应信息 printf("Reply from %3d.%3d.%3d.%3d ID=%x Byte=%drnrn", (addr[0]), (addr[1]), (addr[2]), (addr[3]), htons(PingReply.ID), (rlen + 6)); ping_reply_received = 1; // 标记已收到响应 } } // 处理Ping请求包(本地作为接收方时收到的ICMP Echo Request) else if (data_buf[0] == PING_REQUEST) { // 解析Ping请求包数据 PingReply.Code = data_buf[1]; PingReply.Type = data_buf[2]; PingReply.CheckSum = (data_buf[3] < 8) + data_buf[2]; PingReply.ID = (data_buf[5] < 8) + data_buf[4]; PingReply.SeqNum = (data_buf[7] < 8) + data_buf[6]; // 复制数据部分 for (i = 0; i < len - 8; i++) { PingReply.Data[i] = data_buf[8 + i]; } // 校验和验证 tmp_checksum = PingReply.CheckSum; PingReply.CheckSum = 0; if (tmp_checksum != PingReply.CheckSum) { printf(" n CheckSum is incorrect %x should be %x n", (tmp_checksum), htons(PingReply.CheckSum)); } else { // 校验通过可在此添加处理逻辑 } // 输出请求信息 printf(" Request from %d.%d.%d.%d ID:%x SeqNum:%x :data size %d bytesrn", (addr[0]), (addr[1]), (addr[2]), (addr[3]), (PingReply.ID), (PingReply.SeqNum), (rlen + 6)); ping_reply_received = 1; // 标记已收到请求 } // 处理未知类型消息 else { printf(" Unknown msg. n"); // 修正原注释拼写错误(Unkonwn -?> Unknown) } }
ping_reply()函数主要用于处理接收的信息。它通过 recvfrom接收数据,根据数据包头信息判断是回复还是请求,提取并解析相关信息,计算校验和并进行检查,根据不同情况输出信息,如错误提示、回复来源信息或请求来源信息等,并设置接收状态标志。
8运行结果
烧录例程运行后,首先进行了PHY链路检测,然后打印设置网络信息,最ping目标IP收到回复,如下图所示:
9总结
本文讲解了如何在 W55MH32芯片上通过 IPRAW模式实现 ICMP协议中的 PING命令,以进行网络连通性测试,通过实战例程展示了从发送 PING请求、接收并解析回复到统计结果的完整过程。文章详细介绍了 IPRAW模式和 PING命令的概念、特点、应用场景、基本工作流程和报文解析,帮助读者理解其在网络测试和故障排查中的实际应用价值。
下一篇文章将聚焦 ARP协议,解析其核心原理及在网络通信中的应用,同时讲解如何在W55MH32上实现 ARP协议,敬请期待!
WIZnet是一家无晶圆厂半导体公司,成立于 1998年。产品包括互联网处理器 iMCU?,它采用 TOE(TCP/IP卸载引擎)技术,基于独特的专利全硬连线 TCP/IP。iMCU?面向各种应用中的嵌入式互联网设备。
WIZnet在全球拥有 70多家分销商,在香港、韩国、美国设有办事处,提供技术支持和产品营销。
香港办事处管理的区域包括:澳大利亚、印度、土耳其、亚洲(韩国和日本除外)。
审核编辑 黄宇
-
嵌入式
+关注
关注
5154文章
19713浏览量
318227 -
Ping
+关注
关注
0文章
70浏览量
16463
发布评论请先 登录
即刻启程,踏上W55MH32高性能以太网单片机学习之路!

WIZnet W55MH32以太网单片机开发教程 第十一章 通用定时器(上篇)

第二章 W55MH32 DHCP示例

第五章 W55MH32 UDP示例

第六章 W55MH32 UDP?Multicast示例

第九章 W55MH32 HTTP Server示例

第十章 W55MH32 SNTP示例

第十一章 W55MH32 SMTP示例

第十二章 W55MH32 NetBIOS示例

第十三章 W55MH32 UPnP端口转发示例

第十四章 W55MH32 TFTP示例

第十五章 W55MH32 SNMP示例

第十七章 W55MH32 ARP示例

第十八章 W55MH32 FTP_Server示例

第二十六章 W55MH32?上位机搜索和配置示例

评论