当前位置: 首页 > news >正文

STM32H743-ARM例程35-DHCP

目录

  • 实验平台
  • DHCP
  • STM32CubeMX生成工程
  • 实验代码
  • 实验现象

实验平台

硬件:银杏科技GT7000双核心开发板-ARM-STM32H743XIH6,银杏科技iToolXE仿真器
软件:最新版本STM32CubeH7固件库,STM32CubeMX v6.10.0,开发板环境MDK v5.35,TCP&UDP测试工具,串口工具putty
网盘资料包:链接: https://pan.baidu.com/s/1Y3nwaY4SMxfoUsdqPm2R3w?pwd=inba 提取码: inba

DHCP

  DHCP(Dynamic Host Configuration Protocol,动态主机配置协议)是一个局域网的网络协议,通常被应用在大型的局域网络环境中,主要作用是集中的管理、分配 IP 地址,使网络环境中的主机动态的获得 IP 地址、Gateway 地址、DNS 服务器地址等信息,并能够提升地址的使用率。
  用于自动分配 IP 地址和其他网络配置信息(如子网掩码、默认网关、DNS 服务器)的协议。DHCP 简化了网络管理,允许设备在加入网络时自动获取必要的配置,而无需手动设置。
在这里插入图片描述

工作原理
  DHCP 使用客户端-服务器模型,通过广播和单播通信实现 IP 地址的自动分配。
  DHCP获得ip地址的4步骤:discover­>offer­>request­>ack(nak)

  1. DHCP 发现(DHCP Discover)
    当设备(DHCP 客户端)加入网络时,它会发送一个 DHCP 发现广播包,寻找可用的 DHCP 服务器。
    在这里插入图片描述
    客户端广播 DHCP Discover 包,寻找可用的 DHCP 服务器。
    局域网中的所有设备都会收到该请求。

  2. DHCP 提供(DHCP Offer)
    DHCP 服务器收到 DHCP Discover 包后,会从地址池中选择一个可用的 IP 地址,并通过 DHCP Offer 包提供给客户端。
    在这里插入图片描述
    DHCP 服务器发送 DHCP Offer 包,提供可用的 IP 地址和其他配置信息。
    DHCP Offer 包可以是广播或单播的。

  3. DHCP 请求(DHCP Request)
    客户端收到 DHCP Offer 包后,会发送一个 DHCP 请求包,确认接受提供的 IP 地址。
    在这里插入图片描述
    客户端广播 DHCP Request 包,确认接受提供的 IP 地址。
    局域网中的所有设备都会收到该请求。

  4. DHCP 确认(DHCP Acknowledge)
    DHCP 服务器收到 DHCP Request 包后,会发送一个 DHCP 确认包,正式分配 IP 地址和其他配置信息。
    在这里插入图片描述
    DHCP 服务器发送 DHCP Acknowledge 包,正式分配 IP 地址和其他配置信息。
    DHCP Acknowledge 包可以是广播或单播的。

DHCP的核心概念
  DHCP服务器:负责分配IP地址和其他网络配置的设备。最常见的例子就是我们家中的无线路由器,它内置了DHCP服务器功能。
  DHCP客户端:请求并接受IP地址配置的网络设备,如电脑、手机、智能电视等。
  IP地址池:DHCP服务器可以分配出去的IP地址范围。例如:192.168.1.100 到 192.168.1.200。
  租期:IP地址被分配给客户端后,并非永久占有,而是有一个使用期限。租期到期前,客户端需要向服务器请求续租。这确保了IP地址资源可以被循环利用,不会因为设备离线而永久占用。
  DHCP中继:由于DHCP请求最初是以广播形式发送的,而广播包通常无法跨越路由器到达其他子网。DHCP中继代理可以帮助在不同子网之间转发DHCP请求和回复,使得一个DHCP服务器能够为多个物理子网服务。
