abner_ma 发表于 2025-7-31 15:11

【CH32V317W-R0开发板】以太网测评之DHCP

本帖最后由 abner_ma 于 2025-7-31 17:52 编辑

   CH32V *单片机是基于青稞 RISC-V 内核设计的工业级通用微控制器。青稞(C-SKY)RISC-V4F 内核是由中天微(后被阿里巴巴收购,并入平头哥半导体)开发的基于RISC-V架构的嵌入式处理器内核,支持单精度浮点运算(F扩展),主要面向IoT、边缘计算和低功耗嵌入式市场。包括 CH32V305 连接型 MCU,CH32V307/CH32V317 互联型 MCU、CH32V208 无线型 MCU 等。CH32V30x 和 CH32V31x 系列基于青稞 V4F微处理器设计,支持单精度浮点指令和快速中断响应,支持 144MHz 主频零等待运行,提供 8 组串口、4 组电机 PWM 高级定时器、SDIO、DVP 数字图像接口、4 组模拟运放、双 ADC 单元、双 DAC 单元,内置USB2.0 高速 PHY 收发器(480Mbps)、千兆以太网 MAC 控制器及 10 兆物理层收发器、10/100 兆物理层收发器(仅适用于 CH32V317)等。
    CH32V317 支持用户选择字配置为(192K FLASH+128K SRAM)、(224K FLASH+96K SRAM)、(256KFLASH+64K SRAM)、(288K FLASH+32K SRAM)、(128K FLASH+192K SRAM)几种组合中的一种。FLASH 闪存表示的是零等待运行区域 R0WAIT,CH32V317 支持(480K-R0WAIT)字节的非零等待区域。
   串口提供了 3 组通用同步/异步串口收发器(USART1、USART2、USART3),以及 5 组通用异步收发器(UART4、UART5、UART6、UART7、UART8)。支持全双工异步通信、同步单向通信以及半双工单线通信,也支持 LIN(局部互连网),兼容 ISO7816 的智能卡协议和 IrDA SIR ENDEC 传输编解码规范,以及调制解调器(CTS/RTS 硬件流控)操作。还允许多处理器通信。其采用分数波特率发生器系统,并支持 DMA 操作连续通讯。       CH32V3xx 基于 RISC-V 指令集设计,其架构中将内核、仲裁单元、DMA 模块、SRAM 存储等部分通过多组总线实现交互。设计中集成通用 DMA 控制器以减轻 CPU 负担、提高访问效率,应用多级时钟管理机制降低了外设的运行功耗,同时兼有数据保护机制,时钟自动切换保护等措施增加了系统稳定性。
    RISC-V4F 支持 RISC-V 指令集 IMAFC 子集,增加了单精度浮点运算。处理器内部以模块化管理,包含快速可编程中断控制器(PFIC)、内存保护、分支预测模式、扩展指令支持等单元。对外多组总线与外部单元模块相连,实现外部功能模块和内核的交互。青稞微处理器以其极简指令集、多种工作模式、模块化定制扩展等特点可以灵活应用不同场景微控制器设计,例如小面积低功耗嵌入式场景、高性能应用操作系统场景等。
1.支持机器和用户特权模式
2. 快速可编程中断控制器(PFIC)
3.多级硬件中断堆栈
4..串行2线调试接口
5.标准内存保护设计
6. 静态或动态分支预测、高效跳转、冲突检测机制
7. 自定义扩展指

