单片机学习:手把手教你移植LWIP(ENC28J60)

article/2025/11/5 16:32:35

这里只是移植,所以LWIP那么多的协议都不需要管,只要知道哪里需要我们修改,为什么修改就可以了。
这里写图片描述
上图就是整个移植的基本思路,非常清晰的三个层次。其实想想,本质上就是收发数据,只是LWIP协议通过对数据的封装可以实现网络传输。从图中我们就可以看到这里首先需要ENC28J60的驱动,这个驱动需要实现数据的收发,驱动可以在网上找一个。其次就是要移植并修改LWIP协议了。

移植
1.下载LWIP1.4.1和contrib-1.4.1,可以到网上找一个下载,本质上LWIP1.4.1就是LWIP协议的全部,当时我们需要contrib-1.4.1才能完成整个移植。
2.将LWIP1.4.1拷贝到keil新建的工程下面,LWIP下的src是源文件,
这里写图片描述
在keil工程中添加几个组,LWIP-API,LWIP-CORE,LWIP-CORE-IPV4,LWIP-NETIF,LWIP-ARCH。分别将lwip1.4.1下的src中的api全部文件添加到LWIP-API,中,将core中的文件添加到LWIP-CORE中,将core下的ipv4下的文件全部添加到LWIP-CORE-IPV4,将netif中的文件添加到LWIP-NETIF中。到这里lwip的移植就结束了。
这里写图片描述
下面就是将H文件添加在keil中了。
这里写图片描述
3.在lwip的同一目录下,新建ARCH,NET,netconfig文件。在contrib-1.4.1\contrib-1.4.1\ports\win32目录下找到sys_arch.c,在contrib-1.4.1\contrib-1.4.1\ports\win32\include找到lwipopts.h和arch文件夹下的文件,将这些文件都拷贝到keil工程中新建的ARCH目录下。在netconfig目录下新建netconfig.c和netconfig.h文件,在NET目录下新建udp_app.c和udp_app.h文件。
4.好了,移植了这么多的文件也是够乱了,现在来解释一下。ARCH中的cc.h文件里是一些数据类型的定义,为了保证平台的无关性,协议栈只使用了自己定义的数据类型,此外cc中还定义了一些调试信息输出的宏。lwipopts.h定义了内核的预编译的宏,有些文件或服务不需要使用,可以改变这个文件中的宏定义取消编译。这个文件是内核的参数配置文件,非常的重要。sys_arch.c文件只有一个sys_now()函数是有用的,其余的都可以注释掉,这里也要修改一下sys_now()函数。其余的文件都不需要修改。

u32_t sys_now()
{return LocaTime;
}

接着我们需要将ENC28J60的接收发送函数与LWIP协议的底层数据接发接口对接起来。这里对接文件是lwip-1.4.1\src\netif下的ethernetif文件,这个文件定义了五个函数,

static void low_level_init(struct netif *netif)
static err_t low_level_output(struct netif *netif, struct pbuf *p)
static struct pbuf* low_level_input(struct netif *netif)
static void ethernetif_input(struct netif *netif)
err_t ethernetif_init(struct netif *netif)

low_level_init函数初始化mac地址,

static void
low_level_init(struct netif *netif)
{/* set MAC hardware address length */netif->hwaddr_len = ETHARP_HWADDR_LEN;/* set MAC hardware address */netif->hwaddr[0] = macaddress[0];netif->hwaddr[1] = macaddress[1];netif->hwaddr[2] = macaddress[2];netif->hwaddr[3] = macaddress[3];netif->hwaddr[4] = macaddress[4];netif->hwaddr[5] = macaddress[5];/* maximum transfer unit */netif->mtu = netifMTU;/* device capabilities *//* don't set NETIF_FLAG_ETHARP if this device is not an ethernet one */netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_LINK_UP;/* Do whatever else is needed to initialize interface. */  enc28j60Init(netif->hwaddr);
}

我们将ENC28J60的初始化放在这里。
low_level_output函数是传递数据到内核里,我们将enc28j60PacketSend放在里面

