前言 
虽然esp32支持无线联网,也可以同时使用espnow和wifi功能,但是切换这两种网络比较麻烦。使用有线网络也可以提供更低的网络延时,和更稳定的网络访问。这里我们使用常见的w5500模块作为扩展模块 ,如下图所示。 
  
 
该模块使用SPI接口,ESP32C6可以使用SPI2作为通信设备。 
 
 
1.1 引脚设置 
我们先在esp idf官方示范代码里,复制eth网络基本工程(目录是esp-idf/examples/ethernet/basic/)到一个目录里。 
复制了工程之后,我们需要设置spi的引脚(使用idf.py menuconfig命令),将对应引脚设置成图示的内容。 
 
  
 
1.2 参考代码 
 
我在官网Eth网络示范代码的基础上,添加了socket响应部分的代码,完整代码如下 
			
			
			- /* Ethernet Basic Example
 - 
 -    This example code is in the Public Domain (or CC0 licensed, at your option.)
 - 
 -    Unless required by applicable law or agreed to in writing, this
 -    software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
 -    CONDITIONS OF ANY KIND, either express or implied.
 - */
 - #include "esp_eth.h"
 - #include "esp_event.h"
 - #include "esp_log.h"
 - #include "esp_netif.h"
 - #include "ethernet_init.h"
 - #include "freertos/FreeRTOS.h"
 - #include "freertos/task.h"
 - #include "nvs_flash.h"
 - #include "sdkconfig.h"
 - #include <stdio.h>
 - #include <string.h>
 - 
 - #include "lwip/err.h"
 - #include "lwip/sockets.h"
 - #include "lwip/sys.h"
 - #include <lwip/netdb.h>
 - 
 - static const char *TAG = "eth_example";
 - 
 - /** Event handler for Ethernet events */
 - static void eth_event_handler(void *arg, esp_event_base_t event_base,
 -                               int32_t event_id, void *event_data) {
 -   uint8_t mac_addr[6] = {0};
 -   /* we can get the ethernet driver handle from event data */
 -   esp_eth_handle_t eth_handle = *(esp_eth_handle_t *)event_data;
 - 
 -   switch (event_id) {
 -   case ETHERNET_EVENT_CONNECTED:
 -     esp_eth_ioctl(eth_handle, ETH_CMD_G_MAC_ADDR, mac_addr);
 -     ESP_LOGI(TAG, "Ethernet Link Up");
 -     ESP_LOGI(TAG, "Ethernet HW Addr %02x:%02x:%02x:%02x:%02x:%02x", mac_addr[0],
 -              mac_addr[1], mac_addr[2], mac_addr[3], mac_addr[4], mac_addr[5]);
 -     break;
 -   case ETHERNET_EVENT_DISCONNECTED:
 -     ESP_LOGI(TAG, "Ethernet Link Down");
 -     break;
 -   case ETHERNET_EVENT_START:
 -     ESP_LOGI(TAG, "Ethernet Started");
 -     break;
 -   case ETHERNET_EVENT_STOP:
 -     ESP_LOGI(TAG, "Ethernet Stopped");
 -     break;
 -   default:
 -     break;
 -   }
 - }
 - 
 - /** Event handler for IP_EVENT_ETH_GOT_IP */
 - static void got_ip_event_handler(void *arg, esp_event_base_t event_base,
 -                                  int32_t event_id, void *event_data) {
 -   ip_event_got_ip_t *event = (ip_event_got_ip_t *)event_data;
 -   const esp_netif_ip_info_t *ip_info = &event->ip_info;
 - 
 -   ESP_LOGI(TAG, "Ethernet Got IP Address");
 -   ESP_LOGI(TAG, "~~~~~~~~~~~");
 -   ESP_LOGI(TAG, "ETHIP:" IPSTR, IP2STR(&ip_info->ip));
 -   ESP_LOGI(TAG, "ETHMASK:" IPSTR, IP2STR(&ip_info->netmask));
 -   ESP_LOGI(TAG, "ETHGW:" IPSTR, IP2STR(&ip_info->gw));
 -   ESP_LOGI(TAG, "~~~~~~~~~~~");
 - }
 - 
 - void w5500(void) {
 -   // Initialize Ethernet driver
 -   uint8_t eth_port_cnt = 0;
 -   esp_eth_handle_t *eth_handles;
 -   ESP_ERROR_CHECK(example_eth_init(ð_handles, ð_port_cnt));
 - 
 -   // Create instance(s) of esp-netif for Ethernet(s)
 -   if (eth_port_cnt == 1) {
 -     // Use ESP_NETIF_DEFAULT_ETH when just one Ethernet interface is used and
 -     // you don't need to modify default esp-netif configuration parameters.
 -     esp_netif_config_t cfg = ESP_NETIF_DEFAULT_ETH();
 -     esp_netif_t *eth_netif = esp_netif_new(&cfg);
 -     // Attach Ethernet driver to TCP/IP stack
 -     ESP_ERROR_CHECK(
 -         esp_netif_attach(eth_netif, esp_eth_new_netif_glue(eth_handles[0])));
 -   } else {
 -     // Use ESP_NETIF_INHERENT_DEFAULT_ETH when multiple Ethernet interfaces are
 -     // used and so you need to modify esp-netif configuration parameters for
 -     // each interface (name, priority, etc.).
 -     esp_netif_inherent_config_t esp_netif_config =
 -         ESP_NETIF_INHERENT_DEFAULT_ETH();
 -     esp_netif_config_t cfg_spi = {.base = &esp_netif_config,
 -                                   .stack = ESP_NETIF_NETSTACK_DEFAULT_ETH};
 -     char if_key_str[10];
 -     char if_desc_str[10];
 -     char num_str[3];
 -     for (int i = 0; i < eth_port_cnt; i++) {
 -       itoa(i, num_str, 10);
 -       strcat(strcpy(if_key_str, "ETH_"), num_str);
 -       strcat(strcpy(if_desc_str, "eth"), num_str);
 -       esp_netif_config.if_key = if_key_str;
 -       esp_netif_config.if_desc = if_desc_str;
 -       esp_netif_config.route_prio -= i * 5;
 -       esp_netif_t *eth_netif = esp_netif_new(&cfg_spi);
 - 
 -       // Attach Ethernet driver to TCP/IP stack
 -       ESP_ERROR_CHECK(
 -           esp_netif_attach(eth_netif, esp_eth_new_netif_glue(eth_handles[i])));
 -     }
 -   }
 - 
 -   // Register user defined event handers
 -   ESP_ERROR_CHECK(esp_event_handler_register(ETH_EVENT, ESP_EVENT_ANY_ID,
 -                                              ð_event_handler, NULL));
 -   ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, IP_EVENT_ETH_GOT_IP,
 -                                              &got_ip_event_handler, NULL));
 - 
 -   // Start Ethernet driver state machine
 -   for (int i = 0; i < eth_port_cnt; i++) {
 -     ESP_ERROR_CHECK(esp_eth_start(eth_handles[i]));
 -   }
 - }
 - 
 - #define PORT 3333
 - #define KEEPALIVE_IDLE 5
 - #define KEEPALIVE_INTERVAL 5
 - #define KEEPALIVE_COUNT 3
 - 
 - static void do_retransmit(const int sock) {
 -   int len;
 -   char rx_buffer[128];
 - 
 -   do {
 -     len = recv(sock, rx_buffer, sizeof(rx_buffer) - 1, 0);
 -     if (len < 0) {
 -       ESP_LOGE(TAG, "Error occurred during receiving: errno %d", errno);
 -     } else if (len == 0) {
 -       ESP_LOGW(TAG, "Connection closed");
 -     } else {
 -       rx_buffer[len] =
 -           0; // Null-terminate whatever is received and treat it like a string
 -       ESP_LOGI(TAG, "Received %d bytes: %s", len, rx_buffer);
 - 
 -       // send() can return less bytes than supplied length.
 -       // Walk-around for robust implementation.
 -       int to_write = len;
 -       while (to_write > 0) {
 -         int written = send(sock, rx_buffer + (len - to_write), to_write, 0);
 -         if (written < 0) {
 -           ESP_LOGE(TAG, "Error occurred during sending: errno %d", errno);
 -           // Failed to retransmit, giving up
 -           return;
 -         }
 -         to_write -= written;
 -       }
 -     }
 -   } while (len > 0);
 - }
 - 
 - static void tcp_server_task(void *pvParameters) {
 -   char addr_str[128];
 -   int addr_family = (int)pvParameters;
 -   int ip_protocol = 0;
 -   int keepAlive = 1;
 -   int keepIdle = KEEPALIVE_IDLE;
 -   int keepInterval = KEEPALIVE_INTERVAL;
 -   int keepCount = KEEPALIVE_COUNT;
 -   struct sockaddr_storage dest_addr;
 - 
 -   if (addr_family == AF_INET) {
 -     struct sockaddr_in *dest_addr_ip4 = (struct sockaddr_in *)&dest_addr;
 -     dest_addr_ip4->sin_addr.s_addr = htonl(INADDR_ANY);
 -     dest_addr_ip4->sin_family = AF_INET;
 -     dest_addr_ip4->sin_port = htons(PORT);
 -     ip_protocol = IPPROTO_IP;
 -   }
 - 
 -   int listen_sock = socket(addr_family, SOCK_STREAM, ip_protocol);
 -   if (listen_sock < 0) {
 -     ESP_LOGE(TAG, "Unable to create socket: errno %d", errno);
 -     vTaskDelete(NULL);
 -     return;
 -   }
 -   int opt = 1;
 -   setsockopt(listen_sock, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
 - 
 -   ESP_LOGI(TAG, "Socket created");
 - 
 -   int err = bind(listen_sock, (struct sockaddr *)&dest_addr, sizeof(dest_addr));
 -   if (err != 0) {
 -     ESP_LOGE(TAG, "Socket unable to bind: errno %d", errno);
 -     ESP_LOGE(TAG, "IPPROTO: %d", addr_family);
 -     goto CLEAN_UP;
 -   }
 -   ESP_LOGI(TAG, "Socket bound, port %d", PORT);
 - 
 -   err = listen(listen_sock, 1);
 -   if (err != 0) {
 -     ESP_LOGE(TAG, "Error occurred during listen: errno %d", errno);
 -     goto CLEAN_UP;
 -   }
 - 
 -   while (1) {
 - 
 -     ESP_LOGI(TAG, "Socket listening");
 - 
 -     struct sockaddr_storage source_addr; // Large enough for both IPv4 or IPv6
 -     socklen_t addr_len = sizeof(source_addr);
 -     int sock = accept(listen_sock, (struct sockaddr *)&source_addr, &addr_len);
 -     if (sock < 0) {
 -       ESP_LOGE(TAG, "Unable to accept connection: errno %d", errno);
 -       break;
 -     }
 - 
 -     // Set tcp keepalive option
 -     setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, &keepAlive, sizeof(int));
 -     setsockopt(sock, IPPROTO_TCP, TCP_KEEPIDLE, &keepIdle, sizeof(int));
 -     setsockopt(sock, IPPROTO_TCP, TCP_KEEPINTVL, &keepInterval, sizeof(int));
 -     setsockopt(sock, IPPROTO_TCP, TCP_KEEPCNT, &keepCount, sizeof(int));
 -     // Convert ip address to string
 - 
 -     if (source_addr.ss_family == PF_INET) {
 -       inet_ntoa_r(((struct sockaddr_in *)&source_addr)->sin_addr, addr_str,
 -                   sizeof(addr_str) - 1);
 -     }
 - 
 -     ESP_LOGI(TAG, "Socket accepted ip address: %s", addr_str);
 - 
 -     do_retransmit(sock);
 - 
 -     shutdown(sock, 0);
 -     close(sock);
 -   }
 - 
 - CLEAN_UP:
 -   close(listen_sock);
 -   vTaskDelete(NULL);
 - }
 - 
 - void app_main(void) {
 -   ESP_ERROR_CHECK(nvs_flash_init());
 -   ESP_ERROR_CHECK(esp_netif_init());
 -   ESP_ERROR_CHECK(esp_event_loop_create_default());
 - 
 -   w5500();
 -   xTaskCreate(tcp_server_task, "tcp_server", 4096, (void *)AF_INET, 5, NULL);
 - }
 
  复制代码
  
 
1.3 编译调试 
在命令行运行idf.py flash monitor,可以看到终端有以下的输出 
 
  
 
可以看到,已经正确获取到了动态IP地址,接下来在另一个命令行输入,然后随意输入一些内容,可以看到esp32也将对应内容发送了回来。 
复制代码
   
 
  
 |