SPI 通信从入门到精通:时序、硬件、外设实战 一站式全解析

SPI通信

SPI通信的基础知识

对比I2C与SPI通信协议
特性I2CSPI
通信速度标准模式 100kHz,快速模式 400kHz,高速模式 3.4MHz(普及度低)无严格限制,取决于芯片设计(如 W25Q64 支持 80MHz)
硬件复杂度需开漏输出 + 上拉电阻,仅 2 根线(SDA、SCL)至少 4 根线(SCK、MOSI、MISO、SS),每新增 1 个从机需 1 根 SS 线
软件复杂度包含寻址、应答位、半双工切换等复杂逻辑全双工设计,无需寻址,时序简单
功能特性支持多主机、总线仲裁、单总线双向通信仅支持单主机 + 多从机,无应答机制,全双工单向通信
典型场景低速、多设备场景(如传感器、EEPROM)高速、少设备场景(如 Flash、SD 卡、显示屏)
比喻“精打细算的优雅型”(资源高效,功能复杂)“有钱任性的效率型”(牺牲资源换速度)
SPI 通信线与协议特征
  1. 四根核心通信线
    • SCK(串行时钟线):主机输出时钟信号,控制数据收发时序(上升沿 / 下降沿触发移位)。
    • MOSI(主机输出 / 从机输入):主机向从机发送数据的专用通道。
    • MISO(主机输入 / 从机输出):从机向主机返回数据的专用通道。
    • SS(从机选择线,低电平有效):主机通过多根 SS 线独立选中从机(1 个从机对应 1 根 SS 线),无需寻址。
  2. 协议核心特征
    • 同步全双工:时钟线(SCK)同步数据传输,MOSI 和 MISO 独立传输,可同时发送和接收数据。
    • 单主机多从机模型:仅支持 1 个主机,从机通过 SS 线单独激活,同一时刻仅 1 个从机通信。
    • 无应答机制:主机不验证从机是否存在或数据是否接收,需上层协议保证可靠性。
SPI 应用场景与典型器件
  1. Flash 存储器(W25Q64)
    • 引脚映射:CLK=SCK,DI=MOSI,DO=MISO,CS=SS,用于存储大量掉电不丢失数据。
  2. OLED 显示屏
    • 通过 SPI 传输像素数据,引脚名称可能非标准(如用 DIO 代替 MOSI/MISO),需查阅手册确认。
  3. 2.4G 无线模块(NRF24L01)
    • 通过 SPI 读写寄存器配置无线参数,实现设备间通信。
  4. microSD 卡
    • 原生支持 SDIO 协议,兼容 SPI 模式,用于低成本存储扩展。

硬件电路

SPI 硬件电路设计
  1. 典型连接方式
    • 主机侧:引出 SCK、MOSI、MISO 共 3 根公共线,搭配 N 根 SS 线(N 为从机数量)。
    • 从机侧:所有从机的 SCK、MOSI、MISO 分别并联,SS 线独立连接主机。
    • 供电与接地:从机需与主机共地(GND),无独立供电时由主机提供 VCC。
  2. 引脚配置与驱动能力
    • 输出引脚(SCK、MOSI、SS):配置为推挽输出,高低电平驱动能力强,信号边沿陡峭,支持高速传输(兆赫兹级)。
    • 输入引脚(MISO):主机配置为浮空 / 上拉输入,从机未选中时(SS = 高)MISO 需切换为高阻态,避免多从机输出冲突。

移位示意图

SPI 数据传输原理:移位寄存器模型
  1. 核心机制:字节交换
    • 主机和从机各内置一个8 位移位寄存器,通过 SCK 时钟同步移位。
    • 时钟上升沿:寄存器左移一位,最高位通过 MOSI/MISO 输出到通信线。
    • 时钟下降沿:采样通信线上的信号,最低位存入寄存器。
    • 完整流程:8 个时钟周期完成一个字节交换,主机发送的数据传入从机,从机数据传入主机。
  2. 数据收发策略
    • 仅发送:调用字节交换时序,忽略接收数据。
    • 仅接收:发送固定值(如 0X00/0XFF),置换从机数据后读取。
    • 特点:全双工设计导致单方向传输时存在资源浪费(如仅发送时仍需接收空数据)。

