AVRNET源码并移植STM32 ARP和Ethernet的实现过程

控制/MCU

1879人已加入

描述

1.前言

嵌入式以太网开发是一个很有挑战性的工作。通过几个月的学习,个人觉得大致有两条途径。第一条途径,通过高级语言熟悉socket编程,例如C#或C++,熟悉bind,listen,connect,accept等函数,在嵌入式系统中应用 lwIP协议栈。第二种途径,通过分析嵌入式以太网代码,结合TCPIP协议栈规范逐步实践协议栈代码。第一种途径效率高,开发周期短,编写出来的代码性能稳定,第二种途径花的时间长,开发出来的代码功能不完善,但是由于紧紧结合TCPIP规范,可以了解的内容较多,适合学习。本文通过分析和修改AVRNET源码并移植到STM32平台,逐步实现TCPIP协议栈的各个子部分,包括ETHERNET部分,ARP部分,IP部分,ICMP部分,UDP部分,TCP部分和HTTP部分。

本文先实现ethernet部分和ARP部分。

1.2 其他说明

【硬件平台】 STM32+ENC28J60

【编译平台】 IAR 6.5

【IP地址】在实践之前,需要通过ipconfig命令查看PC机的IP地址和MAC地址,AVR的IP地址设定必须和PC机在同一个网段中。例如 :

PC机IP:192.168.1.102

AVR IP: 192.168.1.115

【局域网访问 】

如果有STM32开发板或者其他CPU的开发板的话,可以把开发板的以太网端口连接到路由器LAN端口,只要保证开发板的IP地址和PC机的IP地址在同一个网段。

【广域网访问 】

如果有固定的电信网IP地址的话,可以在路由器中设置静态端口映射,把某个端口映射成局域网内的IP地址和端口号。若没有固定IP地址的话,可使用花生壳软件虚拟一个域名。

2.初始化

以太网协议栈的实现离不开以太网驱动芯片。以太网驱动如何实现请参考——ENC28J60学习笔记。TCPIP的实现离不开两个基本地址,IP地址和MAC地址。在本例中通过以下代码定义和实现。

struct.h头文件中 相关定义:

STM32

main.c函数中的初始化代码:

STM32

MAC地址和IP地址均为自定义的结构体,结构体中为一个字节数组。严格来说,MAC地址不能胡乱定义,应严格遵守相关规范,如果条件允许的话可以使用带有全球唯一的MAC地址的EEPROM芯片。

3.实现ETHERNET

TCPIP是一系列协议的组合,其中最有名的为TCP协议和IP协议。但是千万不要忽视最底层的协议结构——ETHERNET。ETHERNET包括14个字节,称之为以太网首部,其中前六个字节为目标MAC地址,紧着的6个字节为源MAC地址,最后的两个字节为协议类型。以太网的实现通信时必须要知道双方的MAC地址,发送方不明确接收方的地址便通过ARP协议寻找目标MAC地址,如果依然没有结果则可只能把该报文转发给路由器,让路由器处理该报文。协议类型只需关心两种,0800的IP协议和0806的ARP协议。

ethernet.h中相关宏定义

STM32

ethernet.c中相关函数

STM32

eth_generate_header函数实现了填充以太网首部的功能,第一个输入参数为发送接收缓冲区。第二个参数为IP类型,在AVRNET项目中传入的参数不是0800的IP协议类型就是0806的ARP协议类型。第三个参数为目标MAC地址,由于本机MAC地址作为了全局变量,可以在函数内部填充到缓冲区中。

4.实现ARP

为了使用最少的代码实现TCPIP功能,假设通过IP发送报文时已经确认了目标的IP地址,设备总是先被动的通过ARP先让PC机知道其MAC地址,这样当PC机发送UDP或者TCP报文时,在报文中已经包含了PC机的IP地址,设备仅需从rxtx_buffer中取出PC机IP地址。ARP协议是一个找邻居的过程,是一个广播找MAC的过程。发出者通过广播报文确认某个IP的MAC地址。ARP首部包括,2字节硬件类型,2字节协议类型,1字节硬件长度,1字节协议长度,2字节操作码,6字节发送者硬件地址,4字节发送者IP地址,6字节目标硬件地址和4字节目标IP地址。

在使用ARP协议时需要注意三点:

第一,操作码分为两种——ARP请求和ARP响应,ARP请求的编码为1,ARP响应的编码为2,先有请求后有响应。第二,发送ARP协议请求时请求方明确对方IP地址,但是不明确对方MAC地址,所以在请求报文中MAC地址全部以0替代。第三,由于不知道对方的MAC地址,所以只能通过广播帧发送以太网数据,所以以太网首部的前6个字节被FF填充。

为了便于ARP功能的实现,在arp.h文件中定义了以下宏定义

STM32

STM32

在没有操作系统的支持下,一般通过一个无限循环实现子功能的实现。项目中通过某个process不断查询是否存在网卡数据,如果有网卡数据则立刻保存源MAC地址。因为项目中没有维护ARP表,所以必须及时记录发送方的MAC地址,以便向它返回数据。紧着便是查询该报文是否为ARP请求,如果是ARP请求则返回ARP响应。具体代码如下 :

STM32

4.1 查询ARP报文

查询该报文是否是针对设备的ARP报文需要确认三点,第一:确认以太网首部中的协议类型是否为ARP协议类型,ARP协议类型的值为0806H。第二,查询该ARP报文是否为ARP请求,该步骤需要到ARP首部中查询ARP操作码,ARP请求的操作码为1。第三,查询该ARP请求中的MAC地址是否和本机MAC匹配。

最后通过宏定义ARP_DEBUD决定是否通过串口输出发起者IP地址和MAC地址。通过串口打印可以确认该ARP报文的发起者。

STM32

4.2 生成ARP首部

生成ARP首部还是紧紧围绕两个地址展开,即目标MAC地址和目标IP地址,在ARP响应过程中,源MAC地址和IP地址现在转变为了目标MAC地址和IP地址。

STM32

4.3 响应ARP请求

ARP响应可以体现出TCP IP报文产生的基本过程,即层层包装。先包装以太网首部,在包装ARP首部,最后通过ENC28J60发送即可。

STM32

5.测试

PC机通过ping命令发送一个ICMP报文,ping命令是确认网络是否连接的命令,例如发送ping 192.168.1.115,由于PC机不明确该IP地址的MAC地址,所以会先发送一个ARP请求。STM32设备可捕获该ARP请求,并通过串口输出发送ARP请求的设备的IP地址和MAC地址。此时先不用理会是否可以ping通,因为会在以后的文章中实现。

在开始之前可以通过ipconfig /all指令查询本机的IP地址和MAC地址,通过arp -a指令查询PC机中ARP缓冲表。如果有必要可使用arp –d清除缓冲表的所有内容。

STM32

图1 串口打印结果

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分