【全能小网关|CH32V208】--7.DHCP
<p> 本篇讲述用沁恒CH32V208开发板实现DHCP.</p><p>一.了解与准备</p>
<p> DHCP(Dynamic Host Configuration Protocol),动态主机配置协议,是一个应用层协议。当我们将客户主机ip地址设置为动态获取方式时,DHCP服务器就会根据DHCP协议给客户端分配IP,使得客户机能够利用这个IP上网。可以用Wireshark抓取DHCP包。</p>
<p> CH32V208芯片自带以太网MAC,内置10MPHY,支持10M以太网,我们可以看到芯片引脚直接与网口座连接,这款芯片具备蓝牙与以太网功能,比较适合做小型IOT网关。</p>
<p> 沁恒自有一套WCHNET协议栈库,该协议栈库提供了TCP/IP 子程序库,集成了 TCP、UDP、ARP、RARP、ICMP、IGMP等以太网协议栈,可以同时支持 TCP、UDP 和 IPRAW 三种模式。在SDK里有一个专门文档介绍,可以根据需要参考详细说明使用。</p>
<p> </p>
<p>二.代码准备</p>
<p>1.获取芯片MAC地址</p>
<pre>
<code>#define ROM_CFG_USERADR_ID 0x1FFFF7E8
/*********************************************************************
* @fn WCHNET_GetMacAddr
*
* @brief Get MAC address
*
* @return none.
*/
void WCHNET_GetMacAddr( uint8_t *p )
{
uint8_t i;
uint8_t *macaddr=(uint8_t *)(ROM_CFG_USERADR_ID+5);
for(i=0;i<6;i++)
{
*p = *macaddr;
p++;
macaddr--;
}
}</code></pre>
<p>2.配置DHCP主机名,这个由库函数完成</p>
<pre>
<code>WCHNET_DHCPSetHostname("WCHNET"); //Configure DHCP host name</code></pre>
<p>3.以太网库初始化</p>
<pre>
<code>/*********************************************************************
* @fn ETH_LibInit
*
* @brief Ethernet library initialization program
*
* @returncommand status
*/
uint8_t ETH_LibInit( uint8_t *ip, uint8_t *gwip, uint8_t *mask, uint8_t *macaddr )
{
uint8_t s;
struct _WCH_CFGcfg;
memset(&cfg,0,sizeof(cfg));
cfg.TxBufSize = ETH_TX_BUF_SZE;
cfg.TCPMss = WCHNET_TCP_MSS;
cfg.HeapSize = WCHNET_MEM_HEAP_SIZE;
cfg.ARPTableNum = WCHNET_NUM_ARP_TABLE;
cfg.MiscConfig0 = WCHNET_MISC_CONFIG0;
cfg.MiscConfig1 = WCHNET_MISC_CONFIG1;
cfg.led_link = ETH_LedLinkSet;
cfg.led_data = ETH_LedDataSet;
cfg.net_send = ETH_TxPktChainMode;
cfg.CheckValid = WCHNET_CFG_VALID;
s = WCHNET_ConfigLIB(&cfg);
if(s){
return (s);
}
s = WCHNET_Init(ip,gwip,mask,macaddr);
ETH_Init(macaddr);
return (s);
}
</code></pre>
<p>4.启动DHCP,使用的库函数,回调函数里获取ip分配</p>
<pre>
<code>/*********************************************************************
* @fn WCHNET_DHCPCallBack
*
* @brief DHCPCallBack
*
* @param status - status returned by DHCP
* 0x00 - Success
* 0x01 - Failure
* arg - Data returned by DHCP
*
* @returnDHCP status
*/
u8 WCHNET_DHCPCallBack(u8 status, void *arg)
{
u8 *p;
u8 tmp = {0, 0, 0, 0};
if(!status)
{
p = arg;
printf("DHCP Success\r\n");
/*If the obtained IP is the same as the last IP, exit this function.*/
if(!memcmp(IPAddr, p ,sizeof(IPAddr)))
return READY;
/*Determine whether it is the first successful IP acquisition*/
if(memcmp(IPAddr, tmp ,sizeof(IPAddr))){
/*The obtained IP is different from the last value,
* then disconnect the last connection.*/
WCHNET_SocketClose(SocketId, TCP_CLOSE_NORMAL);
}
memcpy(IPAddr, p, 4);
memcpy(GWIPAddr, &p, 4);
memcpy(IPMask, &p, 4);
printf("IPAddr = %d.%d.%d.%d \r\n", (u16)IPAddr, (u16)IPAddr,
(u16)IPAddr, (u16)IPAddr);
printf("GWIPAddr = %d.%d.%d.%d \r\n", (u16)GWIPAddr, (u16)GWIPAddr,
(u16)GWIPAddr, (u16)GWIPAddr);
printf("IPMask = %d.%d.%d.%d \r\n", (u16)IPMask, (u16)IPMask,
(u16)IPMask, (u16)IPMask);
printf("DNS1: %d.%d.%d.%d \r\n", p, p, p, p);
printf("DNS2: %d.%d.%d.%d \r\n", p, p, p, p);
WCHNET_CreateTcpSocket(); //Create a TCP connection
return READY;
}
else
{
printf("DHCP Fail %02x \r\n", status);
/*Determine whether it is the first successful IP acquisition*/
if(memcmp(IPAddr, tmp ,sizeof(IPAddr))){
/*The obtained IP is different from the last value*/
WCHNET_SocketClose(SocketId, TCP_CLOSE_NORMAL);
}
return NoREADY;
}
}</code></pre>
<p>5.主函数循环里调用wchnet主任务函数,其内由库组成</p>
<pre>
<code>/*********************************************************************
* @fn WCHNET_MainTask
*
* @brief library main task function
*
* @returnnone.
*/
void WCHNET_MainTask(void)
{
WCHNET_NetInput( ); /* Ethernet data input */
WCHNET_PeriodicHandle( ); /* Protocol stack time-related task processing */
WCHNET_HandlePhyNegotiation( );
}
</code></pre>
<p>6.检测中断事件,并做处理</p>
<pre>
<code>/*检测以太网全局中断*/
WCHNET_QueryGlobalInt()
/*获取以太网状态及处理*/
/*********************************************************************
* @fn WCHNET_HandleGlobalInt
*
* @brief Global Interrupt Handle
*
* @returnnone
*/
void WCHNET_HandleGlobalInt(void)
{
u8 intstat;
u16 i;
u8 socketint;
intstat = WCHNET_GetGlobalInt(); //get global interrupt flag
if (intstat & GINT_STAT_UNREACH) //Unreachable interrupt
{
printf("GINT_STAT_UNREACH\r\n");
}
if (intstat & GINT_STAT_IP_CONFLI) //IP conflict
{
printf("GINT_STAT_IP_CONFLI\r\n");
}
if (intstat & GINT_STAT_PHY_CHANGE) //PHY status change
{
i = WCHNET_GetPHYStatus();
if (i & PHY_Linked_Status)
printf("PHY Link Success\r\n");
}
if (intstat & GINT_STAT_SOCKET) { //socket related interrupt
for (i = 0; i < WCHNET_MAX_SOCKET_NUM; i++) {
socketint = WCHNET_GetSocketInt(i);
if (socketint)
WCHNET_HandleSockInt(i, socketint);
}
}
}</code></pre>
<p>7.main函数如下</p>
<pre>
<code>/*********************************************************************
* @fn main
*
* @brief Main program
*
* @returnnone
*/
int main(void)
{
u8 i;
Delay_Init();
USART_Printf_Init(115200); //USART initialize
printf("DHCP Test\r\n");
if((SystemCoreClock == 60000000) || (SystemCoreClock == 120000000))
printf("SystemClk:%d\r\n", SystemCoreClock);
else
printf("Error: Please choose 60MHz and 120MHz clock when using Ethernet!\r\n");
printf("net version:%x\n", WCHNET_GetVer());
if( WCHNET_LIB_VER != WCHNET_GetVer()){
printf("version error.\n");
}
WCHNET_GetMacAddr(MACAddr); //get the chip MAC address
printf("mac addr:");
for(i = 0; i < 6; i++)
printf("%x ", MACAddr);
printf("\n");
TIM2_Init();
WCHNET_DHCPSetHostname("WCHNET"); //Configure DHCP host name
i = ETH_LibInit(IPAddr,GWIPAddr,IPMask,MACAddr); //Ethernet library initialize
mStopIfError(i);
if(i == WCHNET_ERR_SUCCESS)
printf("WCHNET_LibInit Success\r\n");
WCHNET_DHCPStart(WCHNET_DHCPCallBack); //Start DHCP
while(1)
{
/*Ethernet library main task function,
* which needs to be called cyclically*/
WCHNET_MainTask();
/*Query the Ethernet global interrupt,
* if there is an interrupt, call the global interrupt handler*/
if(WCHNET_QueryGlobalInt())
{
WCHNET_HandleGlobalInt();
}
}
}
</code></pre>
<p> </p>
<p>三.测验</p>
<div style="text-align: center;"></div>
<p> </p>
<p> 编译烧录后,插上网线,上电,可看到日志如上,DHCP获取IP信息成功。</p>
<div style="text-align: center;"> </div>
页:
[1]