• 方案介紹
    • 一、前言
    • 二、硬件設(shè)計(jì)
  • 附件下載
  • 相關(guān)推薦
申請入駐 產(chǎn)業(yè)圖譜

基于STM32的輕量級Web服務(wù)器設(shè)計(jì)

06/04 10:21
590
加入交流群
掃碼加入
獲取工程師必備禮包
參與熱點(diǎn)資訊討論

更多詳細(xì)資料請聯(lián)系.docx

共1個(gè)文件

一、前言


STM32+ENC28J60+UIP協(xié)議棧實(shí)現(xiàn)WEB服務(wù)器

1.1 開發(fā)背景

本項(xiàng)目的目的是構(gòu)建一個(gè)基于STM32F103ZET6微控制器嵌入式Web服務(wù)器,以滿足遠(yuǎn)程監(jiān)控和控制嵌入式設(shè)備的需求。隨著物聯(lián)網(wǎng)技術(shù)的快速發(fā)展,遠(yuǎn)程監(jiān)控和控制嵌入式設(shè)備變得越來越重要。本項(xiàng)目通過選擇STM32F103ZET6作為主控芯片,結(jié)合ENC28J60網(wǎng)卡實(shí)現(xiàn)網(wǎng)絡(luò)通信,并移植UIP協(xié)議棧來構(gòu)建輕量級的Web服務(wù)器。

項(xiàng)目還集成了DS18B20溫度傳感器、LED燈模塊和高電平觸發(fā)的有源蜂鳴器,以實(shí)現(xiàn)遠(yuǎn)程監(jiān)控和控制STM32設(shè)備端的功能,如LED燈和蜂鳴器的控制,以及設(shè)備端溫度和RTC時(shí)間的顯示。這種設(shè)計(jì)使得用戶能夠通過瀏覽器訪問服務(wù)器,實(shí)時(shí)查看和控制嵌入式設(shè)備,為物聯(lián)網(wǎng)應(yīng)用提供了一種靈活、高效的解決方案。

image-20240530155757078

1.2 實(shí)現(xiàn)的功能

(1)網(wǎng)絡(luò)通信搭建:通過STM32F103ZET6微控制器與ENC28J60以太網(wǎng)控制器的集成,利用SPI接口實(shí)現(xiàn)數(shù)據(jù)傳輸,成功移植UIP輕量級TCP/IP協(xié)議棧,從而在嵌入式平臺(tái)上搭建起一個(gè)功能完備的Web服務(wù)器。

(2)網(wǎng)頁服務(wù):在STM32內(nèi)部存儲(chǔ)一個(gè)簡易的網(wǎng)頁文件,該網(wǎng)頁設(shè)計(jì)用于用戶界面展示及交互。當(dāng)用戶使用任何標(biāo)準(zhǔn)的Web瀏覽器訪問此服務(wù)器的IP地址時(shí),即可加載并顯示該網(wǎng)頁內(nèi)容。

(3)遠(yuǎn)程控制功能

  • LED燈控制:網(wǎng)頁上設(shè)有控制按鈕或界面元素,允許用戶遠(yuǎn)程開關(guān)連接到STM32的LED燈模塊,實(shí)現(xiàn)遠(yuǎn)程照明控制演示。
  • 蜂鳴器控制:同樣通過網(wǎng)頁界面,用戶能激活或關(guān)閉STM32連接的高電平觸發(fā)的有源蜂鳴器,完成遠(yuǎn)程報(bào)警或信號提示功能的測試。

(4)環(huán)境監(jiān)測與顯示

  • 溫度監(jiān)控:集成DS18B20數(shù)字溫度傳感器,周期性采集環(huán)境溫度數(shù)據(jù),并通過Web界面實(shí)時(shí)顯示給用戶,提供基本的環(huán)境監(jiān)測能力。
  • 實(shí)時(shí)時(shí)鐘顯示:利用STM32內(nèi)置的RTC(實(shí)時(shí)時(shí)鐘)模塊,獲取并準(zhǔn)確顯示當(dāng)前的時(shí)間信息,增強(qiáng)系統(tǒng)的實(shí)用性和用戶交互體驗(yàn)。

