MCU通过以太网通信有很多种方式,有的内部自带以太网接口(如stm32f107的某些型号);如果没有,也可以在外围连接以太网芯片来实现。外接的以太网芯片,又分为带网络协议栈和不带协议栈的,带网络协议栈的典型如W5500,不带网络协议栈的典型的如EN28J60、DM9000等。
使用自带以太网接口、或是使用不带网络协议栈的芯片时,都要由软件来实现网络协议栈。通常来讲,自带网络协议栈的芯片使用简单,但灵活性差一些,由软件实现网络协议栈灵活性高,但实现复杂。
本节我们来学习使用ENC28J60芯片来实现以太网通信,网络协议栈使用一套极其精简的代码,只实现基本的ping、TCP、UDP通信功能。
本节的例子使用的开发环境是cubemx 6.1.0,pack版本是1.8.0;硬件使用的是stm32f103VET6和ENC28J60。
1)cubemx工程配置
先看一下硬件连接图:
ENC28J60这款芯片可实现10M的以太网通信,与MCU是使用SPI接口,接在SPI1口上,使用软件控制CS线,另外还连接了RST复位引脚、INT中断引脚。
配置SPI接口时,在cubemx中如下图设置:
选择全双工,配置为速率为不大于20M(因为ENC28J60的SPI接口时钟最大20M)
配置GPIO,PB7为输出CS、PE1为输出RST、PA6为输入INT:
把堆栈设置大一些,因为后面在代码中会申请比较大的内存变量:
到这里,cubemx里的设置就已经完成了,现在可以生成keil的代码工程了。
2)keil中的代码编写
打开生成的keil工程,添加一些代码源文件:
(可在文末关注公众号获取完整代码)
添加完成后,我们来看这里的代码实现过程。
这一套函数最早是老外在AVR单片机上实现的,代码以及其精简的函数实现了网络协议栈。
spi_enc28j60.c中实现了芯片和硬件SPI的接口;
enc28j60.c实现了芯片的初始化、网络数据包的收发等函数;
ip_arp_udp_tcp.c实现了网络协议栈;
web_sever.c则是实现了应用层的使用函数。
移植到我们的硬件环境中,只需要修改spi_enc28j60.c这个文件相关的函数即可。
spi_enc28j60.c文件里实现的是spi接口的初始化和访问enc28j60的基本读写函数:
初始化函数中,由于cubemx自动生成的代码中已有GPIO和SPI接口的初始化,所以这里可以跳过,只拉低一下复位线PE1即可。
SPI1_ReadWrite这个函数,需要实现的是一个字节的读写,我们直接调用HAL库函数HAL_SPI_TransmitReceive实现。
另外,在enc28j60.h文件中,实现片选线的拉高和拉低定义:
这样就移植完毕了。
Main函数中,只需要先调用初始化函数SPI_Enc28j60_Init,就可以调用应用层的函数了。
应用层的函数是在web_sever.c文件中的Web_Server函数实现的,它的主要处理过程如下:
先设置MAC地址、IP地址,然后进入while(1)循环,在循环中判断enc28j60是否收到数据,如果收到,则通过下面的几个if去判断收到的是什么类型的数据,再对应处理。
以收到UDP数据包处理为例,讲解处理过程:
收到数据后,先判断ip是否相符,不一致则返回;
接收的数据被存放在 buf 数组中,软件通过判断 buf 数组里的IP_PROTO_P这个字段来确定是否是UDP数据包,如果是,则再判断是否是1200端口收到的;
都符合则需要处理,处理过程就是把发来的数据都返回:先获取数据长度,再缓存,最后通过make_udp_reply_from_request函数发送回去。
Tcp的处理是实现了一个网页,可以通过计算机端访问,代码较长,这里就不放了,有兴趣可以获取源码了解。
3)运行测试程序
将代码编译、下载到开发板运行,开发板通过网线连接到计算机。
计算机端设置IP地址为192.168.1.18(只要和开发板的ip地址192.168.1.15在一个网段就行)。
测试网络是否连通:
在终端上输入ping 192.168.1.15:
可以看到ping有回复,说明网络已经可以通信了。
测试udp通信:
使用网络调试助手,设置udp连接,远端ip为192.168.1.15,远程端口为1200,本地端口也设置为1200。
连接后,发送数据,可以看到接收到同样的数据回复。
测试TCP功能(实现网页):
在计算机上用浏览器打开网址:192.168.1.15/123456,可以打开一个网页,如下图所示,点击打开LED/关闭LED,网址后会多出现一个 /0或/1,通过这个网址的变化可以控制开发板上的灯亮灭。该网页是应用层通过tcp按http协议格式发送的数据,所以tcp通信也是成功的。
4)注意事项
a) enc28j60的功耗不小,在使用时需要供电能力足够,如果仅使用usb接口的5v给开发板供电,有可能会通信不成功;
b) 本节中的例子,是用软件实现了一个极其精简的网络协议栈,有很多功能缺失,也有很多容错处理不完善,只能用于演示试验,做产品时建议移植相对完善的网络协议栈,如LwIP、uIP等都适用于小资源的MCU,本系列文章后续会有讲解。
好了,本节使用enc28j60实现以太网通信的功能就讲到这里了。
欢迎关注我的公众号,可留言“资料”获取相关源码和资料: