【以太网接口芯片----CH392T Webserver应用】单片机实现Webserver网络控制

一、简介:

  在单片机应用需求中通过以太网进行数据远程传输交互成为如今主流,但对于开发者来说,网络协议栈开发的时间和成本会占用很多资源,所以选用一款便于开发的以太网芯片是一个很好的选择。

因此,不考虑开发协议栈,但能实现快速联网可以选择两种方案:

  1. 无线:MCU+无线模组。
  2. 有线:MCU+以太网协议栈芯片。

  而在一些工业场景中,考虑到环境的复杂性,选择有线以太网方案是一个不错的选择。对于不带MAC+PHY的单片机来说是无法拓展网口,因此需要一个转接芯片,通过串口\SPI\并口等简单通讯外设接口来扩展出网口。

  本文会基于沁恒微电子的以太网协议栈芯片CH392T来做一个远程Web浏览器控制的示例(主控芯片为CH32V307,SPI接口),简单演示通过以太网进行参数修改、数据传输、远程控制。

图形用户界面, 应用程序

描述已自动生成

  CH392 是以太网协议栈管理芯片,自带 10M以太网介质传输层(MAC)和物理层(PHY),完全兼容IEEE802.3 协议,内置IP、DHCP、ARP、ICMP、IGMP、UDP、TCP等以太网协议栈固件。

图示, 示意图

描述已自动生成

CH392支持两种通讯接口:SPI 接口或者异步串口,单片机/DSP/MCU/MPU 等控制器可以通过上述任何一种通讯接口控制CH392芯片进行以太网通讯。

 

二、应用: 

  Webserver是客户端通过HTTP协议来进行请求访问,采用请求/响应模型。而HTTP是基于TCP协议进行报文封装,因此对于CH392只需应用在TCPserver模式,并对收发数据进行协议层封装解析即可。

   单片机的SPI接口对CH392T进行参数配置,基于例程和手册说明,CH392T操作步骤:初始化SPI接口(注意SPI时序和模式,可以通过check命令码保证接口正常)-----初始化392(如手册描述)-----配置socket模式并打开(手册描述)-----中断处理,此步骤不详细描述。

  完成CH392T的基础配置后进行HTTP协议的封装和解析。对于HTTP协议:

   基本步骤可以分为以下几步:

  1. 客户端发起请求:用户通过客户端(如浏览器)输入 URL,客户端向服务器发起一个 HTTP 请求。
  2. 服务器处理请求:服务器接收到请求后,根据请求的类型(如GET、POST等)和请求的资源,进行相应的处理。
  3. 服服务器返回响应:服务器将处理结果包装成HTTP响应消息,发送回客户端。
  4. 客户端加载页面:客户端接收到响应后,根据响应内容(如HTML、图片等)加载页面,展示给用户。

   MCU通过对CH392T的接收中断的Buffer进行解析,并将改参数传递致HTTP协议解析函数中进行请求类型分析,在WebServer函数中进行数据类型分解,根据所请求的类型CH392会发送不同HTML Buffer数据,HTML封装在HTTPS底层库中(详细下载底部链接例程查看),主要是CH392根据不同请求来进行HTML的Buffer打包发送。

 1 void WebServer(void)
 2 {
 3     if(flag & RECVDATA )
 4     {
 5         flag  &= ~RECVDATA;
 6         ParseHttpRequest(http_request,RecvBuffer);    
 7         switch (http_request->METHOD)  
 8         {
 9             case METHOD_ERR :
10             break;
11             case METHOD_HEAD:
12             case METHOD_POST:
13             case METHOD_GET:
14                 name = (char*)GetUriName((char *)http_request->URI);
15                 if (!strcmp(name, "/")) {http_request->TYPE = PTYPE_HTML;}
16 
17                 else { ParseUriType(&http_request->TYPE, name);  }
18                 if(http_request->TYPE == PTYPE_CGI)
19                 {
20                     LedControl(http_request->URI);                                                                    /*LED控制部分*/
21                     ptr1 =  strstr((char *)(http_request->URI),"CH392SETING") ;                                       /*查找接收缓冲区(浏览器请求信息),确认是否有CH392设置请求*/
22                     if(ptr1 !=NULL)
23                     {
24                         ptr1 = strstr((char *)(http_request->URI),"IP");                                                /*从浏览器请求信息中提取 IP 信息*/
25                         if (ptr1 !=NULL)
26                         {
27                             printf("******IP计算****************************************\n");
28                             IpSeting((http_request->URI),ip);
29                             printf("New IP address = %d.%d.%d.%d\n",(UINT16)ip[0],(UINT16)ip[1],(UINT16)ip[2],(UINT16)ip[3]);        
30                             i = memcmp(lastip,ip,4);                                                                         /*与上一次提取的IP进行对比,查看是否改变,如果改变则顺序执行下面的IP设置部分,否则跳过*/
31                             if(i){                                                                                           /*IP改变*/
32                                 flag |=IPCHANGE;                                                                            /*IP改变,flag标志位0置1*/
33                                 printf("ip change\n");
34                                 memcpy (CH392IPAddr,ip,4);                                                                  /*更新CH392的IP信息*/
35                                 memcpy (lastip,ip,4);                                                                       /*新的IP值赋给前一次,方便下次比较*/
36                                 IpRefrsh(HtmlBuffer,ip);
37                             }
38                         }            
39 
40                         ptr1 = strstr((char *)(http_request->URI),"PORT");                                                /*从请求信息中提取Port信息*/   
41                         if (ptr1 !=NULL)
42                         {
43                             printf("******PORT计算****************************************\n");
44                             port = PortSeting(http_request->URI);
45                             printf("New Port = %2d\n",(UINT16)port);
46                             if(port != lastport)                                                                             /*与上一次提取的Port进行对比,查看是否改变,如果改变则顺序执行下面的Port设置部分,否则跳过*/
47                             {
48                                 flag |=PORTCHANGE;                                                                              /*IP改变,flag标志位1置1*/
49                                 Socket0SourPort = port;
50                                 lastport = port;
51                                 printf("port change\n");
52                                 PortRefresh(HtmlBuffer,port);
53                             }
54                         }
55                     }
56 
57                     ptr1 = strstr((char *)(http_request->URI),"monitor");                                           /*查找接收缓冲区(浏览器请求信息),确认是否有查看监控信息请求*/
58                     if(ptr1 !=NULL)
59                     {
60                         ADCData(ADC);
61                         TempratureRefresh(HtmlBuffer,ADC[0]);
62                         CurrentRefresh(HtmlBuffer,ADC[1]);
63                         VoltageRefresh(HtmlBuffer,ADC[2]);
64                     }
65                 }
66 
67                 MakeHttpResponse(httpweb,http_request->TYPE);
68                 CH392CMDSendData(socket_num,httpweb,strlen((char*)httpweb));                                                   /*发送响应报文*/
69                 CH392CMDGetSocketInt(socket_num);
70                 len = sizeof(HtmlBuffer);
71                 SockInf.RemLen = len;
72 
73                 if(len > 1460)len = 1460;
74                 CH392CMDSendData(socket_num,HtmlBuffer,len);
75                 SockInf.SendLen = len;                                                                             /* 保存发送的长度 */
76                 SockInf.pSend = HtmlBuffer;
77         }
78     }
79 
80 }

 