項(xiàng)目不僅實(shí)現(xiàn)了從硬件選型、網(wǎng)絡(luò)配置到軟件開發(fā)的全過程,還展示了物聯(lián)網(wǎng)技術(shù)在實(shí)際應(yīng)用中的一個(gè)小而完整的案例,即通過簡單的Web界面遠(yuǎn)程監(jiān)控和控制物理設(shè)備,體現(xiàn)了STM32平臺(tái)在物聯(lián)網(wǎng)領(lǐng)域的靈活性與強(qiáng)大功能。

1.3 硬件模塊組成

(1)主控制器模塊

  • STM32F103ZET6微控制器:作為系統(tǒng)的核心處理器,負(fù)責(zé)運(yùn)行控制程序、管理外設(shè)通信、處理網(wǎng)絡(luò)數(shù)據(jù)包及執(zhí)行用戶指令。它擁有豐富的外設(shè)資源,如SPI、USART、I2C等,支持高速運(yùn)算和低功耗操作,是實(shí)現(xiàn)項(xiàng)目功能的基礎(chǔ)。

(2)網(wǎng)絡(luò)通信模塊

  • ENC28J60以太網(wǎng)控制器:通過SPI接口與STM32連接,提供物理層數(shù)據(jù)鏈路層的網(wǎng)絡(luò)功能,實(shí)現(xiàn)與外部網(wǎng)絡(luò)的連接。它是項(xiàng)目中實(shí)現(xiàn)Web服務(wù)器功能的關(guān)鍵組件,支持以太網(wǎng)數(shù)據(jù)包的收發(fā),使嵌入式設(shè)備能夠接入互聯(lián)網(wǎng)。

(3)溫度監(jiān)測模塊

  • DS18B20數(shù)字溫度傳感器:通過單總線(One-Wire)接口與STM32通信,用于精確測量環(huán)境溫度。該傳感器具有體積小、精度高、直接數(shù)字輸出等特點(diǎn),非常適合嵌入式系統(tǒng)中的溫度監(jiān)控應(yīng)用。

(4)輸出控制模塊

  • LED燈模塊:作為基本的輸出設(shè)備,通過GPIO(通用輸入輸出端口)直接由STM32控制,用于響應(yīng)用戶的控制命令,如點(diǎn)亮或熄滅,以直觀展示控制效果。
  • 有源蜂鳴器:通過高電平觸發(fā)的方式連接至STM32的一個(gè)GPIO引腳,根據(jù)控制信號產(chǎn)生聲音,實(shí)現(xiàn)報(bào)警或狀態(tài)反饋功能。

(5)電源模塊:為確保所有硬件組件穩(wěn)定工作,需要一個(gè)合適的電源供應(yīng)模塊,為STM32微控制器、ENC28J60網(wǎng)卡、傳感器及外圍電路提供穩(wěn)定的電壓和電流

1.4 ENC28J60網(wǎng)卡介紹

ENC28J60是一款集成MAC(Media Access Control,媒體訪問控制)和10BASE-T PHY(物理層)的以太網(wǎng)控制器,特別適合于嵌入式系統(tǒng)和微控制器應(yīng)用。

以下是ENC28J60網(wǎng)卡的一些關(guān)鍵特性與介紹:

(1)接口類型:它使用SPI(Serial Peripheral Interface,串行外設(shè)接口)作為與外部微控制器通信的主要方式,這使得它能夠以較少的引腳數(shù)(通常為4或5條線)與諸如STM32、Arduino等微控制器連接,降低了硬件設(shè)計(jì)的復(fù)雜度。