总体架构框图。

   
    以太网收发器(ETH)
   CH32V307、CH32F207 芯片的 MAC 支持 MII/RMII/RGMII 接口且内置一个 10Mbps PHY;CH32V317 芯片支持以太网控制器 MAC 和内置 10Mbps/100Mbps PHY。以太网 MAC 通过 SMI 接口控制 PHY,接口的时序由 MAC 自动实现,无需用户通过软件生成。RGMII接口支持发送时钟相位翻转和相对数据延迟,最大延迟 4 纳秒。以太网 MAC 支持标准 IEEE802.3 协议的以太网,支持魔法帧和特定唤醒帧。以太网收发器搭配的DMA 控制器以描述符的形式进行数据的收发管理和内存搬运,描述符的数量由用户根据沟通密集程度自行确定,DMA 控制器能以 32 位宽的速度向描述符指定的内存空间写入接收到的数据或从取出将发送的数据。此外,以太网收发器的 MAC 还支持 IEEE1588 精确时间协议。   CH32V3X7作为一款集成RISC-V内核的微控制器,其以太网模块支持动态主机配置协议(DHCP),可实现自动获取IP地址、子网掩码、网关等网络参数,简化网络设备配置流程。沁恒官方提供WCHNET协议栈库,封装了DHCP客户端功能,用户仅需调用WCHNET_DHCPStart()函数即可启动DHCP服务,无需深入理解协议细节。
   

   

#ifndef __WCHNET_H__
#define __WCHNET_H__

