4、设备端网络接口:以太网接口、Wi-Fi接口、蜂窝模块接口的硬件与驱动抽象
在嵌入式设备中,网络接口是TCP/IP通信的物理基础。不同接口的硬件特性、驱动模型和抽象方式直接影响上层协议栈的移植与调试。本章从硬件接口、驱动抽象层、数据收发路径三个维度,系统梳理以太网、Wi-Fi、蜂窝模块三种典型网络接口的实现要点。
核心观点:驱动抽象层的目标是让上层TCP/IP协议栈(如LwIP、uC/TCP-IP)不感知底层物理接口差异,通过统一的网络接口控制块(NIC)结构体完成数据收发。
4.1 三种网络接口的硬件特性对比
| 特性维度 | 以太网接口 | Wi-Fi接口 | 蜂窝模块接口 |
|---|---|---|---|
| 物理层介质 | 双绞线(RJ45)、光纤 | 2.4GHz/5GHz 射频 | LTE/NB-IoT/5G NR 射频 |
| 典型芯片 | LAN8720、DP83848、W5500 | ESP8266、ESP32、RTL8720 | SIM800、EC20、BC95、Air720 |
| 主机接口 | RMII/MII、SPI、MAC+PHY集成 | SDIO、SPI、USB、UART | UART(AT指令)、USB(PPP/RNDIS)、SPI |
| 驱动复杂度 | 中(需处理PHY状态机、中断) | 高(需处理802.11协议栈、扫描、加密) | 中(AT指令解析、PPP拨号或RNDIS) |
| 数据帧格式 | 标准以太网帧(MAC+IP+Payload) | 802.11帧(需桥接或转换) | PPP帧或AT+IPD数据段 |
| 典型速率 | 10/100/1000 Mbps | 11~150 Mbps(实际受环境限制) | 150 kbps~100 Mbps(取决于制式) |
选型提示:对于实时性要求高的工业控制场景,优先选择RMII接口的独立以太网PHY;对于低功耗数据采集,蜂窝模块的UART+AT指令方案成本最低;Wi-Fi适合中等速率、无需布线的室内场景。
4.2 驱动抽象层设计:统一NIC接口
驱动抽象层(DAL)的核心是定义一个通用的网络接口控制块(NIC),将不同物理接口的操作封装为统一的函数指针集合。以下是一个典型的NIC结构体定义:
/* 统一网络接口控制块 */
typedef struct netif {
struct netif *next; /* 链表指针 */
ip_addr_t ip_addr; /* IP地址 */
ip_addr_t netmask; /* 子网掩码 */
ip_addr_t gw; /* 默认网关 */
netif_input_fn input; /* 数据接收回调 */
netif_output_fn output; /* 数据发送函数 */
netif_linkoutput_fn linkoutput; /* 链路层发送函数 */
netif_status_callback_fn link_callback; /* 链路状态变化回调 */
void *state; /* 驱动私有数据指针 */
u16_t mtu; /* 最大传输单元 */
u8_t hwaddr_len; /* MAC地址长度 */
u8_t hwaddr[NETIF_MAX_HWADDR_LEN]; /* MAC地址 */
u8_t flags; /* 状态标志位 */
} netif_t;
驱动适配要点:所有接口的驱动必须实现
linkoutput(底层帧发送)和 input(中断或轮询接收)两个核心函数。Wi-Fi和蜂窝模块的驱动还需要额外处理连接管理(关联AP、附着网络)。
4.3 以太网接口驱动实现要点
以太网驱动通常分为MAC层和PHY层两部分。MAC层负责帧封装、CRC校验、DMA传输;PHY层负责物理信号编码、链路检测、自动协商。驱动初始化流程如下:
- GPIO与时钟配置:初始化RMII/MII接口引脚,使能MAC时钟。
- PHY复位与识别:通过MDIO总线读取PHY ID寄存器,确认PHY型号。
- 自动协商配置:设置PHY工作模式(10/100M、全双工/半双工)。
- MAC初始化:设置MAC地址、接收过滤器、DMA描述符环。
- 中断注册:注册接收完成中断、链路状态变化中断。
- 链路状态轮询:周期性读取PHY状态寄存器,更新链路标志。
4.4 Wi-Fi接口驱动与抽象
Wi-Fi驱动的复杂度远高于以太网,因为驱动层需要处理802.11协议栈的扫描、关联、认证、密钥协商等操作。常见的驱动抽象方式有两种:
| 抽象方式 | 实现原理 | 典型芯片 | 优点 | 缺点 |
|---|---|---|---|---|
| FullMAC方案 | Wi-Fi芯片内部完成802.11协议处理,主机通过SDIO/SPI收发以太网帧 | ESP32、RTL8720 | 主机驱动简单,只需处理MAC帧收发 | 芯片成本高,灵活性低 |
| SoftMAC方案 | 主机驱动实现802.11协议栈,芯片仅提供射频收发 | ath9k、mt7601 | 灵活性高,可定制协议 | 驱动开发工作量大,实时性要求高 |
在嵌入式RTOS场景下,FullMAC方案更常见。驱动抽象层需要额外提供以下接口:
/* Wi-Fi 管理接口(驱动抽象层扩展) */
typedef struct wifi_ops {
int (*init)(void); /* 初始化Wi-Fi模块 */
int (*scan)(wifi_scan_result_t *results, int n); /* 扫描可用AP */
int (*connect)(const char *ssid, const char *pwd); /* 连接AP */
int (*disconnect)(void); /* 断开连接 */
int (*get_rssi)(int *rssi); /* 获取信号强度 */
void (*set_power_save)(int enable); /* 设置省电模式 */
} wifi_ops_t;
驱动适配技巧:Wi-Fi驱动通常需要维护一个连接状态机(IDLE → SCANNING → AUTHENTICATING → ASSOCIATED → GOT_IP)。建议在驱动层实现状态机,并通过回调通知上层协议栈链路状态变化。
4.5 蜂窝模块接口驱动与抽象
蜂窝模块的驱动抽象最为特殊,因为大多数模块通过UART接口使用AT指令进行控制,数据通道则通过PPP拨号或RNDIS虚拟网卡实现。驱动抽象层需要处理两个层面的抽象:
- 控制面:AT指令的封装与解析,包括网络注册、信号质量查询、PDP上下文激活。
- 数据面:PPP协议栈或RNDIS驱动,将串口数据流转换为IP数据包。
蜂窝模块驱动初始化的关键步骤:
- 模块上电与复位:通过GPIO控制模块电源和复位引脚,等待模块启动(通常需要2~5秒)。
- AT指令握手:发送
AT\r\n等待OK响应,确认模块通信正常。 - SIM卡检测:发送
AT+CPIN?检查SIM卡状态。 - 网络注册:发送
AT+CREG?或AT+CGREG?等待网络注册成功。 - PDP上下文激活:发送
AT+CGDCONT=1,"IP","apn"和ATD*99#建立数据连接。 - 数据通道建立:启动PPP拨号或等待RNDIS枚举完成。
/* 蜂窝模块驱动初始化示例(伪代码) */
int cellular_init(cellular_dev_t *dev) {
/* 1. 硬件复位 */
gpio_set(dev->reset_pin, 1);
delay_ms(100);
gpio_set(dev->reset_pin, 0);
delay_ms(3000);
/* 2. AT握手 */
if (at_send_cmd(dev, "AT", "OK", 5000) != 0) {
return -1; /* 模块无响应 */
}
/* 3. 检查SIM卡 */
if (at_send_cmd(dev, "AT+CPIN?", "READY", 10000) != 0) {
return -2; /* SIM卡异常 */
}
/* 4. 等待网络注册 */
while (1) {
if (at_send_cmd(dev, "AT+CREG?", "+CREG: 0,1", 5000) == 0) break;
if (at_send_cmd(dev, "AT+CREG?", "+CREG: 0,5", 5000) == 0) break;
delay_ms(1000);
}
/* 5. 激活PDP上下文 */
at_send_cmd(dev, "AT+CGDCONT=1,\"IP\",\"cmnet\"", "OK", 5000);
at_send_cmd(dev, "ATD*99#", "CONNECT", 15000);
/* 6. 启动PPP */
ppp_init(dev->uart_handle);
return 0;
}
常见问题:蜂窝模块的AT指令响应时间差异很大(从毫秒到几十秒),驱动中所有AT指令必须设置合理的超时时间。建议使用状态机方式管理AT指令队列,避免阻塞整个系统。
4.6 多接口共存与优先级管理
实际设备可能同时具备多个网络接口(例如以太网+Wi-Fi+蜂窝备份)。驱动抽象层需要支持多NIC实例,并提供接口优先级和路由策略:
| 场景 | 接口优先级 | 路由策略 | 切换条件 |
|---|---|---|---|
| 工业网关 | 以太网 > Wi-Fi > 蜂窝 | 主备切换,故障时降级 | 以太网链路断开 → 启用Wi-Fi → 蜂窝 |
| 移动终端 | Wi-Fi > 蜂窝 | 优先Wi-Fi,无可用AP时使用蜂窝 | Wi-Fi信号低于阈值 → 切换蜂窝 |
| 数据采集器 | 蜂窝(主)、以太网(配置用) | 默认路由走蜂窝,以太网仅用于本地调试 | 固定配置,不自动切换 |
实现建议:在驱动抽象层维护一个
netif_active 链表,每个NIC节点包含 priority 和 status 字段。上层协议栈根据优先级选择默认路由,当高优先级接口链路断开时自动切换到次高优先级接口。
驱动抽象层的最终目标是:上层协议栈不关心底层是哪种物理接口,所有接口通过统一的 netif_t 结构体进行数据收发和状态管理。这种抽象方式使得TCP/IP协议栈的移植工作与具体硬件解耦,大幅提高代码复用性和可维护性。