(2)兼容性:ENC28J60兼容IEEE 802.3標(biāo)準(zhǔn),這意味著它可以無縫地融入標(biāo)準(zhǔn)以太網(wǎng)網(wǎng)絡(luò)環(huán)境中。它支持10Mbps的傳輸速率,適用于不需要高速網(wǎng)絡(luò)連接的應(yīng)用場景。

(3)集成功能:除了MAC和PHY層之外,ENC28J60還集成了其他一些功能,如緩沖區(qū)管理、DMA(Direct Memory Access,直接內(nèi)存訪問)支持、以及對多種網(wǎng)絡(luò)幀類型的支持,包括廣播、多播和單播。

(4)網(wǎng)絡(luò)功能:能夠?qū)崿F(xiàn)完整的以太網(wǎng)數(shù)據(jù)包的發(fā)送和接收,支持IP、TCP、UDP網(wǎng)絡(luò)協(xié)議棧。開發(fā)者通常會(huì)結(jié)合LwIP(Lightweight IP)這樣的輕量級TCP/IP協(xié)議棧來實(shí)現(xiàn)網(wǎng)絡(luò)通信。

(5)物理層特性:支持10BASE-T標(biāo)準(zhǔn),可以通過RJ45接口連接雙絞線(UTP),支持自動(dòng)極性和交叉檢測,可工作在全雙工或半雙工模式下。

(6)功耗與封裝:ENC28J60設(shè)計(jì)考慮到了低功耗應(yīng)用的需求,適合電池供電設(shè)備。它通常采用SSOP(Shrink Small Outline Package)或QFN(Quad Flat No-Leads)等小型封裝形式,便于在空間受限的設(shè)計(jì)中使用。

(7)靈活性與應(yīng)用:由于其SPI接口和相對較低的成本,ENC28J60被廣泛應(yīng)用于各種嵌入式項(xiàng)目中,如物聯(lián)網(wǎng)設(shè)備智能家居、工業(yè)控制、遠(yuǎn)程監(jiān)控系統(tǒng)等。

ENC28J60以其集成度高、接口靈活、成本效益好等特點(diǎn),成為了許多嵌入式系統(tǒng)設(shè)計(jì)中實(shí)現(xiàn)網(wǎng)絡(luò)連接的優(yōu)選解決方案。

1.5 UIP協(xié)議棧

UIP(Micro IP)協(xié)議棧是一種專門為資源受限的嵌入式系統(tǒng)設(shè)計(jì)的輕量級TCP/IP協(xié)議棧。它最初由Adam Dunkels在SICS(瑞典計(jì)算機(jī)科學(xué)研究所)開發(fā),目的是使即便是8位微控制器也能輕松實(shí)現(xiàn)網(wǎng)絡(luò)通信,而不必負(fù)擔(dān)全尺寸TCP/IP協(xié)議棧的開銷。下面是UIP協(xié)議棧的詳細(xì)介紹:

【1】目標(biāo)與特點(diǎn)

  • 輕量化設(shè)計(jì):UIP的核心目標(biāo)是在保持TCP/IP協(xié)議核心功能的同時(shí),盡可能減小代碼大小和內(nèi)存占用。其代碼量通常僅為幾千字節(jié),RAM消耗最低可達(dá)幾百字節(jié),這使得它非常適合于微控制器等資源有限的環(huán)境。
  • 事件驅(qū)動(dòng)編程:UIP采用了事件驅(qū)動(dòng)的編程模型,而不是基于多線程或中斷驅(qū)動(dòng)的方法。這種設(shè)計(jì)減少了對內(nèi)存的需求,并且簡化了程序邏輯,使得協(xié)議棧更加易于理解和維護(hù)。
  • 協(xié)議支持:盡管精簡,UIP仍實(shí)現(xiàn)了網(wǎng)絡(luò)層(IP)、網(wǎng)絡(luò)互聯(lián)層(ARP)、傳輸層(TCP)和部分應(yīng)用層(如ICMP ping)的基本功能。它還支持UDP,盡管可能不如TCP那樣全面。對于不常用的TCP/IP特性,如窗口縮放、時(shí)間戳等,則被省略以減少資源消耗。
  • 無操作系統(tǒng)依賴:UIP設(shè)計(jì)為可以在“裸機(jī)”環(huán)境下運(yùn)行,即不需要操作系統(tǒng)的支持,這使得它非常靈活,可以部署在各種嵌入式平臺(tái)上。