#include "stdint.h"
#ifndef NET_LIB
#include "net_config.h"
#endif
#ifdef __cplusplus
extern "C" {
#endif

#define WCHNET_LIB_VER                  0x11 /* 库版本号 */
#define WCHNET_CFG_VALID                0x12345678 /* 配置值有效标志 */

/* LED状态 @LED_STAT */
#defineLED_ON                         0
#defineLED_OFF                        1

/* PHY 状态 @PHY_STAT */
#define PHY_LINK_SUCCESS                (1 << 2) /* PHY建立连接 */
#define PHY_AUTO_SUCCESS                (1 << 5) /* PHY自动协商完成 */

/* 库初始化状态 @CFG_INIT_STAT */
#defineINIT_OK                        0x00
#defineINIT_ERR_RX_BUF_SIZE         0x01
#defineINIT_ERR_TCP_MSS               0x02
#defineINIT_ERR_HEAP_SIZE             0x03
#defineINIT_ERR_ARP_TABLE_NEM         0x04
#defineINIT_ERR_MISC_CONFIG0          0x05
#defineINIT_ERR_MISC_CONFIG1          0x06
#defineINIT_ERR_FUNC_SEND             0x09
#defineINIT_ERR_CHECK_VALID         0xFF

/* Socket 工作模式定义,协议类型 */
#define PROTO_TYPE_IP_RAW               0   /* IP层原始数据 */
#define PROTO_TYPE_UDP                  2   /* UDP协议类型 */
#define PROTO_TYPE_TCP                  3   /* TCP协议类型 */

/* 中断状态 */
/* 以下为 GLOB_INT 会产生的状态 */
#define GINT_STAT_UNREACH               (1 << 0) /* 不可达中断*/
#define GINT_STAT_IP_CONFLI             (1 << 1) /* IP冲突*/
#define GINT_STAT_PHY_CHANGE            (1 << 2) /* PHY状态改变 */
#define GINT_STAT_SOCKET                (1 << 4) /* socket 产生中断 */

/*以下为 Sn_INT 会产生的状态*/
#define SINT_STAT_RECV                  (1 << 2) /* socket端口接收到数据或者接收缓冲区不为空 */
#define SINT_STAT_CONNECT               (1 << 3) /* 连接成功,TCP模式下产生此中断 */
#define SINT_STAT_DISCONNECT            (1 << 4) /* 连接断开,TCP模式下产生此中断 */
#define SINT_STAT_TIM_OUT               (1 << 6) /* ARP和TCP模式下会发生此中断 */


/* Definitions for error constants. @ERR_T */
#define ERR_T
#define WCHNET_ERR_SUCCESS            0x00/* No error, everything OK */
#define WCHNET_ERR_BUSY               0x10/* busy */
#define WCHNET_ERR_MEM                  0x11/* Out of memory error */
#define WCHNET_ERR_BUF                  0x12/* Buffer error */
#define WCHNET_ERR_TIMEOUT            0x13/* Timeout */
#define WCHNET_ERR_RTE                  0x14/* Routing problem */
#define WCHNET_ERR_ABRT               0x15/* Connection aborted */
#define WCHNET_ERR_RST                  0x16/* Connection reset */
#define WCHNET_ERR_CLSD               0x17/* Connection closed */
#define WCHNET_ERR_CONN               0x18/* Not connected */
#define WCHNET_ERR_VAL                  0x19/* Illegal value */
#define WCHNET_ERR_ARG                  0x1a/* Illegal argument */
#define WCHNET_ERR_USE                  0x1b/* Address in use */
#define WCHNET_ERR_IF                   0x1c/* Low-level netif error*/
#define WCHNET_ERR_ISCONN               0x1d/* Already connected */
#define WCHNET_ERR_INPROGRESS         0x1e/* Operation in progress */
#define WCHNET_ERR_SOCKET_MEM         0X20/* Socket information error */
#define WCHNET_ERR_UNSUPPORT_PROTO      0X21/* unsupported protocol type */
#define WCHNET_RET_ABORT                0x5F/* command process fail */
#define WCHNET_ERR_UNKNOW               0xFA/* unknow */

/* 不可达代码 */
#define UNREACH_CODE_HOST               0   /* 主机不可达 */
#define UNREACH_CODE_NET                1   /* 网络不可达 */
#define UNREACH_CODE_PROTOCOL         2   /* 协议不可达 */
#define UNREACH_CODE_PROT               3   /* 端口不可达 */
/*其他值请参考RFC792文档*/

/* TCP关闭参数 */
#define TCP_CLOSE_NORMAL                0   /* 正常关闭,进行4此握手 */
#define TCP_CLOSE_RST                   1   /* 复位连接,并关闭*/
#define TCP_CLOSE_ABANDON               2   /* 内部丢弃连接,不会发送任何终止报文 */

/* socket状态 */
#define SOCK_STAT_CLOSED                0X00/* socket关闭 */
#define SOCK_STAT_OPEN                  0X05/* socket打开 */

/* TCP状态 */
#define TCP_CLOSED                      0   /* TCP关闭 */
#define TCP_LISTEN                      1   /* TCP监听 */
#define TCP_SYN_SENT                  2   /* SYN发送,连接请求 */
#define TCP_SYN_RCVD                  3   /* SYN接收,接收到连接请求 */
#define TCP_ESTABLISHED               4   /* TCP连接建立 */
#define TCP_FIN_WAIT_1                  5   /* WAIT_1状态 */
#define TCP_FIN_WAIT_2                  6   /* WAIT_2状态 */
#define TCP_CLOSE_WAIT                  7   /* 等待关闭 */
#define TCP_CLOSING                     8   /* 正在关闭 */
#define TCP_LAST_ACK                  9   /* LAST_ACK*/
#define TCP_TIME_WAIT                   10    /* 2MSL等待 */

/* 以下值为固定值不可以更改 */
#define WCHNET_MEM_ALIGN_SIZE(size)    (((size) + WCHNET_MEM_ALIGNMENT - 1) & ~(WCHNET_MEM_ALIGNMENT - 1))
#define WCHNET_SIZE_IPRAW_PCB          0xFF   /* IPRAW PCB大小 */
#define WCHNET_SIZE_UDP_PCB            0x30   /* UDP PCB大小 */
#define WCHNET_SIZE_TCP_PCB            0xFF   /* TCP PCB大小 */
#define WCHNET_SIZE_TCP_PCB_LISTEN   0x40   /* TCP LISTEN PCB大小 */
#define WCHNET_SIZE_IP_REASSDATA       0x40   /* IP分片管理*/
#define WCHNET_SIZE_PBUF               0x40   /* Packet Buf */
#define WCHNET_SIZE_TCP_SEG            0x60   /* TCP SEG结构 */
#define WCHNET_SIZE_MEM                0x0c   /* sizeof(struct mem) */
#define WCHNET_SIZE_ARP_TABLE          0x20   /* sizeof ARP table */

#define WCHNET_SIZE_POOL_BUF         WCHNET_MEM_ALIGN_SIZE(WCHNET_TCP_MSS + 40 + 14) /* pbuf池大小 */
#define WCHNET_MEMP_SIZE               ((WCHNET_MEM_ALIGNMENT - 1) +                                                 \
                        (WCHNET_NUM_IPRAW * WCHNET_MEM_ALIGN_SIZE(WCHNET_SIZE_IPRAW_PCB)) +                        \
                        (WCHNET_NUM_UDP * WCHNET_MEM_ALIGN_SIZE(WCHNET_SIZE_UDP_PCB)) +                            \
                        (WCHNET_NUM_TCP * WCHNET_MEM_ALIGN_SIZE(WCHNET_SIZE_TCP_PCB)) +                            \
                        (WCHNET_NUM_TCP_LISTEN * WCHNET_MEM_ALIGN_SIZE(WCHNET_SIZE_TCP_PCB_LISTEN)) +            \
                        (WCHNET_NUM_TCP_SEG * WCHNET_MEM_ALIGN_SIZE(WCHNET_SIZE_TCP_SEG)) +                        \
                        (WCHNET_NUM_IP_REASSDATA * WCHNET_MEM_ALIGN_SIZE(WCHNET_SIZE_IP_REASSDATA)) +            \
                        (WCHNET_NUM_PBUF * (WCHNET_MEM_ALIGN_SIZE(WCHNET_SIZE_PBUF) + WCHNET_MEM_ALIGN_SIZE(0))) + \
                        (WCHNET_NUM_POOL_BUF * (WCHNET_MEM_ALIGN_SIZE(WCHNET_SIZE_PBUF) + WCHNET_MEM_ALIGN_SIZE(WCHNET_SIZE_POOL_BUF))))

