0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

基于STM32的WEB服務(wù)器設(shè)計(jì)

DS小龍哥-嵌入式技術(shù) ? 來源:DS小龍哥-嵌入式技術(shù) ? 作者:DS小龍哥-嵌入式技 ? 2022-02-28 14:03 ? 次閱讀

?一、環(huán)境介紹

MCU:STM32F103ZET6

網(wǎng)卡:ENC28J60

協(xié)議棧: UIP

開發(fā)軟件:Keil5

二、功能介紹

STM32控制ENC28J60+UIP協(xié)議棧創(chuàng)建TCP服務(wù)器(WEB服務(wù)器),支持瀏覽器訪問完成數(shù)據(jù)傳輸。 瀏覽器可以實(shí)時(shí)顯示溫度、時(shí)間、可以控制STM32開發(fā)板上的LED燈、蜂鳴器。

基于STM32的WEB服務(wù)器設(shè)計(jì)

?

poYBAGDYdXCAWkKMAAAAK8RNs4s030.png基于STM32的WEB服務(wù)器設(shè)計(jì)

?

poYBAGDYdXCAWkKMAAAAK8RNs4s030.png基于STM32的WEB服務(wù)器設(shè)計(jì)

?

poYBAGDYdXCAWkKMAAAAK8RNs4s030.png

基于STM32的WEB服務(wù)器設(shè)計(jì)

?

poYBAGDYdXCAWkKMAAAAK8RNs4s030.png

基于STM32的WEB服務(wù)器設(shè)計(jì)poYBAGDYdXCAWkKMAAAAK8RNs4s030.png

?

基于STM32的WEB服務(wù)器設(shè)計(jì)poYBAGDYdXCAWkKMAAAAK8RNs4s030.png

?

三、ENC28J60芯片介紹

ENC28J60 是帶有行業(yè)標(biāo)準(zhǔn)串行外設(shè)接口(Serial Peripheral Interface,SPI)的獨(dú)立以太網(wǎng) 控制器。它可作為任何配備有 SPI 的控制器的以太網(wǎng)接口。ENC28J60 符合 IEEE 802.3 的全部規(guī)范,采用了一系列包過濾機(jī)制以對(duì)傳入數(shù)據(jù)包進(jìn)行限制。 它還提供了一個(gè)內(nèi)部 DMA 模塊, 以實(shí)現(xiàn)快速數(shù)據(jù)吞吐和硬件支持的 IP 校驗(yàn)和計(jì)算。 與主控制器的通信通過兩個(gè)中斷引腳和 SPI 實(shí)現(xiàn),數(shù)據(jù)傳輸速率高達(dá) 10 Mb/s。兩個(gè)專用的引腳用于連接 LED,進(jìn)行網(wǎng)絡(luò)活動(dòng)狀態(tài)指示。ENC28J60 總共只有 28 腳,提供 QFN/TF。

ENC28J60 的主要特點(diǎn)如下:

兼容 IEEE802.3 協(xié)議的以太網(wǎng)控制器

集成 MAC 和 10 BASE-T 物理層

支持全雙工和半雙工模式

數(shù)據(jù)沖突時(shí)可編程自動(dòng)重發(fā)

SPI 接口速度可達(dá) 10Mbps

8K 數(shù)據(jù)接收和發(fā)送雙端口 RAM

提供快速數(shù)據(jù)移動(dòng)的內(nèi)部 DMA 控制器

可配置的接收和發(fā)送緩沖區(qū)大小

兩個(gè)可編程 LED 輸出

帶7個(gè)中斷源的兩個(gè)中斷引腳

TTL 電平輸入

提供多種封裝:SOIC/SSOP/SPDIP/QFN 等。

ENC28J60 由七個(gè)主要功能模塊組成:

1) SPI 接口,充當(dāng)主控制器和 ENC28J60 之間通信通道。

2) 控制寄存器,用于控制和監(jiān)視 ENC28J60。

3) 雙端口 RAM 緩沖器,用于接收和發(fā)送數(shù)據(jù)包。

4) 判優(yōu)器,當(dāng) DMA、發(fā)送和接收模塊發(fā)出請(qǐng)求時(shí)對(duì) RAM 緩沖器的訪問進(jìn)行控制。

5) 總線接口,對(duì)通過 SPI 接收的數(shù)據(jù)和命令進(jìn)行解析。

6) MAC(Medium Access Control)模塊,實(shí)現(xiàn)符合 IEEE 802.3 標(biāo)準(zhǔn)的 MAC 邏輯。

7) PHY(物理層)模塊,對(duì)雙絞線上的模擬數(shù)據(jù)進(jìn)行編碼和譯碼。

ENC28J60 還包括其他支持模塊,諸如振蕩器、片內(nèi)穩(wěn)壓器、電平變換器(提供可以接受 5V 電壓的 I/O 引腳)和系統(tǒng)控制邏輯。

poYBAGDYdXCAWkKMAAAAK8RNs4s030.png

四、UIP 簡介

uIP 由瑞典計(jì)算機(jī)科學(xué)學(xué)院(網(wǎng)絡(luò)嵌入式系統(tǒng)小組)的Adam Dunkels 開發(fā)。其源代碼由C 語 言編寫,并完全公開,uIP 的最新版本是 1.0 版本。 uIP 協(xié)議棧去掉了完整的 TCP/IP 中不常用的功能,簡化了通訊流程,但保留了網(wǎng)絡(luò)通信 必須使用的協(xié)議,設(shè)計(jì)重點(diǎn)放在了 IP/TCP/ICMP/UDP/ARP 這些網(wǎng)絡(luò)層和傳輸層協(xié)議上,保證 了其代碼的通用性和結(jié)構(gòu)的穩(wěn)定性。