总结
  DHCP是现代TCP/IP网络不可或缺的核心服务之一。它通过自动化的方式管理IP地址分配,极大地简化了网络部署和维护工作,保证了网络的稳定性和可扩展性,是实现“即插即用”网络体验的关键技术。
  我们日常生活中,无论是在家中、办公室还是咖啡馆,能够轻松连接Wi-Fi并立即上网,背后都有DHCP在默默工作。

STM32CubeMX生成工程

我们参考前面章节STM32H743-结合CubeMX新建HAL库MDK工程,打开CubeMX软件,重复步骤不再展示。我们来看配置MPU配置、以太网部分和Lwip部分配置如下图所示:
配置以太网。选用RMII(精简的独立于介质接口)模式
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
MPU配置
在这里插入图片描述
LWIP配置
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

实验代码

1. 主函数

int main(void)
{/* USER CODE BEGIN 1 *//* USER CODE END 1 *//* MPU Configuration--------------------------------------------------------*/MPU_Config();
/* Enable the CPU Cache *//* Enable I-Cache---------------------------------------------------------*/SCB_EnableICache();/* Enable D-Cache---------------------------------------------------------*/SCB_EnableDCache();/* 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_USART6_UART_Init();/* USER CODE BEGIN 2 */uart6.initialize(115200);uart6.printf("\x0c");uart6.printf("GT7000 OK!\r\n");HAL_GPIO_WritePin(PHYAD0_GPIO_Port,PHYAD0_Pin,GPIO_PIN_RESET);eth_udp.initialize();eth_tcps_init();uart6.printf("initialize OK!\r\n");/* USER CODE END 2 *//* Infinite loop *//* USER CODE BEGIN WHILE */while (1){MX_LWIP_Process();if(uart6.receive_ok_flag == 1){uart6.receive_ok_flag = 0;memset(buffer,0,20);memcpy(buffer,uart6.receive_buffer,20);     for(i = 0;i < 20;i ++){buffer[i] = tolower(buffer[i]);}           if(memcmp(buffer,"dhcp",strlen("dhcp")) == 0){              lwip_dhcp_task();               }else if(memcpy(buffer,"clear",strlen("clear")) == 0){uart6.printf("\x0c");}else{uart6.printf("\r\nCommand not found!\r\n");}       }/* USER CODE END WHILE *//* USER CODE BEGIN 3 */}/* USER CODE END 3 */
}

2.DHCP相关函数