#define HEAP_MEM_ALIGN_SIZE          (WCHNET_MEM_ALIGN_SIZE(WCHNET_SIZE_MEM))
#define WCHNET_RAM_HEAP_SIZE         (WCHNET_MEM_HEAP_SIZE + (2 * HEAP_MEM_ALIGN_SIZE) + WCHNET_MEM_ALIGNMENT)
#define WCHNET_RAM_ARP_TABLE_SIZE    (WCHNET_SIZE_ARP_TABLE * WCHNET_NUM_ARP_TABLE)

/* LED回调结构体 */
typedef void (*led_callback)( uint8_t setbit );

/* LED回调结构体 */
typedef uint32_t (*eth_tx_set )( uint16_t len, uint32_t *pBuff );

/* DNS回调结构体 */
typedef void (*dns_callback)( const char *name, uint8_t *ipaddr, void *callback_arg );

/* DHCP回调结构体 */
typedef uint8_t (*dhcp_callback)( uint8_t status, void * );

// 接收回调函数
struct _SCOK_INF;
typedef void (*pSockRecv)( struct _SCOK_INF *, uint32_t, uint16_t, uint8_t *, uint32_t);

/* sokcet信息表 */
typedef struct _SCOK_INF
{
    uint32_t IntStatus;                     /* 中断状态 */
    uint32_t SockIndex;                     /* Socket索引值 */
    uint32_t RecvStartPoint;                  /* 接收缓冲区的开始指针 */
    uint32_t RecvBufLen;                      /* 接收缓冲区长度 */
    uint32_t RecvCurPoint;                  /* 接收缓冲区的当前指针 */
    uint32_t RecvReadPoint;                   /* 接收缓冲区的读指针 */
    uint32_t RecvRemLen;                      /* 接收缓冲区的剩余长度 */
    uint32_t ProtoType;                     /* 协议类型 */
    uint32_t ScokStatus;                      /* 低字节Socket状态,次低字节为TCP状态,仅TCP模式下有意义 */
    uint32_t DesPort;                         /* 目的端口 */
    uint32_t SourPort;                        /* 源端口在IPRAW模式下为协议类型 */
    uint8_tIPAddr;                     /* Socket目标IP地址 32bit*/
    void *Resv1;                              /* 保留,内部使用,用于保存各个PCB */
    void *Resv2;                              /* 保留,内部使用,TCP Server使用 */
    pSockRecv AppCallBack;                  /* 接收回调函数*/
} SOCK_INF;