【2】核心組件

  • IP層:負(fù)責(zé)數(shù)據(jù)包的路由和分片重組,實(shí)現(xiàn)基本的網(wǎng)絡(luò)層功能。
  • ARP層地址解析協(xié)議,用于將IP地址轉(zhuǎn)換為MAC地址,確保數(shù)據(jù)包能夠正確送達(dá)物理網(wǎng)絡(luò)層。
  • ICMP層:因特網(wǎng)控制消息協(xié)議,主要用于網(wǎng)絡(luò)診斷,如ping命令的實(shí)現(xiàn)。
  • TCP層傳輸控制協(xié)議,用于建立可靠的、面向連接的數(shù)據(jù)傳輸服務(wù),盡管在UIP中進(jìn)行了大幅簡化以適應(yīng)嵌入式環(huán)境。
  • 內(nèi)存管理:由于嵌入式系統(tǒng)內(nèi)存資源有限,UIP實(shí)現(xiàn)了高效的內(nèi)存塊管理和緩沖區(qū)分配機(jī)制。

【3】應(yīng)用與優(yōu)勢

  • 應(yīng)用廣泛:UIP被廣泛應(yīng)用于物聯(lián)網(wǎng)設(shè)備、智能家居、傳感器網(wǎng)絡(luò)、嵌入式Web服務(wù)器等場景。
  • 易于移植:由于其代碼結(jié)構(gòu)清晰、依賴少,UIP很容易被移植到不同的微控制器平臺(tái)上。
  • 資源效率:在保證基本網(wǎng)絡(luò)功能的同時(shí),極大地節(jié)省了系統(tǒng)資源,使得低成本、低功耗的設(shè)備也能實(shí)現(xiàn)網(wǎng)絡(luò)連接。

1.6 添加UIP協(xié)議棧實(shí)現(xiàn)創(chuàng)建WEB服務(wù)器步驟

img

img

img

img

img

img

img

1.7 ENC28J60添加UIP協(xié)議棧實(shí)現(xiàn)創(chuàng)建WEB客戶端

img

img

img

img

img

1.8 ENC28J60移植UIP協(xié)議并編寫服務(wù)器測試示例

img

img

img

img

img

img

img

img

img

img

img

img

img

img

img

img

img

img

img

img

1.9 ENC28J60移植UIP協(xié)議并編寫客戶端測試示例

img

img

img

img

img

img

img

img

img

img

img

img

img

img

img

img

二、硬件設(shè)計(jì)

2.1 接線說明

【1】ENC28J60接線

image-20240415233409988

【2】LED燈接線

image-20240415233516888

【3】蜂鳴器接線

image-20240415233530012

【4】DS18B20接線

image-20240415233547945

2.2 代碼與服務(wù)器交互的控制

這是判斷網(wǎng)頁下發(fā)的請求。

image-20240415233906046

image-20240415233845331

2.3 修改網(wǎng)頁的頁面

這個(gè)是寫好的網(wǎng)頁模版:

image-20240415233956201

代碼如下:

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>WEB服務(wù)器設(shè)計(jì)</title>
<style>
	.LED{
		margin-left: 10px;
	}
	.font{
		font-size:30px;
		width:130px;
		height:60px;
	}
	.LED:hover{
		background: red;
	}
	.LED value{
		background: blue;
	}
