【以太网接口芯片----CH394Q】通过以太网接口芯片CH394Q使用DHCP和DNS(底部附代码链接)

一、简介:

  本文会基于沁恒微电子以太网协议栈芯片CH394进行DHCP和DNS示例(主控芯片为CH32V307,SPI接口),简单演示通过UDP模式下进行DHCP报文发送和解析,同时利用DNS进行域名访问。

图形用户界面, 应用程序

描述已自动生成

  CH394芯片自带10/100M以太网介质传输层MAC和物理层收发器PHY,完全兼容IEEE802.3协议, 内置了IP、ARP、ICMP、IGMP、UDP、TCP等以太网协议栈固件。单片机系统可以方便的通过CH394芯 片进行网络通讯。CH394支持网络唤醒模式(WOL)和掉电模式。

 

 二、应用: 

  DHCP过程是通过UDP作为传输协议,设备端通过UDP将消息传输到具有DHCP服务器设备的67号端口,DHCP服务器返回消息给客户端的68号端口。大致流程为设备端发起DHCP DISCOVER报文请求HDCP------DHCP服务器提供OFFER------设备端发送Request报文确认------服务器发起ACK,DHCP成功。具体流程和协议内容可以看此贴DHCP介绍与实现方法 - 小小小学僧 - 博客园。 

  程序步骤:

  1、初始化SPI接口--->复位CH394Q--->检测PHY状态--->初始化CH394--->收发缓存  

    CH394Q_GPIO_Init();
    CH394Q_SPIPort_Init();
    Delay_Ms(100);
    CH394Q_ResetHW();                              // CH394Q硬件复位
    printf("\r\n CH394Q EVT Test Demo \r\n");
    i = CH394Q_GetCHIPV();
    printf(" CH394Q CHIPV : %2x\r\n", i);
    CH394Q_PHY_Check();                            // PHY连接检测

    CH394Q_InfParam(CH394Q_IPAddr, CH394Q_IPMask , CH394Q_GWIPAddr, CH394Q_MACAddr); // 设置CH394Q网络参数
    CH394Q_SocketBuf_Init(TX_BUFF, RX_BUFF);       // 初始化8个Socket的发送接收缓存大小

 

        2、DHCP运行:封装DHCP DISCOVER报文------创建UDP SOCKET(SOCKET3)发送该报文------接收DHCP服务器offer数据并解析DHCP服务器提供的IP等参数------通过UDP发送DHCP request报文-------接收DHCP服务器的ACK报文,此时表明DHCP成功。其他情况下通过定时器进行计数,当DHCP流程进入某一阶段相应状态执行计数超时,则重新进行DHCP DIscover报文发送,直到DHCP流程完成。(报文封装和校验附件代码查看)
 
