Cadence与Matlab协同实现GM-ID曲线提取与可视化实战
2026/9/28 19:53:21
SPI(Serial Peripheral Interface,串行外设接口)是一种高速的同步串行通信总线,由Motorola公司开发,广泛应用于单片机与外设之间的短距离高速通信。SPI总线需要4根线(SCK时钟线、MOSI主出从入线、MISO主入从出线、CS片选线),通信速率远高于I2C,可达几十Mbps。STM32F407 系列芯片提供了多达 6 个 SPI 接口,支持多种工作模式和通信速率,可连接各种 SPI 设备,如 Flash 存储器、SD 卡、LCD 显示屏、传感器等。本文从 SPI 的基本原理出发,详细讲解 STM32F407 SPI 的配置方法、代码实现、通信协议以及实际应用案例,帮助你快速掌握 SPI 通信技术。
SPI 是一种同步串行通信总线,主要用于主设备与从设备之间的高速数据传输,其主要特点包括:
关键参数:
STM32F407 系列芯片提供了 6 个 SPI 接口(SPI1-SPI6):
| SPI | 引脚 | 最大通信速率 | 适用场景 |
|---|---|---|---|
| SPI1 | PA5(SCK), PA6(MISO), PA7(MOSI), PA4(NSS) | 42MHz | 主要SPI接口,支持高速模式 |
| SPI2 | PB13(SCK), PB14(MISO), PB15(MOSI), PB12(NSS) | 42MHz | 辅助SPI接口 |
| SPI3 | PB3(SCK), PB4(MISO), PB5(MOSI), PA15(NSS) | 42MHz | 辅助SPI接口 |
| SPI4 | PE2(SCK), PE5(MISO), PE6(MOSI), PE4(NSS) | 42MHz | 辅助SPI接口 |
| SPI5 | PF7(SCK), PF8(MISO), PF9(MOSI), PF6(NSS) | 42MHz | 辅助SPI接口 |
| SPI6 | PG13(SCK), PG12(MISO), PG14(MOSI), PG8(NSS) | 42MHz | 辅助SPI接口 |
关键特性:
SPI 通信的基本流程包括:
SPI 支持四种时钟模式,由 CPOL(Clock Polarity,时钟极性)和 CPHA(Clock Phase,时钟相位)决定:
模式0(CPOL=0, CPHA=0):
模式1(CPOL=0, CPHA=1):
模式2(CPOL=1, CPHA=0):
模式3(CPOL=1, CPHA=1):
SPI 支持两种数据传输格式:
全双工模式:
半双工模式:
以 SPI1 为例,使用标准库配置 SPI 的基本步骤:
#include"stm32f4xx.h"#defineSPI_SPEED10000000// SPI通信速率:10MHz/** * @brief 初始化SPI1 * @param 无 * @retval 无 */voidSPI1_Init(void){GPIO_InitTypeDef GPIO_InitStructure;SPI_InitTypeDef SPI_InitStructure;// 1. 使能时钟RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA,ENABLE);RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1,ENABLE);// 2. 配置GPIO// SCK, MISO, MOSIGPIO_InitStructure.GPIO_Pin=GPIO_Pin_5|GPIO_Pin_6|GPIO_Pin_7;GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF;GPIO_InitStructure.GPIO_OType=GPIO_OType_PP;GPIO_InitStructure.GPIO_PuPd=GPIO_PuPd_UP;GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;GPIO_Init(GPIOA,&GPIO_InitStructure);// NSS(片选,使用软件控制)GPIO_InitStructure.GPIO_Pin=GPIO_Pin_4;GPIO_InitStructure.GPIO_Mode=GPIO_Mode_OUT;GPIO_InitStructure.GPIO_OType=GPIO_OType_PP;GPIO_InitStructure.GPIO_PuPd=GPIO_PuPd_UP;GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;GPIO_Init(GPIOA,&GPIO_InitStructure);// 设置NSS为高电平(不选中)GPIO_SetBits(GPIOA,GPIO_Pin_4);// 3. 将GPIO引脚连接到SPI1GPIO_PinAFConfig(GPIOA,GPIO_PinSource5,GPIO_AF_SPI1);// SCKGPIO_PinAFConfig(GPIOA,GPIO_PinSource6,GPIO_AF_SPI1);// MISOGPIO_PinAFConfig(GPIOA,GPIO_PinSource7,GPIO_AF_SPI1);// MOSI// 4. 配置SPI1SPI_InitStructure.SPI_Direction=SPI_Direction_2Lines_FullDuplex;// 全双工模式SPI_InitStructure.SPI_Mode=SPI_Mode_Master;// 主模式SPI_InitStructure.SPI_DataSize=SPI_DataSize_8b;// 8位数据SPI_InitStructure.SPI_CPOL=SPI_CPOL_Low;// 时钟极性:低电平SPI_InitStructure.SPI_CPHA=SPI_CPHA_1Edge;// 时钟相位:第一个边沿SPI_InitStructure.SPI_NSS=SPI_NSS_Soft;// 软件片选SPI_InitStructure.SPI_BaudRatePrescaler=SPI_BaudRatePrescaler_4;// 分频系数:4SPI_InitStructure.SPI_FirstBit=SPI_FirstBit_MSB;// MSB先传输SPI_InitStructure.SPI_CRCPolynomial=7;// CRC多项式SPI_Init(SPI1,&SPI_InitStructure);// 5. 使能SPI1SPI_Cmd(SPI1,ENABLE);}/** * @brief SPI发送和接收一个字节 * @param SPIx: SPI接口,如SPI1、SPI2等 * @param data: 要发送的数据 * @retval 接收到的数据 */uint8_tSPI_TransferByte(SPI_TypeDef*SPIx,uint8_tdata){// 等待发送缓冲区为空while(SPI_I2S_GetFlagStatus(SPIx,SPI_I2S_FLAG_TXE)==RESET);// 发送数据SPI_I2S_SendData(SPIx,data);// 等待接收缓冲区非空while(SPI_I2S_GetFlagStatus(SPIx,SPI_I2S_FLAG_RXNE)==RESET);// 返回接收到的数据returnSPI_I2S_ReceiveData(SPIx);}/** * @brief SPI发送数据 * @param SPIx: SPI接口,如SPI1、SPI2等 * @param data: 要发送的数据数组 * @param length: 数据长度 * @retval 无 */voidSPI_SendData(SPI_TypeDef*SPIx,uint8_t*data,uint16_tlength){uint16_ti;for(i=0;i<length;i++){SPI_TransferByte(SPIx,data[i]);}}/** * @brief SPI接收数据 * @param SPIx: SPI接口,如SPI1、SPI2等 * @param data: 存储接收数据的数组 * @param length: 数据长度 * @retval 无 */voidSPI_ReceiveData