</style>
</head>
<body>
	<div style="border:1px solid black;text-align: center;width:600px;height:500px;margin:auto;">
		<h1>基于STM32的WEB服務(wù)器設(shè)計(jì)</h1>
		<h1>微信公眾號:DS小龍哥嵌入式技術(shù)資訊</h1>
		<h1>這是基于ENC28J60+UIP協(xié)議棧設(shè)計(jì)的WEB服務(wù)器</h1>
		<div class="paren_LED ">
			<button class="LED font" v="on1" num = "1">LED1</button>
			<button class="LED font" v="on2" num = "2">LED2</button>
			<button class="LED font" v="on3" num = "3">LED3</button>
			<button class="LED font" v="on4" num = "4">LED4</button>
			<button class="LED font" v="on5" num = "5" style="display: block;margin-left:23px;margin-top:5px;">蜂鳴器</button>
		</div>
		<div style="text-align: left;">
			<span class="font" style="margin-left:22px">溫度:</span><input style="font-size: 30px" value="23℃" id="wendu"/>
		</div>
		<div style="text-align: left;">
			<span class="font" style="margin-left:22px">時(shí)間:</span><input style="font-size: 30px" value="1s" id="time"/>
		</div>
	</div>
	<script>
	var LED = document.getElementsByClassName("paren_LED")[0];
	var wendu = document.getElementById("wendu");
	var time = document.getElementById("time");
	var xhr = new XMLHttpRequest();
	var xhr2 = new XMLHttpRequest();
	//控制燈的按鈕
	LED.onclick = function(e){
		var status = e.target.getAttribute("v");
		var paren_LED = LED.children;
		xhr.open("GET","test?data="+status,true);
		//xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
		xhr.send();
		xhr.onreadystatechange = function () {
            if(xhr.readyState==4&&xhr.status==200){
            	//獲取后臺(tái)的數(shù)據(jù)
            	var data = xhr.responseText;
				var sta = e.target.getAttribute("num");
				e.target.setAttribute("v",data+sta);
            	 for(var i=0;i<paren_LED.length;i++){
     				var str = paren_LED[i].getAttribute("v");
					var st = str.substring(0,str.length-1);
     				if("off"==st){
     					paren_LED[i].style.background="blue";
     				}else if("on"==st){
     					paren_LED[i].style.background="";
     				}else if("Beep_on"==st){
     					paren_LED[i].style.background="";
     				}else if("Beep_off"==st){
     					paren_LED[i].style.background="blue";
     				}
     			}
            }
    	}
	}
	//定時(shí)器
	var wd =  function(){
		xhr2.open("GET","test?data=temp",true);
		xhr2.send();
		xhr2.onreadystatechange = function () {
			var data = xhr2.responseText.split("&"); 
			wendu.value= data[0]+"℃";
			time.value = data[1]+"s";
		}
	};
	setInterval("wd()",1000);
	</script>
</body>
</html>

將這個(gè)文件轉(zhuǎn)為C語言數(shù)組放到單片機(jī)代碼工程里就行了。

如何轉(zhuǎn)換? 用winhex 這個(gè)工具。

image-20240415234141048

替換這個(gè)數(shù)組就行了:

image-20240415234221592

2.4 設(shè)置網(wǎng)卡地址

因?yàn)榘遄邮庆o態(tài)IP,為了方便通信,ENC28J60通過網(wǎng)線直接與電腦網(wǎng)口連接。 設(shè)置固定的IP地址。

image-20240415234301652

2.5 程序運(yùn)行效果

【1】下載程序

image-20240415234504402

【2】串口看效果

image-20240415234520817

【3】ping板子IP地址

image-20240415234420460

【4】打開網(wǎng)頁看效果

image-20240415234546440

2.6 ENC28J60驅(qū)動(dòng)代碼

#include "delay.h"
#include <stdio.h>
#include "enc28j60.h"	

