大家好,欢迎来到IT知识分享网。
单片机以太网方案
单片机想要使用以太网的话,通常有以下几种方案:
- 如果 MCU 内部集成 MAC 控制器,则只需外接一个 PHY 芯片就可以了
- 如果 MCU 内部没有 MAC 控制器,需要外接 MAC 芯片和 PHY 芯片,这两颗芯片可以分立也可以集成在一颗芯片中
以上两种方案,MAC + PHY 完成了 TCP/IP 五层模型的最低两层,即物理层和数据链路层。上面几层,如网络层、传输层、应用层则需要在 MCU 中实现。当然,普通程序员要想实现 IP 层、TCP/UDP 层还是有一定难度的。不过不用担心,我们可以使用成熟的开源 TCP/IP 协议栈,如 uIP、LwIP。它们都是轻量级的 TCP/IP 协议栈,适用于资源受限的单片机。
- 使用硬件 TCP/IP 协议栈,MCU 只需要实现应用层代码就可以了
例如,使用 W5500 芯片,传输层及其以下全部由外部这颗芯片完成,MCU 只需要配置 W5500,从 W5500 收发数据,完成应用层逻辑就可以了。还有一种方案是 MCU 外接一个串口转以太网模块,原理和使用 W5500 方案类似。
ENC28J60
ENC28J60 属于上面介绍的方案 2,ENC28J60 单颗芯片集成了 MAC 和 PHY,提供 SPI 接口用来和 MCU 通信。
寄存器 —— 硬件的灵活性体现
缓冲器 —— 硬件的价值体现
说到底 ENC28J60 的功能是从 IP 层拿数据并发送出去,或者将收到的数据送给 IP 层。这两个方向的操作都需要用到缓冲器,用来暂存数据。
ENC28J60 读写特性
读取 PHY 寄存器实例
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 */ /* . */ /* select bank 2 begin */ tx_data = 0xA0 | 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 */ /* */ /* 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 */ /* . */ /* 等待 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 */ }
读到的寄存器状态和网线连接状态一致,成功!
免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://haidsoft.com/129488.html