SPI时序基本单元

CPOL控制极性:

CPOL = 0:空闲状态,SCK为低电平

CPOL = 1:空闲状态,SCK为高电平

CPHA控制时序:

CPHA = 0:第一个边沿之前就将数据移出,可以看做在第0个边沿将数据移出,第一个边沿将数据移入。

CPHA = 1:第一个边沿将数据移出,第二个边沿将数据移入。

SPI时序

发送指令3

向SS指定的设备,发送指令(0x06)

指定地址写

向SS指定的设备,发送写指令(0x02), 随后在指定地址(Address[23:0])下,写入指定数据(Data)

![外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传](https://img-home.csdnimg.cn/images/20230724024159.png?

指定地址读

向SS指定的设备,发送读指令(0x03), 随后在指定地址(Address[23:0])下,读取从机数据(Data)

origin_url=STM32.assets%2Fimage-20250524104700333.png&pos_id=img-bjy9ajQz-1749173726581)

软件实现SPI基本时序代码

//MySPI.c

#include "stm32f10x.h"                  // Device header

void MYSPI_W_SS(uint8_t BitValue)
{
	GPIO_WriteBit(GPIOA, GPIO_Pin_4, (BitAction)BitValue);
}

void MYSPI_W_SCK(uint8_t BitValue)
{
	GPIO_WriteBit(GPIOA, GPIO_Pin_5, (BitAction)BitValue);
}

uint8_t MYSPI_R_MISO(void)
{
	return GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_6);
}

void MYSPI_W_MOSI(uint8_t BitValue)
{
	GPIO_WriteBit(GPIOA, GPIO_Pin_7, (BitAction)BitValue);
}

void MySpi_Init(void)
{
	//初始化GPIO口,主机输出引脚配置为推挽模式,输入引脚配置为上拉输入
	//选择GPIO456为输出引脚 7为输入引脚
	//开启gpio时钟信号
   RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
	//初始化gpioinit参数中的结构体
	GPIO_InitTypeDef GPIO_InitStructure;
	//将gpio口设置为推挽输出
	GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP;
	//初始化两个端口
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_7;
	GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
	GPIO_Init(GPIOA,&GPIO_InitStructure);
	
	//将gpio口设置上拉输出
	GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IPU;
	//初始化两个端口
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
	GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
	GPIO_Init(GPIOA,&GPIO_InitStructure);
	
	//配置为GPIO口之后要将 各个线置初始值
	MYSPI_W_SS(1);
	//看模式选择,这里以模式0为例
	MYSPI_W_SCK(0);
}

void MYSPI_Start(void)
{
	MYSPI_W_SS(0);
}
void MYSPI_Stop(void)
{
	MYSPI_W_SS(1);
}
uint8_t MYSPI_SwapData(uint8_t Data)
{
	uint8_t i, ByteReceive = 0x00;
	//ss置0之后直接将数据放在MOSI线上
	for (i = 0; i < 8; i ++)
	{
		MYSPI_W_MOSI(Data & (0x80 >> i));
		MYSPI_W_SCK(1);
		//时钟置一交换数据
		if (MYSPI_R_MISO() == 1){ByteReceive |= (0x80 >> i);}
		MYSPI_W_SCK(0);
	}
	
	return ByteReceive;
}

SPI外设简介

SPI外设基础

1. 硬件 SPI 电路功能(核心优势)

  • 硬件自动处理
    STM32 内部集成硬件 SPI 收发电路,可自动生成时钟(SCK)、控制数据收发(MOSI/MISO),无需 CPU 实时干预(如软件 SPI 需手动翻转 GPIO 电平)。
    • 对比软件 SPI:硬件 SPI 节省 CPU 资源(如发送 1 字节仅需 1 个寄存器操作,软件需 4-8 条 GPIO 指令),传输速度提升(最高 36MHz vs 软件 SPI 的 1-2MHz)。
    • 典型场景:高频数据传输(如 SPI Flash 读写、高速传感器通信)时,硬件 SPI 是唯一可行方案。
  • 寄存器与模块协作
    移位寄存器(自动处理数据移位)、波特率发生器(分频 PCLK 生成 SCK)、数据缓冲区(TDR/RDR)配合工作,实现 “发送 - 接收” 流水线操作(如发送当前字节时,可准备下一字节写入缓冲区,提升连续传输效率)。

