|  | 
        
          |  | 【驱动程序】ENC28J60网卡芯片驱动程序(不含lwIP协议栈) |  
          |   一派掌门 二十级 | 
              【ENC28J60.h】#define EIE 0x1b
 #define EIR 0x1c
 #define ESTAT 0x1d
 #define ECON2 0x1e
 #define ECON1 0x1f
 
 // Bank 0 registers
 #define ERDPTL 0x00
 #define ERDPTH 0x01
 #define EWRPTL 0x02
 #define EWRPTH 0x03
 #define ETXSTL 0x04
 #define ETXSTH 0x05
 #define ETXNDL 0x06
 #define ETXNDH 0x07
 #define ERXSTL 0x08
 #define ERXSTH 0x09
 #define ERXNDL 0x0a
 #define ERXNDH 0x0b
 #define ERXRDPTL 0x0c
 #define ERXRDPTH 0x0d
 #define ERXWRPTL 0x0e
 #define ERXWRPTH 0x0f
 #define EDMASTL 0x10
 #define EDMASTH 0x11
 #define EDMANDL 0x12
 #define EDMANDH 0x13
 #define EDMADSTL 0x14
 #define EDMADSTH 0x15
 #define EDMACSL 0x16
 #define EDMACSH 0x17
 
 // Bank 1 registers
 #define EHT0 0x20
 #define EHT1 0x21
 #define EHT2 0x22
 #define EHT3 0x23
 #define EHT4 0x24
 #define EHT5 0x25
 #define EHT6 0x26
 #define EHT7 0x27
 #define EPMM0 0x28
 #define EPMM1 0x29
 #define EPMM2 0x2a
 #define EPMM3 0x2b
 #define EPMM4 0x2c
 #define EPMM5 0x2d
 #define EPMM6 0x2e
 #define EPMM7 0x2f
 #define EPMCSL 0x30
 #define EPMCSH 0x31
 #define EPMOL 0x34
 #define EPMOH 0x35
 #define EWOLIE 0x36
 #define EWOLIR 0x37
 #define ERXFCON 0x38
 #define EPKTCNT 0x39
 
 // Bank 2 registers
 #define MACON1 0xc0
 #define MACON2 0xc1
 #define MACON3 0xc2
 #define MACON4 0xc3
 #define MABBIPG 0xc4
 #define MAIPGL 0xc6
 #define MAIPGH 0xc7
 #define MACLCON1 0xc8
 #define MACLCON2 0xc9
 #define MAMXFLL 0xca
 #define MAMXFLH 0xcb
 #define MAPHSUP 0xcd
 #define MICON 0xd1
 #define MICMD 0xd2
 #define MIREGADR 0xd4
 #define MIWRL 0xd6
 #define MIWRH 0xd7
 #define MIRDL 0xd8
 #define MIRDH 0xd9
 
 // Bank 3 registers
 #define MAADR1 0xe0
 #define MAADR0 0xe1
 #define MAADR3 0xe2
 #define MAADR2 0xe3
 #define MAADR5 0xe4
 #define MAADR4 0xe5
 #define EBSTSD 0x66
 #define EBSTCON 0x67
 #define EBSTCSL 0x68
 #define EBSTCSH 0x69
 #define MISTAT 0xea
 #define EREVID 0x72
 #define ECOCON 0x75
 #define EFLOCON 0x77
 #define EPAUSL 0x78
 #define EPAUSH 0x79
 
 // 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
 
 /* 指令集, 详见数据手册26页 */
 #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 // 系统复位
 
 #define RXSTART_INIT 0 // 接收缓冲区起始地址
 #define RXSTOP_INIT (0x1fff - 0x0600 - 1) // 接收缓冲区停止地址
 #define TXSTART_INIT (0x1fff - 0x0600) // 发送缓冲区起始地址, 大小约1500字节
 #define TXSTOP_INIT 0x1fff // 发送缓冲区停止地址
 #define MAX_FRAMELEN 1500 // 以太网报文最大长度
 
 void ENC28J60_BeginSend(void);
 void ENC28J60_EndReceive(void);
 uint16_t ENC28J60_GetPacketLength(void);
 uint8_t ENC28J60_GetPacketNum(void);
 void ENC28J60_Init(uint8_t *mac_addr);
 void ENC28J60_InitSend(uint16_t len);
 uint8_t ENC28J60_Read(uint8_t addr);
 void ENC28J60_ReadBuf(uint8_t *p, uint16_t len);
 uint8_t ENC28J60_ReadOP(uint8_t op, uint8_t addr);
 void ENC28J60_SetBank(uint8_t addr);
 void ENC28J60_Write(uint8_t addr, uint8_t data);
 void ENC28J60_WriteBuf(uint8_t *p, uint16_t len);
 void ENC28J60_WriteOP(uint8_t op, uint8_t addr, uint8_t data);
 void ENC28J60_WritePhy(uint8_t addr, uint16_t data);
 
 |  
          |   一派掌门 二十级 | 
              【ENC28J60.c】#include <stm32f10x.h>
 #include "ENC28J60.h"
 
 static uint8_t enc28j60_bank; // 存储区Bank编号, ENC28J60具有Bank0~3共4个存储区, 需要通过ECON1寄存器选择
 static uint16_t enc28j60_next_pkt; // 下一个数据包指针, 详见数据手册P43图7-3
 
 // 开始发送
 void ENC28J60_BeginSend(void)
 {
 ENC28J60_WriteOP(ENC28J60_BIT_FIELD_SET, ECON1, ECON1_TXRTS);
 if (ENC28J60_Read(EIR) & EIR_TXERIF)
 {
 ENC28J60_SetBank(ECON1);
 ENC28J60_WriteOP(ENC28J60_BIT_FIELD_CLR, ECON1, ECON1_TXRTS);
 }
 }
 
 // 结束读取接收缓冲区过程, 移动接收缓冲区指针
 void ENC28J60_EndReceive(void)
 {
 // 移动接收缓冲区读指针
 ENC28J60_Write(ERXRDPTL, enc28j60_next_pkt);
 ENC28J60_Write(ERXRDPTH, enc28j60_next_pkt >> 8);
 
 // 数据包递减
 ENC28J60_WriteOP(ENC28J60_BIT_FIELD_SET, ECON2, ECON2_PKTDEC);
 }
 
 // 获得数据包长度
 uint16_t ENC28J60_GetPacketLength(void)
 {
 uint16_t len = 0;
 uint16_t rxstat;
 
 // 设置接收缓冲器读指针
 ENC28J60_Write(ERDPTL, enc28j60_next_pkt);
 ENC28J60_Write(ERDPTH, enc28j60_next_pkt >> 8);
 
 // 读下一个包的指针
 enc28j60_next_pkt = ENC28J60_ReadOP(ENC28J60_READ_BUF_MEM, 0);
 enc28j60_next_pkt |= ENC28J60_ReadOP(ENC28J60_READ_BUF_MEM, 0) << 8;
 
 // 读包的长度
 len = ENC28J60_ReadOP(ENC28J60_READ_BUF_MEM, 0);
 len |= ENC28J60_ReadOP(ENC28J60_READ_BUF_MEM, 0) << 8;
 len -= 4; // 删除CRC计数
 
 // 读取接收状态
 rxstat = ENC28J60_ReadOP(ENC28J60_READ_BUF_MEM, 0);
 rxstat |= ENC28J60_ReadOP(ENC28J60_READ_BUF_MEM, 0) << 8;
 return len;
 }
 
 // 获取数据包个数
 uint8_t ENC28J60_GetPacketNum(void)
 {
 return ENC28J60_Read(EPKTCNT);
 }
 
 // 初始化
 void ENC28J60_Init(uint8_t *mac_addr)
 {
 ENC28J60_WriteOP(ENC28J60_SOFT_RESET, 0, ENC28J60_SOFT_RESET); // ENC28J60软件复位
 while ((ENC28J60_Read(ESTAT) & ESTAT_CLKRDY) == 0);
 enc28j60_next_pkt = RXSTART_INIT; // 设置接收缓冲区起始地址, 该变量用于每次读取缓冲区时保留下一个包的首地址
 
 // 设置接收缓冲区起始指针
 ENC28J60_Write(ERXSTL, RXSTART_INIT & 0xff);
 ENC28J60_Write(ERXSTH, RXSTART_INIT >> 8);
 
 // 设置接收缓冲区读指针
 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);
 
 // 使能单播过滤, CRC校验, 格式匹配自动过滤
 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);
 
 ENC28J60_Write(MACON1, MACON1_MARXEN | MACON1_TXPAUS | MACON1_RXPAUS); // 使能MAC接收, 允许MAC发送暂停控制帧, 当接收到暂停控制帧时停止发送
 ENC28J60_Write(MACON2, 0x00); // 退出复位状态
 
 // 用0填充所有短帧至60字节长, 并追加一个CRC, 发送CRC使能, 帧长度校验使能, MAC全双工使能
 // 由于ENC28J60不支持802.3的自动协商机制, 所以对端的网络卡需要强制设置为全双工
 ENC28J60_WriteOP(ENC28J60_BIT_FIELD_SET, MACON3, MACON3_PADCFG0 | MACON3_TXCRCEN | MACON3_FRMLNEN | MACON3_FULDPX);
 ENC28J60_Write(MAIPGL, 0x12);
 ENC28J60_Write(MAIPGH, 0x0c);
 ENC28J60_Write(MABBIPG, 0x15);
 
 // 最大帧长度
 ENC28J60_Write(MAMXFLL, MAX_FRAMELEN & 0xff);
 ENC28J60_Write(MAMXFLH, MAX_FRAMELEN >> 8);
 
 // 写入MAC地址
 ENC28J60_Write(MAADR5, mac_addr[0]);
 ENC28J60_Write(MAADR4, mac_addr[1]);
 ENC28J60_Write(MAADR3, mac_addr[2]);
 ENC28J60_Write(MAADR2, mac_addr[3]);
 ENC28J60_Write(MAADR1, mac_addr[4]);
 ENC28J60_Write(MAADR0, mac_addr[5]);
 
 ENC28J60_WritePhy(PHCON1, PHCON1_PDPXMD); // 配置PHY为全双工, LEDB为拉电流
 ENC28J60_WritePhy(PHLCON, 0x0476); // LED状态
 ENC28J60_WritePhy(PHCON2, PHCON2_HDLDIS); // 半双工回环禁止
 ENC28J60_SetBank(ECON1); // 返回BANK0
 ENC28J60_WriteOP(ENC28J60_BIT_FIELD_SET, EIE, EIE_INTIE | EIE_PKTIE | EIE_RXERIE); // 使能中断: 全局中断, 接收中断, 接收错误中断
 ENC28J60_WriteOP(ENC28J60_BIT_FIELD_SET, ECON1, ECON1_RXEN); // 允许接收
 }
 
 void ENC28J60_InitSend(uint16_t len)
 {
 while ((ENC28J60_Read(ECON1) & ECON1_TXRTS) != 0); // 查询发送逻辑复位位
 
 // 设置发送缓冲区起始地址
 ENC28J60_Write(EWRPTL, TXSTART_INIT & 0xff);
 ENC28J60_Write(EWRPTH, TXSTART_INIT >> 8);
 
 // 设置发送缓冲区结束地址 该值对应发送数据包长度
 ENC28J60_Write(ETXNDL, (TXSTART_INIT + len) & 0xff);
 ENC28J60_Write(ETXNDH, (TXSTART_INIT + len) >> 8);
 
 // 发送控制字节: 控制字节为0x00, 表示使用macon3设置
 ENC28J60_WriteOP(ENC28J60_WRITE_BUF_MEM, 0, 0x00);
 }
 
 // 读取寄存器值
 uint8_t ENC28J60_Read(uint8_t addr)
 {
 ENC28J60_SetBank(addr);
 return ENC28J60_ReadOP(ENC28J60_READ_CTRL_REG, addr);
 }
 
 // 读缓冲区
 void ENC28J60_ReadBuf(uint8_t *p, uint16_t len)
 {
 uint8_t data;
 uint8_t first = 1;
 if (len == 0)
 return;
 SPI1->CR1 |= SPI_CR1_SPE;
 SPI1->DR = ENC28J60_READ_BUF_MEM; // 通过SPI发送读取缓冲区命令
 while ((SPI1->SR & SPI_SR_TXE) == 0);
 
 // 循环读取
 while (len--)
 {
 SPI1->DR = 0xff; // 送入下一次要发送的数据
 while ((SPI1->SR & SPI_SR_RXNE) == 0); // 等待本次数据发送完毕
 data = SPI1->DR; // 接收本次数据
 if (first)
 first = 0; // 忽略第一次数据
 else
 *p++ = data;
 while ((SPI1->SR & SPI_SR_TXE) == 0);
 }
 while ((SPI1->SR & SPI_SR_RXNE) == 0);
 *p = SPI1->DR; // 接收最后一次数据
 while (SPI1->SR & SPI_SR_BSY);
 SPI1->CR1 &= ~SPI_CR1_SPE;
 }
 
 uint8_t ENC28J60_ReadOP(uint8_t op, uint8_t addr)
 {
 uint8_t data;
 SPI1->CR1 |= SPI_CR1_SPE; // 启动SPI总线, 同时自动拉低片选信号CS
 SPI1->DR = op | (addr & 0x1f); // 操作码和地址 (1)
 while ((SPI1->SR & SPI_SR_TXE) == 0); // TXE置位时数据(1)刚好发完1位, 可以向DR中放入下次要发送的数据
 SPI1->DR = 0xff; // 送入数据 (2)
 while ((SPI1->SR & SPI_SR_RXNE) == 0); // 等待数据(1)发送完毕
 data = SPI1->DR; // 接收 (1)
 while ((SPI1->SR & SPI_SR_TXE) == 0); // TXE置位时数据(2)刚好发完1位
 if (addr & 0x80) // 如果是MAC和MII寄存器, 第一个读取的字节无效, 该信息包含在地址的最高位
 SPI1->DR = 0xff; // 送入数据 (3), 再次通过SPI读取数据
 while ((SPI1->SR & SPI_SR_RXNE) == 0); // 等待数据(2)发送完毕
 data = SPI1->DR; // 接收 (2)
 if (addr & 0x80)
 {
 while ((SPI1->SR & SPI_SR_RXNE) == 0); // 等待数据(3)发送完毕
 data = SPI1->DR; // 接收 (3)
 }
 while (SPI1->SR & SPI_SR_BSY);
 SPI1->CR1 &= ~SPI_CR1_SPE; // 关闭SPI总线, 同时自动拉高片选信号CS
 return data;
 }
 
 // 设定寄存器存储区域
 void ENC28J60_SetBank(uint8_t addr)
 {
 addr &= 0x60;
 if (addr != enc28j60_bank)
 {
 ENC28J60_WriteOP(ENC28J60_BIT_FIELD_CLR, ECON1, ECON1_BSEL1 | ECON1_BSEL0);
 ENC28J60_WriteOP(ENC28J60_BIT_FIELD_SET, ECON1, addr >> 5);
 enc28j60_bank = addr;
 }
 }
 
 // 写寄存器
 void ENC28J60_Write(uint8_t addr, uint8_t data)
 {
 ENC28J60_SetBank(addr);
 ENC28J60_WriteOP(ENC28J60_WRITE_CTRL_REG, addr, data);
 }
 
 // 写缓冲区
 void ENC28J60_WriteBuf(uint8_t *p, uint16_t len)
 {
 SPI1->CR1 |= SPI_CR1_SPE;
 SPI1->DR = ENC28J60_WRITE_BUF_MEM; // 发送写取缓冲区命令
 while ((SPI1->SR & SPI_SR_TXE) == 0);
 
 // 循环发送
 while (len--)
 {
 SPI1->DR = *p++;
 while ((SPI1->SR & SPI_SR_TXE) == 0);
 }
 while (SPI1->SR & SPI_SR_BSY);
 SPI1->CR1 &= ~SPI_CR1_SPE;
 }
 
 void ENC28J60_WriteOP(uint8_t op, uint8_t addr, uint8_t data)
 {
 SPI1->CR1 |= SPI_CR1_SPE;
 SPI1->DR = op | (addr & 0x1f); // 发送操作码和寄存器地址
 while ((SPI1->SR & SPI_SR_TXE) == 0);
 SPI1->DR = data; // 发送数据
 while ((SPI1->SR & SPI_SR_TXE) == 0);
 while (SPI1->SR & SPI_SR_BSY);
 data = SPI1->DR; // 清RxNE
 SPI1->CR1 &= ~SPI_CR1_SPE;
 }
 
 // 写物理寄存器
 void ENC28J60_WritePhy(uint8_t addr, uint16_t data)
 {
 ENC28J60_Write(MIREGADR, addr);
 ENC28J60_Write(MIWRL, data);
 ENC28J60_Write(MIWRH, data >> 8);
 while (ENC28J60_Read(MISTAT) & MISTAT_BUSY);
 }
 
 |  |
 
         
          |   一派掌门 二十级 | 
              【网卡端口配置:以STM32F103单片机为例】// 配置SPI1
 RCC->APB2ENR = RCC_APB2ENR_IOPAEN | RCC_APB2ENR_SPI1EN;
 GPIOA->CRL = 0xb4bb0080;
 GPIOA->BSRR = GPIO_BSRR_BS1; // PA1为网卡中断输出
 SPI1->CR1 = SPI_CR1_MSTR | SPI_CR1_BR_1; // 主机模式, 时钟至少需要8分频(BR=010), 也就是72MHz/8=9MHz
 SPI1->CR2 = SPI_CR2_SSOE; // 开CS片选输出
 
 |  |
 
         
          |   一派掌门 二十级 | 
              【端口连线】PA1连接外中断端口INT,带上拉电阻输入(CRL=8, 且ODR=1)
 PA4连接片选端口CS,复用推挽50MHz输出(CRL=b)
 PA5连接时钟端口SCK,复用推挽50MHz输出(CRL=b)
 PA6连接端口SO,浮空输入(CRL=4)
 PA7连接端口SI,复用推挽50MHz输出(CRL=b)
 
 当SPE=1时SPI总线启动,CS=0;当SPE=0时SPI总线关闭,CS=1。(SSOE=1)
 SPI总线的Baud Rate必须至少为8分频(=f_PCLK/8),也就是将BR位设为010。
 
 |  |
 
         
          |   一派掌门 二十级 | 
              【头文件中未引用的宏定义】ERXWRPTL, ERXWRPTH, EDMASTL, EDMASTH, EDMANDL, EDMANDH, EDMADSTL, EDMADSTH, EDMACSL, EDMACSH, EHT0, EHT1, EHT2, EHT3, EHT4, EHT5, EHT6, EHT7, EPMM2, EPMM3, EPMM4, EPMM5, EPMM6, EPMM7, EPMOL, EPMOH, EWOLIE, EWOLIR, PHSTAT1, PHHID1, PHHID2, PHSTAT2, PHIE, PHIR, ERXFCON_ANDOR, ERXFCON_MPEN, ERXFCON_HTEN, ERXFCON_MCEN, ERXFCON_BCEN, EIE_DMAIE, EIE_LINKIE, EIE_TXIE, EIE_WOLIE, EIE_TXERIE, EIR_PKTIF, EIR_DMAIF, EIR_LINKIF, EIR_TXIF, EIR_WOLIF, EIR_RXERIF, ESTAT_INT, ESTAT_LATECOL, ESTAT_RXBUSY, ESTAT_TXABRT, ECON2_AUTOINC, ECON2_PWRSV, ECON2_VRPS, ECON1_TXRST, ECON1_RXRST, ECON1_DMAST, ECON1_CSUMEN, MACON1_LOOPBK, MACON1_PASSALL, MACON2_MARST, MACON2_RNDRST, MACON2_MARXRST, MACON2_RFUNRST, MACON2_MATXRST, MACON2_TFUNRST, MACON3_PADCFG2, MACON3_PADCFG1, MACON3_PHDRLEN, MACON3_HFRMLEN, MICMD_MIISCAN, MICMD_MIIRD, MISTAT_NVALID, MISTAT_SCAN, PHCON1_PRST, PHCON1_PLOOPBK, PHCON1_PPWRSV, PHSTAT1_PFDPX, PHSTAT1_PHDPX, PHSTAT1_LLSTAT, PHSTAT1_JBSTAT, PHCON2_FRCLINK, PHCON2_TXDIS, PHCON2_JABBER, PKTCTRL_PHUGEEN, PKTCTRL_PPADEN, PKTCTRL_PCRCEN, PKTCTRL_POVERRIDE
 |  |
 
         
          |   一派掌门 二十级 | 
              【精简后的ENC28J60.h头文件】#define EIE 0x1b
 #define EIR 0x1c
 #define ESTAT 0x1d
 #define ECON2 0x1e
 #define ECON1 0x1f
 
 // Bank 0 registers
 #define ERDPTL 0x00
 #define ERDPTH 0x01
 #define EWRPTL 0x02
 #define EWRPTH 0x03
 #define ETXSTL 0x04
 #define ETXSTH 0x05
 #define ETXNDL 0x06
 #define ETXNDH 0x07
 #define ERXSTL 0x08
 #define ERXSTH 0x09
 #define ERXNDL 0x0a
 #define ERXNDH 0x0b
 #define ERXRDPTL 0x0c
 #define ERXRDPTH 0x0d
 
 // Bank 1 registers
 #define EPMM0 0x28
 #define EPMM1 0x29
 #define EPMCSL 0x30
 #define EPMCSH 0x31
 #define ERXFCON 0x38
 #define EPKTCNT 0x39
 
 // Bank 2 registers
 #define MACON1 0xc0
 #define MACON2 0xc1
 #define MACON3 0xc2
 #define MABBIPG 0xc4
 #define MAIPGL 0xc6
 #define MAIPGH 0xc7
 #define MAMXFLL 0xca
 #define MAMXFLH 0xcb
 #define MIREGADR 0xd4
 #define MIWRL 0xd6
 #define MIWRH 0xd7
 
 // Bank 3 registers
 #define MAADR1 0xe0
 #define MAADR0 0xe1
 #define MAADR3 0xe2
 #define MAADR2 0xe3
 #define MAADR5 0xe4
 #define MAADR4 0xe5
 #define MISTAT 0xea
 
 // PHY registers
 #define PHCON1 0x00
 #define PHCON2 0x10
 #define PHLCON 0x14
 
 #define ERXFCON_UCEN 0x80
 #define ERXFCON_CRCEN 0x20
 #define ERXFCON_PMEN 0x10
 #define EIE_INTIE 0x80
 #define EIE_PKTIE 0x40
 #define EIE_RXERIE 0x01
 #define EIR_TXERIF 0x02
 #define ESTAT_CLKRDY 0x01
 #define ECON2_PKTDEC 0x40
 #define ECON1_TXRTS 0x08
 #define ECON1_RXEN 0x04
 #define ECON1_BSEL1 0x02
 #define ECON1_BSEL0 0x01
 #define MACON1_TXPAUS 0x08
 #define MACON1_RXPAUS 0x04
 #define MACON1_MARXEN 0x01
 #define MACON3_PADCFG0 0x20
 #define MACON3_TXCRCEN 0x10
 #define MACON3_FRMLNEN 0x02
 #define MACON3_FULDPX 0x01
 #define MISTAT_BUSY 0x01
 #define PHCON1_PDPXMD 0x0100
 #define PHCON2_HDLDIS 0x0100
 
 /* 指令集, 详见数据手册26页 */
 #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 // 系统复位
 
 #define RXSTART_INIT 0 // 接收缓冲区起始地址
 #define RXSTOP_INIT (0x1fff - 0x0600 - 1) // 接收缓冲区停止地址
 #define TXSTART_INIT (0x1fff - 0x0600) // 发送缓冲区起始地址, 大小约1500字节
 #define TXSTOP_INIT 0x1fff // 发送缓冲区停止地址
 #define MAX_FRAMELEN 1500 // 以太网报文最大长度
 
 void ENC28J60_BeginSend(void);
 void ENC28J60_EndReceive(void);
 uint16_t ENC28J60_GetPacketLength(void);
 uint8_t ENC28J60_GetPacketNum(void);
 void ENC28J60_Init(uint8_t *mac_addr);
 void ENC28J60_InitSend(uint16_t len);
 uint8_t ENC28J60_Read(uint8_t addr);
 void ENC28J60_ReadBuf(uint8_t *p, uint16_t len);
 uint8_t ENC28J60_ReadOP(uint8_t op, uint8_t addr);
 void ENC28J60_SetBank(uint8_t addr);
 void ENC28J60_Write(uint8_t addr, uint8_t data);
 void ENC28J60_WriteBuf(uint8_t *p, uint16_t len);
 void ENC28J60_WriteOP(uint8_t op, uint8_t addr, uint8_t data);
 void ENC28J60_WritePhy(uint8_t addr, uint16_t data);
 
 |  |
 
         |  |  |