enc28j60c代码简单分析.docx
- 文档编号:10572842
- 上传时间:2023-02-21
- 格式:DOCX
- 页数:21
- 大小:160.93KB
enc28j60c代码简单分析.docx
《enc28j60c代码简单分析.docx》由会员分享,可在线阅读,更多相关《enc28j60c代码简单分析.docx(21页珍藏版)》请在冰豆网上搜索。
enc28j60c代码简单分析
#include"enc28j60.h"
#include"spi.h"
#defineMIN(a,b)(a)<(b)?
(a):
(b)
XDATAu8_tEnc28j60Bank;
XDATAu16_tNextPacketPtr;
voiddelay_100ns()
{
asm("nop");
asm("nop");
asm("nop");
}
voiddelay_ms(intt1)
{
inti;
while(t1--)
{
for(i=10;i;--i)
{
delay_100ns();
}
}
}
//*****************************************************************************//Function:
enc28j60ReadOp
//Description:
//*****************************************************************************u8_tenc28j60ReadOp(u8_top,u8_taddress)
{
u8_tdat1;
//spi模拟接口,开启片选,激活enc28j60
CSN=0;
/*spi模拟接口定义
sbitVCC1=P2^0;//VCC1NOUSE
sbitCSN=P1^4;//CS
sbitSIN=P1^5;//MOSI
sbitSON=P1^6;//MISO
sbitSCKN=P1^7;//SCK
sbitRSTN=P3^5;//RST
sbitINTN=P3^3;//INT
voidWriteByte(u8_ttemp);
u8_tReadByte(void);
*/
//issuereadcommand
delay_100ns();
WriteByte(op|(address&ADDR_MASK));
/*
#defineADDR_MASK 0x1F
SPI操作码op定义(来自enc28j60.h)
#defineENC28J60_READ_CTRL_REG 0x00
#defineENC28J60_READ_BUF_MEM 0x3A
#defineENC28J60_WRITE_CTRL_REG 0x40
#defineENC28J60_WRITE_BUF_MEM 0x7A
#defineENC28J60_BIT_FIELD_SET 0x80
#defineENC28J60_BIT_FIELD_CLR 0xA0
#defineENC28J60_SOFT_RESET 0xFF
注意:
根据WriteByte(op|(address&ADDR_MASK));
操作码后面的参数所示的a为操作寄存器的地址(地址定义可以由enc28j60.h获得),而spi操作码定义op的时候a的位置必须为0,因为还要和控制寄存器的地址进行或运算,而有一些不需要跟寄存器地址的,如:
RBMWBMSC都有具体的操作码,并不需要跟地址,这些指令,在使用的时候必须要将address值赋值为0
*/
//从spi读取字节
dat1=ReadByte();
//判断要读取的地址的最高位是否为1,若为1,则为读取MAC或者MII的寄存器,
//此处必须说明一下,在enj28j60.h头文件中定义了,由E开头的寄存器的最高位为0
//由M开头的寄存器最高位为1
//eg.
//页面0寄存器定义
//#defineERDPTL (0x00|0x00)
//#defineERDPTH (0x01|0x00)
//页面2寄存器定义
//#defineMACON1 (0x00|0x40|0x80)
//#defineMACON2 (0x01|0x40|0x80)
//数据手册12页说明:
//ENC28J60的控制寄存器通常被分为ETH、MAC和MII
//三组寄存器。
名称由“E”开头的寄存器属于ETH组。
//同样,名称由“MA”开头的寄存器属于MAC组,名称
//由“MI”开头的寄存器属于MII组。
//如果地址指向了一个MAC或MII寄存器,则首先从SO
//引脚移出一个无效数据字节,随后从SO引脚移出数据,
//最高位在前。
通过拉高CS引脚的电平可结束RCR操
//作。
/*
*/
if(address&0x80)dat1=ReadByte();
//releaseCS
CSN=1;
return(dat1);
}
//*******************************************************************************************
//
//Function:
enc28j60WriteOp
//Description:
//
//*****************************************************************************
voidenc28j60WriteOp(u8_top,u8_taddress,u8_tmydat)
{
CSN=0;
//issuewritecommand
delay_100ns();
WriteByte(op|(address&ADDR_MASK));
//writedata
WriteByte(mydat);
CSN=1;
delay_100ns();
}
//*******************************************************************************************
//
//Function:
icmp_send_request
//Description:
SendARPrequestpackettodestination.
//
//*******************************************************************************************
voidenc28j60SetBank(u8_taddress)
{
//setthebank(ifneeded)
//#defineBANK_MASK 0x60
/*
由于读取bank0~bank3的地址都为00H~1FH,所以为了区分是哪个bank,必须通过ECON1[1:
0]来区分。
根据enc28j60.h中的寄存器定义,都为最高位(第7位)区分是否为E开头,第5,6位区分为在哪一个bank中,第0~4位为寄存器地址
位域清零(BitFieldClear,BFC)命令用于将ETH控制寄存器中最多8位清零。
注意此命令不能用于MAC寄存器、MII寄存器、PHY寄存器或缓冲存储器。
BFC命令使用提供的数据字节与给定地址寄存器的内容进行逻辑位非与运算。
比如:
如果一个寄存器的内容是
F1h,对17h操作数执行了BFC命令,那么此寄存器内容将变为E0h。
将CS引脚拉为低电平启动BFC命令。
然后,发送BFC操作码及随后的5位地址(A4到A0)。
5位地址决定
要使用当前存储区中的哪一个ETH寄存器。
在发送BFC命令和地址之后,应该发送包含位域清零信息的数据字节,首先发送最高位。
在SCK引脚信号的上升沿会将所提供数据取反,并接着与指定寄存器的内容进行D0位的逻辑与运算。
拉高CS引脚电平可结束BFC命令。
如果在装载8个位前,CS变为高电平,则将中止这个数据字节的操作。
#defineECON1_BSEL1 0x02
#defineECON1_BSEL0 0x01
*/
if((address&BANK_MASK)!
=Enc28j60Bank)
{
//setthebank
enc28j60WriteOp(ENC28J60_BIT_FIELD_CLR,ECON1,(ECON1_BSEL1|ECON1_BSEL0));
/*(ECON1_BSEL1|ECON1_BSEL0)的值为0x03,ENC28J60_BIT_FIELD_CLR指令为0x03和ECON1的内容进行非与运算,即,0x03取反为0xfc,ECON1的内容和0xfc进行与运算,即可对BSEL1和BSEL0两位进行清零*/
enc28j60WriteOp(ENC28J60_BIT_FIELD_SET,ECON1,(address&BANK_MASK)>>5);
Enc28j60Bank=(address&BANK_MASK);
/*注意:
enc28j60.h中的寄存器定义,都为最高位(第7位)区分是否为E开头,第5,6位区分为在哪一个bank中,第0~4位为寄存器地址*/
}
}
//*******************************************************************************************
//
//Function:
icmp_send_request
//Description:
SendARPrequestpackettodestination.
//
//*******************************************************************************************
u8_tenc28j60Read(u8_taddress)
{
//selectbanktoread
enc28j60SetBank(address);
//dotheread
returnenc28j60ReadOp(ENC28J60_READ_CTRL_REG,address);
}
//*******************************************************************************************
//
//Function:
icmp_send_request
//Description:
SendARPrequestpackettodestination.
//
//*******************************************************************************************
voidenc28j60Write(u8_taddress,u8_tmydat)
{
//selectbanktowrite
enc28j60SetBank(address);
//dothewrite
enc28j60WriteOp(ENC28J60_WRITE_CTRL_REG,address,mydat);
}
//*******************************************************************************************
//
//Function:
enc28j60_read_phyreg(u8_taddress)
//*******************************************************************************************
/*
读PHY寄存器可以获取其完整的16位值。
要读PHY寄存器:
1.将要读取的PHY寄存器的地址写入MIREGADR
寄存器。
2.将MICMD.MIIRD置1开始读操作,同时
MISTAT.BUSY位置1。
3.等待10.24µs。
查询MISTAT.BUSY位以确定操
作是否完成。
当忙时,主控制器不应开始任何
MIISCAN操作或写MIWRH寄存器。
当MAC得到寄存器内容时,BUSY位会自动清零。
4.将MICMD.MIIRD位清零。
5.从MIRDL和MIRDH寄存器中读取所需数据。
先
读哪一个寄存器都可以
*/
u16_tenc28j60_read_phyreg(u8_taddress)
{
u16_tmydat;
//setthePHYregisteraddress
enc28j60Write(MIREGADR,address);
//1.将要读取的PHY寄存器的地址写入MIREGADR寄存器。
enc28j60Write(MICMD,MICMD_MIIRD);
/*
#defineMICMD_MIISCAN 0x02
#defineMICMD_MIIRD 0x01
#defineMISTAT_NVALID 0x04
#defineMISTAT_SCAN 0x02
#defineMISTAT_BUSY 0x01
2.将MICMD.MIIRD置1开始读操作,同时MISTAT.BUSY位置1。
*/
//LooptowaituntilthePHYregisterhasbeenreadthroughtheMII
//Thisrequires10.24us
while((enc28j60Read(MISTAT)&MISTAT_BUSY));
/*3.等待10.24µs。
查询MISTAT.BUSY位以确定操
作是否完成。
当忙时,主控制器不应开始任何
MIISCAN操作或写MIWRH寄存器。
当MAC得到寄存器内容时,BUSY位会自动清零*/
//Stopreading这里应该清零
//enc28j60Write(MICMD,MICMD_MIIRD);
enc28j60Write(MICMD,0x0);//将MICMD.MIIRD位清零。
//Obtainresultsandreturn
mydat=enc28j60Read(MIRDL);
mydat|=(enc28j60Read(MIRDH)<<8);
returnmydat;
}
//*******************************************************************************************
////
//*****************************************************************************
/*
当写PHY寄存器时,将一次写入全部的16位数据,不
能对位进行写操作。
如果只需要重新编程寄存器中的某
几位,控制器必须首先读PHY寄存器,修改读到的数
据,然后将数据写回PHY寄存器。
要写PHY寄存器:
1.将要写入的PHY寄存器的地址写入MIREGADR
寄存器。
2.将数据的低8位写入MIWRL寄存器。
3.将数据的高8位写入MIWRH寄存器。
对MIWRH
寄存器的写操作会自动启动MII事务,所以必须
在写入MIWRL后才能写入该寄存器。
MISTAT.BUSY位置1。
在MII操作完成后写PHY寄存器,用时10.24µs。
当
写操作完成后,BUSY位将自动清零。
在忙时主控制器
不应开始MIISCAN或MIIRD操作。
*/
voidenc28j60PhyWrite(u8_taddress,u16_tmydat)
{
//setthePHYregisteraddress
enc28j60Write(MIREGADR,address);
//writethePHYdata
enc28j60Write(MIWRL,mydat&0x00ff);
enc28j60Write(MIWRH,mydat>>8);
//waituntilthePHYwritecompletes
while(enc28j60Read(MISTAT)&MISTAT_BUSY)
{
delay_100ns();
}
}
voidenc28j60ReadBuffer(u16_tlen,u8_t*dat)
{
//assertCS
CSN=0;
//issuereadcommand
delay_100ns();
WriteByte(ENC28J60_READ_BUF_MEM);
while(len--)
{
*dat++=ReadByte();
}
//releaseCS
CSN=1;
}
voidenc28j60WriteBuffer(u16_tlen,u8_t*dat)
{
//assertCS
CSN=0;
//issuewritecommand
WriteByte(ENC28J60_WRITE_BUF_MEM);
//while(!
(SPSR&(1< while(len--) { WriteByte(*dat++); } //releaseCS CSN=1; } ============================================================================================================================================================================================================================================= #defineETHERNET_MIN_PACKET_LENGTH0x3C #defineETHERNET_HEADER_LENGTH0x0E #defineIP_TCP_HEADER_LENGTH40 #defineTOTAL_HEADER_LENGTH(IP_TCP_HEADER_LENGTH+ETHERNET_HEADER_LENGTH) /* //8KRAM 缓冲区分配 接收缓冲区地址0x0000~0x19FE(0x1FFF-0x0600-1=0x19FE),若每一个地址对应一个字节,则,接收缓冲区一共6655字节 //接收缓冲区开始地址 #defineRXSTART_INIT 0x0000 //接收缓冲区结束地址 #defineRXSTOP_INIT (0x1FFF-0x0600-1) 发送缓冲区地址0x19FF~0x1FFF //发送缓冲区开始地址 //一个完整的以太网帧1500字节. #defineTXSTART_INIT (0x1FFF-0x0600) //发送缓冲区结束地址 #defineTXSTOP_INIT 0x1FFF */ voidenc28j60PacketSend(u16_tlen,u8_t*packet) { //Setthewritepointertostartoftransmitbufferarea enc28j60Write(EWRPTL,TXSTART_INIT); enc28j60Write(EWRPTH,TXSTART_INIT>>8); //SettheTXNDpointertocorrespondtothepacketsizegiven enc28j60Write(ETXNDL,(TXSTART_INIT+len)); enc28j60Write(ETXNDH,(TXSTART_INIT+len)>>8); //writeper-packetcontrolbyte enc28j60WriteOp(ENC28J60_WRITE_BUF_MEM,0,0x00); //相当于WriteByte(ENC28J60_WRITE_BUF_MEM); //WriteByte(0x00); //TODO,fixthisup if(uip_len<=TOTAL_HEADER_LENGTH) { //copythepacketintothetransmitbuffer enc28j60WriteBuffer(len,packet); } else { len-=TOTAL_HEADER_LENGTH; enc28j60WriteBuffer(TOTAL_HEADER_LENGTH,packet); enc28j60WriteBuffer(len,(unsignedchar*)uip_appdata); } //sendthecontentsofthetransmitbufferontothenetwork enc28j60WriteOp(ENC28J60_BIT_FIELD_SET,ECON1,ECON1_TXRTS); } u16_tenc28j60PacketReceive(u16_tmaxlen,u8_t*packet) { u16_trxstat,len; if(enc28j60Read(EPKTCNT)==0) { return0; } //看图理解 //Setthereadpointertothestartofthereceivedpacket enc28j60Write(ERDPTL,(NextPacketPtr)); enc28j60Write(ERDPTH,(NextPacketPtr)>>8); /
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- enc28j60c 代码 简单 分析