三、演示:

  根据程序中CH392T的IP参数设置为192.168.100.20

 

  首先在浏览器中输入该IP地址参数并Enter进入:

 

   通过wirehshark抓包可以查看具体流程:Web客户端发起连接请求-----CH392响应---------Web客户端发起GET请求------CH392响应-----Web发起数据端口连接请求------CH392T发送HTML Buffer-----Web客户端接收。

   (正常为了节省时间和传输效率,Web服务端在发送完成后会主动断开该链接,该例程中屏蔽了改操作)

    if(sock_int_socket & SINT_STAT_SENBUF_FREE)                       /* 发送缓冲区空闲,可以继续写入要发送的数据 */
    {
        printf("SINT_STAT_SENBUF_FREE\n");

        if(SockInf.SendLen >= SockInf.RemLen)
        {
            SockInf.RemLen = 0;                                       /* 数据已经发送完毕 */
           // CH392CMDTCPDisconnect(socket_num);             /*发送完成断开连接*/
        }
        else
        {

            SockInf.pSend += SockInf.SendLen;                         /* 对发送指针进行偏移 */
            SockInf.RemLen -= SockInf.SendLen;                        /* 计算剩余长度 */
            if(SockInf.RemLen > 1460)SockInf.SendLen = 1460;          /* 计算本次可以发送的数据长度 */
            else SockInf.SendLen = SockInf.RemLen;
            CH392CMDSendData(sockindex,SockInf.pSend,SockInf.SendLen);   /* 发送数据 */
        }
    }

 

   该流程正常完成后,Web会将MCU中构成的HTML文件进行加载形成如下界面:

 

   左边可以通过Web进行修改CH392的参数和控制LED,右边可以点击watch按钮进行数据查看,点击change将参数修改为192.168.100.64再进行连接,如下图所示:

 

   点击change之后,MCU打印参数如下,CH392T收到参数后,MCU对CH392T进行重新复位并重写相应参数,复位完成后Web中再输入192.168.100.64。

 

   输入完成后通过192.168.100.64可以再次进入演示页面。

例程链接:https://files.cnblogs.com/files/blogs/805237/CH392T_WEB_SERVER.rar?t=1730115828&download=true

posted on 2024-10-28 19:47  sw2222  阅读(1091)  评论(0)    收藏  举报