0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

基于STM32的WEB服务器设计

DS小龙哥-嵌入式技术 来源:DS小龙哥-嵌入式技术 作者:DS小龙哥-嵌入式技 2022-02-28 14:03 次阅读

​一、环境介绍

MCU:STM32F103ZET6

网卡:ENC28J60

协议栈: UIP

开发软件:Keil5

二、功能介绍

STM32控制ENC28J60+UIP协议栈创建TCP服务器(WEB服务器),支持浏览器访问完成数据传输。 浏览器可以实时显示温度、时间、可以控制STM32开发板上的LED灯、蜂鸣器。

基于STM32的WEB服务器设计

poYBAGDYdXCAWkKMAAAAK8RNs4s030.png基于STM32的WEB服务器设计

poYBAGDYdXCAWkKMAAAAK8RNs4s030.png基于STM32的WEB服务器设计

poYBAGDYdXCAWkKMAAAAK8RNs4s030.png

基于STM32的WEB服务器设计

poYBAGDYdXCAWkKMAAAAK8RNs4s030.png

基于STM32的WEB服务器设计poYBAGDYdXCAWkKMAAAAK8RNs4s030.png

基于STM32的WEB服务器设计poYBAGDYdXCAWkKMAAAAK8RNs4s030.png

三、ENC28J60芯片介绍

ENC28J60 是带有行业标准串行外设接口(Serial Peripheral Interface,SPI)的独立以太网 控制器。它可作为任何配备有 SPI 的控制器的以太网接口。ENC28J60 符合 IEEE 802.3 的全部规范,采用了一系列包过滤机制以对传入数据包进行限制。 它还提供了一个内部 DMA 模块, 以实现快速数据吞吐和硬件支持的 IP 校验和计算。 与主控制器的通信通过两个中断引脚和 SPI 实现,数据传输速率高达 10 Mb/s。两个专用的引脚用于连接 LED,进行网络活动状态指示。ENC28J60 总共只有 28 脚,提供 QFN/TF

ENC28J60 的主要特点如下:

兼容 IEEE802.3 协议的以太网控制器

集成 MAC 和 10 BASE-T 物理层

支持全双工和半双工模式

数据冲突时可编程自动重发

SPI 接口速度可达 10Mbps

8K 数据接收和发送双端口 RAM

提供快速数据移动的内部 DMA 控制器

可配置的接收和发送缓冲区大小

两个可编程 LED 输出

带7个中断源的两个中断引脚

TTL 电平输入

提供多种封装:SOIC/SSOP/SPDIP/QFN 等。

ENC28J60 由七个主要功能模块组成:

1) SPI 接口,充当主控制器和 ENC28J60 之间通信通道。

2) 控制寄存器,用于控制和监视 ENC28J60。

3) 双端口 RAM 缓冲器,用于接收和发送数据包。

4) 判优器,当 DMA、发送和接收模块发出请求时对 RAM 缓冲器的访问进行控制。

5) 总线接口,对通过 SPI 接收的数据和命令进行解析。

6) MAC(Medium Access Control)模块,实现符合 IEEE 802.3 标准的 MAC 逻辑。

7) PHY(物理层)模块,对双绞线上的模拟数据进行编码和译码。

ENC28J60 还包括其他支持模块,诸如振荡器、片内稳压器、电平变换器(提供可以接受 5V 电压的 I/O 引脚)和系统控制逻辑。

poYBAGDYdXCAWkKMAAAAK8RNs4s030.png

四、UIP 简介

uIP 由瑞典计算机科学学院(网络嵌入式系统小组)的Adam Dunkels 开发。其源代码由C 语 言编写,并完全公开,uIP 的最新版本是 1.0 版本。 uIP 协议栈去掉了完整的 TCP/IP 中不常用的功能,简化了通讯流程,但保留了网络通信 必须使用的协议,设计重点放在了 IP/TCP/ICMP/UDP/ARP 这些网络层和传输层协议上,保证 了其代码的通用性和结构的稳定性。

由于 uIP 协议栈专门为嵌入式系统而设计,因此还具有如下优越功能:

1) 代码非常少,其协议栈代码不到 6K,很方便阅读和移植。

2) 占用的内存数非常少,RAM 占用仅几百字节。

3) 其硬件处理层、协议栈层和应用层共用一个全局缓存区,不存在数据的拷贝,且发送 和接收都是依靠这个缓存区,极大的节省空间和时间。

4) 支持多个主动连接和被动连接并发。

5) 其源代码中提供一套实例程序:web 服务器,web 客户端,电子邮件发送程序(SMTP 客 户端),Telnet 服务器, DNS 主机名解析程序等。通用性强,移植起来基本不用修改就可以通过。

6) 对数据的处理采用轮循机制,不需要操作系统的支持。 由于 uIP 对资源的需求少和移植容易,大部分的 8 位微控制器都使用过uIP 协议栈, 而且很多的著名的嵌入式产品和项目(如卫星,Cisco 路由器,无线传感器网络)中都在使用 uIP 协议栈。 uIP 相当于一个代码库,通过一系列的函数实现与底层硬件和高层应用程序的通讯,对于 整个系统来说它内部的协议组是透明的,从而增加了协议的通用性。

uIP 提供的接口函数有:

1.初始化 uIP 协议栈:uip_init()

2.处理输入包:uip_input()

3.处理周期计时事件:uip_periodic()

4.开始监听端口:uip_listen()

5.连接到远程主机:uip_connect()

6.接收到连接请求:uip_connected()

7.主动关闭连接:uip_close()

8.连接被关闭:uip_closed()

9.发出去的数据被应答:uip_acked()

10.在当前连接发送数据:uip_send()

11.在当前连接上收到新的数据:uip_newdata()

12.告诉对方要停止连接:uip_stop()

13.连接被意外终止:uip_aborted()

基于STM32的WEB服务器设计

poYBAGDYdXCAWkKMAAAAK8RNs4s030.png

五、核心代码

5.1 main.c

#include "stm32f10x.h"
#include "led.h"
#include "delay.h"
#include "key.h"
#include "usart.h"
#include 
#include 
#include "enc28j60.h"
#include "time.h"

#include "uip.h"
#include "uip_arp.h"
#include "tapdev.h"
#include "timer.h"
#include "uip-conf.h"
#include "httpd.h"
#include "ds18b20.h"
#include "rtc.h"

void uip_EventPoll(void); //事件处理函数
#define UIP_BUF ((struct uip_eth_hdr *)&uip_buf[0])

/*
当Uip接收到Uip接收到底层传递的数据,将接收到的数据通过调用http_appcall(),传递给Webserver处理,
再通过handle_connection()先后调用handle_input()函数和handle_output()函数
handle_input()主要作用是分析http数据流:得到请求的路径、解析出请求的文件名称。
然后调用函数handle_output进行查找对应文件,进行发送到浏览器,完成交互。
注意:浏览器最好使用谷歌浏览器,否则会导致访问失败!
*/