struct _WCH_CFG
{
uint32_t TxBufSize;   /* MAC发送缓冲区大小,保留使用 */
uint32_t TCPMss;      /* TCP MSS大小 */
uint32_t HeapSize;    /* 堆分配内存大小 */
uint32_t ARPTableNum; /* ARP列表个数 */
uint32_t MiscConfig0; /* 杂项配置0 */
/* 位0   TCP发送缓冲区复制 1:复制,0:不复制 */
/* 位1   TCP接收复制优化,内部调试使用 */
/* 位2   删除最早的TCP连接 1:启用,0:禁用*/
/* 位3-7   IP分片的PBUF个数*/
uint32_t MiscConfig1; /* 杂项配置1 */
/* 位0-7   Socket的个数 */
/* 位8-12保留 */
/* 位13    PING使能,1:开启0:关闭*/
/* 位14-18 TCP重传次数*/
/* 位19-23 TCP重传周期,单位为50毫秒*/
/* 位25    发送失败重试,1:启用,0:禁用 */
/* 位26-31 保留 */
led_callback led_link; /* PHY Link状态指示灯 */
led_callback led_data; /* 以太网通信指示灯 */
eth_tx_set net_send;
uint32_t   CheckValid;/* 配置值有效标志,固定值 @WCHNET_CFG_VALID */
};

struct _NET_SYS
{
uint8_tIPAddr;      /* IP地址 32bit */
uint8_tGWIPAddr;      /* 网关地址 32bit */
uint8_tMASKAddr;      /* 子网掩码 32bit */
uint8_tMacAddr;       /* MAC地址 48bit */
uint8_tUnreachIPAddr; /* 不可到达IP */
uint32_t RetranCount;      /* 重试次数 默认为10次 */
uint32_t RetranPeriod;   /* 重试周期,单位MS,默认500MS */
uint32_t PHYStat;          /* PHY状态码 8bit */
uint32_t NetStat;          /* 以太网的状态 ,包含是否打开等 */
uint32_t MackFilt;         /*MAC过滤,默认为接收广播,接收本机MAC 8bit */
uint32_t GlobIntStatus;    /* 全局中断 */
uint32_t UnreachCode;      /* 不可达 */
uint32_t UnreachProto;   /* 不可达协议 */
uint32_t UnreachPort;      /* 不可到达端口 */
uint32_t SendFlag;
uint32_t Flags;
};

/* KEEP LIVE配置结构体 */
struct _KEEP_CFG
{
uint32_t KLIdle;/* KEEPLIVE空闲时间,单位ms */
uint32_t KLIntvl; /* KEEPLIVE周期,单位ms */
uint32_t KLCount; /* KEEPLIVE次数 */
};

/**
* @brief   库初始化.
*
* @param   ip - IP地址
* @param   gwip - 网关
* @param   mask - 子网掩码
* @param   macaddr - MAC地址
*
* @return@ERR_T
*/
uint8_t WCHNET_Init(const uint8_t *ip, const uint8_t *gwip, const uint8_t *mask, const uint8_t *macaddr);

/**
* @brief   获取版本号
*
* @param   None
*
* @return库版本
*/
uint8_t WCHNET_GetVer(void);

/**
* @brief   获取MAC地址
*
* @param(in)   macaddr - 内存地址
*
* @param(out)mac地址
*
* @returnNone
*/
void WCHNET_GetMacAddr(uint8_t *macaddr);

/**
* @brief   库参数配置
*
* @param   cfg -配置参数 @_WCH_CFG
*
* @return库配置初始化状态 @CFG_INIT_STAT
*/
uint8_t WCHNET_ConfigLIB(struct _WCH_CFG *cfg);

/**
* @brief   库主任务函数,需要一直不断调用
*
* @param   None
*
* @returnNone
*/
void WCHNET_MainTask(void);

/**
* @brief   时钟中断服务函数,需配置时钟周期
*
* @param   timperiod - 时钟周期,单位ms
*
* @returnNone
*/
void WCHNET_TimeIsr( uint16_t timperiod);

