LwIP应用开发笔记之一:LwIP无操作系统基本移植
现在,TCP/IP协议的应用无处不在。随着物联网的火爆,嵌入式领域使用TCP/IP协议进行通讯也越来越广泛。在我们的相关产品中,也都有应用,所以我们结合应用实际对相关应用作相应的总结。
1、技术准备
我们采用的开发平台是STM32F407和LwIP协议栈。在开始之前,我们需要做必要的准备工作。
首先要获得LwIP的源码,在网上有很多,不同版本及不同平台的都有,不过我们还是建议直接从官方网站获得。其官方网站如下:
http://savannah.nongnu.org/projects/lwip/
其次,需要硬件平台,我们采用了STM32F407ZG+DM9161的网络接口方式,这并不是必须的,其他硬件平台也是一样的。
最后,因为我们后面要在操作系统下移植,采用的操作系统是FreeRTOS,所以还需下载FreeRTOS的源码。同样简易从官网下载:
https://www.freertos.org/index.html
2、LwIP简要说明
LwIP是一款免费的TCP/IP协议栈,但它的功能趋势十分完备。LwIP 具有三种应用编程接口 (API):
- Raw API:为原始的 LwIP API。它通过事件回调机制进行应用开发。该 API 提供了最好的性能和优化的代码长度,但增加了应用开发的复杂性。
- Netconn API:为高层有序 API,需要实时操作系统 (RTOS)的支持 (提供进程间通讯的方法)。 Netconn API 支持多线程工作。
- BSD Socket API:类似 Berkeley 的套接字 API (开发于 Netconn API 之上) 。
对于以上三种接口,前一种只需要裸机即可调用,后两种需要操作系统才能调用。所以据此LwIP存在两种移植方式:一是,只移植内核,此时应用程序的编写只能基于RAW/Callback API进行。二是,移植内核和上层API,此时应用程序编写可以使用3种API,即:RAW/Callback API、Sequential API和Socket API。
3、LwIP的无操作系统基本移植
在移植之前,我们需要对源码有一些了解,以及清楚API如何使用,才能进行很好的移植。在源码的文件中有两个文本文件:rawapi.txt和sys_arch.txt。在rawapi.txt文件中,作者说明了怎样使用协议栈的Raw/Callback API进行编程。而在sys_arch.txt文件中,说明了如何移植,规定了移植者需要实现的函数宏定义等。接下来我们就据此来实现移植。
其实,进行无操作系统的移植,所需要做的工作并不多,一是需要定义几个协议在所需要的头文件。二是需要编写网卡的驱动程序,而写驱动程序是主要工作所在。
首先我们说需要定义的头文件。根据sys_arch.txt文件中的要求,我们需要实现cc.h、lwipopts.h和perf.h三个头文件,线描述如下:
- cc.h文件主要完成协议栈内部使用的数据类型的定义,以保证平台无关性。
- lwipopts.h文件包含了用户对协议栈内核参数进行的配置。
- perf.h文件是实现与系统统计和测量相关的功能。
其次要实现网卡的驱动,事实上我们采用STM32F407自带的网卡,以及ST的开发库时,驱动大部分都写好了,我们只需要完成硬件IO部分的配置以及一些必要的参数配置就可以了。
接下来就是实现几个必要的函数,按照LwIP作者给出的模板,需要实现5个函数如下:
- low_level_init 调用以太网驱动函数,初始化 STM32F4xx 和 STM32F2x7xx 以太网外设
- low_level_output 调用以太网驱动函数以发送以太网包
- low_level_input 调用以太网驱动函数以接收以太网包
- ethernetif_init 初始化网络接口结构 (netif)并调用low_level_init以初始化以太网外设
- ethernetif_input 调用low_level_input接收包,然后将其提供给LwIP栈
以上这些函数都实现后,我们需要使协议运转起来,所以我们还需要做两件事,一是对协议及网卡初始化;二是实现对数据的轮询,当然也可使用中断方式,不过在这里我们使用查询方式。
初始化部分,除了初始化默认网络接口的参数外,需要注册2个函数,一是初始化网络接口函数ethernetif_init;一是数据包接收函数ethernet_input。实现如下:
/* LwIP初始化配置 */
void LWIP_Init_Configuration(void)
{
/* IP赋值 */
IP_ADDRESS[] = ;
IP_ADDRESS[] = ;
IP_ADDRESS[] = ;
IP_ADDRESS[] = ;
NETMASK_ADDRESS[] = ;
NETMASK_ADDRESS[] = ;
NETMASK_ADDRESS[] = ;
NETMASK_ADDRESS[] = ;
GATEWAY_ADDRESS[] = ;
GATEWAY_ADDRESS[] = ;
GATEWAY_ADDRESS[] = ;
GATEWAY_ADDRESS[] = ; /* 在无操作系统环境下初始化LwIP协议栈 */
lwip_init(); /* 固定IP地址初始化(IPv4) */
IP4_ADDR(&ipaddr, IP_ADDRESS[], IP_ADDRESS[], IP_ADDRESS[], IP_ADDRESS[]);
IP4_ADDR(&netmask, NETMASK_ADDRESS[], NETMASK_ADDRESS[] , NETMASK_ADDRESS[], NETMASK_ADDRESS[]);
IP4_ADDR(&gw, GATEWAY_ADDRESS[], GATEWAY_ADDRESS[], GATEWAY_ADDRESS[], GATEWAY_ADDRESS[]); /* 添加无操作系统的网络接口参数 */
netif_add(&gnetif, &ipaddr, &netmask, &gw, NULL, ðernetif_init, ðernet_input); /* 注册缺省的网络接口 */
netif_set_default(&gnetif); if (netif_is_link_up(&gnetif))
{
/* 连接正常时,启用网络接口 */
netif_set_up(&gnetif);
}
else
{
/* 连接故障时,停止网络接口 */
netif_set_down(&gnetif);
} }
初始化完成需要调用ethernetif_input接收数据才能实现通讯,其实现很简单。
/* 以太网轮循处理函数 */
void EthernetProcess(void)
{
ethernetif_input(&gnetif); /* 无操作系统超时检测 */
sys_check_timeouts(); }
这样每次查询都会检查是否有数据收到,并通过ethernet_input函数发送到协议栈进行处理。其实,可能大家会发现还有一个sys_check_timeouts()函数,它是一个超时检测函数,要求调用一个名为sys_now()的函数来返回系统时钟,而sys_now()函数是我们需要实现的,各个系统复杂程度不同,在这里我们使用了STM32的HAL库,所以实现就很简单了。
4、结论
前面已经完成了无操作系统LwIP的移植,那怎么知道我们的移植是否成功呢?接下来我们对它进行必要的验证。
首先我们查看目标板在网络上的配置是否正确。我们打开命令行窗口,运行ipconfig命令,查看MAC地址和IP地址配置:
我们配置的MAC地址00:08:E1:00:00:00和IP地址192.168.2.110显示正常。接下来我们采用ping命令测试网络链接:
上图显示网络连接正常,说明我们的LwIP在无操作系统情况下移植正常。
欢迎关注:
LwIP应用开发笔记之一:LwIP无操作系统基本移植的更多相关文章
- LwIP应用开发笔记之四:LwIP无操作系统TFTP服务器
前面我们已经实现了UDP的回环客户端和回环服务器的简单应用,接下来我们实现一个基于UDP的简单文件传输协议TFTP. 1.TFTP协议简介 TFTP是TCP/IP协议族中的一个用来在客户机与服务器之间 ...
- LwIP应用开发笔记之七:LwIP无操作系统HTTP服务器
前面我们实现了TCP服务器和客户端的简单应用,接下来我们实现一个基于TCP协议的应用协议,那就是HTTP超文本传输协议 1. HTTP协议简介 超文本传输协议(Hyper Text Transf ...
- LwIP应用开发笔记之八:LwIP无操作系统HTTP客户端
前面我们实现了TCP服务器和客户端的简单应用,接下来我们实现一个基于TCP协议的应用协议,那就是HTTP超文本传输协议 1.HTTP协议简介 超文本传输协议(Hyper Text Transfer P ...
- LwIP应用开发笔记之六:LwIP无操作系统TCP客户端
上一篇我们基于LwIP协议栈的RAW API实现了一个TCP服务器的简单应用,接下来一节我们来实现一个TCP客户端的简单应用. 1.TCP简述 TCP(Transmission Control Pro ...
- LwIP应用开发笔记之五:LwIP无操作系统TCP服务器
前面我们实现了UDP服务器及客户端以及基于其上的TFTP应用服务器.接下来我们将实现同样广泛应用的TCP协议各类应用. 1.TCP简述 TCP(Transmission Control Protoco ...
- LwIP应用开发笔记之二:LwIP无操作系统UDP服务器
前面我们已经完成了LwIP协议栈基于逻辑的基本移植,在这一节我们将以RAW API来实现UDP服务器. 1.UDP协议简述 UDP协议全称是用户数据报协议,在网络中它与TCP协议一样用于处理数据包, ...
- LwIP应用开发笔记之三:LwIP无操作系统UDP客户端
前一节我们实现了基于RAW API的UDP服务器,在接下来,我们进一步利用RAW API实现UDP客户端. 1.UDP协议简述 UDP协议全称是用户数据报协议,在网络中它与TCP协议一样用于处理数据包 ...
- linux学习笔记1:无操作系统时LED驱动
- LwIP协议栈开发嵌入式网络的三种方法分析
LwIP协议栈开发嵌入式网络的三种方法分析 摘要 轻量级的TCP/IP协议栈LwIP,提供了三种应用程序设计方法,且很容易被移植到多任务的操作系统中.本文结合μC/OS-II这一实时操作系统,以 ...
随机推荐
- HTTP 包体
HTTP包体:承载的消息内容 两种传输HTTP包体的方式 定长包体: 不定长包体: HTML FORM表单 HTML FORM表单提交请求时的关键属性 HTML FORM表单提交请求时的关键属性 Mu ...
- select下拉选中显示对应的div隐藏不相关的div
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...
- SQL Server Default Trace查看是谁对数据库进行了DDL操作
在我们的工作中可能会遇到这样一种情形.由于数据库中某些对象被altered/created/deleted,造成我们的应用程序crash. 当我们把问题解决之后,老板可能会问发生了什么?为什么会这样? ...
- YAML_14 tags给指定的任务定义一个调用标识,以后不用重复整个过程,只需要执行tags标签的部分
ansible]# vim adhttp.yml --- - hosts: cache remote_user: root tasks: - copy: src: /r ...
- cube.js 学习(四)cube.js cube 说明
cube 是cube.js data schema 的核心,里面定义了生成sql 的说明 一个比较全的schema 例子 cube(`Users`, { sql: `select * from u ...
- h5页面滑动卡顿解决方法
解决方式: 给滚动的元素加样式:-webkit-overflow-scrolling: touch; -webkit-overflow-scrolling(允许独立的滚动区域和触摸回弹) 如果值为au ...
- noi.ac #36 模拟
\(des\) 存在 \(1000 \times 1000\) 的矩阵,保证元素互不相同,\(2e5\) 次询问,每次询 问给定 \(x, y\) 问存在多少点 \((a, b)\) 满足该元素是 \ ...
- 如何在Eclipse中写Processing的sketch
有时候人们需要写更复杂的sketch,此时Processing提供的IDE就略显单薄,下面将介绍如何在eclipse中开发Processing. 一共分4步: 一.搭建环境:安装JRE.JDK.Ecl ...
- 如何修复GitKraken Inotify Limit Error\idea erro - 升级Ubuntu / Linux inotify限制
GitKraken是一个非常优秀的Git客户端.如果您是软件开发人员,那么您绝对应该试试GitKraken.今天我去了我的一个存储库做了一些提交,但是GitKraken告诉我它已经得到了Inotify ...
- ShellExecute打开文件,打开文件夹的用法
转自https://www.cnblogs.com/nxopen2018/p/11070031.html //方法1 //转换 //char msg[256]; //sprintf_s(msg, &q ...