int main()
{
    u8 key;
    u32 tcnt=0;
    uip_ipaddr_t ipaddr;	//保存IP地址信息

    BeepInit();		  //蜂鸣器初始化
    LedInit();      //LED灯初始化
    UsartInit(USART1,72,115200);
    KeyInit();      //按键初始化
    TimerInit(TIM6,72,10000);  //定时器初始化,
		DS18B20_Init();
		RTC_Init();
	  SET_RTC_TIME(2019,5,24,10,58,20);
    printf("串口工作正常!rn");

    while(tapdev_init())	//初始化ENC28J60错误
    {
        printf("ENC28J60 Init Error!rn");
        Delay72M_Ms(500);
    }
    printf("ENC28J60 初始化成功!rn");

    uip_init();				                  //uIP初始化
    uip_ipaddr(ipaddr, 192,168,1,89);	  //填充开发板IP地址
    uip_sethostaddr(ipaddr);		        //设置开发板IP地址

    uip_ipaddr(ipaddr, 192,168,1,1); 	  //填充开发板网关地址
    uip_setdraddr(ipaddr);	            //设置开发板网关IP地址(其实就是你路由器的IP地址)

    uip_ipaddr(ipaddr, 255,255,255,0);  //填充开发板网络掩码
    uip_setnetmask(ipaddr);             //填充开发板网络掩码
    httpd_init();                       //创建WEB服务器,设置监听端口

    while(1)
    {			
        uip_EventPoll(); 		 //轮询方式处理处理网络数据
    }
}

/*
函数功能:uip事件处理函数,需要将该函数插入用户主循环,循环调用
*/
void uip_EventPoll(void)
{
    u8 i;
    static struct timer  arp_timer; //定义定时器
    static u8 timer_ok=0;

    if(timer_ok==0)//仅初始化一次
    {
        timer_ok = 1;
        timer_set(&arp_timer,CLOCK_SECOND*10);	   	//创建1个10秒的定时器
    }

    uip_len=tapdev_read();	//从网络设备读取一个IP包,得到数据长度.uip_len在uip.c中定义
    if(uip_len>0) 			    //有数据
    {
        //处理IP数据包(只有校验通过的IP包才会被接收)
        if(UIP_BUF->type == htons(UIP_ETHTYPE_IP))//是否是IP包?
        {
            uip_arp_ipin();	//去除以太网头结构,更新ARP表
            uip_input();   	//IP包处理
            //当上面的函数执行后,如果需要发送数据,则全局变量 uip_len > 0
            //需要发送的数据在uip_buf, 长度是uip_len  (这是2个全局变量)
            if(uip_len>0)//需要回应数据
            {
                uip_arp_out();//加以太网头结构,在主动连接时可能要构造ARP请求
                tapdev_send();//发送数据到以太网
            }
        } else if (UIP_BUF->type==htons(UIP_ETHTYPE_ARP))//处理arp报文,是否是ARP请求包?
        {
            uip_arp_arpin();
            //当上面的函数执行后,如果需要发送数据,则全局变量uip_len>0
            //需要发送的数据在uip_buf, 长度是uip_len(这是2个全局变量)
            if(uip_len>0)tapdev_send();//需要发送数据,则通过tapdev_send发送
        }
    }
    //轮流处理每个TCP连接, UIP_CONNS缺省是40个
    for(i=0; i0
        //需要发送的数据在uip_buf, 长度是uip_len (这是2个全局变量)
        if(uip_len>0)
        {
            uip_arp_out();//加以太网头结构,在主动连接时可能要构造ARP请求
            tapdev_send();//发送数据到以太网
        }
    }

    //每隔10秒调用1次ARP定时器函数 用于定期ARP处理,ARP表10秒更新一次,旧的条目会被抛弃
    if(timer_expired(&arp_timer))
    {
        timer_reset(&arp_timer);
        uip_arp_timer();
    }
}

;>
poYBAGDYdXCAWkKMAAAAK8RNs4s030.png

5.2 enc28j60.c

#include "delay.h"
#include 
#include "enc28j60.h"	

/*
以下是ENC28J60驱动移植接口:
MISO--->PA6----主机输入
MOSI--->PA7----主机输出
SCLK--->PA5----时钟信号
CS----->PA4----片选
RESET-->PG15---复位
*/
#define ENC28J60_CS		PAout(4) 	//ENC28J60片选信号
#define ENC28J60_RST	PGout(15)	//ENC28J60复位信号
#define ENC28J60_MOSI PAout(7)  //输出
#define ENC28J60_MISO PAin(6)   //输入
#define ENC28J60_SCLK PAout(5)  //时钟线

static u8 ENC28J60BANK;
static u32 NextPacketPtr;


/*
函数功能:底层SPI接口收发一个字节
说    明:模拟SPI时序,ENC28J60时钟线空闲电平为低电平,在第一个下降沿采集数据
*/
u8 ENC28J60_SPI_ReadWriteOneByte(u8 tx_data)
{
	u16 cnt=0;				 
	while((SPI1->SR&1<<1)==0)		 //等待发送区空--等待发送缓冲为空	
	{
		cnt++;
		if(cnt>=65530)return 0; 	  //超时退出  u16=2个字节
	}	
	SPI1->DR=tx_data;	 	  		      //发送一个byte 
	cnt=0;
	while((SPI1->SR&1<<0)==0) 		//等待接收完一个byte   
	{
		cnt++;
		if(cnt>=65530)return 0;	   //超时退出
	}	  						    
	return SPI1->DR;          		//返回收到的数据				
}


/*
函数功能:复位ENC28J60,包括SPI初始化/IO初始化等
MISO--->PA6----主机输入
MOSI--->PA7----主机输出
SCLK--->PA5----时钟信号
CS----->PA4----片选
RESET-->PG15---复位
*/
void ENC28J60_Reset(void)
{
/*开启时钟*/
	RCC->APB2ENR|=1<<12;   //开启SPI1时钟
	RCC->APB2ENR|=1<<2;    //PA
	GPIOA->CRL&=0X0000FFFF; //清除寄存器
	GPIOA->CRL|=0XB8B30000;
	GPIOA->ODR|=0XF<<4; //   	上拉--输出高电平
	GPIOA->ODR&=~(1<<5);
	
	 RCC->APB2ENR|=1<<8; //2 3 4 5 6 7 8
	 GPIOG->CRH&=0x0FFFFFFF;
	 GPIOG->CRH|=0x30000000;

	/*SPI2基本配置*/
	SPI1->CR1=0X0; 		//清空寄存器
	SPI1->CR1|=0<<15; //选择“双线双向”模式
	SPI1->CR1|=0<<11; //使用8位数据帧格式进行发送/接收;
	SPI1->CR1|=0<<10; //全双工(发送和接收);
	SPI1->CR1|=1<<9;  //启用软件从设备管理
	SPI1->CR1|=1<<8;  //NSS
	SPI1->CR1|=0<<7;  //帧格式,先发送高位
	SPI1->CR1|=0x1<<3;//当总线频率为36MHZ时,SPI速度为18MHZ,高速。
	SPI1->CR1|=1<<2;  //配置为主设备
	SPI1->CR1|=1<<1;  //空闲状态时, SCK保持高电平。
	SPI1->CR1|=1<<0;  //数据采样从第二个时钟边沿开始。
	SPI1->CR1|=1<<6;  //开启SPI设备。
	
	//针对ENC28J60的特点(SCK空闲为低电平)修改SPI的设置
 	SPI1->CR1&=~(1<<6); 	//SPI设备失能
	SPI1->CR1&=~(1<<1); 	//空闲模式下SCK为0 CPOL=0
	SPI1->CR1&=~(1<<0); 	//数据采样从第1个时间边沿开始,CPHA=0  
	SPI1->CR1|=1<<6; 	  	//SPI设备使能
	
	ENC28J60_RST=0;			//复位ENC28J60
	DelayMs(10);	 
	ENC28J60_RST=1;			//复位结束				    
	DelayMs(10);	  
}