/**
* @brief   以太网中断服务函数,产生以太网中断后调用
*
* @param   None
*
* @returnNone
*/
void WCHNET_ETHIsr(void);

/**
* @brief   Get PHY status
*
* @param   None
*
* @returnPHY 状态 @PHY_STAT
*/
uint8_t WCHNET_GetPHYStatus(void);

/**
* @brief   查询全局中断
*
* @param   None
*
* @returnGLOB_INT
*/
uint8_t WCHNET_QueryGlobalInt(void);

/**
* @brief   读全局中断并将全局中断清零
*
* @param   None
*
* @returnGLOB_INT
*/
uint8_t WCHNET_GetGlobalInt(void);

/**
* @brief   创建socket
*
* @param(in)   *socketid - 内存地址
* @param       socinf - 创建socket的配置参数 @SOCK_INF
*
* @param(out)*socketid - socketID值
*
* @return@ERR_T
*/
uint8_t WCHNET_SocketCreat( uint8_t *socketid, SOCK_INF *socinf);

/**
* @brief   Socket发送数据
*
* @param       socketid - socketID值
* @param       *buf - 发送数据首地址
* @param(in)   *len - 内存地址及期望发送的数据长度
*
* @param(out)*len - 实际发送的数据长度
*
* @return@ERR_T
*/
uint8_t WCHNET_SocketSend( uint8_t socketid, uint8_t *buf, uint32_t *len);

/**
* @brief   Socket接收数据
*
* @param       socketid - socketID值
* @param       *buf - 接收数据首地址
* @param(in)   *len - 内存地址及期望读取的数据长度
*
* @param(out)*buf - 写入读取到的数据内容
* @param(out)*len - 实际读取的数据长度
*
* @return@ERR_T
*/
uint8_t WCHNET_SocketRecv( uint8_t socketid, uint8_t *buf, uint32_t *len);

/**
* @brief   获取socket中断并清零
*
* @param   socketid - socketID值
*
* @returnSn_INT
*/
uint8_t WCHNET_GetSocketInt( uint8_t socketid );

/**
* @brief   获取socket接收长度
*
* @param       socketid - socketID值
* @param(in)   *bufaddr - 内存地址
*
* @param(out)*bufaddr - socket数据的首地址
*
* @return数据长度
*/
uint32_t WCHNET_SocketRecvLen( uint8_t socketid, uint32_t *bufaddr);

/**
* @brief   TCP连接
*
* @param   socketid - socketID值
*
* @return@ERR_T
*/
uint8_t WCHNET_SocketConnect( uint8_t socketid);

/**
* @brief   TCP监听
*
* @param   socketid - socketID值
*
* @return@ERR_T
*/
uint8_t WCHNET_SocketListen( uint8_t socketid);

/**
* @brief   关闭socket
*
* @param   socketid - socketID值
* @param   mode - socket为TCP连接,参数为关闭的方式 @TCP关闭参数
*
* @return@ERR_T
*/
uint8_t WCHNET_SocketClose( uint8_t socketid, uint8_t mode );

/**
* @brief   修改接收缓冲区
*
* @param   socketid - socketID值
* @param   bufaddr - 接收缓冲区地址
* @param   bufsize - 接收缓冲区大小
*
* @returnNone
*/
void WCHNET_ModifyRecvBuf( uint8_t socketid, uint32_t bufaddr, uint32_t bufsize);

/**
* @brief   UDP发送,指定目的IP、目的端口
*
* @param       socketid - socketID值
* @param       *buf - 发送数据的地址
* @param(in)   *slen - 期望发送的长度地址
* @param       *sip - 目的IP地址
* @param       port - 目的端口号
*
* @param(out)*slen - 实际发送的长度
*
* @return@ERR_T
*/
uint8_t WCHNET_SocketUdpSendTo( uint8_t socketid, uint8_t *buf, uint32_t *slen, uint8_t *sip, uint16_t port);

/**
* @brief   ASCII码地址转网络地址
*
* @param       *cp - 需转换的ASCII码地址
* @param(in)   *addr - 转换后网络地址存放的内存首地址
*
* @param(out)*addr - 转换后的网络地址
*
* @return0:转换成功1:转换失败
*/
uint8_t WCHNET_Aton(const char *cp, uint8_t *addr);