/*
以下是ENC28J60驅(qū)動(dòng)移植接口:
MISO--->PA6----主機(jī)輸入
MOSI--->PA7----主機(jī)輸出
SCLK--->PA5----時(shí)鐘信號
CS----->PA4----片選
RESET-->PG15---復(fù)位
*/
#define ENC28J60_CS		PAout(4) 	//ENC28J60片選信號
#define ENC28J60_RST	PGout(15)	//ENC28J60復(fù)位信號
#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í)鐘信號
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è)備。
	
	//針對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ù)才是正確的,見手冊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)成。
	//寄存器對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ā)送暫??刂茙ㄓ糜谌p工模式下的流量控制)
	//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)
	//配置非背對背包間間隔寄存器的低字節(jié)
	//MAIPGL。 大多數(shù)應(yīng)用使用12h 編程該寄存器。
	//如果使用半雙工模式,應(yīng)編程非背對背包間間隔
	//寄存器的高字節(jié)MAIPGH。 大多數(shù)應(yīng)用使用0Ch
	//編程該寄存器。
	ENC28J60_Write(MAIPGL,0x12);
	ENC28J60_Write(MAIPGH,0x0C);
	// set inter-frame gap (back-to-back)
	//配置背對背包間間隔寄存器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ā)
	//送請求、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í)器件特定硅片
	//的版本號
	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指針,以對應(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和符號錯(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);
}
  • 更多詳細(xì)資料請聯(lián)系.docx
    下載
意法半導(dǎo)體

意法半導(dǎo)體

意法半導(dǎo)體(ST)集團(tuán)于1987年6月成立,是由意大利的SGS微電子公司和法國Thomson半導(dǎo)體公司合并而成。1998年5月,SGS-THOMSON Microelectronics將公司名稱改為意法半導(dǎo)體有限公司。意法半導(dǎo)體是世界最大的半導(dǎo)體公司之一,公司銷售收入在半導(dǎo)體工業(yè)五大高速增長市場之間分布均衡(五大市場占2007年銷售收入的百分比):通信(35%),消費(fèi)(17%),計(jì)算機(jī)(16%),汽車(16%),工業(yè)(16%)。 據(jù)最新的工業(yè)統(tǒng)計(jì)數(shù)據(jù),意法半導(dǎo)體是全球第五大半導(dǎo)體廠商,在很多市場居世界領(lǐng)先水平。例如,意法半導(dǎo)體是世界第一大專用模擬芯片和電源轉(zhuǎn)換芯片制造商,世界第一大工業(yè)半導(dǎo)體和機(jī)頂盒芯片供應(yīng)商,而且在分立器件、手機(jī)相機(jī)模塊和車用集成電路領(lǐng)域居世界前列.

意法半導(dǎo)體(ST)集團(tuán)于1987年6月成立,是由意大利的SGS微電子公司和法國Thomson半導(dǎo)體公司合并而成。1998年5月,SGS-THOMSON Microelectronics將公司名稱改為意法半導(dǎo)體有限公司。意法半導(dǎo)體是世界最大的半導(dǎo)體公司之一,公司銷售收入在半導(dǎo)體工業(yè)五大高速增長市場之間分布均衡(五大市場占2007年銷售收入的百分比):通信(35%),消費(fèi)(17%),計(jì)算機(jī)(16%),汽車(16%),工業(yè)(16%)。 據(jù)最新的工業(yè)統(tǒng)計(jì)數(shù)據(jù),意法半導(dǎo)體是全球第五大半導(dǎo)體廠商,在很多市場居世界領(lǐng)先水平。例如,意法半導(dǎo)體是世界第一大專用模擬芯片和電源轉(zhuǎn)換芯片制造商,世界第一大工業(yè)半導(dǎo)體和機(jī)頂盒芯片供應(yīng)商,而且在分立器件、手機(jī)相機(jī)模塊和車用集成電路領(lǐng)域居世界前列.收起

查看更多

相關(guān)推薦