/*
函数功能:读取ENC28J60寄存器(带操作码) 
参	  数:op:操作码
					addr:寄存器地址/参数
返 回 值:读到的数据
*/
u8 ENC28J60_Read_Op(u8 op,u8 addr)
{
	u8 dat=0;	 
	ENC28J60_CS=0;	 
	dat=op|(addr&ADDR_MASK);
	ENC28J60_SPI_ReadWriteOneByte(dat);
	dat=ENC28J60_SPI_ReadWriteOneByte(0xFF);
	//如果是读取MAC/MII寄存器,则第二次读到的数据才是正确的,见手册29页
 	if(addr&0x80)dat=ENC28J60_SPI_ReadWriteOneByte(0xFF);
	ENC28J60_CS=1;
	return dat;
}



/*
函数功能:读取ENC28J60寄存器(带操作码) 
参    数:
				op:操作码
				addr:寄存器地址
				data:参数
*/
void ENC28J60_Write_Op(u8 op,u8 addr,u8 data)
{
	u8 dat = 0;	    
	ENC28J60_CS=0;			   
	dat=op|(addr&ADDR_MASK);
	ENC28J60_SPI_ReadWriteOneByte(dat);	  
	ENC28J60_SPI_ReadWriteOneByte(data);
	ENC28J60_CS=1;
}



/*
函数功能:读取ENC28J60接收缓存数据
参    数:
				len:要读取的数据长度
				data:输出数据缓存区(末尾自动添加结束符)
*/
void ENC28J60_Read_Buf(u32 len,u8* data)
{
	ENC28J60_CS=0;			 
	ENC28J60_SPI_ReadWriteOneByte(ENC28J60_READ_BUF_MEM);
	while(len)
	{
		len--;			  
		*data=(u8)ENC28J60_SPI_ReadWriteOneByte(0);
		data++;
	}
	*data='�';
	ENC28J60_CS=1;
}


/*
函数功能:向ENC28J60写发送缓存数据
参    数:
				len:要写入的数据长度
				data:数据缓存区
*/
void ENC28J60_Write_Buf(u32 len,u8* data)
{
	ENC28J60_CS=0;			   
	ENC28J60_SPI_ReadWriteOneByte(ENC28J60_WRITE_BUF_MEM);		 
	while(len)
	{
		len--;
		ENC28J60_SPI_ReadWriteOneByte(*data);
		data++;
	}
	ENC28J60_CS=1;
}

/*
函数功能:设置ENC28J60寄存器Bank
参    数:
				ban:要设置的bank
*/
void ENC28J60_Set_Bank(u8 bank)
{								    
	if((bank&BANK_MASK)!=ENC28J60BANK)//和当前bank不一致的时候,才设置
	{				  
		ENC28J60_Write_Op(ENC28J60_BIT_FIELD_CLR,ECON1,(ECON1_BSEL1|ECON1_BSEL0));
		ENC28J60_Write_Op(ENC28J60_BIT_FIELD_SET,ECON1,(bank&BANK_MASK)>>5);
		ENC28J60BANK=(bank&BANK_MASK);
	}
}


/*
函数功能:读取ENC28J60指定寄存器
参    数:addr:寄存器地址
返 回 值:读到的数据
*/
u8 ENC28J60_Read(u8 addr)
{						  
	ENC28J60_Set_Bank(addr);//设置BANK		 
	return ENC28J60_Read_Op(ENC28J60_READ_CTRL_REG,addr);
}


/*
函数功能:向ENC28J60指定寄存器写数据
参    数:
					addr:寄存器地址
					data:要写入的数据		
*/
void ENC28J60_Write(u8 addr,u8 data)
{					  
	ENC28J60_Set_Bank(addr);		 
	ENC28J60_Write_Op(ENC28J60_WRITE_CTRL_REG,addr,data);
}


/*
函数功能:向ENC28J60的PHY寄存器写入数据
参    数:
				addr:寄存器地址
				data:要写入的数据	
*/
void ENC28J60_PHY_Write(u8 addr,u32 data)
{
	u16 retry=0;
	ENC28J60_Write(MIREGADR,addr);	//设置PHY寄存器地址
	ENC28J60_Write(MIWRL,data);		//写入数据
	ENC28J60_Write(MIWRH,data>>8);		   
	while((ENC28J60_Read(MISTAT)&MISTAT_BUSY)&&retry<0XFFF)retry++;//等待写入PHY结束		  
}