u8 DHCP_run(void)//0
{
    uint8_t  type;
    uint8_t  ret;

if(Conflict_flag == 1) { init_dhcp_client(); /*初始化DHCP客户端*/ TIM2_Init(); /*初始化定时器*/ Conflict_flag = 0; } if(dhcp_state == STATE_DHCP_STOP) { Conflict_flag = 1; return DHCP_STOPPED; } if(CH394Q_GetSn_STA(SOCK_DHCP) != SOCK_UDP) CH394Socket_Init(3, Sn_MODE_UDP, DHCP_CLIENT_PORT, 0x00); ret = DHCP_RUNNING; type = parseDHCPMSG(); switch ( dhcp_state ) { case STATE_DHCP_READY : DHCP_allocated_ip[0] = 0; DHCP_allocated_ip[1] = 0; DHCP_allocated_ip[2] = 0; DHCP_allocated_ip[3] = 0; send_DHCP_DISCOVER(); dhcp_time = 0; dhcp_state = STATE_DHCP_DISCOVER; //Delay_Us(1); break; case STATE_DHCP_DISCOVER : if (type == DHCP_OFFER) { DHCP_allocated_ip[0] = pDHCPMSG->yiaddr[0]; DHCP_allocated_ip[1] = pDHCPMSG->yiaddr[1]; DHCP_allocated_ip[2] = pDHCPMSG->yiaddr[2]; DHCP_allocated_ip[3] = pDHCPMSG->yiaddr[3]; send_DHCP_REQUEST(); dhcp_time = 0; dhcp_state = STATE_DHCP_REQUEST; } else ret = check_DHCP_timeout(); break; case STATE_DHCP_REQUEST : if (type == DHCP_ACK) { if (check_DHCP_leasedIP()) { // Network info assignment from DHCP printf(" DHCP 已获取:\r\n"); printf(" I P 地址:%d.%d.%d.%d\r\n",DHCP_allocated_ip[0],DHCP_allocated_ip[1],DHCP_allocated_ip[2],DHCP_allocated_ip[3]); printf(" 子网掩码:%d.%d.%d.%d\r\n",DHCP_allocated_sn[0],DHCP_allocated_sn[1],DHCP_allocated_sn[2],DHCP_allocated_sn[3]); printf(" 网关地址:%d.%d.%d.%d\r\n",DHCP_allocated_gw[0],DHCP_allocated_gw[1],DHCP_allocated_gw[2],DHCP_allocated_gw[3]); dhcp_ip_assign(); reset_DHCP_timeout(); dhcp_state = STATE_DHCP_LEASED; DHCP_Flag=1; } else { reset_DHCP_timeout(); dhcp_ip_conflict(); dhcp_state = STATE_DHCP_READY; } } else if (type == DHCP_NAK) { printf("> Receive DHCP_NACK\r\n"); reset_DHCP_timeout(); dhcp_state = STATE_DHCP_DISCOVER; } else ret = check_DHCP_timeout(); break; case STATE_DHCP_LEASED : ret = DHCP_IP_LEASED; if ((dhcp_lease_time != DEFAULT_LEASETIME) && ((dhcp_lease_time/2) < dhcp_time)) { #ifdef _DHCP_DEBUG_ printf("> Maintains the IP address \r\n"); #endif type = 0; OLD_allocated_ip[0] = DHCP_allocated_ip[0]; OLD_allocated_ip[1] = DHCP_allocated_ip[1]; OLD_allocated_ip[2] = DHCP_allocated_ip[2]; OLD_allocated_ip[3] = DHCP_allocated_ip[3]; DHCP_XID++; send_DHCP_REQUEST(); reset_DHCP_timeout(); dhcp_state = STATE_DHCP_REREQUEST; } break; case STATE_DHCP_REREQUEST : ret = DHCP_IP_LEASED; if (type == DHCP_ACK) { dhcp_retry_count = 0; if (OLD_allocated_ip[0] != DHCP_allocated_ip[0] || OLD_allocated_ip[1] != DHCP_allocated_ip[1] || OLD_allocated_ip[2] != DHCP_allocated_ip[2] || OLD_allocated_ip[3] != DHCP_allocated_ip[3]) { ret = DHCP_IP_CHANGED; dhcp_ip_update(); #ifdef _DHCP_DEBUG_ printf(">IP changed.\r\n"); #endif } #ifdef _DHCP_DEBUG_ else printf(">IP is continued.\r\n"); #endif reset_DHCP_timeout(); dhcp_state = STATE_DHCP_LEASED; } else if (type == DHCP_NAK) { #ifdef _DHCP_DEBUG_ printf("> Receive DHCP_NACK, Failed to maintain ip\r\n"); #endif reset_DHCP_timeout(); dhcp_state = STATE_DHCP_DISCOVER; } else ret = check_DHCP_timeout(); break; default : break; } return ret; }

 

3、DNS域名解析:创建UDP Socket------封装DNS查询报文------通过UDP Socket发送DNS查询报文(注意DNS的目的端口为固定端口:53,MDNS端口为5353)。------DNS服务器回复DNS应答报文------接收报文并解析(具体报文内容参考该贴:DNS介绍与实现方法 - 小小小学僧 - 博客园),
uint8_t DnsQuery(uint8_t s, uint8_t * name, uint8_t * pSip)
{
    struct dhdr dhp;
    uint16_t len,cnt;

    if(status>1)
    {
        count++;
        printf("count = %2d\n",(uint16_t)count);
        Delay_Ms(1);
        if(count>2000)
        {
            printf("DNS Fail!!!!\n");
            count =0;
            status =0;
        }
    }
    if(status == 1)
    {

        CH394Q_UDPSocketInit(s, Sn_MODE_UDP, 2000);
        status = 2;
        printf("status = 2!\n");
    }
    if(status ==2)
    {
        len = MakeDnsQueryMsg(0,(char *)name, dns_buf, MAX_DNS_BUF_SIZE);
        cnt = CH394Q_SocketSendTo(s,dns_buf,len,DNS_SERVER_IP,IPPORT_DOMAIN);
        if (cnt == 0) return(0);
        else
        {
            status = 3;
            printf("status = 3!\n");
        }
    }
    if(status ==4)
    {
        return(parseMSG(&dhp, dns_buf, pSip));                                                 /*解析响应报文并返回结果*/
    }
    return 0;
}

 

 3、主函数运行:
 while(1)
    {
        DHCP_run();    //DHCP运行

        if(DHCP_Flag==1)
        {
          if(Socket_FLag==0)

          { CH394Q_SetGINTE(0XFF);                         // 使能中断
            CH394Q_SetSINTE(0XFF);                         // 使能socket中断
            printf(" TCP SERVER......\r\n");
            CH394Q_SetSn_MODE(0, Sn_MODE_NA);               //创建TCP SERVER socket
            printf("scoket1=  %x\r\n", CH394Q_GetSn_MODE(0));
            CH394Q_TCPServerSocketInit( 0, Sn_MODE_TCP |Sn_MODE_NA , CH394Q_Port);

            printf("scoket=  %x\r\n", CH394Q_GetSn_MODE(0));
            Socket_FLag=1;
          }
            if(QueryCH394QInterrupt() == 0)
            {
                CH394Q_GlobalInterrupt();
            }
            i=DnsQuery(SOCK_DNS,url_dn1,ip);    //DNS域名解析
            if(i)
            {
                printf("Domain name: %s \n",url_dn1);
                printf(" HTTPs_IP= %d.%d.%d.%d\n\n",ip[0],ip[1],ip[2],ip[3]);
                status = 1;
                break;
            }

        }
    }

 

二、应用:

  将CH394设备接入路由中,运行日志如下,可以看到默认IP是192.168.1.200,DHCP成功后的IP为192.168.1.139,再进行DNS解析百度域名,解析完成后IP地址为180.101.50.242.

 

 

例程链接:https://files.cnblogs.com/files/blogs/805237/CH394Q_DHCP%26DNS.rar?t=1758102429&download=true

 
 
posted on 2024-12-12 15:44  sw2222  阅读(1378)  评论(0)    收藏  举报