继续创造,加快生长!这是我参与「日新计划 10 月更文应战」的第1天,点击查看活动概况
一、ETH简介
STM32F4xx 系列操控器内部集成了一个以太网外设,它实践是一个通过 DMA 操控器进行介质拜访操控(MAC),它的功用就是完成 MAC 层的使命。借助以太网外设,STM32F4xx 操控器能够通过 ETH 外设依照 IEEE 802.3-2002 标准发送和接纳 MAC 数据包。ETH 内部自带专用的 DMA 操控器用于 MAC,ETH 支撑两个工业标准接口介质独立接口(MII)和简化介质独立接口(RMII)用于与外部 PHY 芯片衔接。MII 和 RMII 接口用于 MAC 数据包传输,ETH 还集成了站办理接口(SMI)接口专门用于与外部 PHY 通讯,用于拜访 PHY 芯片寄存器。
物理层定义了以太网运用的传输介质、传输速度、数据编码办法和冲突检测机制,PHY 芯片是物理层功用完成的实体,日子中常用水晶头网线+水晶头插座+PHY 组合构成了物理层。
ETH 有专用的 DMA 操控器,它通过 AHB 主从接口与内核和存储器相连,AHB 主接口用于操控数据传输,而 AHB 从接口用于拜访“操控与状况寄存器”(CSR)空间。在进行数据发送是,先将数据有存储器以 DMA 传输到发送 TX FIFO 进行缓冲,然后由 MAC 内核发送;接纳数据时,RX FIFO 先接纳以太网数据帧,再由 DMA 传输至存储器。ETH 系统功用框图见下图。
二、LwIP简介
LwIP 是 Light Weight Internet Protocol 的缩写,是由瑞士计算机科学院 Adam Dunkels等开发的适用于嵌入式领域的开源轻量级 TCP/IP 协议栈。它能够移植到含有操作系统的渠道中,也能够在无操作系统的渠道下运行。由于它开源、占用的 RAM 和 ROM 比较少、支撑较为完整的 TCP/IP 协议、且非常便于裁剪、调试,被广泛运用在中低端的 32 位操控器渠道。
针对 LwIP 运用开发了测试渠道,其中有一个是在 STM32F4x7 系列操控器运行的 (文件编号为:STSW-STM32070)。
- LwIP官网:savannah.nongnu.org/projects/lw…
2.1 静态IP
静态IP地址(又称固定IP地址)是长时刻分配给一台计算机或网络设备运用的 IP 地址。一般来说,一般是特别的服务器或许采用专线上网的计算机才拥有固定的 IP 地址而且需求比较贵重的费用。静态IP是二级路由有必要用到的。
静态IP是能够直接上网的IP段,该IP在ISP装机时会划分一个IP地址给你,让计算机在衔接网络时不再主动获取网络地址,避免了网络衔接上的困扰,宽带运营商会供给一根一个IP地址、子网掩码、网关和DNS服务器地址给用户。在未运用路由器的情况下,只需求把这根入户网线衔接到电脑上,而且手动设置电脑上的IP地址,这样电脑才能上网。静态IP地址不会改变,而且首要用于互联网上的网站运用或服务。一些游戏者和运用VOIP的人往往也倾向于挑选静态IP地址,由于交流更简单。
动态IP地址和静态IP地址比较。
- 其一:为了节约lP资源,通过电话拨号、ADSL虚拟拨号等办法上网的机器是不分配固定IP地址的。而是由ISP动态临时分配,进步lP地址利用率;
- 其二:在局域网中为了客户机设置简洁,也常采用动态分配IP地址,这意味着您每次衔接互联网时得到的lP地址是不同的。尽管这不影响您拜访互联网,可是您的朋友、用户却不能拜访到您。由于,他们不知道您的计算机在哪里。这就像每个人都有一部电话,但您的电话号码天天都在改变。
三、LAN8720A简介
LAN8720A 是 SMSC 公司(已被 Microchip 公司收购)设计的一个体积小、功耗低、全能型 10/100Mbps 的以太网物理层(PHY)收发器。LAN8720A 总共只要 24Pin,
仅支撑 RMII 接口
。由它组成的网络结构见下图 LAN8720A 通过 RMII 与 MAC 衔接。RJ45 是网络插座,在与 LAN8720A 衔接之间还需求一个变压器,所以一般运用带电压转换和 LED 指示灯的 HY911105A 型号的插座。一般来说,
有必要为运用 RMII 接口的 PHY 供给 50MHz 的时钟源输入到 REF_CLK 引脚
,不过LAN8720A 内部集成 PLL,能够将 25MHz 的时钟源陪频到 50MHz 并在指定引脚输出该时钟,所以咱们能够直接使其与 REF_CLK 衔接到达供给 50MHz 时钟的作用
。
-
PHY 芯片地址设置 LAN8720A 能够通过 PHYAD0 引脚来装备,该引脚与 RXER 引脚复用,芯片内部自带下拉电阻,当硬复位完毕后, LAN8720A 会读取该引脚电平,作为器材的 SMI 地址,接下拉电阻时(浮空也能够,由于芯片内部自带了下拉电阻),设置 SMI 地址为 0,当外接上拉电阻后,能够设置为 1。
-
nINT/REFCLKO 引脚功用装备 nINT/REFCLKO 引脚用于 RMII 接口中 REF_CLK 信号线
-
当 nINTSEL 引脚为低电平时
,它也能够被设置成 50MHz 时钟输出,这样能够直接与 STM32F4xx 的 REF_CLK 引脚衔接为其供给 50MHz 时钟源,这种形式要求为 XTAL1 与 XTAL2 之间或为 XTAL1/CLKIN 供给 25MHz 时钟
,由 LAN8720A 内部 PLL 电路陪频得到 50MHz 时钟,此刻 nIN/REFCLKO 引脚的中止功用不可用,用于 50MHz 时钟输出。 -
当 nINTSEL 引脚为高电平时
,LAN8720A 被设置为时钟输入,即外部时钟源直接供给 50MHz 时钟
接入 STM32F4xx 的 REF_CLK 引脚和 LAN8720A 的 XTAL1/CLKIN 引脚,此刻 nINT/REFCLKO 可用于中止功用
。
nINTSEL 与 LED2 引脚共用,一般运用下拉,LAN8720A 外接 25MHz 石英晶振,通过内部陪频到 50MHz,然后通过 REFCLKO 引脚,输出 50MHz 参阅时钟给 MAC 操控器。这种办法,能够降低 BOM 成本。
- 如果不外接晶振,需求通过板子的MCO1或许MCO2通过分频倍频操作来输出50Mhz来驱动网口。
-
四、引脚散布
ETH 相关硬件在 STM32F4xx 操控器散布情况如下:
接口 | ETH | GPIO |
---|---|---|
MII | MII_TX_CLK | PC3 |
MII_TXD0 | PB12/PG13 | |
MII_TXD1 | PB13/PG14 | |
MII_TXD2 | PC2 | |
MII_TXD3 | PB8/PE2 | |
MII_TX_EN | PB11/PG11 | |
MII_RX_CLK | PA1 | |
MII_RXD0 | PC4 | |
MII_RXD1 | PC5 | |
MII_RXD2 | PB0 | |
MII_RXD3 | PB1 | |
MII_RX_ER | PB10 | |
MII_RX_DV | PA7 | |
MII_CRS | PA0 | |
MII_COL | PA3 | |
RMII | RMII_TXD0 | PB12/PG13 |
RMII_TXD1 | PB13/PG14 | |
RMII_TX_EN | PG11 | |
RMII_RXD0 | PC4 | |
RMII_RXD1 | PC5 | |
RMII_CRS_DV | PA7 | |
RMII_REF_CLK | PA1 | |
SMI | MDIO | PA1 |
MDC | PC1 | |
其他 | PPS_OUT | PB5/PG8 |
五、新建工程
1. 翻开 STM32CubeMX 软件,点击“新建工程”
2. 挑选 MCU 和封装
3. 装备时钟 RCC 设置,挑选 HSE(外部高速时钟) 为 Crystal/Ceramic Resonator(晶振/陶瓷谐振器) 挑选 Clock Configuration,装备系统时钟 SYSCLK 为 168MHz 修正 HCLK 的值为 168 后,输入回车,软件会主动修正一切装备
4. 装备调试形式 非常重要的一步,否则会形成第一次烧录程序后续无法识别调试器 SYS 设置,挑选 Debug 为 Serial Wire
六、ETH
6.1 参数装备
在 Connectivity
中挑选 ETH
设置,形式挑选 RMII
运用简化版MII(介质独立接口)。
-
MII: Medium Independent Interface(介质独立接口),用于衔接介质拜访操控层(MAC)子层和物理层(PHY)之间的标准以太网接口,供给数据传输途径。由于 MII
需求多达16根信号线
,由此发生的 I/O 口需求及功耗较大。关于 MII 接口,一般是外部为 PHY 供给 25MHz 时钟源
,再由 PHY 供给 TX_CLK 和 RX_CLK 时钟,不需求与 MAC 层时钟共同。
-
RMII: Reduced Medium Independent Interface,RMII 接口是 MII 接口的简化版别,MII 需求 16 根通讯线,RMII
只需 7 根通讯
,在功用上是相同的。关于 RMII 接口,一般需求外部直接供给 50MHz 时钟源
,同时接入 MAC 和 PHY。需与MAC层时钟共同,通常从 MAC 层获取该时钟源。现在一般都用RMII形式。
在 Parameter Settings
进行详细参数装备。
Advanced : Ethernet Media Configuration(以太网媒体装备):
-
Auto Negotiation(自适应功用): 挑选
Enabled
,一般挑选使能自适应功用,系统会主动寻找最优作业办法,包括挑选 10MBit/s 或许 100MBit/s 的以太网速度以及全双工形式或半双工形式。LAN8720A支撑自适应功用
-
Speed(以太网速度): 可选 10MBit/s 或 100MBit/s,它设定 ETH_MACCR 寄存器的 FES 位的值,
一般设置 100MBit/s,但在使能自适应功用之后该位设置无效
。 -
Duplex Mode(以太网作业形式): 可选全双工形式或半双工形式,它设定 ETH_MACCR 寄存器 DM 位的值。
一般挑选全双工形式,在使能了自适应功用后该成员设置无效
。
General : Ethernet Configuration(以太网装备):
- Ethernet MAC Address(以太网MAC地址): 默许即可
-
PHY Address(PHY芯片地址):
0
注意:LAN8720A 能够通过 PHYAD0 引脚(如PHY芯片引脚10)来装备,该引脚与 RXER 引脚复用,芯片内部自带下拉电阻,当硬复位完毕后, LAN8720A 会读取该引脚电平,作为器材的 SMI 地址,接下拉电阻时(浮空也能够,由于芯片内部自带了下拉电阻),设置 SMI 地址为 0,当外接上拉电阻后,能够设置为 1。
本硬件 RXER 引脚浮空,其 PHY 芯片地址为 0
。
Ethernet Basic Configuration(以太网根本装备):
-
Rx Mode(接纳形式): 挑选
Polling Mode
轮询办法。ST 官方例程文件包含了中止引脚的相关装备,首要用于指示接纳到以太网帧,咱们这儿不需求运用。 -
TX IP Header Checksum Computation(发送数据校验和): 挑选
By hardware
使能发送数据硬件校验和。这个需求硬件支撑,STM32F4xx 操控器是支撑的
。
在 Advanced Parameters
进行高档参数装备。
-
PHY: 挑选
user PHY
,由于没有我的 PHY 芯片型号 LAN8720A - PHY name: 可改为 PHY 芯片型号 LAN8720A
-
PHY special control/status register Offset(特别操控/状况寄存器): 依照芯片手册填写,
0x1F
-
PHY Speed mask(以太网速度状况位): 依照芯片手册填写,
0x0004
-
PHY Speed mask(以太网作业形式状况位): 依照芯片手册填写,
0x0010
- 其他保持默许
6.2 引脚装备
GPIO 设置,在右边图中找到 ETH 对应引脚,将引脚装备成跟原理图上的共同
七、LwIP
7.1 参数装备
在 Middleware
中挑选 LWIP
设置,勾选 Enabled
使能协议栈。
在 General Settings
进行通用参数装备。
IPv4 – DHCP Options:
-
LWIP_DHCP(DHCP Module): 挑选
Disabled
。运用固定IP地址。
IP Address Settings:
- IP_ADDRESS(IP Address): 填写IP地址。
- NETMASK_ADDRESS(Netmask Address): 填写掩码地址。
- GATEWAY_ADDRESS(Gateway Address): 填写网关地址。
Protocols Options:
-
LWIP_ICMP(ICMP Module Activation)操控报文协议: 挑选
Enabled
。首要用于网络的调试与维护,ping 的时分用。 -
LWIP_IGMP(IGMP Module)互联网组办理协议: 挑选
Disabled
。能够完成多播数据的接纳。 -
LWIP_DNS(DNS Module)域名解析: 挑选
Disabled
。通过域名解析用户就能够在知道服务器域名的情况下,获得该服务器的 IP 地址。 -
LWIP_UDP(UDP Module)用户数据报协议: 挑选
Enabled
。看需求,一般挑选用 TCP 协议。 - MEMP_NUM_UDP_PCB(Number of UDP Connections): UDP协议操控块数量,决议 UDP 协议操控块需求的 POOL 资源。
-
LWIP_TCP(TCP Module)传输操控协议: 挑选
Enabled
。 - MEMP_NUM_TCP_PCB(Number of TDP Connections): 同时活动的TCP衔接数。
在 Key Options
进行要害选项装备。
Infrastructure – OS Awarness Option:
-
NO_SYS(OS Awarness):
OS Not Used
表示无操作系统模拟层,这个宏非常重要,由于无操作系统与有操作系统的移植和编写是彻底不一样的,咱们现在是无操作系统移植。
Infrastructure – Timers Options:
-
LWIP_TIMERS(Use Support For sys_timeout): 默许
Enabled
。运用 LwIP 供给的定时器,用于超时机制。
Infrastructure – Core Locking and MPU Options:
-
SYS_LIGHTWEIGHT_PROT(Memory Functions Protection): 默许
Disabled
。渠道锁,维护要害区域内缓存的分配与开释。
Infrastructure – Heap and Memory Pools Options:
-
MEM_SIZE(Heap Memory Size): 默许
1600 Byte(s)
。堆内存的巨细。如果运用程序将发送很多需求仿制的数据应该设置得大一点。
Infrastructure – Internal Memory Pool Sizes:
-
MEMP_NUM_PBUF(Number of Memory Pool struct Pbufs): 默许
16
。memp 结构的 pbuf 数量,如果运用从 ROM 或许静态存储区发送很多数据时,这个值应该设置大一点。 -
MEMP_NUM_RAW_PCB(Number of Raw Protocol Control Blocks): 默许
4
。 原始衔接(就是运用程不通过传输层直接到IP层获取数据)PCB 的数目,该项依赖 LWIP_RAW 项的开启。 -
MEMP_NUM_TCP_PCB(Number of Listening TCP Connections): 默许
8
。 同时建立激活的 TCP 衔接的数目(要求参数 LWIP_TCP 使能)。 -
MEMP_NUM_TCP_SEG(Number of TCP Segments simultaneously queued): 默许
16
。 最多同时在行列的 TCP_SEG 的数目。
Pbuf Options:
-
PBUF_POOL_SIZE(Number of Buffers in the Pbuf Pool): 默许
16
。 内存池巨细。 -
PBUF_POOL_BUFSIZE(Size of each pbuf in the pbuf pool): 默许
592 Byte(s)
。 每个 pbuf 内存池巨细。
IPv4 – ARP Options:
-
LWIP_ARP(ARP Functionality): 挑选
Enabled
。 地址解析协议,通过目标设备的 IP 地址,查询目标设备的 MAC 地址,以确保通讯的 顺利进行。
Callback – TCP Options:
-
TCP_TTL(Number of Time-To-Live Used by TCP Packets): 默许
255 Node(s)
。TCP TTL时刻。 -
TCP_WND(TCP Receive Window Maximum Size): 默许
2144 Byte(s)
。TCP 窗口长度。 -
TCP_QUEUE_OOSEQ(Allow Out-Of-Order Incoming Packets): 默许
Enabled
。TCP行列到达顺序。如果设备内存不足,则定义为0。 -
TCP_MSS(Maximum Segment Size): 默许
536 Byte(s)
。最大 TCP 报文段,TCP_MSS = MTU – IP 报头巨细 – TCP 报头巨细。 -
TCP_SND_BUF(TCP Sender Buffer Space): 默许
1072 Byte(s)
。TCP 发送缓冲区巨细(字节)。 -
TCP_SND_QUEUELEN(TCP Sender Buffer Space): 默许
1072 Byte(s)
。TCP 发送缓冲区行列的最大长度。
Network Interfaces Options:
-
LWIP_NETIF_STATUS_CALLBACK(Callback Function on Interface Status Changes): 默许
Disabled
。当 netif 状况设置为 up 或 down 时调用此函数。 -
LWIP_NETIF_LINK_CALLBACK(Callback Function on Interface Link Changes): 默许
Enabled
。当 netif 链接设置为 up 或 down 时,将调用此函数。
NETIF – Loopback Interface Options:
-
LWIP_NETIF_LOOPBACK(NETIF Loopback): 默许
Disabled
。支撑发送数据包的目的地 IP。
Thread Safe APIs – Socket Options:
-
LWIP_SOCKET(Socket API): 默许
Disabled
。Socket API。
八、生成代码
输入项目名和项目途径
挑选运用的 IDE 开发环境 MDK-ARM V5
每个外设生成独立的 ’.c/.h’
文件
不勾:一切初始化代码都生成在 main.c
勾选:初始化代码生成在对应的外设文件。 如 GPIO 初始化代码生成在 gpio.c 中。
点击 GENERATE CODE 生成代码
九、修正main.c
在 main()
的死循环中增加 MX_LWIP_Process()
函数。
然后加入以下代码不断打印 IP 地址。
extern struct netif gnetif;
struct dhcp *dhcp;
int main(void)
{
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_LWIP_Init();
MX_USART1_UART_Init();
/* USER CODE BEGIN 2 */
printf("lwip test\n");
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
MX_LWIP_Process();
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
dhcp = netif_dhcp_data(&gnetif);
printf("Static IP address: %s\n", ip4addr_ntoa(&gnetif.ip_addr));
printf("Subnet mask: %s\n", ip4addr_ntoa(&gnetif.netmask));
printf("Default gateway: %s\n", ip4addr_ntoa(&gnetif.gw));
HAL_Delay(1000);
}
/* USER CODE END 3 */
}
查看作用:
运用电脑ping上面的ip:
十、工程代码
链接:pan.baidu.com/s/1ds3cqlt1… 提取码:e4gv
十一、相关API说明
11.1 MX_LWIP_Init
初始化LwIP的内存办理和各个协议层。 按顺序执行了:
- 网络接口的增加
netif_add()
- 初始化底层
ethernetif_init()
然后LwIP就能够用了。
收包用的是调用 low_level_input
把数据包接回来,给 netif->input
处理。
发包则是由 netif->output
交由 etharp_output
制造数据包,调用 low_level_output
发出去。
void MX_LWIP_Init(void)
{
/* IP addresses initialization */
IP_ADDRESS[0] = 192;
IP_ADDRESS[1] = 168;
IP_ADDRESS[2] = 11;
IP_ADDRESS[3] = 196;
NETMASK_ADDRESS[0] = 255;
NETMASK_ADDRESS[1] = 255;
NETMASK_ADDRESS[2] = 255;
NETMASK_ADDRESS[3] = 0;
GATEWAY_ADDRESS[0] = 192;
GATEWAY_ADDRESS[1] = 168;
GATEWAY_ADDRESS[2] = 10;
GATEWAY_ADDRESS[3] = 1;
/* USER CODE BEGIN IP_ADDRESSES */
/* USER CODE END IP_ADDRESSES */
/* Initilialize the LwIP stack without RTOS */
lwip_init();
/* IP addresses initialization without DHCP (IPv4) */
IP4_ADDR(&ipaddr, IP_ADDRESS[0], IP_ADDRESS[1], IP_ADDRESS[2], IP_ADDRESS[3]);
IP4_ADDR(&netmask, NETMASK_ADDRESS[0], NETMASK_ADDRESS[1] , NETMASK_ADDRESS[2], NETMASK_ADDRESS[3]);
IP4_ADDR(&gw, GATEWAY_ADDRESS[0], GATEWAY_ADDRESS[1], GATEWAY_ADDRESS[2], GATEWAY_ADDRESS[3]);
/* add the network interface (IPv4/IPv6) without RTOS */
// 如果有多个接口则需多次调用
// 需求供给一个init函数指针,这个指针指向咱们自己的硬件接口初始化函数,一般来说就是ethernetif.c中的ethernetif_init()
netif_add(&gnetif, &ipaddr, &netmask, &gw, NULL, ðernetif_init, ðernet_input);
/* Registers the default network interface */
// 将网络接口设置为默许的网络接口
netif_set_default(&gnetif);
// 查看是否有链接
if (netif_is_link_up(&gnetif))
{
/* When the netif is fully configured this function must be called */
// 使能网络接口
netif_set_up(&gnetif);
}
else
{
/* When the netif link is down this function must be called */
// 关闭网络接口
netif_set_down(&gnetif);
}
/* Set the link callback function, this function is called on change of link status*/
netif_set_link_callback(&gnetif, ethernetif_update_config);
/* Create the Ethernet link handler thread */
/* USER CODE BEGIN 3 */
/* USER CODE END 3 */
}
/**
* Should be called at the beginning of the program to set up the
* network interface. It calls the function low_level_init() to do the
* actual setup of the hardware.
*
* This function should be passed as a parameter to netif_add().
*
* @param netif the lwip network interface structure for this ethernetif
* @return ERR_OK if the loopif is initialized
* ERR_MEM if private data couldn't be allocated
* any other err_t on error
*/
err_t ethernetif_init(struct netif *netif)
{
LWIP_ASSERT("netif != NULL", (netif != NULL));
#if LWIP_NETIF_HOSTNAME
/* Initialize interface hostname */
netif->hostname = "lwip";
#endif /* LWIP_NETIF_HOSTNAME */
// 初始化name字段
netif->name[0] = IFNAME0;
netif->name[1] = IFNAME1;
/* We directly use etharp_output() here to save a function call.
* You can instead declare your own function an call etharp_output()
* from it if you have to do some checks before sending (e.g. if link
* is available...) */
#if LWIP_IPV4
#if LWIP_ARP || LWIP_ETHERNET
#if LWIP_ARP
netif->output = etharp_output;
#else
/* The user should write its own code in low_level_output_arp_off function */
netif->output = low_level_output_arp_off;
#endif /* LWIP_ARP */
#endif /* LWIP_ARP || LWIP_ETHERNET */
#endif /* LWIP_IPV4 */
#if LWIP_IPV6
netif->output_ip6 = ethip6_output;
#endif /* LWIP_IPV6 */
netif->linkoutput = low_level_output;
/* initialize the hardware */
low_level_init(netif);
return ERR_OK;
}
11.2 MX_LWIP_Process
不断地接纳来自接口的信息,并检查是否延时
/**
* ----------------------------------------------------------------------
* Function given to help user to continue LwIP Initialization
* Up to user to complete or change this function ...
* Up to user to call this function in main.c in while (1) of main(void)
*-----------------------------------------------------------------------
* Read a received packet from the Ethernet buffers
* Send it to the lwIP stack for handling
* Handle timeouts if LWIP_TIMERS is set and without RTOS
* Handle the llink status if LWIP_NETIF_LINK_CALLBACK is set and without RTOS
*/
void MX_LWIP_Process(void)
{
/* USER CODE BEGIN 4_1 */
/* USER CODE END 4_1 */
ethernetif_input(&gnetif);
/* USER CODE BEGIN 4_2 */
/* USER CODE END 4_2 */
/* Handle timeouts */
sys_check_timeouts();
/* USER CODE BEGIN 4_3 */
/* USER CODE END 4_3 */
}
十二、注意事项
用户代码要加在 USER CODE BEGIN N
和 USER CODE END N
之间,否则下次运用 STM32CubeMX 重新生成代码后,会被删去。
• 由 Leung 写于 2022 年 8 月 25 日
• 参阅:从零开始Cubemx装备STM32搭载freeRTOS以及lwip完成tcp网络通讯(二)
STM32cubeMX装备LWIP+FREERTOS
LwIP的装备