由于 uIP 協(xié)議棧專門為嵌入式系統(tǒng)而設(shè)計(jì),因此還具有如下優(yōu)越功能:

1) 代碼非常少,其協(xié)議棧代碼不到 6K,很方便閱讀和移植。

2) 占用的內(nèi)存數(shù)非常少,RAM 占用僅幾百字節(jié)。

3) 其硬件處理層、協(xié)議棧層和應(yīng)用層共用一個(gè)全局緩存區(qū),不存在數(shù)據(jù)的拷貝,且發(fā)送 和接收都是依靠這個(gè)緩存區(qū),極大的節(jié)省空間和時(shí)間。

4) 支持多個(gè)主動(dòng)連接和被動(dòng)連接并發(fā)。

5) 其源代碼中提供一套實(shí)例程序:web 服務(wù)器,web 客戶端,電子郵件發(fā)送程序(SMTP 客 戶端),Telnet 服務(wù)器, DNS 主機(jī)名解析程序等。通用性強(qiáng),移植起來基本不用修改就可以通過。

6) 對(duì)數(shù)據(jù)的處理采用輪循機(jī)制,不需要操作系統(tǒng)的支持。 由于 uIP 對(duì)資源的需求少和移植容易,大部分的 8 位微控制器都使用過uIP 協(xié)議棧, 而且很多的著名的嵌入式產(chǎn)品和項(xiàng)目(如衛(wèi)星,Cisco 路由器,無線傳感器網(wǎng)絡(luò))中都在使用 uIP 協(xié)議棧。 uIP 相當(dāng)于一個(gè)代碼庫,通過一系列的函數(shù)實(shí)現(xiàn)與底層硬件和高層應(yīng)用程序的通訊,對(duì)于 整個(gè)系統(tǒng)來說它內(nèi)部的協(xié)議組是透明的,從而增加了協(xié)議的通用性。

uIP 提供的接口函數(shù)有:

1.初始化 uIP 協(xié)議棧:uip_init()

2.處理輸入包:uip_input()

3.處理周期計(jì)時(shí)事件:uip_periodic()

4.開始監(jiān)聽端口:uip_listen()

5.連接到遠(yuǎn)程主機(jī):uip_connect()

6.接收到連接請(qǐng)求:uip_connected()

7.主動(dòng)關(guān)閉連接:uip_close()

8.連接被關(guān)閉:uip_closed()

9.發(fā)出去的數(shù)據(jù)被應(yīng)答:uip_acked()

10.在當(dāng)前連接發(fā)送數(shù)據(jù):uip_send()

11.在當(dāng)前連接上收到新的數(shù)據(jù):uip_newdata()

12.告訴對(duì)方要停止連接:uip_stop()

13.連接被意外終止:uip_aborted()

基于STM32的WEB服務(wù)器設(shè)計(jì)

?

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); //事件處理函數(shù)
#define UIP_BUF ((struct uip_eth_hdr *)&uip_buf[0])

/*
當(dāng)Uip接收到Uip接收到底層傳遞的數(shù)據(jù),將接收到的數(shù)據(jù)通過調(diào)用http_appcall(),傳遞給Webserver處理,
再通過handle_connection()先后調(diào)用handle_input()函數(shù)和handle_output()函數(shù)
handle_input()主要作用是分析http數(shù)據(jù)流:得到請(qǐng)求的路徑、解析出請(qǐng)求的文件名稱。
然后調(diào)用函數(shù)handle_output進(jìn)行查找對(duì)應(yīng)文件,進(jìn)行發(fā)送到瀏覽器,完成交互。
注意:瀏覽器最好使用谷歌瀏覽器,否則會(huì)導(dǎo)致訪問失敗!
*/

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

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

    while(tapdev_init())	//初始化ENC28J60錯(cuò)誤
    {
        printf("ENC28J60 Init Error!rn");
        Delay72M_Ms(500);
    }
    printf("ENC28J60 初始化成功!rn");

    uip_init();				                  //uIP初始化
    uip_ipaddr(ipaddr, 192,168,1,89);	  //填充開發(fā)板IP地址
    uip_sethostaddr(ipaddr);		        //設(shè)置開發(fā)板IP地址

    uip_ipaddr(ipaddr, 192,168,1,1); 	  //填充開發(fā)板網(wǎng)關(guān)地址
    uip_setdraddr(ipaddr);	            //設(shè)置開發(fā)板網(wǎng)關(guān)IP地址(其實(shí)就是你路由器的IP地址)

    uip_ipaddr(ipaddr, 255,255,255,0);  //填充開發(fā)板網(wǎng)絡(luò)掩碼
    uip_setnetmask(ipaddr);             //填充開發(fā)板網(wǎng)絡(luò)掩碼
    httpd_init();                       //創(chuàng)建WEB服務(wù)器,設(shè)置監(jiān)聽端口

    while(1)
    {			
        uip_EventPoll(); 		 //輪詢方式處理處理網(wǎng)絡(luò)數(shù)據(jù)
    }
}