#include "eth_udp.h"
#include <string.h>
#include "dhcp.h"
#include "uart6.h"
//--------------------- Function Prototype ----------------------//   
void initialize(void);
void receive_data(void *arg,struct udp_pcb *upcb,struct pbuf *p,const ip_addr_t *addr,u16_t port);
void send_data(struct udp_pcb *upcb);
void connection_close(struct udp_pcb *upcb);
void udp_client_send(struct udp_pcb *upcb, char *pData);
void lwip_dhcp_task(void);
//--------------------------- Variable --------------------------// 
ETH_UDP_T eth_udp = {.initialize = initialize,.receive_data = receive_data,.send_data = send_data,.connection_close = connection_close,.receive_ok_flag = 0
};__lwip_dev lwipdev;
uint8_t PCIP_ADDRESS[4] = {192, 168, 31, 220};
extern struct netif gnetif;void initialize(void)
{err_t err;struct ip4_addr rmtipaddr;eth_udp.udppcb = udp_new();//创建一个新的UDP协议控制块IP4_ADDR(&rmtipaddr ,PCIP_ADDRESS[0] ,PCIP_ADDRESS[1] ,PCIP_ADDRESS[2] ,PCIP_ADDRESS[3]);//设置服务器(PC)IP地址udp_connect(eth_udp.udppcb ,&rmtipaddr,REMOTE_PORT);							//连接至远程客户端if (eth_udp.udppcb){err = udp_bind(eth_udp.udppcb ,IP_ADDR_ANY ,LOCAL_PORT);						//给UDP协议控制块绑定端口号和IP地址if(err == ERR_OK){udp_recv(eth_udp.udppcb ,eth_udp.receive_data ,NULL);				//设置接收回调函数}else{udp_remove(eth_udp.udppcb);}}
}static void receive_data(void *arg,struct udp_pcb *upcb,struct pbuf *p,const ip_addr_t *addr,u16_t port)
{uint32_t data_len = 0;struct pbuf *q;if(p!=NULL){memset(eth_udp.receive_buffer,0,EHT_BUFFER_SIZE);for(q=p;q!=NULL;q=q->next){if(q->len > (EHT_BUFFER_SIZE-data_len)) memcpy(eth_udp.receive_buffer + data_len,q->payload,(EHT_BUFFER_SIZE - data_len));else memcpy(eth_udp.receive_buffer+data_len,q->payload,q->len);data_len += q->len;  	if(data_len > EHT_BUFFER_SIZE) break;}eth_udp.receive_ok_flag = 1;pbuf_free(p);}else{udp_disconnect(upcb); } 
} void send_data(struct udp_pcb *upcb)
{struct pbuf *ptr;memcpy(eth_udp.send_buffer,eth_udp.receive_buffer,1024);ptr=pbuf_alloc(PBUF_TRANSPORT,strlen((char*)eth_udp.send_buffer),PBUF_RAM); 	//申请内存if(ptr){pbuf_take(ptr,(char *)eth_udp.send_buffer,strlen((char*)eth_udp.send_buffer));	//拷贝数据udp_send(upcb,ptr);															//发送数据pbuf_free(ptr);																//释放内存}
} void connection_close(struct udp_pcb *upcb)
{udp_disconnect(upcb); udp_remove(upcb);
}void lwip_dhcp_task(void)
{uint32_t ip=0,netmask=0,gw=0;lwipdev.dhcpstatus=0;	//正在DHCP	uart6.printf("正在获取地址...\r\n");ip=gnetif.ip_addr.addr;		//读取新IP地址netmask=gnetif.netmask.addr;//读取子网掩码gw=gnetif.gw.addr;			//读取默认网关 if(ip!=0)   					//当正确读取到IP地址的时候{//flag = 1;lwipdev.dhcpstatus=2;	//DHCP成功uart6.printf("网卡en的MAC地址为:................%d.%d.%d.%d.%d.%d\r\n",\lwipdev.mac[0],lwipdev.mac[1],lwipdev.mac[2],lwipdev.mac[3],lwipdev.mac[4],lwipdev.mac[5]);//解析出通过DHCP获取到的IP地址lwipdev.ip[3]=(uint8_t)(ip>>24); lwipdev.ip[2]=(uint8_t)(ip>>16);lwipdev.ip[1]=(uint8_t)(ip>>8); lwipdev.ip[0]=(uint8_t)(ip);uart6.printf("通过DHCP获取到IP地址..............%d.%d.%d.%d\r\n",lwipdev.ip[0],lwipdev.ip[1],lwipdev.ip[2],lwipdev.ip[3]);//解析通过DHCP获取到的子网掩码地址lwipdev.netmask[3]=(uint8_t)(netmask>>24);lwipdev.netmask[2]=(uint8_t)(netmask>>16);lwipdev.netmask[1]=(uint8_t)(netmask>>8);lwipdev.netmask[0]=(uint8_t)(netmask);uart6.printf("通过DHCP获取到子网掩码............%d.%d.%d.%d\r\n",lwipdev.netmask[0],lwipdev.netmask[1],lwipdev.netmask[2],lwipdev.netmask[3]);//解析出通过DHCP获取到的默认网关lwipdev.gateway[3]=(uint8_t)(gw>>24);lwipdev.gateway[2]=(uint8_t)(gw>>16);lwipdev.gateway[1]=(uint8_t)(gw>>8);lwipdev.gateway[0]=(uint8_t)(gw);uart6.printf("通过DHCP获取到的默认网关..........%d.%d.%d.%d\r\n",lwipdev.gateway[0],lwipdev.gateway[1],lwipdev.gateway[2],lwipdev.gateway[3]);}else if(netif_dhcp_data(&gnetif)->tries >  LWIP_MAX_DHCP_TRIES) //通过DHCP服务获取IP地址失败,且超过最大尝试次数netif_dhcp_data(gnetif)  (netif)->client_data[(id)]{lwipdev.dhcpstatus=0XFF;//DHCP失败.//使用静态IP地址IP4_ADDR(&(gnetif.ip_addr),lwipdev.ip[0],lwipdev.ip[1],lwipdev.ip[2],lwipdev.ip[3]);IP4_ADDR(&(gnetif.netmask),lwipdev.netmask[0],lwipdev.netmask[1],lwipdev.netmask[2],lwipdev.netmask[3]);IP4_ADDR(&(gnetif.gw),lwipdev.gateway[0],lwipdev.gateway[1],lwipdev.gateway[2],lwipdev.gateway[3]);printf("DHCP服务超时,使用静态IP地址!\r\n");printf("网卡en的MAC地址为:................%d.%d.%d.%d.%d.%d\r\n",lwipdev.mac[0],lwipdev.mac[1],lwipdev.mac[2],lwipdev.mac[3],lwipdev.mac[4],lwipdev.mac[5]);printf("静态IP地址........................%d.%d.%d.%d\r\n",lwipdev.ip[0],lwipdev.ip[1],lwipdev.ip[2],lwipdev.ip[3]);printf("子网掩码..........................%d.%d.%d.%d\r\n",lwipdev.netmask[0],lwipdev.netmask[1],lwipdev.netmask[2],lwipdev.netmask[3]);printf("默认网关..........................%d.%d.%d.%d\r\n",lwipdev.gateway[0],lwipdev.gateway[1],lwipdev.gateway[2],lwipdev.gateway[3]);}
}