/*
函数功能:初始化ENC28J60
参    数:macaddr:MAC地址
返 回 值:
				  0,初始化成功;
          1,初始化失败;
*/
u8 ENC28J60_Init(u8* macaddr)
{		
	u16 retry=0;		  
	ENC28J60_Reset(); //复位底层引脚接口
	ENC28J60_Write_Op(ENC28J60_SOFT_RESET,0,ENC28J60_SOFT_RESET);//软件复位
	while(!(ENC28J60_Read(ESTAT)&ESTAT_CLKRDY)&&retry<500)//等待时钟稳定
	{
		retry++;
		DelayMs(1);
	};
	if(retry>=500)return 1;//ENC28J60初始化失败
	// do bank 0 stuff
	// initialize receive buffer
	// 16-bit transfers,must write low byte first
	// set receive buffer start address	   设置接收缓冲区地址  8K字节容量
	NextPacketPtr=RXSTART_INIT;
	// Rx start
	//接收缓冲器由一个硬件管理的循环FIFO 缓冲器构成。
	//寄存器对ERXSTH:ERXSTL 和ERXNDH:ERXNDL 作
	//为指针,定义缓冲器的容量和其在存储器中的位置。
	//ERXST和ERXND指向的字节均包含在FIFO缓冲器内。
	//当从以太网接口接收数据字节时,这些字节被顺序写入
	//接收缓冲器。 但是当写入由ERXND 指向的存储单元
	//后,硬件会自动将接收的下一字节写入由ERXST 指向
	//的存储单元。 因此接收硬件将不会写入FIFO 以外的单
	//元。
	//设置接收起始字节
	ENC28J60_Write(ERXSTL,RXSTART_INIT&0xFF);	
	ENC28J60_Write(ERXSTH,RXSTART_INIT>>8);	  
	//ERXWRPTH:ERXWRPTL 寄存器定义硬件向FIFO 中
	//的哪个位置写入其接收到的字节。 指针是只读的,在成
	//功接收到一个数据包后,硬件会自动更新指针。 指针可
	//用于判断FIFO 内剩余空间的大小  8K-1500。 
	//设置接收读指针字节
	ENC28J60_Write(ERXRDPTL,RXSTART_INIT&0xFF);
	ENC28J60_Write(ERXRDPTH,RXSTART_INIT>>8);
	//设置接收结束字节
	ENC28J60_Write(ERXNDL,RXSTOP_INIT&0xFF);
	ENC28J60_Write(ERXNDH,RXSTOP_INIT>>8);
	//设置发送起始字节
	ENC28J60_Write(ETXSTL,TXSTART_INIT&0xFF);
	ENC28J60_Write(ETXSTH,TXSTART_INIT>>8);
	//设置发送结束字节
	ENC28J60_Write(ETXNDL,TXSTOP_INIT&0xFF);
	ENC28J60_Write(ETXNDH,TXSTOP_INIT>>8);
	// do bank 1 stuff,packet filter:
	// For broadcast packets we allow only ARP packtets
	// All other packets should be unicast only for our mac (MAADR)
	//
	// The pattern to match on is therefore
	// Type     ETH.DST
	// ARP      BROADCAST
	// 06 08 -- ff ff ff ff ff ff -> ip checksum for theses bytes=f7f9
	// in binary these poitions are:11 0000 0011 1111
	// This is hex 303F->EPMM0=0x3f,EPMM1=0x30
	//接收过滤器
	//UCEN:单播过滤器使能位
	//当ANDOR = 1 时:
	//1 = 目标地址与本地MAC 地址不匹配的数据包将被丢弃
	//0 = 禁止过滤器
	//当ANDOR = 0 时:
	//1 = 目标地址与本地MAC 地址匹配的数据包会被接受
	//0 = 禁止过滤器
	//CRCEN:后过滤器CRC 校验使能位
	//1 = 所有CRC 无效的数据包都将被丢弃
	//0 = 不考虑CRC 是否有效
	//PMEN:格式匹配过滤器使能位
	//当ANDOR = 1 时:
	//1 = 数据包必须符合格式匹配条件,否则将被丢弃
	//0 = 禁止过滤器
	//当ANDOR = 0 时:
	//1 = 符合格式匹配条件的数据包将被接受
	//0 = 禁止过滤器
	ENC28J60_Write(ERXFCON,ERXFCON_UCEN|ERXFCON_CRCEN|ERXFCON_PMEN);
	ENC28J60_Write(EPMM0,0x3f);
	ENC28J60_Write(EPMM1,0x30);
	ENC28J60_Write(EPMCSL,0xf9);
	ENC28J60_Write(EPMCSH,0xf7);
	// do bank 2 stuff
	// enable MAC receive
	//bit 0 MARXEN:MAC 接收使能位
	//1 = 允许MAC 接收数据包
	//0 = 禁止数据包接收
	//bit 3 TXPAUS:暂停控制帧发送使能位
	//1 = 允许MAC 发送暂停控制帧(用于全双工模式下的流量控制)
	//0 = 禁止暂停帧发送
	//bit 2 RXPAUS:暂停控制帧接收使能位
	//1 = 当接收到暂停控制帧时,禁止发送(正常操作)
	//0 = 忽略接收到的暂停控制帧
	ENC28J60_Write(MACON1,MACON1_MARXEN|MACON1_TXPAUS|MACON1_RXPAUS);
	// bring MAC out of reset
	//将MACON2 中的MARST 位清零,使MAC 退出复位状态。
	ENC28J60_Write(MACON2,0x00);
	// enable automatic padding to 60bytes and CRC operations
	//bit 7-5 PADCFG2:PACDFG0:自动填充和CRC 配置位
	//111 = 用0 填充所有短帧至64 字节长,并追加一个有效的CRC
	//110 = 不自动填充短帧
	//101 = MAC 自动检测具有8100h 类型字段的VLAN 协议帧,并自动填充到64 字节长。如果不
	//是VLAN 帧,则填充至60 字节长。填充后还要追加一个有效的CRC
	//100 = 不自动填充短帧
	//011 = 用0 填充所有短帧至64 字节长,并追加一个有效的CRC
	//010 = 不自动填充短帧
	//001 = 用0 填充所有短帧至60 字节长,并追加一个有效的CRC
	//000 = 不自动填充短帧
	//bit 4 TXCRCEN:发送CRC 使能位
	//1 = 不管PADCFG如何,MAC都会在发送帧的末尾追加一个有效的CRC。 如果PADCFG规定要
	//追加有效的CRC,则必须将TXCRCEN 置1。
	//0 = MAC不会追加CRC。 检查最后4 个字节,如果不是有效的CRC 则报告给发送状态向量。
	//bit 0 FULDPX:MAC 全双工使能位
	//1 = MAC工作在全双工模式下。 PHCON1.PDPXMD 位必须置1。
	//0 = MAC工作在半双工模式下。 PHCON1.PDPXMD 位必须清零。
	ENC28J60_Write_Op(ENC28J60_BIT_FIELD_SET,MACON3,MACON3_PADCFG0|MACON3_TXCRCEN|MACON3_FRMLNEN|MACON3_FULDPX);
	// set inter-frame gap (non-back-to-back)
	//配置非背对背包间间隔寄存器的低字节
	//MAIPGL。 大多数应用使用12h 编程该寄存器。
	//如果使用半双工模式,应编程非背对背包间间隔
	//寄存器的高字节MAIPGH。 大多数应用使用0Ch
	//编程该寄存器。
	ENC28J60_Write(MAIPGL,0x12);
	ENC28J60_Write(MAIPGH,0x0C);
	// set inter-frame gap (back-to-back)
	//配置背对背包间间隔寄存器MABBIPG。当使用
	//全双工模式时,大多数应用使用15h 编程该寄存
	//器,而使用半双工模式时则使用12h 进行编程。
	ENC28J60_Write(MABBIPG,0x15);
	// Set the maximum packet size which the controller will accept
	// Do not send packets longer than MAX_FRAMELEN:
	// 最大帧长度  1500
	ENC28J60_Write(MAMXFLL,MAX_FRAMELEN&0xFF);	
	ENC28J60_Write(MAMXFLH,MAX_FRAMELEN>>8);
	// do bank 3 stuff
	// write MAC address
	// NOTE: MAC address in ENC28J60 is byte-backward
	//设置MAC地址
	ENC28J60_Write(MAADR5,macaddr[0]);	
	ENC28J60_Write(MAADR4,macaddr[1]);
	ENC28J60_Write(MAADR3,macaddr[2]);
	ENC28J60_Write(MAADR2,macaddr[3]);
	ENC28J60_Write(MAADR1,macaddr[4]);
	ENC28J60_Write(MAADR0,macaddr[5]);
	//配置PHY为全双工  LEDB为拉电流
	ENC28J60_PHY_Write(PHCON1,PHCON1_PDPXMD);	 
	// no loopback of transmitted frames	 禁止环回
	//HDLDIS:PHY 半双工环回禁止位
	//当PHCON1.PDPXMD = 1 或PHCON1.PLOOPBK = 1 时:
	//此位可被忽略。
	//当PHCON1.PDPXMD = 0 且PHCON1.PLOOPBK = 0 时:
	//1 = 要发送的数据仅通过双绞线接口发出
	//0 = 要发送的数据会环回到MAC 并通过双绞线接口发出
	ENC28J60_PHY_Write(PHCON2,PHCON2_HDLDIS);
	// switch to bank 0
	//ECON1 寄存器
	//寄存器3-1 所示为ECON1 寄存器,它用于控制
	//ENC28J60 的主要功能。 ECON1 中包含接收使能、发
	//送请求、DMA 控制和存储区选择位。	   
	ENC28J60_Set_Bank(ECON1);
	// enable interrutps
	//EIE: 以太网中断允许寄存器
	//bit 7 INTIE: 全局INT 中断允许位
	//1 = 允许中断事件驱动INT 引脚
	//0 = 禁止所有INT 引脚的活动(引脚始终被驱动为高电平)
	//bit 6 PKTIE: 接收数据包待处理中断允许位
	//1 = 允许接收数据包待处理中断
	//0 = 禁止接收数据包待处理中断
	ENC28J60_Write_Op(ENC28J60_BIT_FIELD_SET,EIE,EIE_INTIE|EIE_PKTIE);
	// enable packet reception
	//bit 2 RXEN:接收使能位
	//1 = 通过当前过滤器的数据包将被写入接收缓冲器
	//0 = 忽略所有接收的数据包
	ENC28J60_Write_Op(ENC28J60_BIT_FIELD_SET,ECON1,ECON1_RXEN);
	if(ENC28J60_Read(MAADR5)== macaddr[0])return 0;//初始化成功
	else return 1; 	  

}

