资讯详情

ENC28J60 简介

单片机以太网方案

  1. 如果 MCU 内部集成 MAC 控制器只需要外接一个 PHY 芯片就够了
  2. 如果 MCU 内部没有 MAC 需要外接的控制器 MAC 芯片和 PHY 这两个芯片可以分立或集成在一个芯片中

以上两种方案,MAC PHY 完成了 TCP/IP 物理层和数据链路层是五层模型的最低两层。网络层、传输层、应用层等上述层需要在 MCU 中实现。当然,普通程序员想要实现 IP 层、TCP/UDP 层还是很难的。但别担心,我们可以使用成熟的开源 TCP/IP 协议栈,如 uIP、LwIP。它们都是轻量级的 TCP/IP 协议栈适用于资源有限的单片机。

  1. 使用硬件 TCP/IP 协议栈,MCU 只需实现应用层代码即可。

例如,使用 W5500 芯片、传输层及以下均由外部芯片完成,MCU 只需要配置 W5500,从 W5500 收发数据,完成应用层逻辑。另一种方案是 MCU 原理和使用外接串口转以太网模块 W5500 方案类似。

ENC28J60

ENC28J60 属于上述方案 2,ENC28J60 单颗芯片集成了 MAC 和 PHY,提供 SPI 接口用来和 MCU 通信。

寄存器 —— 体现了硬件的灵活性

在方案 2 网络层、传输层、应用层 以软件的形式 CPU 物理层和数据链路层以硬件的形式实现 ENC28J60 尽管如此 ENC28J60 它是一个硬件,我们不能编程和修改它的功能,但它仍然具有一定的灵活性,即可配置的寄存器。我们可以设置寄存器来控制最低两层,或者读取寄存器来监控最低两层。 例如,我们可以设置它 ECON1 控制接收使能和发送请求的寄存器DMA、选择存储区等。 还可以设置 PHCON1 控制寄存器 PHY 模块复位等功能。

缓冲器 —— 硬件的价值体现

说到底 ENC28J60 的功能是从 IP 层将数据并发送,或将收到的数据发送给 IP 层。这两个方向的操作都需要缓冲器来临时存储数据。

ENC28J60 读写特性

ENC28J60 存储器有三种类型: ? 控制寄存器 ? 以太网缓冲器 ? PHY 寄存器 其中 MCU 可以通过 SPI 用指令直接读写界面 。但不能通过 SPI 直接访问接口 PHY 寄存器,只可以通过 MAC 中的 MII 访问这些寄存器。 可以理解为 SPI 是和 MAC 相连的,可以直接访问 MAC 但是 PHY 只与 MAC 通过 RMII、MIIM 接口连接,所以想读 PHY 寄存器的值必须通过 MAC,进一步说就是通过 MAC 的 MIIM 接口,或通过 MAC 的 MII 寄存器。 在这里插入图片描述 ENC28J60 所有的存取器都是静态的 RAM 实现的方式。 可用于控制寄存器存储空间 ECON1 选择寄存器中存储区的位置 BSEL1:BSEL0 进行选择。 每个存储区都是 32 字节长,可用 5 地址值寻址。 所有存储区最后五个单元 (1Bh 到 1Fh)都指向同一组寄存器:EIE、EIR、ESTAT、ECON2 和 ECON1。 它们是控制和监控设备工作的关键寄存器, 下图为所有控制寄存器: 能够从任意 Bank 访问 ECON1 因为 ECON1 中存有选择 Bank 的两个 bit,倘若 ECON1 只能在 Bank 0 一旦访问权转换为中访, Bank 2,而 Bank 2 又无法访问 ECON1 来选择 Bank,那不是悲催吗?只能停留在 Bank 2 了。。。??

读取 PHY 寄存器实例

下面大致写一段代码读取 PHY 的 PHSTAT1 该寄存器的寄存器 bit2 表示链路状态 我们一步一步地写 代码

