dirty 发表于 2024-7-13 12:17

【全能小网关|CH32V208】--7.DHCP

<p>&nbsp; &nbsp; &nbsp; 本篇讲述用沁恒CH32V208开发板实现DHCP.</p>

<p>一.了解与准备</p>

<p>&nbsp; &nbsp; &nbsp; DHCP(Dynamic Host Configuration Protocol),动态主机配置协议,是一个应用层协议。当我们将客户主机ip地址设置为动态获取方式时,DHCP服务器就会根据DHCP协议给客户端分配IP,使得客户机能够利用这个IP上网。可以用Wireshark抓取DHCP包。</p>

<p>&nbsp; &nbsp; &nbsp; CH32V208芯片自带以太网MAC,内置10MPHY,支持10M以太网,我们可以看到芯片引脚直接与网口座连接,这款芯片具备蓝牙与以太网功能,比较适合做小型IOT网关。</p>

<p>&nbsp; &nbsp; &nbsp;沁恒自有一套WCHNET协议栈库,该协议栈库提供了TCP/IP 子程序库,集成了 TCP、UDP、ARP、RARP、ICMP、IGMP等以太网协议栈,可以同时支持 TCP、UDP 和 IPRAW 三种模式。在SDK里有一个专门文档介绍,可以根据需要参考详细说明使用。</p>

<p>&nbsp;</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&lt;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(&amp;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(&amp;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, &amp;p, 4);
      memcpy(IPMask, &amp;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 &amp; GINT_STAT_UNREACH)                              //Unreachable interrupt
    {
      printf("GINT_STAT_UNREACH\r\n");
    }
    if (intstat &amp; GINT_STAT_IP_CONFLI)                            //IP conflict
    {
      printf("GINT_STAT_IP_CONFLI\r\n");
    }
    if (intstat &amp; GINT_STAT_PHY_CHANGE)                           //PHY status change
    {
      i = WCHNET_GetPHYStatus();
      if (i &amp; PHY_Linked_Status)
            printf("PHY Link Success\r\n");
    }
    if (intstat &amp; GINT_STAT_SOCKET) {                           //socket related interrupt
      for (i = 0; i &lt; 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 &lt; 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>&nbsp;</p>

<p>三.测验</p>

<div style="text-align: center;"></div>

<p>&nbsp; &nbsp; &nbsp;</p>

<p>&nbsp; &nbsp; &nbsp; 编译烧录后,插上网线,上电,可看到日志如上,DHCP获取IP信息成功。</p>

<div style="text-align: center;">&nbsp;</div>
页: [1]
查看完整版本: 【全能小网关|CH32V208】--7.DHCP