2. 数据帧配置(8 位 / 16 位,高低位先行)

  • 数据长度
    • 8 位(默认):通信以字节为单位,兼容大多数 SPI 设备(如 W5500、ADXL345 等),代码实现简单(直接操作 uint8_t 类型)。
    • 16 位:适用于需双字节对齐的场景(如部分 LCD 驱动的命令传输),但需注意从设备是否支持(实际应用较少,需额外处理数据拆分 / 合并)。
  • 传输顺序
    • 高位先行(MSB First):SPI 标准模式,与 FMC、SPI 协议兼容(如 0x34 → 先传0011高位部分)。
    • 低位先行(LSB First):通过LSBfirst位配置(如串口通信常用,STM32 中需明确从设备需求,否则会导致数据错误)。

3. 时钟频率(分频与 SPI1/SPI2 差异)

  • 分频计算
    SCK 频率 = f_PCLK / 分频系数(2、4、8…256),例:
    • SPI1(APB2,72MHz):最大频率 72/2=36MHz(适合高速设备)。
    • SPI2(APB1,36MHz):最大频率 36/2=18MHz(适合中速设备,如 SD 卡低速模式)。
  • 选择策略
    • 从设备最大支持频率决定分频系数(如 W5500 支持 25MHz,SPI1 可设为72/3=24MHz,留有余量)。
    • 高频传输时,需检查 PCB 布线(SCK 线短、阻抗匹配),避免信号失真。

4. 多主机模型与通信模式

  • 多主机模式(硬件 NSS)
    通过 NSS 引脚实现主机竞争(输出低电平声明主机,输入低电平响应其他主机),但实际中多用 GPIO 模拟片选(CS)(如 PA4 控制从机,简化代码,避免硬件 NSS 的复杂配置)。
  • 通信模式精简
    • 半双工:分时复用 MOSI(发送 / 接收切换),节省 1 根引脚(如仅需单向传输时,MISO 可复用为 GPIO)。
    • 单工:仅发送(MOSI)或仅接收(MISO),适用于单向数据流(如 SPI 从机仅回传数据,无需主机发送)。

5. DMA 支持与 I2S 兼容

  • DMA 传输
    配置 SPI_DMA 使能后,可批量传输数据(如数组、缓冲区),CPU 只需初始化传输,后续由 DMA 自动处理(减少中断开销,提升大数据量传输效率,如 LCD 图像显示、音频流传输)。
  • I2S 协议兼容(STM32F103C8T6 特性)
    • 功能:支持数字音频信号传输(与 I²C 无关联,I2S 专注音频,SPI 专注通用串行通信)。
    • 注意:STM32F103C8T6 的 SPI 外设仅部分型号支持 I2S(需查阅手册确认,实际开发中若涉及音频,优先使用专用 I2S 外设)。

6. SPI 资源(SPI1、SPI2 引脚与特性)

  • SPI1(APB2,高速)
    • 引脚:PA5(SCK)、PA6(MISO)、PA7(MOSI)、PA4(NSS,可重映射至 PB3-5,需禁用 JTAG)。
    • 特性:高频优先(如连接高速 SPI Flash、以太网 PHY)。
  • SPI2(APB1,中速)
    • 引脚:PB13(SCK)、PB14(MISO)、PB15(MOSI)、PB12(NSS)。
    • 特性:与低速外设(如 SD 卡、传感器)配合,避免占用高速 APB2 总线资源。

SPI框图

1. 数据传输路径与核心模块

