欧美性猛交XXXX免费看蜜桃,成人网18免费韩国,亚洲国产成人精品区综合,欧美日韩一区二区三区高清不卡,亚洲综合一区二区精品久久

打開(kāi)APP
userphoto
未登錄

開(kāi)通VIP,暢享免費電子書(shū)等14項超值服

開(kāi)通VIP
ENC28J60驅動(dòng)移植
http://blog.csdn.net/xukai871105/article/details/13931833
0.相關(guān)資料
相關(guān)資料中包括其他精彩博文和代碼倉庫
嵌入式 TCP IP 資料匯總】       【ENC28J60學(xué)習筆記——索引】 【第1部分】【第2部分】【第3部分】【第4部分
STM32NET學(xué)習筆記——索引
uIP學(xué)習筆記
LwIP學(xué)習筆記——STM32 ENC28J60移植與入門(mén)
1前言
嵌入式以太網(wǎng)開(kāi)發(fā),可以分為兩個(gè)部分,一個(gè)是以太網(wǎng)收發(fā)芯片的使用,一個(gè)是嵌入式以太網(wǎng)協(xié)議棧的實(shí)現。以太網(wǎng)收發(fā)芯片的使用要比串口收發(fā)芯片的使用復雜的多,市面上流通比較廣泛的以太網(wǎng)收發(fā)芯片種類(lèi)還不少,有SPI接口的ENC28J60,也有并口形式的RTL8019S,CS8900A等。嵌入式以太網(wǎng)協(xié)議棧有著(zhù)名的uIP協(xié)議棧,Lwip協(xié)議棧,還有其他嵌入式高手開(kāi)發(fā)的協(xié)議棧。無(wú)論是硬件還是軟件,都無(wú)法分出高低,適合項目需求的才是最好的。
1.1 寫(xiě)作理由
再說(shuō)明一下我寫(xiě)作的理由。以前從淘寶上購買(mǎi)過(guò)ENC28J60,店家信誓旦旦地說(shuō)能提供51AVR LPC STM32等多個(gè)平臺的代碼,可以實(shí)現一個(gè)網(wǎng)頁(yè)控制LED。頭腦一熱買(mǎi)了回來(lái),買(mǎi)回來(lái)才發(fā)現,店家提供的資料零零散散,不易弄懂。幾經(jīng)周轉,發(fā)現原來(lái)這些ENC28J60的代碼都出自一個(gè)地方——AVRNET,源自老外的一個(gè)開(kāi)源項目。把最原始的代碼拿來(lái)細細品味,以太網(wǎng)協(xié)議就不那么神秘了。在這里說(shuō)一下ENC28J60的使用,熟悉了ENC28J60的驅動(dòng)可以分幾步走。第一步,通過(guò)ENC28J60移植uIP或者lwIP協(xié)議棧,實(shí)現TCP或是UDP通信,第二,順著(zhù)AVRNET項目走,實(shí)現一個(gè)簡(jiǎn)單的web服務(wù)器,運行靜態(tài)或者動(dòng)態(tài)網(wǎng)頁(yè)。嵌入式以太網(wǎng)和計算機以太網(wǎng)開(kāi)發(fā)不同,對于TCP通信而言沒(méi)有socket套接字,對于網(wǎng)頁(yè)編程而言也沒(méi)有IIS或PHP,所示實(shí)現起來(lái)會(huì )相對麻煩,但是也非常有樂(lè )趣。
1.2 資料準備
嵌入式以太網(wǎng)開(kāi)發(fā)是非常復雜的工作,在開(kāi)始之前最好先大致瀏覽ENC28J60的使用手冊。除此之外,需要認真閱讀TCP IP相關(guān)知識,推薦一本圖書(shū)《嵌入式Internet TCP/IP基礎、實(shí)現和應用》。嵌入式開(kāi)發(fā)是一個(gè)反復借鑒的過(guò)程,該部分代碼參考了AVRNET項目和奮斗開(kāi)發(fā)板的相關(guān)范例?!?a target="_blank" >AVRNET項目網(wǎng)址鏈接】
雖然AVRNET項目所使用的MCU為ATmega32,但是認真閱讀源代碼之后也可以方便的移植到其他的MCU平臺,例如STM8、STM32和MSP430等。
2 寄存器和寄存器操作
ENC28J60的寄存器很多,操作這些寄存器需要一個(gè)良好的代碼組織工作。在A(yíng)VRNET項目中,把ENC28J60的驅動(dòng)分解成ENC28J60.h文件和ENC28J60.c文件。H文件中主要描述ENC28J60寄存器的基本定義,而C文件主要實(shí)現了這些寄存器的操作。
2.1 寄存器定義
首先分析一下ENC28J60.h這個(gè)頭文件。閱讀數據手冊之后,會(huì )發(fā)現ENC28J60寄存器數量較多,通過(guò)分析和整理,操作ENC28J60的寄存器需要注意以下3點(diǎn)。
【1】共有三種不同形式的寄存器——控制寄存器,以太網(wǎng)寄存器 和PHY寄存器,不同的寄存器以不同的字母開(kāi)頭,以E、 MA和MI加以區分。操作這三種不同的寄存器需要不同的組合命令。
【2】 寄存器被分布在4個(gè)不同的bank中,也就是說(shuō)存在地址相同的寄存器,但是這些寄存器卻位于不同的分區中,在操作寄存器之前必須選中正確的bank。
【3】 雖然存在4個(gè)bank,但是有5個(gè)寄存器在4個(gè)bank的位置相同,它們是EIE、 EIR、ESTAT、ECON1、ECON2。
AVRNET項目中,寄存器被定義成8位長(cháng)度,而這8位長(cháng)度包含了三個(gè)部分,地址bit7(最高位)用以區分PHY和MAC寄存器,PHY寄存器的操作最為特殊;地址bit6和bit5用以區分BANK,2位空間正好區分4個(gè)BANK;地址的最后5位才是寄存器的地址。通過(guò)這種方式就可以區分所有的寄存器了。列舉了幾行代碼。由于頭文件很長(cháng),所以不全部列出。
[cpp]
// bank0 寄存器
#define ERDPTL            (0x00|0x00)
#define ERDPTH            (0x01|0x00)
#define EWRPTL            (0x02|0x00)
// bank1 寄存器
#define EHT0              (0x00|0x20)
#define EHT1              (0x01|0x20)
#define EHT2              (0x02|0x20)
// bank2 寄存器
#define MACON1           (0x00|0x40|0x80)
#define MACON2           (0x01|0x40|0x80)
#define MACON3           (0x02|0x40|0x80)
//bank3 寄存器
#define MAADR1           (0x00|0x60|0x80)
#define MAADR0           (0x01|0x60|0x80)
#define MAADR3           (0x02|0x60|0x80)
例如ERDPTH為位于BANK0的以太網(wǎng)寄存器,第一個(gè)數字0x01代表BANKx中的具體地址,該地址為0x01,第二個(gè)數字0x00代表BANK編號,該BANK地址為0;EHT1為位于BANK1中的控制寄存器,第一個(gè)0x01代表BANKx中的具體地址,該地址為0x01,第二個(gè)0x20代表BANK編號,此處BANK編號為1。請注意由于BANK編號被保存在BIT6和BIT5,所以此處為0x20而不是0x10;MACON2為位于BANK2的以太網(wǎng)寄存器,第一個(gè)數字0x01代表在該BANKx中的寄存器地址,第二個(gè)數字0x40代表BANK編號,此處BANK編號為2,而第三個(gè)數字0x80代表該寄存器為以太網(wǎng)寄存器或是PHY寄存器,該寄存器的操作比較特殊。
為了方便寄存器操作,頭文件中還定義了寄存器地址操作的掩碼,簡(jiǎn)單而言就是需要查看哪些位,不需要查看哪些位。
[cpp]
/* 寄存器地址掩碼 */
#defineADDR_MASK        0x1F
/* 存儲區域掩碼 */
#defineBANK_MASK        0x60
/* MAC和MII寄存器掩碼*/
#defineSPRD_MASK         0x80
另外還有比較特殊的5個(gè)控制寄存器,EIE,EIR,ESTAT,ECON2和ECON1
[cpp]
/* 關(guān)鍵寄存器 */
#defineEIE                     0x1B
#defineEIR                     0x1C
#defineESTAT                   0x1D
#defineECON2                  0x1E
#defineECON1                  0x1F
2.2 寄存器操作命令
寄存器操作命令也可稱(chēng)為寄存器操作碼。為了實(shí)現寄存器的操作,ENC28J60定義了6+1個(gè)寄存器操作命令(操作碼)。操作相關(guān)寄存器至少有讀寄存器命令,寫(xiě)寄存器命令;發(fā)送或接收以太網(wǎng)數據則必有寫(xiě)緩沖區命令或讀緩沖區命令;為了加快操作,對于某些控制寄存器而言還可以有置位或者清零某位的命令;最后加上一個(gè)軟件復位命令,錦上添花。
[cpp]
/* 讀控制寄存器 */
#define ENC28J60_READ_CTRL_REG         0x00
/* 讀緩沖區 */
#define ENC28J60_READ_BUF_MEM          0x3A
/* 寫(xiě)控制寄存器 */
#define ENC28J60_WRITE_CTRL_REG        0x40
/* 寫(xiě)緩沖區 */
#define ENC28J60_WRITE_BUF_MEM         0x7A
/* 位域置位 */
#define ENC28J60_BIT_FIELD_SET         0x80
/* 位域清零 */
#define ENC28J60_BIT_FIELD_CLR         0xA0
/* 系統復位 */
#define ENC28J60_SOFT_RESET            0xFF
2.3 接收和發(fā)送緩沖區分配
以太網(wǎng)數據的接收和發(fā)送離不開(kāi)驅動(dòng)芯片內部的RAM,也可稱(chēng)之為硬件緩沖區。ENC28J60包括8K 的硬件緩沖區,該硬件緩沖區一部分被接收緩沖區使用,另一部分為發(fā)送緩沖區使用??刂艵NC28J60的最終目的為操作該硬件緩沖區。執行以太網(wǎng)發(fā)送命令時(shí),向發(fā)送緩沖區中填充數據,并觸發(fā)相關(guān)寄存器發(fā)送以太網(wǎng)數據;執行以太網(wǎng)接收命令時(shí),通過(guò)查詢(xún)相關(guān)寄存器或者外部中斷的方式獲得以太網(wǎng)數據輸入事件,接著(zhù)從接收緩沖區中讀取相關(guān)數據。
(1) 把緩沖區劃分為兩個(gè)部分。把8K的硬件緩沖區劃分為兩個(gè)部分至少需要四個(gè)參數,接收緩沖區需要一個(gè)起始地址和一個(gè)結束地址加以描述,發(fā)送緩沖區也需要一個(gè)起始地址和一個(gè)結束地址加以描述。最理想的方式,兩個(gè)緩沖區完全占據了8K的硬件緩沖區,完美地利用這一空間。由于ENC28J60的寄存器長(cháng)度為8位,而硬件緩沖區的大小為8K,所以前面提到的4個(gè)地址需要8個(gè)寄存器才可以完全描述,需要把單個(gè)地址分為高8位和低8位。在A(yíng)VRNET項目中,接收緩沖區較大,而發(fā)送緩沖區較小。在以太網(wǎng)協(xié)議中,最大的報文長(cháng)度為1518字節,而最小報文長(cháng)度為60字節。發(fā)送緩沖區等于或略大于1518字節,剩余的部分全部分配給接收緩沖區。接收緩沖區較大也是考慮到AVR的處理能力有限,若某個(gè)時(shí)間點(diǎn)收到多個(gè)以太網(wǎng)報文,可以先把報文閑置與硬件緩沖區中,待MCU空閑時(shí)再從緩沖區中取出。
[cpp]
/* 接收緩沖區起始地址 */
#define RXSTART_INIT                0x00
/* 接收緩沖區停止地址 */
#define RXSTOP_INIT                 (0x1FFF - 0x0600 - 1)
/* 發(fā)送緩沖區起始地址 發(fā)送緩沖區大小約1500字節*/
#define TXSTART_INIT                (0x1FFF - 0x0600)
/* 發(fā)送緩沖區停止地址 */
#define TXSTOP_INIT                 0x1FFF
圖2.1 硬件緩沖區結構
(2) 對于發(fā)送緩沖區而言,需要指定發(fā)送緩沖區寫(xiě)指針,使用寫(xiě)緩沖區命令操作該部分緩沖區,寫(xiě)指針的地址會(huì )不斷增長(cháng),若遇到結束地址會(huì )重新返回起始地址。對于接收緩沖區而言就稍微復雜一點(diǎn),每次讀取之前必須明確該次操作時(shí)的讀指針位置,根據前文的代碼,緩沖區讀指針的起始地址為0,在第一次讀操作發(fā)生之后需要立即計算下次讀操作的讀指針地址。ENC28J60讀緩沖區時(shí),被讀取的內容并不全是以太網(wǎng)負載,在以太網(wǎng)負載之前還有下一個(gè)數據包的地址指針(占兩個(gè)字節),接收狀態(tài)向量(占4個(gè)字節),之后才是“真實(shí)”以太網(wǎng)負載,該負載包括目標MAC地址,源MAC地址,數據包類(lèi)型等等;最后為CRC校驗字節。
圖2.2 接收數據包結構
3 寄存器操作實(shí)現
ENC28j60的寄存器操作分為2+2+2部分,分別為寫(xiě)寄存器和讀寄存器部分,讀緩沖區和寫(xiě)緩沖區部分,寫(xiě)PHY寄存器和讀PHY寄存器部分。
3.1 讀寫(xiě)寄存器
讀或寫(xiě)寄存器的函數如下:
[cpp] view plain copy
unsigned char enc28j60Read(unsigned char address)
{
/* 設定寄存器地址區域 */
enc28j60SetBank(address);
/* 讀取寄存器值 發(fā)送讀寄存器命令和地址 */
return enc28j60ReadOp(ENC28J60_READ_CTRL_REG, address);
}
void enc28j60Write(unsigned char address, unsigned char data)
{
/* 設定寄存器地址區域 */
enc28j60SetBank(address);
/* 寫(xiě)寄存器值 發(fā)送寫(xiě)寄存器命令和地址 */
enc28j60WriteOp(ENC28J60_WRITE_CTRL_REG, address, data);
}
讀寫(xiě)寄存器的分為兩步,第一步為選定寄存器的BANK編號,第二步使用寫(xiě)命令或讀命令,操作指定地址的寄存器。在ENC28J60中,由ECON1中的低兩位(BIT1-BIT1)保存BANK編號,ECON1是比較特殊的控制寄存器, 4個(gè)BANK均具有該寄存器且該寄存器的地址相同。Enc28j60Bank為全局變量,用于保存當前的BANK編號,如果兩次操作控制寄存器在同一個(gè)BANK時(shí),該變量保持不變,若兩次操作的控制寄存器位于不同的BANK,那么BANK的值會(huì )變?yōu)樾碌腂ANK編號。
[cpp] view plain copy
void enc28j60SetBank(unsigned char address)
{
/* 計算本次寄存器地址在存取區域的位置 */
if((address & BANK_MASK) != Enc28j60Bank)
{
/* 清除ECON1的BSEL1 BSEL0 詳見(jiàn)數據手冊15頁(yè) */
enc28j60WriteOp(ENC28J60_BIT_FIELD_CLR, ECON1, (ECON1_BSEL1|ECON1_BSEL0));
/* 請注意寄存器地址的宏定義,bit6 bit5代碼寄存器存儲區域位置 */
enc28j60WriteOp(ENC28J60_BIT_FIELD_SET, ECON1, (address & BANK_MASK)>>5);
/* 重新確定當前寄存器存儲區域 */
Enc28j60Bank = (address & BANK_MASK);
}
}
unsigned char enc28j60ReadOp(unsigned char op, unsigned char address)
{
unsigned char dat = 0;
/* CS拉低 使能ENC28J60 */
ENC28J60_CSL();
/* 操作碼和地址 */
dat = op | (address & ADDR_MASK);
/* 通過(guò)SPI寫(xiě)數據*/
spi_sendbyte(dat);
/* 通過(guò)SPI讀出數據 */
dat = spi_sendbyte(0xFF);
/* 如果是MAC和MII寄存器,第一個(gè)讀取的字節無(wú)效,該信息包含在地址的最高位 */
if(address & 0x80)
{
/* 再次通過(guò)SPI讀取數據 */
dat = spi_sendbyte(0xFF);
}
/* CS拉高 禁止ENC28J60 */
ENC28J60_CSH();
/* 返回數據 */
return dat;
}
讀控制寄存器實(shí)際上就是嚴格遵守數據手冊的操作要求。由于讀MAC和MII寄存器時(shí),第一個(gè)接收到的字節為無(wú)效字節,第二個(gè)字節才為有效字節。程序通過(guò)寄存器地址的最高位來(lái)判斷是否為MAC或MII寄存器。寫(xiě)寄存器函數較為簡(jiǎn)單,第一次字節包括操作碼和寄存器地址,第二個(gè)字節為數據。在這兩個(gè)函數中參數op為ENC28J60的指令,或稱(chēng)之為操作碼,該指令占據SPI首字節的前3位,參數address為寄存器地址,參數data為寄存器的具體值。
ENC28J60_CSL()和ENC28J60_CSH()為操作CS端口的操作宏,而spi_sendbyte()可通過(guò)SPI發(fā)送一個(gè)字節。修改這些函數即可在其他平臺上操作ENC28J60。不過(guò)請特別注意,在使用其他開(kāi)發(fā)板時(shí)由于SPI總線(xiàn)上可能掛載多個(gè)設備,單獨使用ENC28J60時(shí)需要把其他設備的CS端口拉高,或安裝一個(gè)上拉電阻。
[cpp] view plain copy
unsigned char enc28j60ReadOp(unsigned char op, unsigned char address)
{
unsigned char dat = 0;
/* CS拉低 使能ENC28J60 */
ENC28J60_CSL();
/* 操作碼和地址 */
dat = op | (address & ADDR_MASK);
/* 通過(guò)SPI寫(xiě)數據*/
spi_sendbyte(dat);
/* 通過(guò)SPI讀出數據 */
dat = spi_sendbyte(0xFF);
/* 如果是MAC和MII寄存器,第一個(gè)讀取的字節無(wú)效,該信息包含在地址的最高位 */
if(address & 0x80)
{
/* 再次通過(guò)SPI讀取數據 */
dat = spi_sendbyte(0xFF);
}
/* CS拉高 禁止ENC28J60 */
ENC28J60_CSH();
/* 返回數據 */
return dat;
}
void enc28j60WriteOp(unsigned char op, unsigned char address, unsigned char data)
{
unsigned char dat = 0;
/* 使能ENC28J60 */
ENC28J60_CSL();
/* 通過(guò)SPI發(fā)送 操作碼和寄存器地址 */
dat = op | (address & ADDR_MASK);
/* 通過(guò)SPI1發(fā)送數據 */
spi_sendbyte(dat);
/* 準備寄存器數值 */
dat = data;
/* 通過(guò)SPI發(fā)送數據 */
spi_sendbyte(dat);
/* 禁止ENC28J60 */
ENC28J60_CSH();
}
3.2 讀寫(xiě)緩沖區
讀寫(xiě)緩沖區的操作也易于理解的。需要說(shuō)明的是,兩個(gè)函數具有相同的輸入參數,參數len代表被操作數據的長(cháng)度,pdata為被操作數據的指針。和寄存器讀寫(xiě)函數相似,發(fā)送或接收數據之前需要發(fā)送特定的操作碼。
[cpp] view plain copy
void enc28j60ReadBuffer(unsigned int len, unsigned char* pdata)
{
/* 使能ENC28J60 */
ENC28J60_CSL();
/* 通過(guò)SPI發(fā)送讀取緩沖區命令*/
spi_sendbyte(ENC28J60_READ_BUF_MEM);
/* 循環(huán)讀取 */
while(len)
{
len--;
/* 讀取數據 */
*pdata = (unsigned char)spi_sendbyte(0);
/* 地址指針累加 */
pdata++;
}
/* 禁止ENC28J60 */
ENC28J60_CSH();
}
void enc28j60WriteBuffer(unsigned int len, unsigned char* pdata)
{
/* 使能ENC28J60 */
ENC28J60_CSL();
/* 通過(guò)SPI發(fā)送寫(xiě)取緩沖區命令*/
spi_sendbyte(ENC28J60_WRITE_BUF_MEM);
/* 循環(huán)發(fā)送 */
while(len)
{
len--;
/* 發(fā)送數據 */
spi_sendbyte(*pdata);
/* 地址指針累加 */
pdata++;
}
/* 禁止ENC28J60 */
ENC28J60_CSH();
}
3.3 讀寫(xiě)PHY寄存器
PHY寄存器和被ENC28J60控制的LED指示燈有關(guān),控制該寄存器可以控制LED驅動(dòng)方式和發(fā)生相應事件時(shí)LED顯示方式。一般情況下,一個(gè)LED指示燈用于指示網(wǎng)絡(luò )狀態(tài)(常亮可理解為網(wǎng)絡(luò )接通),另一個(gè)LED指示燈顯示接收活動(dòng),有數據輸入時(shí)產(chǎn)生一個(gè)點(diǎn)亮脈沖。PHY是比較特殊的寄存器,先要想一個(gè)控制寄存器寫(xiě)入PHY寄存器的地址,再向兩個(gè)控制寄存器依次寫(xiě)入PHY寄存器的具體數據的高8位和低8位,最后等待PHY寄存器操作完成。
[cpp] view plain copy
void enc28j60PhyWrite(unsigned char address, unsigned int data)
{
/* 向MIREGADR寫(xiě)入地址 詳見(jiàn)數據手冊19頁(yè)*/
enc28j60Write(MIREGADR, address);
/* 寫(xiě)入低8位數據 */
enc28j60Write(MIWRL, data);
/* 寫(xiě)入高8位數據 */
enc28j60Write(MIWRH, data>>8);
/* 等待PHY寄存器寫(xiě)入完成 */
while(enc28j60Read(MISTAT) & MISTAT_BUSY);
}
本站僅提供存儲服務(wù),所有內容均由用戶(hù)發(fā)布,如發(fā)現有害或侵權內容,請點(diǎn)擊舉報。
打開(kāi)APP,閱讀全文并永久保存 查看更多類(lèi)似文章
猜你喜歡
類(lèi)似文章
LWIP 無(wú)操作系統的移植
基于51單片機嵌入式WEB的控制系統
干貨 | 汽車(chē)以太網(wǎng)互聯(lián)技術(shù)
硬件協(xié)議棧芯片W3100A
51驅動(dòng)W5500做TCPClient
解讀ENC28J60嵌入式網(wǎng)絡(luò )接口電路
更多類(lèi)似文章 >>
生活服務(wù)
分享 收藏 導長(cháng)圖 關(guān)注 下載文章
綁定賬號成功
后續可登錄賬號暢享VIP特權!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服

欧美性猛交XXXX免费看蜜桃,成人网18免费韩国,亚洲国产成人精品区综合,欧美日韩一区二区三区高清不卡,亚洲综合一区二区精品久久