3. 坐标系与姿态运动学

硬件接口设计这块,说白了就是让芯片的SPI模块和外面的传感器、存储器能正常“对话”。很多新手上来就写代码,结果发现数据死活不对——大概率是引脚没配好,或者电气特性没搞明白。我刚开始做项目时也踩过这个坑,后来才意识到,硬件接口才是SPI通信的基石。

3.1 STM32的SPI外设框图解读

先看STM32。它的SPI外设框图,我习惯把它拆成三个部分来看:

  • 时钟生成单元:由波特率发生器、时钟极性和相位控制组成。说白了就是决定SCK的频率和波形。
  • 数据移位单元:包含8/16位移位寄存器和收发缓冲区。数据就是在这里被串行化或并行化的。
  • 控制与状态单元:包括主从模式选择、中断/DMA请求、各种标志位(TXE、RXNE、BSY等)。

我记得有一次调试一个AD7793的SPI通信,数据总是错位。后来查了STM32的参考手册才发现,它的SPI数据寄存器是16位的,而AD7793要求8位数据。嗯,这里要注意:STM32的SPI_DR寄存器在16位模式下,读写操作必须对齐。

关键点:STM32的SPI外设支持主模式和从模式,但大多数传感器应用我们都用主模式。从模式一般用于多机通信或特殊场景。

3.2 ESP32的SPI外设框图解读

ESP32的SPI外设和STM32不太一样。它有三个SPI控制器:SPI0、SPI1和SPI2(也叫HSPI和VSPI)。其中SPI0和SPI1是内部使用的,我们能用的是SPI2。

ESP32的SPI框图有个特点:它支持DMA直连。这意味着大数据传输时,CPU可以解放出来干别的事。我在做摄像头图像采集时就用到了这个特性,效果确实不错。

特性 STM32 SPI ESP32 SPI
控制器数量 1-6个(视型号) 3个(2个可用)
数据位宽 8/16位 8/16/32/64位
DMA支持 可选 内置
时钟频率 最高fPCLK/2 最高80MHz
多片选支持 软件控制 硬件支持

个人经验:ESP32的SPI2默认引脚是GPIO18(SCK)、GPIO19(MISO)、GPIO23(MOSI)、GPIO5(CS)。但你可以通过GPIO矩阵映射到任意引脚——这个灵活性是STM32没有的。

3.3 GPIO复用功能配置

配置SPI引脚,说白了就是告诉芯片:“这几个引脚别当普通IO用,给我当SPI用”。

STM32的配置方式:

// 以STM32F4为例,配置SPI1引脚
GPIO_InitTypeDef GPIO_InitStruct = {0};

// 使能GPIO时钟
__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_SPI1_CLK_ENABLE();

// 配置PA5(SCK), PA6(MISO), PA7(MOSI)为复用功能
GPIO_InitStruct.Pin = GPIO_PIN_5 | GPIO_PIN_6 | GPIO_PIN_7;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF5_SPI1;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

ESP32的配置方式:

// 使用Arduino框架配置SPI引脚
SPI.begin(18, 19, 23, 5);  // SCK, MISO, MOSI, CS

// 或者使用ESP-IDF方式
spi_bus_config_t buscfg = {
    .mosi_io_num = 23,
    .miso_io_num = 19,
    .sclk_io_num = 18,
    .quadwp_io_num = -1,
    .quadhd_io_num = -1,
    .max_transfer_sz = 4096
};
spi_bus_initialize(SPI2_HOST, &buscfg, SPI_DMA_CH_AUTO);

避坑指南:我曾经在STM32上把SPI引脚配成了推挽输出而不是复用推挽,结果SCK波形完全不对。记住:SPI的SCK、MOSI必须配成复用功能,MISO配成复用输入。

3.4 SPI引脚电气特性与上拉电阻选择

电气特性这块,很多人容易忽略。我直接说结论:

  • SCK和MOSI:输出引脚,不需要上拉。但如果你担心浮空,可以加10kΩ下拉。
  • MISO:输入引脚,建议加10kΩ上拉。特别是从设备不驱动MISO时,防止浮空导致误触发。
  • CS:片选信号,必须加10kΩ上拉。防止在设备未选中时浮空,导致误通信。
引脚 方向 推荐上拉 说明
SCK 输出 不需要 主设备驱动,电平确定
MOSI 输出 不需要 主设备驱动,电平确定
MISO 输入 10kΩ上拉 防止浮空,提高抗干扰
CS 输出 10kΩ上拉 防止误选中从设备

个人习惯:我一般会在CS和MISO上各加一个10kΩ上拉电阻。虽然STM32和ESP32内部都有上拉,但外部电阻更可靠,特别是长线传输时。

3.5 PCB布局注意事项

PCB布局这块,我踩过的坑比代码还多。直接上干货:

  1. 信号线等长:SCK、MOSI、MISO这三根线尽量等长,特别是高速SPI(>10MHz)。长度差不要超过信号上升时间的1/10。
  2. 避免直角走线:直角会导致阻抗突变,产生反射。用45度角或圆弧过渡。
  3. 地平面完整:SPI信号线下面要有完整的地平面。不要跨分割,否则信号质量会变差。
  4. 去耦电容:每个SPI设备附近放一个0.1μF去耦电容,靠近电源引脚放置。
  5. 远离干扰源:SPI线不要靠近晶振、DC-DC转换器、大电流走线。

我曾经做过一个项目,SPI通信距离约15cm,用了杜邦线连接。结果10MHz下数据全是错的。后来换成屏蔽线,并在两端加了33Ω串联电阻,问题才解决。长线传输时,串联电阻可以抑制振铃。

3.6 知识结构总览

下面这张图总结了本章的核心内容,你可以把它当作硬件设计的检查清单:

SPI硬件接口设计知识结构 SPI硬件接口设计 外设框图解读 STM32:时钟/移位/控制 ESP32:DMA直连/多控制器 GPIO复用配置 STM32:AF模式/Alternate ESP32:GPIO矩阵映射 电气特性与上拉 SCK/MOSI:无需上拉 MISO/CS:10kΩ上拉 PCB布局注意事项 等长/45度角/地平面 去耦/远离干扰/串联电阻 硬件设计决定SPI通信的成败

硬件接口设计这块,说白了就是三个字:配、拉、布。配好引脚复用,拉好上拉电阻,布好PCB走线。这三步做好了,SPI通信就成功了一大半。