(1)移位寄存器(Shift Register)

  • 功能
    • 实现数据的串行移位(主模式下:MOSI 输出数据右移,MISO 输入数据左移;从模式反之)。
    • 通过LSBFIRST控制位(CR1 寄存器)选择高位先行(MSB First,默认,左移)**或**低位先行(LSB First,右移),匹配从设备时序要求。
  • 会议关联:移位寄存器是硬件 SPI 自动生成时序的核心,无需软件模拟(对比软件 SPI 的手动移位),提升传输效率。

(2)发送 / 接收缓冲区(TDR/RDR)

  • 功能
    • 发送缓冲区(TDR):数据写入后,自动转入移位寄存器发送(置位TXE(发送缓冲区空)标志,CR2 的TXEIE可使能中断)。
    • 接收缓冲区(RDR):移位寄存器接收数据后存入,置位RXNE(接收缓冲区非空)标志(CR2 的RXNEIE可使能中断)。
    • 共享地址(DR 寄存器):写入时操作 TDR,读取时操作 RDR,通过硬件 RDR,通过硬件自动区分(会议中强调需关注TXE/RXNE标志位,避免数据冲突)。
  • 会议关联:缓冲区实现 “发送 - 接收” 流水线(如发送当前字节时,可准备下一字节写入 TDR),支持连续传输(提升高频场景效率)。

(3)波特率发生器(Baud Rate Generator)

  • 功能
    • 输入PCLK(SPI1 为 APB2 时钟,SPI2 为 APB1 时钟),通过CR1寄存器 的BR[2:0]位选择分频系数(2、4、8…256),输出SCK时钟。
    • 与移位寄存器同步,确保数据移位与时钟边沿严格对齐(硬件 SPI 波形紧贴 SCK 边缘,会议中对比软件 SPI 的延迟问题)。
  • 会议关联:SPI1(72MHz PCLK)最高频率 36MHz,SPI2(36MHz PCLK)最高 18MHz,需根据从设备性能配置分频(如低速设备用大分频,避免时序错误)。

2. 控制电路与寄存器功能

(1)CR1 寄存器(主控制寄存器)

  • 关键位
    • SPE(SPI 使能)、MSTR(主模式,1 = 主机,0 = 从机)、CPOL/CPHA(时钟极性 / 相位,配置 SPI 模式 0-3)。
    • BR[2:0](波特率分频)、LSBFIRST(传输顺序)、SSM/SSI(软件 NSS 控制,会议中推荐用软件模拟片选,简化多主机场景)。
  • 会议关联:主从模式切换时,MOSI/MISO 需交叉连接(主机 MOSI→从机 MOSI,主机 MISO←从机 MISO),通过MSTR位配置。

(2)CR2 寄存器(辅助控制寄存器)

  • 关键位
    • TXEIE/RXNEIE(发送 / 接收中断使能,配合 DMA 时需配置)、SSOE(NSS 输出使能,硬件多主机模式用,实际少用)。
  • 会议关联:中断 / DMA 使能用于大数据量传输(如 DMA 模式下,批量数据由硬件自动搬运,减少 CPU 负载)。

(3)SR 寄存器(状态寄存器)

  • 关键位
    • TXE(发送空,可写新数据)、RXNE(接收非空,需读数据)、BUSY(传输中,禁止配置寄存器)、OVR(接收溢出,需清除)。
  • 会议关联:非连续传输时,需轮询TXE/RXNE标志(如代码中while(SPI_I2S_GetFlagStatus(...))),确保数据正确收发。

3. NSS 引脚与多主机模型

  • 功能
    • 硬件多主机模式:NSS 输出低电平声明主机(SSOE=1时,NSS 引脚自动控制),输入低电平表示被其他主机控制(需外部电路连接多设备 NSS)。
    • 实际应用:软件模拟 NSS(CS 引脚)(如 PA4 作为通用 GPIO,通过代码拉低 / 拉高控制从机),避免硬件多主机的复杂配置(会议中强调此方法更灵活,适用于大多数场景)。
  • 会议关联:NSS 引脚在框图中为独立输入,硬件多主机仅作了解,工程中优先用软件片选(简化代码,降低硬件依赖)。