/*
函数功能:读取EREVID
参    数:
*/
u8 ENC28J60_Get_EREVID(void)
{
	//在EREVID 内也存储了版本信息。 EREVID 是一个只读控
	//制寄存器,包含一个5 位标识符,用来标识器件特定硅片
	//的版本号
	return ENC28J60_Read(EREVID);
}



/*
函数功能:通过ENC28J60发送数据包到网络
参    数:
					len   :数据包大小
          packet:数据包
*/
void ENC28J60_Packet_Send(u32 len,u8* packet)
{
	//设置发送缓冲区地址写指针入口
	ENC28J60_Write(EWRPTL,TXSTART_INIT&0xFF);
	ENC28J60_Write(EWRPTH,TXSTART_INIT>>8);
	//设置TXND指针,以对应给定的数据包大小	   
	ENC28J60_Write(ETXNDL,(TXSTART_INIT+len)&0xFF);
	ENC28J60_Write(ETXNDH,(TXSTART_INIT+len)>>8);
	//写每包控制字节(0x00表示使用macon3的设置) 
	ENC28J60_Write_Op(ENC28J60_WRITE_BUF_MEM,0,0x00);
	//复制数据包到发送缓冲区
	//printf("len:%drn",len);	//监视发送数据长度
 	ENC28J60_Write_Buf(len,packet);
 	//发送数据到网络
	ENC28J60_Write_Op(ENC28J60_BIT_FIELD_SET,ECON1,ECON1_TXRTS);
	//复位发送逻辑的问题。参见Rev. B4 Silicon Errata point 12.
	if((ENC28J60_Read(EIR)&EIR_TXERIF))ENC28J60_Write_Op(ENC28J60_BIT_FIELD_CLR,ECON1,ECON1_TXRTS);
}


/*
函数功能:从网络获取一个数据包内容
函数参数:
				maxlen:数据包最大允许接收长度
				packet:数据包缓存区
返 回 值:收到的数据包长度(字节)	
*/
u32 ENC28J60_Packet_Receive(u32 maxlen,u8* packet)
{
	u32 rxstat;
	u32 len;    													 
	if(ENC28J60_Read(EPKTCNT)==0)return 0;  //是否收到数据包?	   
	//设置接收缓冲器读指针
	ENC28J60_Write(ERDPTL,(NextPacketPtr));
	ENC28J60_Write(ERDPTH,(NextPacketPtr)>>8);	   
	// 读下一个包的指针
	NextPacketPtr=ENC28J60_Read_Op(ENC28J60_READ_BUF_MEM,0);
	NextPacketPtr|=ENC28J60_Read_Op(ENC28J60_READ_BUF_MEM,0)<<8;
	//读包的长度
	len=ENC28J60_Read_Op(ENC28J60_READ_BUF_MEM,0);
	len|=ENC28J60_Read_Op(ENC28J60_READ_BUF_MEM,0)<<8;
 	len-=4; //去掉CRC计数
	//读取接收状态
	rxstat=ENC28J60_Read_Op(ENC28J60_READ_BUF_MEM,0);
	rxstat|=ENC28J60_Read_Op(ENC28J60_READ_BUF_MEM,0)<<8;
	//限制接收长度	
	if (len>maxlen-1)len=maxlen-1;	
	//检查CRC和符号错误
	// ERXFCON.CRCEN为默认设置,一般我们不需要检查.
	if((rxstat&0x80)==0)len=0;//无效
	else ENC28J60_Read_Buf(len,packet);//从接收缓冲器中复制数据包	    
	//RX读指针移动到下一个接收到的数据包的开始位置 
	//并释放我们刚才读出过的内存
	ENC28J60_Write(ERXRDPTL,(NextPacketPtr));
	ENC28J60_Write(ERXRDPTH,(NextPacketPtr)>>8);
	//递减数据包计数器标志我们已经得到了这个包 
 	ENC28J60_Write_Op(ENC28J60_BIT_FIELD_SET,ECON2,ECON2_PKTDEC);
	return(len);
}



poYBAGDYdXCAWkKMAAAAK8RNs4s030.png

5.3 enc28j60.h

#include "sys.h"    
#ifndef __ENC28J60_H
#define __ENC28J60_H	  
#include "stm32f10x.h"

