STM32F103C8T6+DM9051以太网功能实现方案

一、系统概述

DM9051 是一款单芯片10/100M以太网控制器,集成MAC和PHY,支持SPI/并口接口,适合嵌入式系统。本设计基于STM32F103C8T6(Cortex-M3,72MHz,64KB Flash,20KB RAM)与DM9051通过SPI接口实现以太网通信,支持TCP/IP协议栈(LwIP),实现网络数据收发、远程监控、数据上传等功能,适用于工业物联网、智能家居网关、远程数据采集等场景。

二、硬件设计

1. 系统架构

SPI
MII/RMII
RJ45
I2C/SPI
GPIO
STM32F103C8T6
DM9051以太网控制器
网络变压器 HR911105A
以太网
传感器/外设
LED/按键
3.3V电源

2. 关键硬件连接

(1)核心芯片连接
DM9051引脚 功能 STM32F103C8T6引脚 说明
VCC 电源(3.3V) 3.3V 需加100nF去耦电容
GND GND 共地
SPI_CS SPI片选 PA4 (SPI1_NSS) 低有效
SPI_SCK SPI时钟 PA5 (SPI1_SCK) 模式0(CPOL=0, CPHA=0)
SPI_MOSI SPI主发从收 PA7 (SPI1_MOSI) 数据线
SPI_MISO SPI主收从发 PA6 (SPI1_MISO) 数据线
INT 中断输出 PB0 (EXTI0) 下降沿触发,通知数据到达
RST 复位 PB1 (GPIO) 低有效,上电复位
(2)网络物理层连接
  • 网络变压器 :采用HR911105A (带网络指示灯),连接DM9051的TXP/TXNRXP/RXN引脚,中心抽头接3.3V和GND(通过100nF电容隔直)。

  • RJ45接口 :连接网络变压器,加TVS管(如SMAJ5.0A) 防静电,加LED指示灯(连接DM9051的LED引脚,显示连接状态)。

3. 电路设计要点

  • 电源滤波 :DM9051的VCC引脚旁加10μF电解电容+100nF瓷片电容,抑制电源噪声。

  • SPI时序 :STM32的SPI配置为主模式、8位数据、CPOL=0、CPHA=0,时钟频率≤10MHz(DM9051支持最高20MHz)。

  • 中断处理:INT引脚接STM32的外部中断线(如EXTI0),下降沿触发,在中断服务函数中读取DM9051的接收缓冲区。

三、软件设计

1. 开发环境

  • IDE:Keil MDK-ARM(V5.38)

  • 协议栈:LwIP(轻量级TCP/IP,V2.1.3)

  • 驱动库:STM32标准外设库(V3.5.0)

2. 软件架构

API调用
数据收发
SPI通信
GPIO/EXTI
MII
应用层
LwIP协议栈
DM9051驱动
STM32硬件层
DM9051芯片
网络变压器+RJ45

3. 关键代码实现

(1)DM9051驱动初始化
c 复制代码
#include "dm9051.h"
#include "spi.h"
#include "stm32f10x_gpio.h"

// DM9051寄存器地址
#define DM9051_NCR      0x00  // 网络控制寄存器
#define DM9051_TCR      0x01  // 发送控制寄存器
#define DM9051_RCR      0x05  // 接收控制寄存器
#define DM9051_MAC_ADDR 0x0A  // MAC地址寄存器(6字节)
#define DM9051_PHY      0x10  // PHY控制寄存器

// DM9051初始化
void DM9051_Init(void) {
  // 1. 硬件复位
  GPIO_ResetBits(GPIOB, GPIO_Pin_1);  // RST=0
  Delay_ms(10);
  GPIO_SetBits(GPIOB, GPIO_Pin_1);    // RST=1
  Delay_ms(100);
  
  // 2. 读取芯片ID(0x9051)
  uint16_t id = DM9051_ReadReg(DM9051_VIDL) | (DM9051_ReadReg(DM9051_VIDH) << 8);
  if (id != 0x9051) { /* 错误处理 */ }
  
  // 3. 配置MAC地址(示例:00:E0:4C:12:34:56)
  uint8_t mac[6] = {0x00, 0xE0, 0x4C, 0x12, 0x34, 0x56};
  for (int i=0; i<6; i++) {
    DM9051_WriteReg(DM9051_MAC_ADDR + i, mac[i]);
  }
  
  // 4. 配置接收控制寄存器(RCR)
  DM9051_WriteReg(DM9051_RCR, 0x2F);  // 接收使能,广播/多播/单播都接收
  
  // 5. 配置发送控制寄存器(TCR)
  DM9051_WriteReg(DM9051_TCR, 0x00);  // 正常发送模式
  
  // 6. 使能中断(INT)
  DM9051_WriteReg(DM9051_IMR, 0x01);  // 使能接收中断
}
(2)SPI读写函数
c 复制代码
// SPI写1字节
void DM9051_WriteReg(uint8_t reg, uint8_t data) {
  GPIO_ResetBits(GPIOA, GPIO_Pin_4);  // CS=0
  SPI1_Write(reg | 0x80);  // 写寄存器(最高位1)
  SPI1_Write(data);
  GPIO_SetBits(GPIOA, GPIO_Pin_4);    // CS=1
}

