【以太网接口芯片----CH394 Webserver应用】使用以太网接口芯片CH394芯片搭建Webserver(底部附代码链接)
一、简介:
本文会基于沁恒微电子最新的以太网协议栈芯片CH394来做一个远程Web浏览器控制的示例(主控芯片为CH32V307,SPI接口),简单演示通过以太网进行参数修改、数据传输、远程控制。相较于之前的CH395芯片,CH394的通信速度更快、功耗更低、外围电路更精简,因此选择CH394芯片来拓展需要网口的应用产品是不错的选择。
CH394芯片自带10/100M以太网介质传输层MAC和物理层收发器PHY,完全兼容IEEE802.3协议, 内置了IP、ARP、ICMP、IGMP、UDP、TCP等以太网协议栈固件。单片机系统可以方便的通过CH394芯 片进行网络通讯。CH394支持网络唤醒模式(WOL)和掉电模式。
二、应用:
Webserver是客户端通过HTTP协议来进行请求访问,采用请求/响应模型。而HTTP是基于TCP协议进行报文封装,因此对于CH394只需应用在TCPserver模式,并对收发数据进行协议层封装解析即可。
CH394初始化配置如下:
初始化SPI接口--->复位CH394Q--->检测PHY状态--->初始化CH394--->收发缓存、中断、socket中断使能--->初始化socket和使能keeplive。
CH394Q_GPIO_Init(); CH394Q_SPIPort_Init(); restart: 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(CH394IPAddr, CH394IPMask , CH394GWIPAddr, CH394MACAddr); // 设置CH394Q网络参数 CH394Q_SocketBuf_Init(TX_BUFF, RX_BUFF); // 初始化8个Socket的发送接收缓存大小 CH394Q_SetGINTE(0XFF); // 使能中断 CH394Q_SetSINTE(0XFF); // 使能socket中断 printf(" TCP SERVER......\r\n"); CH394Q_TCPServerSocketInit( 0, Sn_MODE_TCP, Socket0SourPort); CH394Q_TCPServerSocketInit( 1, Sn_MODE_TCP, Socket0SourPort); CH394Q_TCPServerSocketInit( 2, Sn_MODE_TCP, Socket0SourPort); CH394Q_SetSn_KEEPALIVE(0,2); CH394Q_SetSn_KEEPALIVE(1,2);
CH394Q_SetSn_KEEPALIVE(2,2);
完成CH394的基础配置后,进入主循环处理CH394的中断并对HTTP协议的封装和解析。
while(1) { if(QueryCH394QInterrupt() == 0) { CH394Q_GlobalInterrupt(); } WebServer(); /*http数据解析*/ if((flag & IPCHANGE )|( flag & PORTCHANGE) ) /*IP或者Port改变则复位CH394并重新初始化*/ { flag &=~(IPCHANGE|PORTCHANGE) ; printf("reset all!\n"); CH394Q_ResetHW(); Delay_Ms(200); /* 延时200毫秒 */ printf("restart\n"); goto restart; } }
对于HTTP协议:基本步骤可以分为以下几步:
- 客户端发起请求:用户通过客户端(如浏览器)输入 URL,客户端向服务器发起一个 HTTP 请求。
- 服务器处理请求:服务器接收到请求后,根据请求的类型(如GET、POST等)和请求的资源,进行相应的处理。
- 服服务器返回响应:服务器将处理结果包装成HTTP响应消息,发送回客户端。
- 客户端加载页面:客户端接收到响应后,根据响应内容(如HTML、图片等)加载页面,展示给用户。
MCU通过对CH394的接收中断的Buffer进行解析,并将改参数传递致HTTP协议解析函数中进行请求类型分析,在WebServer函数中进行数据类型分解,根据所请求的类型CH394会发送不同HTML Buffer数据,HTML封装在HTTPS底层库中(详细下载底部链接例程查看),主要是CH394根据不同请求来进行HTML的Buffer打包发送。
void WebServer(void) //HTML数据解析和发送
{
if(flag & RECVDATA )
{
printf("WebServer\n");
flag &= ~RECVDATA;
ParseHttpRequest(http_request,RecvBuffer);
switch (http_request->METHOD)
{
case METHOD_ERR :
break;
case METHOD_HEAD:
case METHOD_POST:
case METHOD_GET:
printf("WebServer 22222\n");
name = (char*)GetUriName((char *)http_request->URI);
if (!strcmp(name, "/")) {http_request->TYPE = PTYPE_HTML;}
else { ParseUriType(&http_request->TYPE, name); }
if(http_request->TYPE == PTYPE_CGI)
{
LedControl(http_request->URI); /*LED控制部分*/
ptr1 = strstr((char *)(http_request->URI),"CH395SETING") ; /*查找接收缓冲区(浏览器请求信息),确认是否有CH395设置请求*/
if(ptr1 !=NULL)
{
ptr1 = strstr((char *)(http_request->URI),"IP"); /*从浏览器请求信息中提取 IP 信息*/
if (ptr1 !=NULL)
{
printf("******IP计算****************************************\n");
IpSeting((http_request->URI),ip);
printf("New IP address = %d.%d.%d.%d\n",(UINT16)ip[0],(UINT16)ip[1],(UINT16)ip[2],(UINT16)ip[3]);
i = memcmp(lastip,ip,4); /*与上一次提取的IP进行对比,查看是否改变,如果改变则顺序执行下面的IP设置部分,否则跳过*/
if(i){ /*IP改变*/
flag |=IPCHANGE; /*IP改变,flag标志位0置1*/
printf("ip change\n");
memcpy (CH394IPAddr,ip,4); /*更新CH395的IP信息*/
memcpy (lastip,ip,4); /*新的IP值赋给前一次,方便下次比较*/
IpRefrsh(HtmlBuffer,ip);
}
}
ptr1 = strstr((char *)(http_request->URI),"PORT"); /*从请求信息中提取Port信息*/
if (ptr1 !=NULL)
{
printf("******PORT计算****************************************\n");
port = PortSeting(http_request->URI);
printf("New Port = %2d\n",(UINT16)port);
if(port != lastport) /*与上一次提取的Port进行对比,查看是否改变,如果改变则顺序执行下面的Port设置部分,否则跳过*/
{
flag |=PORTCHANGE; /*IP改变,flag标志位1置1*/
Socket0SourPort = port;
lastport = port;
printf("port change\n");
PortRefresh(HtmlBuffer,port);
}
}
}
ptr1 = strstr((char *)(http_request->URI),"monitor"); /*查找接收缓冲区(浏览器请求信息),确认是否有查看监控信息请求*/
if(ptr1 !=NULL)
{
ADCData(ADC);
TempratureRefresh(HtmlBuffer,ADC[0]);
CurrentRefresh(HtmlBuffer,ADC[1]);
VoltageRefresh(HtmlBuffer,ADC[2]);
}
}
MakeHttpResponse(httpweb,http_request->TYPE); /*发送响应报文*/
CH394Q_SocketTCPSend(SocketNUM, httpweb, strlen((char*)httpweb));//394发送HTML文件数据
Delay_Ms(1);
len = sizeof(HtmlBuffer);
SockInf.RemLen = len; /* 保存长度 */
if(len > 2048)len = 1200; /* 发送缓冲区最大为2048 */
CH394Q_SocketTCPSend(SocketNUM, HtmlBuffer, len);
Delay_Ms(1);
SockInf.SendLen = len; /* 保存发送的长度 */
SockInf.pSend = HtmlBuffer; /* 发送换取区指针 */
}
}
}
三、演示:
根据程序中CH394的IP参数设置为192.168.1.200,首先在浏览器中输入该IP地址参数并Enter进入:
通过wirehshark抓包可以查看具体流程:Web客户端发起连接请求-----CH394响应---------Web客户端发起GET请求------CH394响应-----Web发起数据端口连接请求------CH394发送HTML Buffer-----Web客户端接收。
该流程正常完成后,Web会将MCU中构成的HTML文件进行加载形成如下界面:
左边可以通过Web进行修改CH394的参数和控制LED,右边可以点击watch按钮进行数据查看,点击change将参数修改为192.168.1.100再进行连接。
在IP输入框修改IP为192.168.1.100,点击change之后,MCU打印参数如下,CH394收到参数后,MCU对394进行重新复位并重写相应参数,复位完成后Web中再输入192.168.1.100。
输入完成后通过192.168.1.100可以再次进入演示页面。
例程链接:https://files.cnblogs.com/files/blogs/805237/CH394_Webserver.rar?t=1732692356&download=true(IDE为MRS,如果编译程序后报缺失LD文件错误,可以将编译器中的LD文件夹删除,然后回到工程文件夹中重新复制粘贴一下SRC文件夹中的LD文件夹到编译器中)