static err_t
low_level_output(struct netif *netif, struct pbuf *p)
{struct pbuf *q;unsigned int i = 0;  #if ETH_PAD_SIZEpbuf_header(p, -ETH_PAD_SIZE); /* drop the padding word */
#endiffor(q = p; q != NULL; q = q->next) {/* Send the data from the pbuf to the interface, one pbuf at atime. The size of the data in each pbuf is kept in the ->lenvariable. */memcpy(&Tx_Data_Buf[i], (u8_t*)q->payload, q->len); i = i + q->len;}enc28j60PacketSend(i,Tx_Data_Buf); //·¢ËÍÊý¾Ý°ü#if ETH_PAD_SIZEpbuf_header(p, ETH_PAD_SIZE); /* reclaim the padding word */
#endifLINK_STATS_INC(link.xmit);return ERR_OK;

low_level_input函数接受内核数据,我们将enc28j60PacketReceive放到里面

static struct pbuf *
low_level_input(struct netif *netif)
{struct pbuf *p, *q;u16_t len;unsigned int i =0;/* Obtain the size of the packet and put it into the "len"variable. */len = enc28j60PacketReceive(1520 *4,  Data_Buf);	if(len == 0) return 0;#if ETH_PAD_SIZElen += ETH_PAD_SIZE; /* allow room for Ethernet padding */
#endif/* We allocate a pbuf chain of pbufs from the pool. */p = pbuf_alloc(PBUF_RAW, len, PBUF_POOL);if (p != NULL) {#if ETH_PAD_SIZEpbuf_header(p, -ETH_PAD_SIZE); /* drop the padding word */
#endif/* We iterate over the pbuf chain until we have read the entire* packet into the pbuf. */for(q = p; q != NULL; q = q->next) {/* Read enough bytes to fill this pbuf in the chain. The* available data in the pbuf is given by the q->len* variable.* This does not necessarily have to be a memcpy, you can also preallocate* pbufs for a DMA-enabled MAC and after receiving truncate it to the* actually received size. In this case, ensure the tot_len member of the* pbuf is the sum of the chained pbuf len members.*/memcpy((u8_t*)q->payload, (u8_t*)&Data_Buf[i], q->len);i = i + q->len;}#if ETH_PAD_SIZEpbuf_header(p, ETH_PAD_SIZE); /* reclaim the padding word */
#endifLINK_STATS_INC(link.recv);} else {//drop packet();LINK_STATS_INC(link.memerr);LINK_STATS_INC(link.drop);}return p;  
}

其余的就不需要我们了,这里直接移植的ethernetif文件默认是不编译的,我们将#if 0给取消掉。
新建的netconfig文件就是配置网络参数了,比如ip地址,mac地址,还有最重要的LwIP_Periodic_Handle函数,处理内核的定时函数,如何TCP定时,ARP定时。定时采用systick进行定时,每20ms中断一次,执行一次LwIP_Periodic_Handle。
基本上lwip的移植就结束了。


http://chatgpt.dhexx.cn/article/TSMnyq7q.shtml

相关文章

单片机 STM32 HAL 网络模块 ENC28J60

文章目录 一、 简介二、特性三、示例代码 一、 简介 ENC28J60 是带有行业标准串行外设接口(Serial Peripheral Interface,SPI)的独立以太网控制器。它可作为任何配备有 SPI 的控制器的以太网接口。ENC28J60 符合IEEE 802.3的全部规范&#x…

ENC28J60 简介

单片机以太网方案 单片机想要使用以太网的话,通常有以下几种方案: 如果 MCU 内部集成 MAC 控制器,则只需外接一个 PHY 芯片就可以了如果 MCU 内部没有 MAC 控制器,需要外接 MAC 芯片和 PHY 芯片,这两颗芯片可以分立也…

c语言程序设计 国外教材,标准C程序设计(第7版国外计算机科学经典教材)

导语 内容提要 E.巴拉古路萨米著李周芳译的《标准C程序设计(第7版国外计算机科学经典教材)》专门用于满足渴望成为程序员的学生,最新版按照Bloom分类法所定的学习目标来呈现主题,支持基于学习的成果。本书解释了基本概念和高级内容,且主要关注…

学习C语言的教材

作者: 阮一峰 日期: 2011年9月18日 我的C语言是自学的,这些年看过不少教材。 下面,我对其中一些教材做个点评。 1. How to Think Like a Computer Scientist: C version 这是我读过最易懂的C语言教材。 虽然它只讲解最基本的语法&…

新概念c语言周二强07答案,新概念C语言能力教程(普通高等教育十二五规划教材)...

导语 内容提要 周二强编写的《新概念C语言能力教程(普通高等教育十二五规划教材)》以先进的教学理念为指导,以培养编程能力与学习能力为目标,从全新的角度解析了C语言,高屋建瓴地阐释了C语言学习中的诸多难点,对序列点、指针等概念…

计算机程序c语言教材,全国计算机等级考试二级C语言程序设计教材(2018年版)...

2018年计算机二级教材:C语言程序设计 简介 书名:全国计算机等级考试二级教程——C语言程序设计(2018年版) 作者:教育部考试中心 出版社:高等教育出版社 出版时间:2017年11月 ISBN:9787040488524 定价&#…

树莓派(0)C语言教材学习

学习日记的功能主要是记录学习C语言的知识还有难上手的地方,之后会记录配置树莓派环境还有设计linux环境下C语言的实验题目 目前在K&R的《C语言程序设计》教材学习,前面的内容没有难度,基本上和高级程序设计语言的学习思路一样&#xff0…

国内C语言教材中几种值得商榷的说法

作者:巨同升 “C语言程序设计”这门课程在国内高校普遍开设已有近三十年,课程的建设和研究取得了长足的进步,涌现出了数量众多、各具特色的C语言教材。尽管如此,在许多C语言教材中还或多或少地存在着一些不准确甚至是值得商榷的说…

既然谭浩强的C语言教材不好,那应该选什么书作C语言教材?

易道云学院C语言/C语法学习不在于你看了多少书,而在于你实实在在写了多少有效代码。易道云学院 回到这个问题,其实我个人认为,看什么样的书,也是需要应对不一样的场景易道云学院去有目的地涉猎。我暂时想到了几种情况,…

c语言课本答案解析宋士银,c语言教材

22.40定价:28.00(8折) /2007-02-01 根据教育部高等学校计算机科学与技术教学指导委员会提出的《关于进一步加强高等学校计算机基础教学的意见暨计算机基础课程教学基本要求》的有关要求,编者组织了一批多年工作在教学一线且有丰富教学经验的教师编写了《…

C语言的环境变量配置

一、编辑器选择与安装 这边选用的编辑器是比较常见的devc,当然vscode和vc也都可以用来学习C语言,要软件和C语言环境变量的话可以加QQ群:373270625 第一步全部默认勾选就行无脑下一步 第二步选择一个放软件的文件夹,我这边选择的…

Jmeter环境变量配置

解压后 电脑桌面----》“计算机”图标----》鼠标右键选择“属性”----》点击高级系统设置----》高级---》环境变量页面 1.在系统变量框,点击“新建”,建立一个变量:JMETER_HOME,值为你解压的jmeter安装路径 2.配置classpath变量&#xff0c…

java设置环境变量jre_JRE环境变量配置图解

JRE(Java Runtime Environment,Java运行环境),运行JAVA程序所必须的环境的集合,包含JVM标准实现及Java核心类库。如果大家需要查看JRE环境变量配置图解过程,看完本文你的问题也就迎刃而解了。 我们这里使用jre-7u67-windows-i586的32位JRE安装包,大小只有20多M,比JDK7小了…

Anaconda环境变量配置

Anaconda Anaconda环境变量配置 学习自用 解决问题 例如在VSCode中使用虚拟环境运行python代码导致的问题 *ImportError: DLL load failed while importing win32gui*新建系统变量,添加Anaconda安装路径 以后想用其他环境直接修改变量值就可以了 新建环境变量 变…

npm环境变量配置

NPM 使用介绍 NPM是随同NodeJS一起安装的包管理工具,能解决NodeJS代码部署上的很多问题,常见的使用场景有以下几种: 允许用户从NPM服务器下载别人编写的第三方包到本地使用。允许用户从NPM服务器下载并安装别人编写的命令行程序到本地使用。…

windows 10中R的环境变量配置

创建于:20221113 修改于:20221113 文章目录 1、情况介绍2、环境变量配置3、参考资料 1、情况介绍 win10 64bit系统中,已经安装好了R,Rtools ,Rstudio,并且已经配置了java开发环境。 上述两个链接讲述的非…

SVN环境变量配置

1、环境变量配置 2、复制地址 3、环境变量配置: 步骤: 右击电脑属性、高级系统设置、高级、环境变量、 系统变量、找到Path、双击进入、新建粘贴到刚刚复制的地址,确定即可。

Mac环境变量配置(Java)

1.打开终端: 2.输入命令:【/usr/libexec/java_home -V】,查看默认的jdk下载地址(绿色下划线的就是jdk默认路径)(注意⚠️:命令行终端是区分大小写的【-v 是不对的,必须是大写 -V】) …

adb环境变量配置

关于adb 什么ADB如何配置CMD命令窗口的使用 什么是adb 首先,我们先说说,adb是什么,他的全称叫安卓调试桥,也就是Android debug bridge ,它是连接Windows平台和安卓手机之间的软件调试工具,很适合软件开发…

Android环境变量配置

1 先再到本地SDK位置,C:\Users\27322\AppData\Local\Android\Sdk ​ 本地SDK路径,android studio安装默认路径 2 新建环境变量:ANDROID_HOME,值:C:\Users\27322\AppData\Local\Android\Sdk ​ 右键我的电脑&#xff0…