/*
函數(shù)功能:uip事件處理函數(shù),需要將該函數(shù)插入用戶主循環(huán),循環(huán)調(diào)用
*/
void uip_EventPoll(void)
{
    u8 i;
    static struct timer  arp_timer; //定義定時(shí)器
    static u8 timer_ok=0;

    if(timer_ok==0)//僅初始化一次
    {
        timer_ok = 1;
        timer_set(&arp_timer,CLOCK_SECOND*10);	   	//創(chuàng)建1個(gè)10秒的定時(shí)器
    }

    uip_len=tapdev_read();	//從網(wǎng)絡(luò)設(shè)備讀取一個(gè)IP包,得到數(shù)據(jù)長度.uip_len在uip.c中定義
    if(uip_len>0) 			    //有數(shù)據(jù)
    {
        //處理IP數(shù)據(jù)包(只有校驗(yàn)通過的IP包才會(huì)被接收)
        if(UIP_BUF->type == htons(UIP_ETHTYPE_IP))//是否是IP包?
        {
            uip_arp_ipin();	//去除以太網(wǎng)頭結(jié)構(gòu),更新ARP表
            uip_input();   	//IP包處理
            //當(dāng)上面的函數(shù)執(zhí)行后,如果需要發(fā)送數(shù)據(jù),則全局變量 uip_len > 0
            //需要發(fā)送的數(shù)據(jù)在uip_buf, 長度是uip_len  (這是2個(gè)全局變量)
            if(uip_len>0)//需要回應(yīng)數(shù)據(jù)
            {
                uip_arp_out();//加以太網(wǎng)頭結(jié)構(gòu),在主動(dòng)連接時(shí)可能要構(gòu)造ARP請(qǐng)求
                tapdev_send();//發(fā)送數(shù)據(jù)到以太網(wǎng)
            }
        } else if (UIP_BUF->type==htons(UIP_ETHTYPE_ARP))//處理arp報(bào)文,是否是ARP請(qǐng)求包?
        {
            uip_arp_arpin();
            //當(dāng)上面的函數(shù)執(zhí)行后,如果需要發(fā)送數(shù)據(jù),則全局變量uip_len>0
            //需要發(fā)送的數(shù)據(jù)在uip_buf, 長度是uip_len(這是2個(gè)全局變量)
            if(uip_len>0)tapdev_send();//需要發(fā)送數(shù)據(jù),則通過tapdev_send發(fā)送
        }
    }
    //輪流處理每個(gè)TCP連接, UIP_CONNS缺省是40個(gè)
    for(i=0; i0
        //需要發(fā)送的數(shù)據(jù)在uip_buf, 長度是uip_len (這是2個(gè)全局變量)
        if(uip_len>0)
        {
            uip_arp_out();//加以太網(wǎng)頭結(jié)構(gòu),在主動(dòng)連接時(shí)可能要構(gòu)造ARP請(qǐng)求
            tapdev_send();//發(fā)送數(shù)據(jù)到以太網(wǎng)
        }
    }

    //每隔10秒調(diào)用1次ARP定時(shí)器函數(shù) 用于定期ARP處理,ARP表10秒更新一次,舊的條目會(huì)被拋棄
    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驅(qū)動(dòng)移植接口:
MISO--->PA6----主機(jī)輸入
MOSI--->PA7----主機(jī)輸出
SCLK--->PA5----時(shí)鐘信號(hào)
CS----->PA4----片選
RESET-->PG15---復(fù)位
*/
#define ENC28J60_CS		PAout(4) 	//ENC28J60片選信號(hào)
#define ENC28J60_RST	PGout(15)	//ENC28J60復(fù)位信號(hào)
#define ENC28J60_MOSI PAout(7)  //輸出
#define ENC28J60_MISO PAin(6)   //輸入
#define ENC28J60_SCLK PAout(5)  //時(shí)鐘線

static u8 ENC28J60BANK;
static u32 NextPacketPtr;


/*
函數(shù)功能:底層SPI接口收發(fā)一個(gè)字節(jié)
說    明:模擬SPI時(shí)序,ENC28J60時(shí)鐘線空閑電平為低電平,在第一個(gè)下降沿采集數(shù)據(jù)
*/
u8 ENC28J60_SPI_ReadWriteOneByte(u8 tx_data)
{
	u16 cnt=0;				 
	while((SPI1->SR&1<<1)==0)		 //等待發(fā)送區(qū)空--等待發(fā)送緩沖為空	
	{
		cnt++;
		if(cnt>=65530)return 0; 	  //超時(shí)退出  u16=2個(gè)字節(jié)
	}	
	SPI1->DR=tx_data;	 	  		      //發(fā)送一個(gè)byte 
	cnt=0;
	while((SPI1->SR&1<<0)==0) 		//等待接收完一個(gè)byte   
	{
		cnt++;
		if(cnt>=65530)return 0;	   //超時(shí)退出
	}	  						    
	return SPI1->DR;          		//返回收到的數(shù)據(jù)				
}


/*
函數(shù)功能:復(fù)位ENC28J60,包括SPI初始化/IO初始化等
MISO--->PA6----主機(jī)輸入
MOSI--->PA7----主機(jī)輸出
SCLK--->PA5----時(shí)鐘信號(hào)
CS----->PA4----片選
RESET-->PG15---復(fù)位
*/
void ENC28J60_Reset(void)
{
/*開啟時(shí)鐘*/
	RCC->APB2ENR|=1<<12;   //開啟SPI1時(shí)鐘
	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位數(shù)據(jù)幀格式進(jìn)行發(fā)送/接收;
	SPI1->CR1|=0<<10; //全雙工(發(fā)送和接收);
	SPI1->CR1|=1<<9;  //啟用軟件從設(shè)備管理
	SPI1->CR1|=1<<8;  //NSS
	SPI1->CR1|=0<<7;  //幀格式,先發(fā)送高位
	SPI1->CR1|=0x1<<3;//當(dāng)總線頻率為36MHZ時(shí),SPI速度為18MHZ,高速。
	SPI1->CR1|=1<<2;  //配置為主設(shè)備
	SPI1->CR1|=1<<1;  //空閑狀態(tài)時(shí), SCK保持高電平。
	SPI1->CR1|=1<<0;  //數(shù)據(jù)采樣從第二個(gè)時(shí)鐘邊沿開始。
	SPI1->CR1|=1<<6;  //開啟SPI設(shè)備。
	
	//針對(duì)ENC28J60的特點(diǎn)(SCK空閑為低電平)修改SPI的設(shè)置
 	SPI1->CR1&=~(1<<6); 	//SPI設(shè)備失能
	SPI1->CR1&=~(1<<1); 	//空閑模式下SCK為0 CPOL=0
	SPI1->CR1&=~(1<<0); 	//數(shù)據(jù)采樣從第1個(gè)時(shí)間邊沿開始,CPHA=0  
	SPI1->CR1|=1<<6; 	  	//SPI設(shè)備使能
	
	ENC28J60_RST=0;			//復(fù)位ENC28J60
	DelayMs(10);	 
	ENC28J60_RST=1;			//復(fù)位結(jié)束				    
	DelayMs(10);	  
}


/*
函數(shù)功能:讀取ENC28J60寄存器(帶操作碼) 
參	  數(shù):op:操作碼
					addr:寄存器地址/參數(shù)
返 回 值:讀到的數(shù)據(jù)
*/
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寄存器,則第二次讀到的數(shù)據(jù)才是正確的,見手冊(cè)29頁
 	if(addr&0x80)dat=ENC28J60_SPI_ReadWriteOneByte(0xFF);
	ENC28J60_CS=1;
	return dat;
}