int main(void) { 
            /* USER CODE BEGIN 1 */  uint8_t tx_data = 0x00;  uint8_t rx_data = 0x00;  uint16_t pyh_data;   /* USER CODE END 1 */    /* MCU Configuration----------------------------------------------------------*/    /* Reset of all peripherals, Initializes the Flash interface and the Systick. */   HAL_Init();    /* Configure the system clock */   SystemClock_Config();    /* Initialize all configured peripherals */   MX_GPIO_Init();   MX_SPI1_Init();   MX_USART1_UART_Init();    /* USER CODE BEGIN 2 */ /* 1111111111111111111. */ /* select bank 2 begin */  tx_data = 0x0 | 0x1F;	// BFC | ECONT1 // BF
	HAL_GPIO_WritePin(SPI1_CS_GPIO_Port, SPI1_CS_Pin, GPIO_PIN_RESET);
	HAL_SPI_Transmit(&hspi1, &tx_data, 1, 10);
	
	tx_data = 0x03;	// 清除最低两位 // 03
	HAL_SPI_Transmit(&hspi1, &tx_data, 1, 10);
	HAL_GPIO_WritePin(SPI1_CS_GPIO_Port, SPI1_CS_Pin, GPIO_PIN_SET);		// 拉高 CS 引脚可结束 BFC 命令
	
	tx_data = 0x80 | 0x1F;	// BFS | ECONT1 // 9F
	HAL_GPIO_WritePin(SPI1_CS_GPIO_Port, SPI1_CS_Pin, GPIO_PIN_RESET);
	HAL_SPI_Transmit(&hspi1, &tx_data, 1, 10);
	
	tx_data = 0x02;	// 10h 表示选中 bank2 // 02
	HAL_SPI_Transmit(&hspi1, &tx_data, 1, 10);
	HAL_GPIO_WritePin(SPI1_CS_GPIO_Port, SPI1_CS_Pin, GPIO_PIN_SET);		// 拉高 CS 引脚可结束 BFS 命令
/* select bank 2 end */



/* MIREGADR(14h) <-- PHSTAT1(01h) begin */
	tx_data = 0x40 | 0x14;	// WCR | MIREGADR(14h) // 地址 // 54
	HAL_GPIO_WritePin(SPI1_CS_GPIO_Port, SPI1_CS_Pin, GPIO_PIN_RESET);
	HAL_SPI_Transmit(&hspi1, &tx_data, 1, 10);
	
	tx_data = 0x01;	// PHSTAT1(01h) // 值 // 01
	HAL_SPI_Transmit(&hspi1, &tx_data, 1, 10);
	HAL_GPIO_WritePin(SPI1_CS_GPIO_Port, SPI1_CS_Pin, GPIO_PIN_SET);
/* MIREGADR(14h) <-- PHSTAT1(01h) end */


/* 2222222222222222222 */
/* MICMD(12h) <-- MIIRD(01h) begin */			// 92
	tx_data = 0x80 | 0x12;	// BFS | MICMD(12h) // 地址
	HAL_GPIO_WritePin(SPI1_CS_GPIO_Port, SPI1_CS_Pin, GPIO_PIN_RESET);
	HAL_SPI_Transmit(&hspi1, &tx_data, 1, 10);
	
	tx_data = 0x01;	// MIIRD(01h) // 值 // 01
	HAL_SPI_Transmit(&hspi1, &tx_data, 1, 10);
	HAL_GPIO_WritePin(SPI1_CS_GPIO_Port, SPI1_CS_Pin, GPIO_PIN_SET);
/* MICMD(12h) <-- MIIRD(01h) end */


/* select bank 3 begin */
	tx_data = 0x80 | 0x1F;	// BFS | ECONT1 // 9F
	HAL_GPIO_WritePin(SPI1_CS_GPIO_Port, SPI1_CS_Pin, GPIO_PIN_RESET);
	HAL_SPI_Transmit(&hspi1, &tx_data, 1, 10);
	
	tx_data = 0x03;	// 11h 表示选中 bank2 // 03
	HAL_SPI_Transmit(&hspi1, &tx_data, 1, 10);
	HAL_GPIO_WritePin(SPI1_CS_GPIO_Port, SPI1_CS_Pin, GPIO_PIN_SET);		// À­¸ß CS Òý½Å¿É½áÊø BFS ÃüÁî
/* select bank 3 end */


/* MISTAT(0Ah) <-- BUSY(01h) begin */
	tx_data = 0x80 | 0x0A;	// BFS | MICMD(0Ah) // 地址 // 8A
	HAL_GPIO_WritePin(SPI1_CS_GPIO_Port, SPI1_CS_Pin, GPIO_PIN_RESET);
	HAL_SPI_Transmit(&hspi1, &tx_data, 1, 10);
	
	tx_data = 0x01;	// BUSY(01h) // 值 // 01
	HAL_SPI_Transmit(&hspi1, &tx_data, 1, 10);
	HAL_GPIO_WritePin(SPI1_CS_GPIO_Port, SPI1_CS_Pin, GPIO_PIN_SET);
/* MISTAT(0Ah) <-- BUSY(01h) end */

/* 333333333333333333. */
/* 等待 10.24us */
// HAL_Delay(1);

/* MISTAT(0Ah) */
// tx_data = 0x00 | 0x0A; // RCR | MISTAT(0Ah) // µØÖ·
// HAL_GPIO_WritePin(SPI1_CS_GPIO_Port, SPI1_CS_Pin, GPIO_PIN_RESET);
// HAL_SPI_Transmit(&hspi1, &tx_data, 1, 10);
// 
// HAL_SPI_Transmit(&hspi1, &rx_data, 1, 10); // ¶ÁÖµ
// HAL_GPIO_WritePin(SPI1_CS_GPIO_Port, SPI1_CS_Pin, GPIO_PIN_SET);
///* MIREGADR(14h) <-- PHSTAT1(01h) end */
// printf("rx_data = 0x%x\r\n", rx_data);

/* 4 */
/* select bank 2 begin */
	tx_data = 0xA0 | 0x1F;	// BFC | ECONT1
	HAL_GPIO_WritePin(SPI1_CS_GPIO_Port, SPI1_CS_Pin, GPIO_PIN_RESET);
	HAL_SPI_Transmit(&hspi1, &tx_data, 1, 10);
	
	tx_data = 0x03;	// Çå³ý×îµÍÁ½Î»
	HAL_SPI_Transmit(&hspi1, &tx_data, 1, 10);
	HAL_GPIO_WritePin(SPI1_CS_GPIO_Port, SPI1_CS_Pin, GPIO_PIN_SET);		// À­¸ß CS Òý½Å¿É½áÊø BFC ÃüÁî
	
	tx_data = 0x80 | 0x1F;	// BFS | ECONT1
	HAL_GPIO_WritePin(SPI1_CS_GPIO_Port, SPI1_CS_Pin, GPIO_PIN_RESET);
	HAL_SPI_Transmit(&hspi1, &tx_data, 1, 10);
	
	tx_data = 0x02;	// 10h ±íʾѡÖÐ bank2
	HAL_SPI_Transmit(&hspi1, &tx_data, 1, 10);
	HAL_GPIO_WritePin(SPI1_CS_GPIO_Port, SPI1_CS_Pin, GPIO_PIN_SET);		// À­¸ß CS Òý½Å¿É½áÊø BFS ÃüÁî
/* select bank 2 end */

/* MICMD(12h) <-- MIIRD(01h) begin */
	tx_data = 0xA0 | 0x12;	// BFC | MICMD(12h) // µØÖ·
	HAL_GPIO_WritePin(SPI1_CS_GPIO_Port, SPI1_CS_Pin, GPIO_PIN_RESET);
	HAL_SPI_Transmit(&hspi1, &tx_data, 1, 10);
	
	tx_data = 0x01;	// MIIRD(01h) // Öµ
	HAL_SPI_Transmit(&hspi1, &tx_data, 1, 10);
	HAL_GPIO_WritePin(SPI1_CS_GPIO_Port, SPI1_CS_Pin, GPIO_PIN_SET);
/* MICMD(12h) <-- MIIRD(01h) end */

/* 5 */
/* read MIRDL(18h) begin */
	tx_data = 0x00 | 0x18;	// RCR | MIRDL(18h) // µØÖ·
	HAL_GPIO_WritePin(SPI1_CS_GPIO_Port, SPI1_CS_Pin, GPIO_PIN_RESET);
	HAL_SPI_Transmit(&hspi1, &tx_data, 1, 10);
	
	HAL_SPI_Receive(&hspi1, &rx_data, 1, 10); // ¶ÁÖµ
// printf("rx_data = 0x%x\r\n", rx_data);
	
	HAL_SPI_Receive(&hspi1, &rx_data, 1, 10); // ¶ÁÖµ
	HAL_GPIO_WritePin(SPI1_CS_GPIO_Port, SPI1_CS_Pin, GPIO_PIN_SET);
// printf("rx_data = 0x%x\r\n", rx_data);

	pyh_data = rx_data;

/* read MIRDH(19h) begin */
	tx_data = 0x00 | 0x19;	// RCR | MIRDH(19h) // µØÖ·
	HAL_GPIO_WritePin(SPI1_CS_GPIO_Port, SPI1_CS_Pin, GPIO_PIN_RESET);
	HAL_SPI_Transmit(&hspi1, &tx_data, 1, 10);
	HAL_SPI_Receive(&hspi1, &rx_data, 1, 10);
	
	HAL_SPI_Receive(&hspi1, &rx_data, 1, 10); // ¶ÁÖµ
	HAL_GPIO_WritePin(SPI1_CS_GPIO_Port, SPI1_CS_Pin, GPIO_PIN_SET);
/* read MIRDH(19h) end */
// printf("rx_data = 0x%x\r\n", rx_data);

	pyh_data = pyh_data + (rx_data << 8);
	printf("pyh_data = 0x%x\r\n", pyh_data);
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  { 
        
  /* USER CODE END WHILE */

  /* USER CODE BEGIN 3 */
// printf("helo\r\n");
		HAL_GPIO_TogglePin(LED_GPIO_Port, LED_Pin);
		HAL_Delay(1000);



		
// printf("0x%X: 0x%x\n", tx_data, rx_data);
// cr_addr++;
  }
  /* USER CODE END 3 */

}

插拔网线        读取到的 PHSTAT1 寄存器值 插上网线,值为 0x1804,即 bit2 = 1; 拔掉网线,值为 0x1800,即 bit2 = 0。

读到的寄存器状态和网线连接状态一致,成功!

标签: 51对射光电传感器pz集成电路mc10h210mgj95连接器

锐单商城拥有海量元器件数据手册IC替代型号,打造 电子元器件IC百科大全!

锐单商城 - 一站式电子元器件采购平台