////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// ENC28J60 Control Registers
// Control register definitions are a combination of address,
// bank number, and Ethernet/MAC/PHY indicator bits.
// - Register address         (bits 0-4)
// - Bank number              (bits 5-6)
// - MAC/PHY indicator        (bit 7)
#define ADDR_MASK        0x1F
#define BANK_MASK        0x60
#define SPRD_MASK        0x80
// All-bank registers
#define EIE              0x1B
#define EIR              0x1C
#define ESTAT            0x1D
#define ECON2            0x1E
#define ECON1            0x1F
// Bank 0 registers
#define ERDPTL           (0x00|0x00)
#define ERDPTH           (0x01|0x00)
#define EWRPTL           (0x02|0x00)
#define EWRPTH           (0x03|0x00)
#define ETXSTL           (0x04|0x00)
#define ETXSTH           (0x05|0x00)
#define ETXNDL           (0x06|0x00)
#define ETXNDH           (0x07|0x00)
#define ERXSTL           (0x08|0x00)
#define ERXSTH           (0x09|0x00)
#define ERXNDL           (0x0A|0x00)
#define ERXNDH           (0x0B|0x00)
//ERXWRPTH:ERXWRPTL 寄存器定义硬件向FIFO 中
//的哪个位置写入其接收到的字节。 指针是只读的,在成
//功接收到一个数据包后,硬件会自动更新指针。 指针可
//用于判断FIFO 内剩余空间的大小。
#define ERXRDPTL         (0x0C|0x00)
#define ERXRDPTH         (0x0D|0x00)
#define ERXWRPTL         (0x0E|0x00)
#define ERXWRPTH         (0x0F|0x00)
#define EDMASTL          (0x10|0x00)
#define EDMASTH          (0x11|0x00)
#define EDMANDL          (0x12|0x00)
#define EDMANDH          (0x13|0x00)
#define EDMADSTL         (0x14|0x00)
#define EDMADSTH         (0x15|0x00)
#define EDMACSL          (0x16|0x00)
#define EDMACSH          (0x17|0x00)
// Bank 1 registers
#define EHT0             (0x00|0x20)
#define EHT1             (0x01|0x20)
#define EHT2             (0x02|0x20)
#define EHT3             (0x03|0x20)
#define EHT4             (0x04|0x20)
#define EHT5             (0x05|0x20)
#define EHT6             (0x06|0x20)
#define EHT7             (0x07|0x20)
#define EPMM0            (0x08|0x20)
#define EPMM1            (0x09|0x20)
#define EPMM2            (0x0A|0x20)
#define EPMM3            (0x0B|0x20)
#define EPMM4            (0x0C|0x20)
#define EPMM5            (0x0D|0x20)
#define EPMM6            (0x0E|0x20)
#define EPMM7            (0x0F|0x20)
#define EPMCSL           (0x10|0x20)
#define EPMCSH           (0x11|0x20)
#define EPMOL            (0x14|0x20)
#define EPMOH            (0x15|0x20)
#define EWOLIE           (0x16|0x20)
#define EWOLIR           (0x17|0x20)
#define ERXFCON          (0x18|0x20)
#define EPKTCNT          (0x19|0x20)
// Bank 2 registers
#define MACON1           (0x00|0x40|0x80)
#define MACON2           (0x01|0x40|0x80)
#define MACON3           (0x02|0x40|0x80)
#define MACON4           (0x03|0x40|0x80)
#define MABBIPG          (0x04|0x40|0x80)
#define MAIPGL           (0x06|0x40|0x80)
#define MAIPGH           (0x07|0x40|0x80)
#define MACLCON1         (0x08|0x40|0x80)
#define MACLCON2         (0x09|0x40|0x80)
#define MAMXFLL          (0x0A|0x40|0x80)
#define MAMXFLH          (0x0B|0x40|0x80)
#define MAPHSUP          (0x0D|0x40|0x80)
#define MICON            (0x11|0x40|0x80)
#define MICMD            (0x12|0x40|0x80)
#define MIREGADR         (0x14|0x40|0x80)
#define MIWRL            (0x16|0x40|0x80)
#define MIWRH            (0x17|0x40|0x80)
#define MIRDL            (0x18|0x40|0x80)
#define MIRDH            (0x19|0x40|0x80)
// Bank 3 registers
#define MAADR1           (0x00|0x60|0x80)
#define MAADR0           (0x01|0x60|0x80)
#define MAADR3           (0x02|0x60|0x80)
#define MAADR2           (0x03|0x60|0x80)
#define MAADR5           (0x04|0x60|0x80)
#define MAADR4           (0x05|0x60|0x80)
#define EBSTSD           (0x06|0x60)
#define EBSTCON          (0x07|0x60)
#define EBSTCSL          (0x08|0x60)
#define EBSTCSH          (0x09|0x60)
#define MISTAT           (0x0A|0x60|0x80)
#define EREVID           (0x12|0x60)
#define ECOCON           (0x15|0x60)
#define EFLOCON          (0x17|0x60)
#define EPAUSL           (0x18|0x60)
#define EPAUSH           (0x19|0x60)
// PHY registers
#define PHCON1           0x00
#define PHSTAT1          0x01
#define PHHID1           0x02
#define PHHID2           0x03
#define PHCON2           0x10
#define PHSTAT2          0x11
#define PHIE             0x12
#define PHIR             0x13
#define PHLCON           0x14	   
// ENC28J60 ERXFCON Register Bit Definitions
#define ERXFCON_UCEN     0x80
#define ERXFCON_ANDOR    0x40
#define ERXFCON_CRCEN    0x20
#define ERXFCON_PMEN     0x10
#define ERXFCON_MPEN     0x08
#define ERXFCON_HTEN     0x04
#define ERXFCON_MCEN     0x02
#define ERXFCON_BCEN     0x01
// ENC28J60 EIE Register Bit Definitions
#define EIE_INTIE        0x80
#define EIE_PKTIE        0x40
#define EIE_DMAIE        0x20
#define EIE_LINKIE       0x10
#define EIE_TXIE         0x08
#define EIE_WOLIE        0x04
#define EIE_TXERIE       0x02
#define EIE_RXERIE       0x01
// ENC28J60 EIR Register Bit Definitions
#define EIR_PKTIF        0x40
#define EIR_DMAIF        0x20
#define EIR_LINKIF       0x10
#define EIR_TXIF         0x08
#define EIR_WOLIF        0x04
#define EIR_TXERIF       0x02
#define EIR_RXERIF       0x01
// ENC28J60 ESTAT Register Bit Definitions
#define ESTAT_INT        0x80
#define ESTAT_LATECOL    0x10
#define ESTAT_RXBUSY     0x04
#define ESTAT_TXABRT     0x02
#define ESTAT_CLKRDY     0x01
// ENC28J60 ECON2 Register Bit Definitions
#define ECON2_AUTOINC    0x80
#define ECON2_PKTDEC     0x40
#define ECON2_PWRSV      0x20
#define ECON2_VRPS       0x08
// ENC28J60 ECON1 Register Bit Definitions
#define ECON1_TXRST      0x80
#define ECON1_RXRST      0x40
#define ECON1_DMAST      0x20
#define ECON1_CSUMEN     0x10
#define ECON1_TXRTS      0x08
#define ECON1_RXEN       0x04
#define ECON1_BSEL1      0x02
#define ECON1_BSEL0      0x01
// ENC28J60 MACON1 Register Bit Definitions
#define MACON1_LOOPBK    0x10
#define MACON1_TXPAUS    0x08
#define MACON1_RXPAUS    0x04
#define MACON1_PASSALL   0x02
#define MACON1_MARXEN    0x01
// ENC28J60 MACON2 Register Bit Definitions
#define MACON2_MARST     0x80
#define MACON2_RNDRST    0x40
#define MACON2_MARXRST   0x08
#define MACON2_RFUNRST   0x04
#define MACON2_MATXRST   0x02
#define MACON2_TFUNRST   0x01
// ENC28J60 MACON3 Register Bit Definitions
#define MACON3_PADCFG2   0x80
#define MACON3_PADCFG1   0x40
#define MACON3_PADCFG0   0x20
#define MACON3_TXCRCEN   0x10
#define MACON3_PHDRLEN   0x08
#define MACON3_HFRMLEN   0x04
#define MACON3_FRMLNEN   0x02
#define MACON3_FULDPX    0x01
// ENC28J60 MICMD Register Bit Definitions
#define MICMD_MIISCAN    0x02
#define MICMD_MIIRD      0x01
// ENC28J60 MISTAT Register Bit Definitions
#define MISTAT_NVALID    0x04
#define MISTAT_SCAN      0x02
#define MISTAT_BUSY      0x01
// ENC28J60 PHY PHCON1 Register Bit Definitions
#define PHCON1_PRST      0x8000
#define PHCON1_PLOOPBK   0x4000
#define PHCON1_PPWRSV    0x0800
#define PHCON1_PDPXMD    0x0100
// ENC28J60 PHY PHSTAT1 Register Bit Definitions
#define PHSTAT1_PFDPX    0x1000
#define PHSTAT1_PHDPX    0x0800
#define PHSTAT1_LLSTAT   0x0004
#define PHSTAT1_JBSTAT   0x0002
// ENC28J60 PHY PHCON2 Register Bit Definitions
#define PHCON2_FRCLINK   0x4000
#define PHCON2_TXDIS     0x2000
#define PHCON2_JABBER    0x0400
#define PHCON2_HDLDIS    0x0100