/**
* @brief   网络地址转ASCII地址
*
* @param   *ipaddr - socketID值
*
* @return转换后的ASCII地址
*/
uint8_t *WCHNET_Ntoa( uint8_t *ipaddr);

/**
* @brief   设置socket的TTL
*
* @param   socketid - socketID值
* @param   ttl - TTL值
*
* @return@ERR_T
*/
uint8_t WCHNET_SetSocketTTL( uint8_t socketid, uint8_t ttl);

/**
* @brief   立即启动TCP重传
*
* @param   socketid - socketID值
*
* @returnNone
*/
void WCHNET_RetrySendUnack( uint8_t socketid);

/**
* @brief   查询未发送成功的数据包
*
* @param       socketid - socketID值
* @param(in)   *addrlist - 存放的内存首地址
* @param       lislen - 存放的内存大小
*
* @param(out)*addrlist - 未发送成功的数据包地址列表
*
* @return未发送和未应答的数据段的个数
*/
uint8_t WCHNET_QueryUnack( uint8_t socketid, uint32_t *addrlist, uint16_t lislen );

/**
* @brief   DHCP启动
*
* @param   dhcp - 应用层回调函数
*
* @return@ERR_T
*/
uint8_t WCHNET_DHCPStart( dhcp_callback dhcp );

/**
* @brief   DHCP停止
*
* @param   None
*
* @return@ERR_T
*/
uint8_t WCHNET_DHCPStop( void );

/**
* @brief   配置DHCP主机名
*
* @param   *name - DHCP主机名首地址
*
* @return0成功,否则失败
*/
uint8_t WCHNET_DHCPSetHostname(char *name);

/**
* @brief   Initialize the resolver: set up the UDP pcb and configure the default server
*
* @param   *dnsip - dns服务器IP地址
* @param   port - dns服务器端口号
*
* @returnNone
*/
void WCHNET_InitDNS( uint8_t *dnsip, uint16_t port);

/**
* Resolve a hostname (string) into an IP address.
*
* @param   hostname - the hostname that is to be queried
* @param   addr   - pointer to a struct ip_addr where to store the address if it is already
*                     cached in the dns_table (only valid if ERR_OK is returned!)
* @param   found    - a callback function to be called on success, failure or timeout (only if
*                     ERR_INPROGRESS is returned!)
* @param   arg      - argument to pass to the callback function
*
* @return@ERR_T
*   WCHNET_ERR_SUCCESS if hostname is a valid IP address string or the host name is already in the local names table.
*   ERR_INPROGRESS   enqueue a request to be sent to the DNS server for resolution if no errors are present.
*/
uint8_t WCHNET_HostNameGetIp( const char *hostname, uint8_t *addr, dns_callback found, void *arg );

/**
* @brief   配置库KEEP LIVE参数
*
* @param   *cfg - KEEPLIVE配置参数
*
* @returnNone
*/
void WCHNET_ConfigKeepLive( struct _KEEP_CFG *cfg );

/**
* @brief   配置socket KEEP LIVE使能
*
* @param   socketid - socketID值
* @param   enable - 1:启用0:关闭
*
* @return@ERR_T
*/
uint8_t WCHNET_SocketSetKeepLive( uint8_t socketid, uint8_t enable );

/**
* @brief   PHY状态改变配置
*
* @param   phy_stat - PHY状态值
*
* @returnNone
*/
void WCHNET_PhyStatus( uint32_t phy_stat );