/*
函數(shù)功能:讀取ENC28J60寄存器(帶操作碼) 
參    數(shù):
				op:操作碼
				addr:寄存器地址
				data:參數(shù)
*/
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;
}



/*
函數(shù)功能:讀取ENC28J60接收緩存數(shù)據(jù)
參    數(shù):
				len:要讀取的數(shù)據(jù)長度
				data:輸出數(shù)據(jù)緩存區(qū)(末尾自動(dòng)添加結(jié)束符)
*/
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;
}


/*
函數(shù)功能:向ENC28J60寫發(fā)送緩存數(shù)據(jù)
參    數(shù):
				len:要寫入的數(shù)據(jù)長度
				data:數(shù)據(jù)緩存區(qū)
*/
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;
}

/*
函數(shù)功能:設(shè)置ENC28J60寄存器Bank
參    數(shù):
				ban:要設(shè)置的bank
*/
void ENC28J60_Set_Bank(u8 bank)
{								    
	if((bank&BANK_MASK)!=ENC28J60BANK)//和當(dāng)前bank不一致的時(shí)候,才設(shè)置
	{				  
		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);
	}
}


/*
函數(shù)功能:讀取ENC28J60指定寄存器
參    數(shù):addr:寄存器地址
返 回 值:讀到的數(shù)據(jù)
*/
u8 ENC28J60_Read(u8 addr)
{						  
	ENC28J60_Set_Bank(addr);//設(shè)置BANK		 
	return ENC28J60_Read_Op(ENC28J60_READ_CTRL_REG,addr);
}


/*
函數(shù)功能:向ENC28J60指定寄存器寫數(shù)據(jù)
參    數(shù):
					addr:寄存器地址
					data:要寫入的數(shù)據(jù)		
*/
void ENC28J60_Write(u8 addr,u8 data)
{					  
	ENC28J60_Set_Bank(addr);		 
	ENC28J60_Write_Op(ENC28J60_WRITE_CTRL_REG,addr,data);
}


/*
函數(shù)功能:向ENC28J60的PHY寄存器寫入數(shù)據(jù)
參    數(shù):
				addr:寄存器地址
				data:要寫入的數(shù)據(jù)	
*/
void ENC28J60_PHY_Write(u8 addr,u32 data)
{
	u16 retry=0;
	ENC28J60_Write(MIREGADR,addr);	//設(shè)置PHY寄存器地址
	ENC28J60_Write(MIWRL,data);		//寫入數(shù)據(jù)
	ENC28J60_Write(MIWRH,data>>8);		   
	while((ENC28J60_Read(MISTAT)&MISTAT_BUSY)&&retry<0XFFF)retry++;//等待寫入PHY結(jié)束		  
}