// ENC28J60 Packet Control Byte Bit Definitions
#define PKTCTRL_PHUGEEN  0x08
#define PKTCTRL_PPADEN   0x04
#define PKTCTRL_PCRCEN   0x02
#define PKTCTRL_POVERRIDE 0x01

// SPI operation codes
#define ENC28J60_READ_CTRL_REG       0x00
#define ENC28J60_READ_BUF_MEM        0x3A
#define ENC28J60_WRITE_CTRL_REG      0x40
#define ENC28J60_WRITE_BUF_MEM       0x7A
#define ENC28J60_BIT_FIELD_SET       0x80
#define ENC28J60_BIT_FIELD_CLR       0xA0
#define ENC28J60_SOFT_RESET          0xFF

// The RXSTART_INIT should be zero. See Rev. B4 Silicon Errata
// buffer boundaries applied to internal 8K ram
// the entire available packet buffer space is allocated
//
// start with recbuf at 0/
#define RXSTART_INIT     0x0
// receive buffer end
#define RXSTOP_INIT      (0x1FFF-1518-1)
// start TX buffer at 0x1FFF-0x0600, pace for one full ethernet frame (0~1518 bytes)
#define TXSTART_INIT     (0x1FFF-1518)
// stp TX buffer at end of mem
#define TXSTOP_INIT      0x1FFF
// max frame length which the conroller will accept:
#define   MAX_FRAMELEN    1518        // (note: maximum ethernet frame length would be 1518)
////////////////////////////////////////////////////////////////////////////////////////////////////////////////


void ENC28J60_Reset(void);
u8 ENC28J60_Read_Op(u8 op,u8 addr);
void ENC28J60_Write_Op(u8 op,u8 addr,u8 data);
void ENC28J60_Read_Buf(u32 len,u8* data);
void ENC28J60_Write_Buf(u32 len,u8* data);
void ENC28J60_Set_Bank(u8 bank);
u8 ENC28J60_Read(u8 addr);
void ENC28J60_Write(u8 addr,u8 data);
void ENC28J60_PHY_Write(u8 addr,u32 data);
u8 ENC28J60_Init(u8* macaddr);
u8 ENC28J60_Get_EREVID(void);
void ENC28J60_Packet_Send(u32 len,u8* packet);
u32 ENC28J60_Packet_Receive(u32 maxlen,u8* packet);  
#endif
poYBAGDYdXCAWkKMAAAAK8RNs4s030.png

5.4 httpd-fs.c

/*
 * Copyright (c) 2001, Swedish Institute of Computer Science.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. Neither the name of the Institute nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 *
 * This file is part of the lwIP TCP/IP stack.
 *
 * Author: Adam Dunkels 
 *
 * $Id: httpd-fs.c,v 1.1 2006/06/07 09:13:08 adam Exp $
 */

#include "httpd.h"
#include "httpd-fs.h"
#include "httpd-fsdata.h"

#ifndef NULL
#define NULL 0
#endif /* NULL */

#include "httpd-fsdata.c"

#if HTTPD_FS_STATISTICS
static u16_t count[HTTPD_FS_NUMFILES];
#endif /* HTTPD_FS_STATISTICS */

/*-----------------------------------------------------------------------------------*/
static u8_t
httpd_fs_strcmp(const char *str1, const char *str2)
{
    u8_t i;
    i = 0;
loop:

    if(str2[i] == 0 ||
            str1[i] == 'r' ||
            str1[i] == 'n') {
        return 0;
    }

    if(str1[i] != str2[i]) {
        return 1;
    }


    ++i;
    goto loop;
}
#include 
#include 
#include "led.h"
#include "ds18b20.h"
#include "stm32f10x.h"
#include "rtc.h"

extern const unsigned char web_data[];
extern const  char led1_on[];
extern const  char led1_off[];

char ds18b20_temp[100]; //存放DS18B20温度信息
u16 ds18b20_T;
u16 ds18b20_intT,ds18b20_decT; 	  //温度值的整数和小数部分

/*-----------------------------------------------------------------------------------*/
int
httpd_fs_open(const char *name, struct httpd_fs_file *file)
{
 	 //第一次的默认页面
	 if(strstr(name,"/index.html"))
	 {
		  file->data=(char*)web_data;
      file->len = sizeof(web_data);
		 	 return 1;
	 }
	 else if(strstr(name,"/404.html"))
	 {
			file->data=(char*)data_404_html;
      file->len = sizeof(data_404_html);
		 	return 0; 
	 }
	 else if(strstr(name,"/test?data=off1"))
	 {
			file->data=(char*)led1_on;
      file->len = strlen(led1_on);
		  LED1=1;
		 	return 1; 
	 }
	 else if(strstr(name,"/test?data=on1"))
	 {
			file->data=(char*)led1_off;
      file->len = strlen(led1_off);
		  LED1=0;
		 	return 1; 
	 }
	 else if(strstr(name,"/test?data=off2"))
	 {
			file->data=(char*)led1_on;
      file->len = strlen(led1_on);
		  LED2=1;
		 	return 1; 
	 }
	 else if(strstr(name,"/test?data=on2"))
	 {
			file->data=(char*)led1_off;
      file->len = strlen(led1_off);
		  LED2=0;
		 	return 1; 
	 }
	 else if(strstr(name,"/test?data=off3"))
	 {
			file->data=(char*)led1_on;
      file->len = strlen(led1_on);
		  LED3=1;
		 	return 1; 
	 }
	 else if(strstr(name,"/test?data=on3"))
	 {
			file->data=(char*)led1_off;
      file->len = strlen(led1_off);
		  LED3=0;
		 	return 1; 
	 }
	 else if(strstr(name,"/test?data=off4"))
	 {
			file->data=(char*)led1_on;
      file->len = strlen(led1_on);
		  LED4=1;
		 	return 1; 
	 }
	 else if(strstr(name,"/test?data=on4"))
	 {
			file->data=(char*)led1_off;
      file->len = strlen(led1_off);
		  LED4=0;
		 	return 1; 
	 }
	 else if(strstr(name,"/test?data=off5"))
	 {
			file->data=(char*)led1_on;
      file->len = strlen(led1_on);
		  BEEP=0;
		 	return 1; 
	 }
	 else if(strstr(name,"/test?data=on5"))
	 {
			file->data=(char*)led1_off;
      file->len = strlen(led1_off);
		  BEEP=1;
		 	return 1; 
	 }
	 else if(strstr(name,"/test?data=temp"))
	 {
		 	/*读取温度信息*/
			ds18b20_T=DS18B20_Get_Temp();
			ds18b20_intT = ds18b20_T >> 4;             //分离出温度值整数部分
			ds18b20_decT = ds18b20_T & 0xF;            //分离出温度值小数部分
		  //printf("%d-%d-%d %d:%d:%drn",rtc_time.year,rtc_time.mon,rtc_time.day,rtc_time.hour,rtc_time.min,rtc_time.sec);
		
		  sprintf(ds18b20_temp,"%d.%d&%d-%d-%d %d:%d:%d",ds18b20_intT,ds18b20_decT,rtc_time.year,rtc_time.mon,rtc_time.day,rtc_time.hour,rtc_time.min,rtc_time.sec);
			file->data=(char*)ds18b20_temp;
      file->len = strlen(ds18b20_temp);
		 	return 1; 
	 }
   return 0;
}