实验现象

  本实验例程采用的 LWIP 版本位 2.1.2,其中包含了 DHCP 协议,在对 LWIP 的 DHCP功能进行使能和启动后,即可通过路由器对设备进行 IP 地址的分配。
  我们需要一根网线将GT7000的网口与路由器的网口连接,然后运行程序在putty串口工具输入“dhcp”进行自动分配IP。如下图所示
在这里插入图片描述
按“Win+R” 输入命令“cmd”,输入 ping 加获取到的 IP,如:ping 192.168.31.119 等待打印结果。
在这里插入图片描述

http://www.dtcms.com/a/553393.html

相关文章:

  • 概率论直觉(一):大数定律
  • 数据结构—栈和队列
  • JavaSE知识分享——继承(下)
  • Linux性能分析:常用工具与指令
  • 软件测试面试的排序算法问题如何回答
  • Verilog和FPGA的自学笔记8——按键消抖与模块化设计
  • 深入解析 display: flow-root:现代CSS布局的隐藏利器
  • 汕头网站制作方法购物网站价格
  • 电商网站建设精准扶贫的目的建筑施工特种证书查询入口官网
  • spring-ai advisors 使用与源码分析
  • 关键词解释:点积(Dot Product)在深度学习中的意义
  • 本地部署DeepSeek-OCR:打造高效的PDF文字识别服务
  • 机器视觉系统中工业相机的常用术语解读
  • 【论文精读】GenRec:基于扩散模型统一视频生成与识别任务
  • seo提高网站排名wordpress内容页不显示
  • Velero(原名Heptio Ark) 是一个专为 Kubernetes 设计的开源备份恢复工具
  • 企业网站模板中文 产品列表深圳福田区住房和建设局网站
  • 制作网站的价格一般由什么组成
  • Spring MVC 架构总览与请求处理流程
  • 网站推广的优势有做二手厨房设备的网站吗
  • 请问聊城做网站wordpress模板个人博客
  • 蒲福风力等级表
  • 小小电脑安装logisim-evolution
  • C# 六自由度机械臂正反解计算
  • 【开题答辩全过程】以 基于Java的旅游网站的设计与开发为例,包含答辩的问题和答案
  • 【深入学习Vue丨第一篇】Props 完全指南
  • U-net 系列算法总结
  • 什么网站可以做模型挣钱网站建设公司有多少家
  • 网站建设的杂志建筑专业网站建设
  • vue3+ts面试题(一)JSX,SFC