4. 通信电路与模式支持

  • 全双工模式:默认,MOSI(发送)和 MISO(接收)同时工作(框图中双箭头表示双向数据流)。
  • 半双工 / 单工模式:通过BIDIMODE(CR1)配置,分时复用 MOSI(发送 / 接收切换,半双工)或仅用 MOSI/MISO 单方向(单工),节省引脚资源(会议中提到此类精简模式了解即可,全双工为常用场景)。
  • I2S 兼容:部分 SPI 外设(如 STM32F4 系列)可通过配置支持 I2S 协议(数字音频传输),但 STM32F103C8T6 中 SPI 与 I2S 功能需查阅手册确认(会议中指出与 I²C 区别,I2S 专注音频,SPI 为通用串行通信)。

SPI基本结构

左移高位移出去,通过 GPIO 到 MOSI,从 MOSI 输出,显然这是 SPI 的主机,对吧?

之后移入的数据从 MiSO 进来,通过 GPIO 到移位寄存器的低位,这样循环8次,就能实现主机和重机交换一个字节,然后 TDR 和 RDR 的配合可以实现连续的数据流。

另外 TDR 数据整体转入移位寄存器会置 TXE 标志位。

移位寄存器数据整体转读 RDR 的时刻至 RXNE 标志位

然后剩下的部分波特率发生器产生时钟输出到 SCK 引脚。数据控制器就看成是一个管理员,它控制着所有电路的运行,最后开关控制就是 SBI CMD 初始化之后给个 enable 使能整个外设。

另外这里我并没有换 SS 重新选择硬件,这个硬件我们还是使用普通的 GPIO 来模拟即可。在一主多从的模型下,GPIO 模拟的 SS 是最佳选择。

主模式全双工连续传输

1. 连续传输核心机制

  • 流水线操作
    发送(TDR)与接收(RDR)缓冲区配合移位寄存器,实现数据无缝衔接传输(如发送数据 2 时,数据 1 正在移位;接收数据 1 时,数据 2 正在发送),SCK 无间隙,效率达硬件 SPI 极限(对比非连续传输的字节间间隙,会议强调高频场景必用)。
  • 标志位同步
    • TXE(发送空):TDR 空时置位(硬件自动),软件可立即写入下一字节(如示例中写入 0xF2 时,TXE=1,无需等待 0xF1 发送完毕,实现连续填充)。
    • RXNE(接收非空):RDR 有数据时置位(硬件自动),软件需及时读取(如读取 0xA1 后,RXNE 清零,为接收 0xA2 腾出空间,避免溢出)。
    • BSY(忙):传输中置位(硬件自动),禁止寄存器配置(确保传输过程原子性,会议提到配置 SPI 前需等待 BSY=0)。

2. 数据收发流程(主模式全双工)

  • 发送逻辑
    • 写入数据 1(0xF1)→ TDR,TXE 清零(开始传输),BSY 置位。
    • 数据 1 移位发送时,TXE 置位(硬件自动),立即写入数据 2(0xF2)→ TDR(流水线,无间隙)。
    • 数据 2 移位时,写入数据 3(0xF3),实现连续发送(SCK 始终有效,无空闲周期)。
  • 接收逻辑
    • 数据 1(0xA1)经 MISO→移位寄存器→RDR,RXNE 置位(硬件自动),软件读取(清零 RXNE)。
    • 数据 2(0xA2)在数据 1 发送时接收(流水线),RXNE 再次置位,依此类推,实现并行收发(全双工优势,发送与接收同步进行)。

非连续传输

1. 非连续传输原理与特性
  • 字节间间隙:发送完一个字节后,SCK 存在空闲周期(如示例中数据 1、2、3 发送时,SCK 间有明显间隙),导致传输效率低于连续传输。此特性源于软件需等待TXE标志(前一数据发送完毕)后再写入新数据,硬件未形成流水线操作。
  • 标志位控制
    • TXE(发送空):TDR 数据发送后自动置位,软件通过轮询(while(SPI_I2S_GetFlagStatus(...)))确保前一数据发送完毕,再写入新数据(避免缓冲区冲突)。
    • BSY(忙):传输过程中置位,发送完毕后清零,软件需等待 BSY=0 以确认所有数据发送完成(如初始化或配置 SPI 前检查 BSY 状态)。