/*-----------------------------------------------------------------------------------*/
void
httpd_fs_init(void)
{
#if HTTPD_FS_STATISTICS
    u16_t i;
    for(i = 0; i < HTTPD_FS_NUMFILES; i++) {
        count[i] = 0;
    }
#endif /* HTTPD_FS_STATISTICS */
}
/*-----------------------------------------------------------------------------------*/
#if HTTPD_FS_STATISTICS
u16_t httpd_fs_count
(char *name)
{
    struct httpd_fsdata_file_noconst *f;
    u16_t i;

    i = 0;
    for(f = (struct httpd_fsdata_file_noconst *)HTTPD_FS_ROOT;
            f != NULL;
            f = (struct httpd_fsdata_file_noconst *)f->next) {

        if(httpd_fs_strcmp(name, f->name) == 0) {
            return count[i];
        }
        ++i;
    }
    return 0;
}
#endif /* HTTPD_FS_STATISTICS */
/*-----------------------------------------------------------------------------------*/
@sics.se>
poYBAGDYdXCAWkKMAAAAK8RNs4s030.png

审核编辑:汤梓红

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 服务器
    +关注

    关注

    12

    文章

    9021

    浏览量

    85184
  • STM32
    +关注

    关注

    2266

    文章

    10871

    浏览量

    354817
  • TCP
    TCP
    +关注

    关注

    8

    文章

    1350

    浏览量

    78986
收藏 人收藏

    评论

    相关推荐

    nginx隐藏版本号与WEB服务器信息

    nginx不仅可以隐藏版本信息,还支持自定义web服务器信息 先看看最终的隐藏结果吧 具体怎么实现呢,其实也很简单,请往下看 1 官网下载最新稳定版 wget http://nginx.org
    的头像 发表于 11-22 10:25 93次阅读
    nginx隐藏版本号与<b class='flag-5'>WEB</b><b class='flag-5'>服务器</b>信息

    使用zabbix监控云服务器的方法

    Zabbix环境 在开始监控云服务器之前,你需要准备Zabbix环境。这包括安装Zabbix服务器、Zabbix代理和配置Web界面。 2.1 安装Zabbix服务器 Zabbix
    的头像 发表于 11-08 10:47 163次阅读

    独立服务器与云服务器的区别

    随着互联网技术的飞速发展,企业对于服务器的需求日益增加,而服务器市场也随之出现了多种类型的产品,其中最常见的是独立服务器和云服务器。这两种服务器
    的头像 发表于 10-12 14:34 207次阅读

    使用NS1串口服务器HTTP模式上传服务器数据

    HTTP协议工作于客户端-服务端架构之上。浏览作为HTTP客户端通过URL向HTTP服务端即Web服务器发送所有请求。
    的头像 发表于 08-30 12:36 272次阅读
    使用NS1串口<b class='flag-5'>服务器</b>HTTP模式上传<b class='flag-5'>服务器</b>数据

    如何使用espconn api实现一个Web服务器

    我正在尝试使用 espconn api 实现一个 Web 服务器。 在一些请求之后,我收到将此错误(err1,超过最大时间值)写入 uart,下一个espconn_send导致致命异常 (28)。 没有关于此的文档... 我该如何解决这个问题?
    发表于 07-18 07:46

    将ESP8266配置为带有AT命令的Web服务器,AT命令回复HTTP GET出现错误怎么解决?

    我已将ESP8266配置为带有 AT 命令的 Web 服务器。当浏览连接时,它会向我发送一个请求[i]GET /favicon.ico我想用一个[i]错误 404 未找到. 如何在响应 IPD 时发送的数据包中执行此操作?
    发表于 07-16 08:29

    服务器和虚拟服务器的区别是什么

    服务器和虚拟服务器是两种常见的服务器类型,它们在很多方面有相似之处,但也有一些关键的区别。本文将详细介绍云服务器和虚拟服务器的区别,包括它
    的头像 发表于 07-02 09:48 652次阅读

    服务器操作系统有几种?

    web版适用2G运行内存,都是添加4G运 行内存也只有鉴别2G,中小型企业大多数应用标准版,要是想布署集群服务器必须使用商业版。 2、Windows 2008 Windows server 2008
    发表于 03-29 16:59

    linux服务器和windows服务器

    Linux服务器和Windows服务器是目前应用最广泛的两种服务器操作系统。两者各有优劣,也适用于不同的应用场景。本文将 对Linux服务器和Windows
    发表于 02-22 15:46

    服务器连接应用解决方案

    、ATM等终端,甚至包括火车系统等大型设备)提供计算或应用服务。根据服务器所提供的服务类型,可以分为多种形式,如文件服务器、数据库服务器应用
    的头像 发表于 02-19 12:38 246次阅读
    <b class='flag-5'>服务器</b>连接应用解决方案

    Apache服务器和Nginx服务器

    Apache和Nginx都是常见的开源Web服务器软件,它们用于处理HTTP请求并提供网站和应用程序的服务。下面是对Apache和Nginx的一些基本特点的比较: 一、Apache HTTP
    的头像 发表于 01-22 16:48 519次阅读

    独立服务器和云服务器的区别

    独立服务器和云服务器的区别是很多用户在选择服务器时要做的课程,那么独立服务器和云服务器的区别有哪些呢?
    的头像 发表于 01-17 10:58 807次阅读

    什么是web服务器?如何选择服务器配置?

    Web服务器是一种软件或硬件设备,用于托管和提供网页内容。它接收客户端(如浏览)发送的HTTP请求,并返回相应的网页内容或其他资源,以实现更高的性能和可靠性。它是网站和应用程序在互联网上构建和交付
    的头像 发表于 01-03 15:25 1056次阅读

     物理服务器和大宽服务器怎么选

    物理服务器和大宽服务器的选择需要根据具体的业务需求来决定。物理服务器是一种独立的、非虚拟化的计算机设备,它通常被用作高性能应用、数据库、存储和网络等关键业务应用的运行平台。常见的物理服务器
    的头像 发表于 12-20 10:50 546次阅读

    显示Web服务器中的内存使用情况

    Web服务器上,您可以在“内存”选项卡的“诊断”网页上找到有关各个内存区域当前使用情况的信息。
    的头像 发表于 12-18 10:18 781次阅读
    显示<b class='flag-5'>Web</b><b class='flag-5'>服务器</b>中的内存使用情况