/*
函數(shù)功能:初始化ENC28J60
參    數(shù):macaddr:MAC地址
返 回 值:
				  0,初始化成功;
          1,初始化失敗;
*/
u8 ENC28J60_Init(u8* macaddr)
{		
	u16 retry=0;		  
	ENC28J60_Reset(); //復(fù)位底層引腳接口
	ENC28J60_Write_Op(ENC28J60_SOFT_RESET,0,ENC28J60_SOFT_RESET);//軟件復(fù)位
	while(!(ENC28J60_Read(ESTAT)&ESTAT_CLKRDY)&&retry<500)//等待時(shí)鐘穩(wěn)定
	{
		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	   設(shè)置接收緩沖區(qū)地址  8K字節(jié)容量
	NextPacketPtr=RXSTART_INIT;
	// Rx start
	//接收緩沖器由一個(gè)硬件管理的循環(huán)FIFO 緩沖器構(gòu)成。
	//寄存器對(duì)ERXSTH:ERXSTL 和ERXNDH:ERXNDL 作
	//為指針,定義緩沖器的容量和其在存儲(chǔ)器中的位置。
	//ERXST和ERXND指向的字節(jié)均包含在FIFO緩沖器內(nèi)。
	//當(dāng)從以太網(wǎng)接口接收數(shù)據(jù)字節(jié)時(shí),這些字節(jié)被順序?qū)懭?	//接收緩沖器。 但是當(dāng)寫入由ERXND 指向的存儲(chǔ)單元
	//后,硬件會(huì)自動(dòng)將接收的下一字節(jié)寫入由ERXST 指向
	//的存儲(chǔ)單元。 因此接收硬件將不會(huì)寫入FIFO 以外的單
	//元。
	//設(shè)置接收起始字節(jié)
	ENC28J60_Write(ERXSTL,RXSTART_INIT&0xFF);	
	ENC28J60_Write(ERXSTH,RXSTART_INIT>>8);	  
	//ERXWRPTH:ERXWRPTL 寄存器定義硬件向FIFO 中
	//的哪個(gè)位置寫入其接收到的字節(jié)。 指針是只讀的,在成
	//功接收到一個(gè)數(shù)據(jù)包后,硬件會(huì)自動(dòng)更新指針。 指針可
	//用于判斷FIFO 內(nèi)剩余空間的大小  8K-1500。 
	//設(shè)置接收讀指針字節(jié)
	ENC28J60_Write(ERXRDPTL,RXSTART_INIT&0xFF);
	ENC28J60_Write(ERXRDPTH,RXSTART_INIT>>8);
	//設(shè)置接收結(jié)束字節(jié)
	ENC28J60_Write(ERXNDL,RXSTOP_INIT&0xFF);
	ENC28J60_Write(ERXNDH,RXSTOP_INIT>>8);
	//設(shè)置發(fā)送起始字節(jié)
	ENC28J60_Write(ETXSTL,TXSTART_INIT&0xFF);
	ENC28J60_Write(ETXSTH,TXSTART_INIT>>8);
	//設(shè)置發(fā)送結(jié)束字節(jié)
	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:單播過濾器使能位
	//當(dāng)ANDOR = 1 時(shí):
	//1 = 目標(biāo)地址與本地MAC 地址不匹配的數(shù)據(jù)包將被丟棄
	//0 = 禁止過濾器
	//當(dāng)ANDOR = 0 時(shí):
	//1 = 目標(biāo)地址與本地MAC 地址匹配的數(shù)據(jù)包會(huì)被接受
	//0 = 禁止過濾器
	//CRCEN:后過濾器CRC 校驗(yàn)使能位
	//1 = 所有CRC 無效的數(shù)據(jù)包都將被丟棄
	//0 = 不考慮CRC 是否有效
	//PMEN:格式匹配過濾器使能位
	//當(dāng)ANDOR = 1 時(shí):
	//1 = 數(shù)據(jù)包必須符合格式匹配條件,否則將被丟棄
	//0 = 禁止過濾器
	//當(dāng)ANDOR = 0 時(shí):
	//1 = 符合格式匹配條件的數(shù)據(jù)包將被接受
	//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 接收數(shù)據(jù)包
	//0 = 禁止數(shù)據(jù)包接收
	//bit 3 TXPAUS:暫??刂茙l(fā)送使能位
	//1 = 允許MAC 發(fā)送暫停控制幀(用于全雙工模式下的流量控制)
	//0 = 禁止暫停幀發(fā)送
	//bit 2 RXPAUS:暫??刂茙邮帐鼓芪?	//1 = 當(dāng)接收到暫??刂茙瑫r(shí),禁止發(fā)送(正常操作)
	//0 = 忽略接收到的暫停控制幀
	ENC28J60_Write(MACON1,MACON1_MARXEN|MACON1_TXPAUS|MACON1_RXPAUS);
	// bring MAC out of reset
	//將MACON2 中的MARST 位清零,使MAC 退出復(fù)位狀態(tài)。
	ENC28J60_Write(MACON2,0x00);
	// enable automatic padding to 60bytes and CRC operations
	//bit 7-5 PADCFG2:PACDFG0:自動(dòng)填充和CRC 配置位
	//111 = 用0 填充所有短幀至64 字節(jié)長,并追加一個(gè)有效的CRC
	//110 = 不自動(dòng)填充短幀
	//101 = MAC 自動(dòng)檢測具有8100h 類型字段的VLAN 協(xié)議幀,并自動(dòng)填充到64 字節(jié)長。如果不
	//是VLAN 幀,則填充至60 字節(jié)長。填充后還要追加一個(gè)有效的CRC
	//100 = 不自動(dòng)填充短幀
	//011 = 用0 填充所有短幀至64 字節(jié)長,并追加一個(gè)有效的CRC
	//010 = 不自動(dòng)填充短幀
	//001 = 用0 填充所有短幀至60 字節(jié)長,并追加一個(gè)有效的CRC
	//000 = 不自動(dòng)填充短幀
	//bit 4 TXCRCEN:發(fā)送CRC 使能位
	//1 = 不管PADCFG如何,MAC都會(huì)在發(fā)送幀的末尾追加一個(gè)有效的CRC。 如果PADCFG規(guī)定要
	//追加有效的CRC,則必須將TXCRCEN 置1。
	//0 = MAC不會(huì)追加CRC。 檢查最后4 個(gè)字節(jié),如果不是有效的CRC 則報(bào)告給發(fā)送狀態(tài)向量。
	//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)
	//配置非背對(duì)背包間間隔寄存器的低字節(jié)
	//MAIPGL。 大多數(shù)應(yīng)用使用12h 編程該寄存器。
	//如果使用半雙工模式,應(yīng)編程非背對(duì)背包間間隔
	//寄存器的高字節(jié)MAIPGH。 大多數(shù)應(yīng)用使用0Ch
	//編程該寄存器。
	ENC28J60_Write(MAIPGL,0x12);
	ENC28J60_Write(MAIPGH,0x0C);
	// set inter-frame gap (back-to-back)
	//配置背對(duì)背包間間隔寄存器MABBIPG。當(dāng)使用
	//全雙工模式時(shí),大多數(shù)應(yīng)用使用15h 編程該寄存
	//器,而使用半雙工模式時(shí)則使用12h 進(jìn)行編程。
	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
	//設(shè)置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	 禁止環(huán)回
	//HDLDIS:PHY 半雙工環(huán)回禁止位
	//當(dāng)PHCON1.PDPXMD = 1 或PHCON1.PLOOPBK = 1 時(shí):
	//此位可被忽略。
	//當(dāng)PHCON1.PDPXMD = 0 且PHCON1.PLOOPBK = 0 時(shí):
	//1 = 要發(fā)送的數(shù)據(jù)僅通過雙絞線接口發(fā)出
	//0 = 要發(fā)送的數(shù)據(jù)會(huì)環(huán)回到MAC 并通過雙絞線接口發(fā)出
	ENC28J60_PHY_Write(PHCON2,PHCON2_HDLDIS);
	// switch to bank 0
	//ECON1 寄存器
	//寄存器3-1 所示為ECON1 寄存器,它用于控制
	//ENC28J60 的主要功能。 ECON1 中包含接收使能、發(fā)
	//送請(qǐng)求、DMA 控制和存儲(chǔ)區(qū)選擇位。	   
	ENC28J60_Set_Bank(ECON1);
	// enable interrutps
	//EIE: 以太網(wǎng)中斷允許寄存器
	//bit 7 INTIE: 全局INT 中斷允許位
	//1 = 允許中斷事件驅(qū)動(dòng)INT 引腳
	//0 = 禁止所有INT 引腳的活動(dòng)(引腳始終被驅(qū)動(dòng)為高電平)
	//bit 6 PKTIE: 接收數(shù)據(jù)包待處理中斷允許位
	//1 = 允許接收數(shù)據(jù)包待處理中斷
	//0 = 禁止接收數(shù)據(jù)包待處理中斷
	ENC28J60_Write_Op(ENC28J60_BIT_FIELD_SET,EIE,EIE_INTIE|EIE_PKTIE);
	// enable packet reception
	//bit 2 RXEN:接收使能位
	//1 = 通過當(dāng)前過濾器的數(shù)據(jù)包將被寫入接收緩沖器
	//0 = 忽略所有接收的數(shù)據(jù)包
	ENC28J60_Write_Op(ENC28J60_BIT_FIELD_SET,ECON1,ECON1_RXEN);
	if(ENC28J60_Read(MAADR5)== macaddr[0])return 0;//初始化成功
	else return 1; 	  

}

/*
函數(shù)功能:讀取EREVID
參    數(shù):
*/
u8 ENC28J60_Get_EREVID(void)
{
	//在EREVID 內(nèi)也存儲(chǔ)了版本信息。 EREVID 是一個(gè)只讀控
	//制寄存器,包含一個(gè)5 位標(biāo)識(shí)符,用來標(biāo)識(shí)器件特定硅片
	//的版本號(hào)
	return ENC28J60_Read(EREVID);
}



/*
函數(shù)功能:通過ENC28J60發(fā)送數(shù)據(jù)包到網(wǎng)絡(luò)
參    數(shù):
					len   :數(shù)據(jù)包大小
          packet:數(shù)據(jù)包
*/
void ENC28J60_Packet_Send(u32 len,u8* packet)
{
	//設(shè)置發(fā)送緩沖區(qū)地址寫指針入口
	ENC28J60_Write(EWRPTL,TXSTART_INIT&0xFF);
	ENC28J60_Write(EWRPTH,TXSTART_INIT>>8);
	//設(shè)置TXND指針,以對(duì)應(yīng)給定的數(shù)據(jù)包大小	   
	ENC28J60_Write(ETXNDL,(TXSTART_INIT+len)&0xFF);
	ENC28J60_Write(ETXNDH,(TXSTART_INIT+len)>>8);
	//寫每包控制字節(jié)(0x00表示使用macon3的設(shè)置) 
	ENC28J60_Write_Op(ENC28J60_WRITE_BUF_MEM,0,0x00);
	//復(fù)制數(shù)據(jù)包到發(fā)送緩沖區(qū)
	//printf("len:%drn",len);	//監(jiān)視發(fā)送數(shù)據(jù)長度
 	ENC28J60_Write_Buf(len,packet);
 	//發(fā)送數(shù)據(jù)到網(wǎng)絡(luò)
	ENC28J60_Write_Op(ENC28J60_BIT_FIELD_SET,ECON1,ECON1_TXRTS);
	//復(fù)位發(fā)送邏輯的問題。參見Rev. B4 Silicon Errata point 12.
	if((ENC28J60_Read(EIR)&EIR_TXERIF))ENC28J60_Write_Op(ENC28J60_BIT_FIELD_CLR,ECON1,ECON1_TXRTS);
}


/*
函數(shù)功能:從網(wǎng)絡(luò)獲取一個(gè)數(shù)據(jù)包內(nèi)容
函數(shù)參數(shù):
				maxlen:數(shù)據(jù)包最大允許接收長度
				packet:數(shù)據(jù)包緩存區(qū)
返 回 值:收到的數(shù)據(jù)包長度(字節(jié))	
*/
u32 ENC28J60_Packet_Receive(u32 maxlen,u8* packet)
{
	u32 rxstat;
	u32 len;    													 
	if(ENC28J60_Read(EPKTCNT)==0)return 0;  //是否收到數(shù)據(jù)包?	   
	//設(shè)置接收緩沖器讀指針
	ENC28J60_Write(ERDPTL,(NextPacketPtr));
	ENC28J60_Write(ERDPTH,(NextPacketPtr)>>8);	   
	// 讀下一個(gè)包的指針
	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計(jì)數(shù)
	//讀取接收狀態(tài)
	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和符號(hào)錯(cuò)誤
	// ERXFCON.CRCEN為默認(rèn)設(shè)置,一般我們不需要檢查.
	if((rxstat&0x80)==0)len=0;//無效
	else ENC28J60_Read_Buf(len,packet);//從接收緩沖器中復(fù)制數(shù)據(jù)包	    
	//RX讀指針移動(dòng)到下一個(gè)接收到的數(shù)據(jù)包的開始位置 
	//并釋放我們剛才讀出過的內(nèi)存
	ENC28J60_Write(ERXRDPTL,(NextPacketPtr));
	ENC28J60_Write(ERXRDPTH,(NextPacketPtr)>>8);
	//遞減數(shù)據(jù)包計(jì)數(shù)器標(biāo)志我們已經(jīng)得到了這個(gè)包 
 	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 中
//的哪個(gè)位置寫入其接收到的字節(jié)。 指針是只讀的,在成
//功接收到一個(gè)數(shù)據(jù)包后,硬件會(huì)自動(dòng)更新指針。 指針可
//用于判斷FIFO 內(nèi)剩余空間的大小。
#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; 	  //溫度值的整數(shù)和小數(shù)部分

/*-----------------------------------------------------------------------------------*/
int
httpd_fs_open(const char *name, struct httpd_fs_file *file)
{
 	 //第一次的默認(rèn)頁面
	 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;             //分離出溫度值整數(shù)部分
			ds18b20_decT = ds18b20_T & 0xF;            //分離出溫度值小數(shù)部分
		  //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

審核編輯:湯梓紅

?

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • 服務(wù)器
    +關(guān)注

    關(guān)注

    12

    文章

    8701

    瀏覽量

    84568
  • STM32
    +關(guān)注

    關(guān)注

    2258

    文章

    10828

    瀏覽量

    352509
  • TCP
    TCP
    +關(guān)注

    關(guān)注

    8

    文章

    1324

    瀏覽量

    78759
收藏 人收藏

    評(píng)論

    相關(guān)推薦

    使用NS1串口服務(wù)器HTTP模式上傳服務(wù)器數(shù)據(jù)

    HTTP協(xié)議工作于客戶端-服務(wù)端架構(gòu)之上。瀏覽作為HTTP客戶端通過URL向HTTP服務(wù)端即Web服務(wù)器發(fā)送所有請(qǐng)求。
    的頭像 發(fā)表于 08-30 12:36 ?124次閱讀
    使用NS1串口<b class='flag-5'>服務(wù)器</b>HTTP模式上傳<b class='flag-5'>服務(wù)器</b>數(shù)據(jù)

    如何使用espconn api實(shí)現(xiàn)一個(gè)Web服務(wù)器

    我正在嘗試使用 espconn api 實(shí)現(xiàn)一個(gè) Web 服務(wù)器。 在一些請(qǐng)求之后,我收到將此錯(cuò)誤(err1,超過最大時(shí)間值)寫入 uart,下一個(gè)espconn_send導(dǎo)致致命異常 (28)。 沒有關(guān)于此的文檔... 我該如何解決這個(gè)問題?
    發(fā)表于 07-18 07:46

    什么是web服務(wù)器?如何選擇服務(wù)器配置?

    Web服務(wù)器是一種軟件或硬件設(shè)備,用于托管和提供網(wǎng)頁內(nèi)容。它接收客戶端(如瀏覽)發(fā)送的HTTP請(qǐng)求,并返回相應(yīng)的網(wǎng)頁內(nèi)容或其他資源,以實(shí)現(xiàn)更高的性能和可靠性。它是網(wǎng)站和應(yīng)用程序在互聯(lián)網(wǎng)上構(gòu)建和交付
    的頭像 發(fā)表于 01-03 15:25 ?979次閱讀

    顯示Web服務(wù)器中的內(nèi)存使用情況

    Web服務(wù)器上,您可以在“內(nèi)存”選項(xiàng)卡的“診斷”網(wǎng)頁上找到有關(guān)各個(gè)內(nèi)存區(qū)域當(dāng)前使用情況的信息。
    的頭像 發(fā)表于 12-18 10:18 ?569次閱讀
    顯示<b class='flag-5'>Web</b><b class='flag-5'>服務(wù)器</b>中的內(nèi)存使用情況

    基于ARM平臺(tái)的嵌入式WEB服務(wù)器的設(shè)計(jì)與實(shí)現(xiàn)

    電子發(fā)燒友網(wǎng)站提供《基于ARM平臺(tái)的嵌入式WEB服務(wù)器的設(shè)計(jì)與實(shí)現(xiàn).pdf》資料免費(fèi)下載
    發(fā)表于 10-27 10:45 ?1次下載
    基于ARM平臺(tái)的嵌入式<b class='flag-5'>WEB</b><b class='flag-5'>服務(wù)器</b>的設(shè)計(jì)與實(shí)現(xiàn)

    如何配置及訪問S7-1200的Web服務(wù)器功能?

    TIA Portal 從 V17 版本開始、S7-1200 CPU 從 V4.5 版本開始,Web 服務(wù)器支持現(xiàn)代 API 和證書處理。
    的頭像 發(fā)表于 10-26 16:19 ?3052次閱讀
    如何配置及訪問S7-1200的<b class='flag-5'>Web</b><b class='flag-5'>服務(wù)器</b>功能?

    基于單片機(jī)的嵌入式web服務(wù)器設(shè)計(jì)與實(shí)現(xiàn)

    電子發(fā)燒友網(wǎng)站提供《基于單片機(jī)的嵌入式web服務(wù)器設(shè)計(jì)與實(shí)現(xiàn).pdf》資料免費(fèi)下載
    發(fā)表于 10-26 14:36 ?0次下載
    基于單片機(jī)的嵌入式<b class='flag-5'>web</b><b class='flag-5'>服務(wù)器</b>設(shè)計(jì)與實(shí)現(xiàn)

    變電站自動(dòng)化系統(tǒng)中嵌入式Web服務(wù)器的設(shè)計(jì)與實(shí)現(xiàn)

    電子發(fā)燒友網(wǎng)站提供《變電站自動(dòng)化系統(tǒng)中嵌入式Web服務(wù)器的設(shè)計(jì)與實(shí)現(xiàn).doc》資料免費(fèi)下載
    發(fā)表于 10-26 14:12 ?0次下載
    變電站自動(dòng)化系統(tǒng)中嵌入式<b class='flag-5'>Web</b><b class='flag-5'>服務(wù)器</b>的設(shè)計(jì)與實(shí)現(xiàn)

    嵌入式Web服務(wù)器的實(shí)現(xiàn)及其CGI應(yīng)用

    電子發(fā)燒友網(wǎng)站提供《嵌入式Web服務(wù)器的實(shí)現(xiàn)及其CGI應(yīng)用.pdf》資料免費(fèi)下載
    發(fā)表于 10-25 10:55 ?0次下載
    嵌入式<b class='flag-5'>Web</b><b class='flag-5'>服務(wù)器</b>的實(shí)現(xiàn)及其CGI應(yīng)用

    ESP8266可作為Web服務(wù)器嗎?怎么實(shí)現(xiàn)?

    ESP8266可作為Web服務(wù)器嗎怎么實(shí)現(xiàn)
    發(fā)表于 10-24 08:17

    基于Android的嵌入式Web服務(wù)器設(shè)計(jì)

    電子發(fā)燒友網(wǎng)站提供《基于Android的嵌入式Web服務(wù)器設(shè)計(jì).pdf》資料免費(fèi)下載
    發(fā)表于 10-20 09:56 ?0次下載
    基于Android的嵌入式<b class='flag-5'>Web</b><b class='flag-5'>服務(wù)器</b>設(shè)計(jì)

    基于嵌入式Web服務(wù)器的遠(yuǎn)程控制系統(tǒng)設(shè)計(jì)

    電子發(fā)燒友網(wǎng)站提供《基于嵌入式Web服務(wù)器的遠(yuǎn)程控制系統(tǒng)設(shè)計(jì).pdf》資料免費(fèi)下載
    發(fā)表于 10-18 11:17 ?0次下載
    基于嵌入式<b class='flag-5'>Web</b><b class='flag-5'>服務(wù)器</b>的遠(yuǎn)程控制系統(tǒng)設(shè)計(jì)

    基于ARM處理的嵌入式WEB服務(wù)器設(shè)計(jì)

    電子發(fā)燒友網(wǎng)站提供《基于ARM處理的嵌入式WEB服務(wù)器設(shè)計(jì).pdf》資料免費(fèi)下載
    發(fā)表于 10-11 11:38 ?0次下載
    基于ARM處理<b class='flag-5'>器</b>的嵌入式<b class='flag-5'>WEB</b><b class='flag-5'>服務(wù)器</b>設(shè)計(jì)

    服務(wù)器類型有哪些?

    中一些關(guān)鍵服務(wù)器類型包括有: 1、網(wǎng)絡(luò)服務(wù)器 Web服務(wù)器旨在通過客戶端程序(Web瀏覽)(例
    的頭像 發(fā)表于 10-08 17:17 ?910次閱讀

    基于單片機(jī)的Web服務(wù)器設(shè)計(jì)

    1.單片機(jī)Web服務(wù)器傳輸速度快、有成熟的。協(xié)議棧軟件可以利用2.外圍芯片少,成本低,開發(fā)速度快3.Web瀏覽廣泛使用4.社會(huì)需求量大
    發(fā)表于 09-25 08:25