2. 数据发送流程(主模式全双工)
  • 单字节发送:写入数据→等待 TXE(前一发送完成,首次发送时 TXE 初始为 1)→发送→等待 BSY(当前发送完成)。
  • 多字节非连续发送:每字节发送均需独立轮询 TXE 和 BSY,导致字节间 SCK 间隙(如示例中数据 2、3 写入时,TXE 已置位但软件未及时操作,产生间隙)。代码逻辑简单(4 行核心代码),但效率较低,适合小数据量场景(如传感器命令交互)。
  • 简单来说就是一个发来等读走之后再继续发送的逻辑 (后面会代码实现该模式)

软件/硬件波形对比

在这里插入图片描述

硬件实现SPI基本时序代码

//SPI.c

#include "stm32f10x.h"                  // Device header

void MYSPI_W_SS(uint8_t BitValue)
{
	GPIO_WriteBit(GPIOA, GPIO_Pin_4, (BitAction)BitValue);
}

void MySpi_Init(void)
{
	//1.配置GPIO
	//开启gpio时钟信号
   RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
	//初始化gpioinit参数中的结构体
	GPIO_InitTypeDef GPIO_InitStructure;
	//将gpio口设置为推挽输出 使用软件进行片选操作
	GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP;
	//初始化两个端口
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;
	GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
	GPIO_Init(GPIOA,&GPIO_InitStructure);
	
	//将gpio 6 口设置上拉输出
	GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IPU;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
	GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
	GPIO_Init(GPIOA,&GPIO_InitStructure);
	
	//配置GPIO 5 7 口为复用推挽输出,因为是由片上外设控制GPIO口
	GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_7;
	GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
	GPIO_Init(GPIOA,&GPIO_InitStructure);
	
	//配置SPI1外设
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1,ENABLE);
    //初始化SPI1 
    SPI_InitTypeDef SPI_InitStruct;
    //配置主从模式
    SPI_InitStruct.SPI_Mode = SPI_Mode_Master;
	//配置时钟频率 分频越大 频率越小
    SPI_InitStruct.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_128;
    //使用模式0 空闲为低电平 第一个边沿接受数据
	//相位 配置第几个边沿接受数据
	SPI_InitStruct.SPI_CPHA = SPI_CPHA_1Edge;
	//极性 配置SCK空闲为高还是低电平
    SPI_InitStruct.SPI_CPOL = SPI_CPOL_Low;
	//CRC校验的多项式 默认为7
    SPI_InitStruct.SPI_CRCPolynomial = 7;
    //数据 8 或者 16
	SPI_InitStruct.SPI_DataSize = SPI_DataSize_8b;
    //方向 
	SPI_InitStruct.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
	//配置 高位还是低位先行
    SPI_InitStruct.SPI_FirstBit = SPI_FirstBit_MSB;
	//SS片选
    SPI_InitStruct.SPI_NSS = SPI_NSS_Soft;
    SPI_Init(SPI1, &SPI_InitStruct);
   
	//开启SPI开关
	SPI_Cmd(SPI1, ENABLE);
	//配置完后将片选默认为1,不选中
	MYSPI_W_SS(1);
}

void MYSPI_Start(void)
{
	MYSPI_W_SS(0);
}
void MYSPI_Stop(void)
{
	MYSPI_W_SS(1);
}

//采用非连续传输
uint8_t MYSPI_SwapData(uint8_t Data)
{
	//等待发送寄存器为空
	while(SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET);
	//不用将标志位手动清除 当发送数据会自动清除
	
	//从移位寄存器 发送数据
	SPI_I2S_SendData(SPI1, Data);
	
	//等待接收寄存器为非空
	while(SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) == RESET);
	//当接收数据 会自动将标志位清除
	
	//从移位寄存器 接收数据
	return SPI_I2S_ReceiveData(SPI1);
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值