// SPI读1字节
uint8_t DM9051_ReadReg(uint8_t reg) {
  GPIO_ResetBits(GPIOA, GPIO_Pin_4);  // CS=0
  SPI1_Write(reg & 0x7F);  // 读寄存器(最高位0)
  uint8_t data = SPI1_Read();
  GPIO_SetBits(GPIOA, GPIO_Pin_4);    // CS=1
  return data;
}
(3)LwIP协议栈移植
  1. 配置LwIP :在lwipopts.h中设置内存大小、网络参数:

    c 复制代码
    #define MEM_SIZE        (8 * 1024)   // 内存池大小(8KB)
    #define TCP_MSS         1460       // TCP最大段大小
    #define IP_ADDR         "192.168.1.100"  // 本机IP
    #define NETMASK         "255.255.255.0"  // 子网掩码
    #define GW_ADDR         "192.168.1.1"    // 网关
  2. 初始化LwIP

    c 复制代码
    #include "lwip/init.h"
    #include "lwip/netif.h"
    #include "netif/ethernetif.h"
    
    struct netif netif;  // 网络接口结构体
    
    void LwIP_Init(void) {
      lwip_init();  // 初始化LwIP协议栈
    
      // 添加网络接口(DM9051驱动)
      struct ip_addr ipaddr, netmask, gw;
      IP4_ADDR(&ipaddr, 192,168,1,100);
      IP4_ADDR(&netmask, 255,255,255,0);
      IP4_ADDR(&gw, 192,168,1,1);
      netif_add(&netif, &ipaddr, &netmask, &gw, NULL, &ethernetif_init, &tcpip_input);
    
      netif_set_default(&netif);  // 设置默认网络接口
      netif_set_up(&netif);        // 启动网络接口
    }
(4)TCP服务器示例
c 复制代码
#include "lwip/tcp.h"
#include "lwip/err.h"

// TCP连接回调函数
static err_t tcp_server_recv(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err) {
  if (p != NULL) {
    // 回显数据
    tcp_write(tpcb, p->payload, p->len, 1);
    tcp_output(tpcb);
    pbuf_free(p);  // 释放pbuf
  } else {
    // 连接关闭
    tcp_close(tpcb);
  }
  return ERR_OK;
}

// TCP服务器初始化
void TCP_Server_Init(void) {
  struct tcp_pcb *tpcb = tcp_new();  // 创建TCP控制块
  tcp_bind(tpcb, IP_ADDR_ANY, 8080);  // 绑定端口8080
  tpcb = tcp_listen(tpcb);            // 监听连接
  tcp_accept(tpcb, tcp_server_recv);  // 设置接收回调
}

参考代码 STM32F103C8T6+DM9051实现以太网功能 www.youwenfan.com/contentcsu/160933.html

四、系统测试

1. 测试工具

  • 网络调试助手(如NetAssist):测试TCP/UDP通信

  • Ping命令 :测试网络连通性(如ping 192.168.1.100

  • Wireshark:抓包分析网络数据

2. 测试步骤

  1. 硬件检查:用万用表测量3.3V电源、SPI信号是否正常,网络变压器指示灯是否亮。

  2. 驱动测试:读取DM9051的ID寄存器(0x9051),确认通信正常。

  3. LwIP测试 :通过netif结构体查看IP地址、子网掩码是否正确。

  4. 应用测试:用TCP客户端连接开发板的8080端口,发送数据,观察是否回显。

五、优化与注意事项

1. 性能优化

  • SPI速率:提高SPI时钟至18MHz(DM9051支持最高20MHz),加快数据收发。

  • LwIP配置 :使用静态内存分配MEM_LIBC_MALLOC=0),减少堆内存碎片。

  • 中断优先级 :将DM9051的中断优先级设为(如NVIC_PriorityGroup_2,抢占优先级1),确保数据及时处理。

2. 常见问题解决

  • 无法连接网络:检查MAC地址、IP地址是否冲突,网络变压器是否接反(TX/RX是否交叉)。

  • 数据丢包 :增大LwIP的接收缓冲区(PBUF_POOL_SIZE),或在DM9051中开启FIFO溢出保护

  • SPI通信错误:用示波器测量SPI的SCK、MOSI、MISO信号,确认时序是否符合DM9051要求(模式0,CPOL=0,CPHA=0)。

六、总结

本设计通过STM32F103C8T6+DM9051+SPI实现了以太网功能,结合LwIP协议栈支持TCP/IP通信,具备低成本、低功耗、易扩展特点。系统可进一步扩展为Web服务器(通过HTTP协议)、MQTT客户端(连接云平台),适用于工业物联网、智能家居等场景。

相关推荐
IT_阿水1 小时前
基于STM32河流水质检测
stm32·单片机·嵌入式硬件
黑白园2 小时前
STM32定时器中断
stm32·单片机·嵌入式硬件
weixin_456808383 小时前
【沁恒蓝牙开发】ADC DMA定时采样、转化
单片机·嵌入式硬件
华普微HOPERF4 小时前
MCU+BLE射频+丰富外设,BLE SoC如何高效传输数据?
单片机·嵌入式硬件
振南的单片机世界4 小时前
时钟开关:不用的外设,把它的时钟关掉,省电!
stm32·单片机·嵌入式硬件
金色光环4 小时前
SCPI添加错误码
stm32·scpi
iCxhust5 小时前
将8088 BootLoader分拆烧写到8086 ROM中
stm32·单片机·嵌入式硬件·51单片机·微机原理
国科安芯5 小时前
商业航天电机控制领域抗辐射 MCU 芯片应用研究
网络·单片机·嵌入式硬件·安全性测试
charlie1145141916 小时前
嵌入式C++工程实践第20篇:GPIO 输入模式内部电路 —— 芯片是如何“听“到外部信号的
开发语言·c++·stm32·单片机