#ifdef __cplusplus
}
#endif
#endif
main.c
void WCHNET_HandleGlobalInt(void)
{
    u8initstat;
    u16 i;
    u8socketinit;

    initstat = WCHNET_GetGlobalInt(); /* 获取全局中断标志*/
    if(initstat & GINT_STAT_UNREACH){/* 不可达中断 */
      debug_printf("GINT_STAT_UNREACH\r\n");
    }
    if(initstat & GINT_STAT_IP_CONFLI){/* IP冲突中断 */
      debug_printf("GINT_STAT_IP_CONFLI\r\n");
    }
    if(initstat & GINT_STAT_PHY_CHANGE){/* PHY状态变化中断 */
      i = WCHNET_GetPHYStatus(); /* 获取PHY连接状态*/
      if(i & PHY_Linked_Status) {
            debug_printf("PHY Link connected\r\n");
      }
      else {
            debug_printf("PHY Link disconnected\r\n");
      }
    }
    if(initstat & GINT_STAT_SOCKET){//socket通信
      for(i = 0; i < WCHNET_MAX_SOCKET_NUM; i++){
            socketinit = WCHNET_GetSocketInt(i);
            if(socketinit){//有事件需要处理

            }
      }
    }
}

/*********************************************************************
* @fn      WCHNET_DHCPCallBack
*
* @brief   DHCPCallBack
*
* @returnDHCP status
*/
u8 WCHNET_DHCPCallBack(u8 status, void *arg)
{
    u8 *p;
    if(!status){
      p = arg;
      printf("DHCP Success\r\n");
      memcpy(eth_ip_addr, p, 4);
      memcpy(eth_gwip_addr, &p, 4);
      memcpy(eth_ip_mask, &p, 4);
      debug_printf("eth_ip_addr: %d.%d.%d.%d\r\n",eth_ip_addr,eth_ip_addr,eth_ip_addr,eth_ip_addr);
      debug_printf("eth_gwip_addr: %d.%d.%d.%d\r\n",eth_gwip_addr,eth_gwip_addr,eth_gwip_addr,eth_gwip_addr);
      debug_printf("eth_ip_mask: %d.%d.%d.%d\r\n",eth_ip_mask,eth_ip_mask,eth_ip_mask,eth_ip_mask);
      debug_printf("DNS1: %d.%d.%d.%d \r\n", p, p, p, p);
      debug_printf("DNS2: %d.%d.%d.%d \r\n", p, p, p, p);
      return 0;
    }
    else{
      debug_printf("DHCP Fail %02x \r\n", status);
      return 1;
    }
}

int main(void)
{
      NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
      delay_init();
      uart_init(115200, 115200);

      //初始化以太网
      if (eth_init()!=0) {
            debug_printf("eth_init err\r\n");
            delay_ms(100);
      __disable_irq();
      NVIC_SystemReset();//重启
    }
      WCHNET_DHCPStart(WCHNET_DHCPCallBack);               /*开始DHCP,返回结果在WCHNET_DHCPCallBack函数中*/

      printf("start\r\n");
      while(1)
    {
      WCHNET_MainTask();         /*以太网库主任务函数,需要循环调用*/
      if(WCHNET_QueryGlobalInt())/*查询以太网全局中断,如果有中断,调用全局中断处理函数*/
      {
            WCHNET_HandleGlobalInt();
      }
      }
}
MAC地址:需唯一,可通过WCHNET_GetMacAddr()获取芯片内置地址或手动设置。
回调函数:通过WCHNET_DHCPStart()注册,用于接收DHCP事件(成功/失败/超时)。
主机名:可选配置,便于在路由器设备列表中识别设备。


应用场景:

[*]物联网设备
CH32V307作为边缘节点,通过DHCP快速接入局域网,实现数据上传至云端(如MQTT协议)。例如,智能家居中的温湿度传感器,通电后自动获取IP并连接服务器。
[*]工业自动化
在工厂网络中,设备需频繁更换位置或IP地址。DHCP功能可避免手动配置错误,提升部署效率。例如,PLC模块通过DHCP获取临时IP,完成调试后恢复静态IP。
[*]开发调试阶段
使用DHCP可快速验证网络功能,无需预先规划IP地址。结合ping命令或网络调试助手,可快速定位连接问题。



风之呢喃 发表于 2025-8-1 13:46

能ping通对吧。楼主是否可以把工程文件打包一份上传一下。
页: [1]
查看完整版本: 【CH32V317W-R0开发板】以太网测评之DHCP