STM32——SPI

  • SPI协议
  • SPI接口
  • SPI接口框图
  • SPI工作原理
  • 时钟信号的相位和极性
    • CPHA = 0
    • CPHA = 1
  • SPI中断
    • 状态标志
      • 发送缓存器空闲标志(TXE)
      • 接收缓冲器非空(RXNE)
      • 忙BUSY标志
  • SPI引脚配置
  • 从设备引脚管理(NSS)
    • ①软件模式:
    • ②硬件模式:
  • SPI结构体
  • SPI配置过程
    • ①配置引脚,使能时钟
    • ②初始化SPI,设置工作模式
    • ③使能SPIx
    • ④SPI传输数据
    • ⑤查看SPI传输状态
  • 整合
    • 初始化SPI
  • 读写字节
    • 设置SPI的波特率
    • spi.h
    • spi.c

SPI协议

SPI是英语Serial Peripheral interface的缩写,顾名思义就是串行外围设备接口。是Motorola首先在其MC68HCXX系列处理器上定义的。

SPI,是一种高速的,全双工,同步的通信总线,并且在芯片的管脚上只占用四根线,节约了芯片的管脚,同时为PCB的布局上节省了空间,提供方便,主要应用在EEPROM,FLASH,实时时钟,AD转换器还有数字信号处理直接。

SPI接口

SPI总线包括4条逻辑线,定义如下:

MISO:Master input slave output 主机输入,从机输出(数据来自从机);

MOSI:Master output slave input 主机输出,从机输入(数据来自主机);

SCLK:Serial Clock 串行时钟信号,由主机产生发送给从机;SCLK也可以是SCK

SS:Slave Select 片选信号,由主机发送,以控制与哪个从机通信,通常是低电平有效信号。

SPI接口框图

SPI工作原理

①硬件为四根线。

②主机和从机都有一个串行移位寄存器,主机通过SPI的串行移位寄存器写入一个字节发送一次传输。

③串行移位寄存器通过MOSI信号线将字节发送给从机,从机将自己的串行移位寄存器的内容通过MISO返回给主机,这样两个移位寄存器的内容被交换。

④外设的读写操作同步完成,只进行写操作,则忽略读操作;主机只进行从机的读操作,则主机须发送一个空字节给从机引发传输。

时钟信号的相位和极性

SPI_CR寄存器的CPOL和CPHA位,能够组合成四种可能的时序关系,CPOL(时钟极性)位控制在没有数据传输时时钟的空闲状态电平,此位对主模式和从模式下的设备都有效。如果CPOL被清’0’,SCK引脚在空闲状态下保持低电平;如果CPOL被置‘1’,SCK引脚在空闲状态保持高电平。

CPHA = 0

如果CPHA位被清0,SCK时钟的第一个边沿(0为下降沿,1为上升沿)进行数据位采集,数据在第一个时钟边沿被锁存。

CPHA = 1

如果CPHA(时钟相位)位被置‘1’,SCK时钟的第二个边沿(0为下降沿,1为上升沿)进行数据位的采样,数据在第二个时钟边沿被锁存.

SPI中断

状态标志

通过三个标志可以完全监控SPI总线的状态

发送缓存器空闲标志(TXE)

此标志为1的时候,表示发送缓冲寄存器为空,可以写入下一个待发送数据进入缓冲器中,当写入SPI_DR(数据寄存器)时,TXE标志被清除。

接收缓冲器非空(RXNE)

此标志为1表明接收缓冲器中包含有效数据,读SPI数据寄存器可以清楚此标志。

忙BUSY标志

BSY标志由硬件设置与清楚,此标志表明SPI通信层的状态。

SPI引脚配置

从设备引脚管理(NSS)

①软件模式:

可以设置SPI_CR1寄存器的SSM位来使能这种模式,在这种模式下NSS引脚可以用作它用,而内部NSS信号电平可以通过写SPI_CR1的SSI位来驱动。

②硬件模式:

第一种情况:NSS输出使能,当STM32工作为SPI模式的时,NSS输出已经通过SPI_CR2寄存器的SSOE位使能,这时NSS引脚被拉低,所有NSS引脚与这个主SPI的NSS引脚相连并配置为硬件NSS的SPI设备,将自动变成从的SPI设备。

第二种情况:NSS输出被关闭:允许操作于多主环境。

SPI结构体

typedef struct
{uint16_t SPI_Direction;           //方向   uint16_t SPI_Mode;                //模式uint16_t SPI_DataSize;            //数据大小uint16_t SPI_CPOL;                //时钟极性uint16_t SPI_CPHA;                //时钟相位uint16_t SPI_NSS;                 //NSS位uint16_t SPI_BaudRatePrescaler;   //波特率uint16_t SPI_FirstBit;            //选择数据传送方向高位开始还是低位开始    uint16_t SPI_CRCPolynomial;       //CRC校验位
}SPI_InitTypeDef;

SPI配置过程

①配置引脚,使能时钟

void GPIO_Init(GPIO_TypeDef* GPIOx, GPIO_InitTypeDef* GPIO_InitStruct);

②初始化SPI,设置工作模式

void SPI_Init(SPI_TypeDef* SPIx, SPI_InitTypeDef* SPI_InitStruct);

③使能SPIx

void SPI_Cmd(SPI_TypeDef* SPIx, FunctionalState NewState);

④SPI传输数据

void SPI_I2S_SendData(SPI_TypeDef* SPIx, uint16_t Data);
uint16_t SPI_I2S_ReceiveData(SPI_TypeDef* SPIx);

⑤查看SPI传输状态

FlagStatus SPI_I2S_GetFlagStatus(SPI_TypeDef* SPIx, uint16_t SPI_I2S_FLAG);

整合

初始化SPI

#include "SPI.h"
#include "stm32f10x.h"void SPI2_Init(void)//SPI2初始化   主模式
{SPI_InitTypeDef  SPI_InitStructure;GPIO_InitTypeDef GPIO_InitStructure;/* Enable SPI1 and GPIOA clocks */RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2,ENABLE);/* Configure SPI1 pins: NSS, SCK, MISO and MOSI */GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15;//SCK MOSI GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;//PB13/14/15复用推挽输出                GPIO_Init(GPIOB, &GPIO_InitStructure);GPIO_SetBits(GPIOB,GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15);//PB13/14/15上拉/* SPI2 configuration */ SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex; //SPI2设置为两线全双工SPI_InitStructure.SPI_Mode = SPI_Mode_Master;                     //设置SPI2为主模式SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;                  //SPI发送接收8位帧结构SPI_InitStructure.SPI_CPOL = SPI_CPOL_High;                          //串行时钟在不操作(空闲)时,时钟为高电平SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;                    //第二个时钟沿开始采样数据(此处为上升沿采集数据)SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;                          //NSS信号由软件(使用SSI位)管理SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_8; //定义波特率预分频的值:波特率预分频值为8,分频后为9MHZSPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;                 //数据传输从MSB位开始  高位SPI_InitStructure.SPI_CRCPolynomial = 7;                          //CRC值计算的多项式SPI_Init(SPI2, &SPI_InitStructure);/* Enable SPI2  */SPI_Cmd(SPI2, ENABLE);                                            //使能SPI1外设
}

读写字节

u8 SPI2_ReadWriteByte(u8 Data)
{unsigned char t = 0;while(SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_TXE) == RESET){t++;if(t>=200){return 0;}}SPI_I2S_SendData(SPI2, Data);while(SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_RXNE) == RESET){t++;if(t>=200){return 0;}}return SPI_I2S_ReceiveData(SPI2);}

设置SPI的波特率

void SPI2_SetSpeed(u8 SPI_BaudRatePrescaler)
{assert_param(IS_SPI_BAUDRATE_PRESCALER(SPI_BaudRatePrescaler));SPI2->CR1 &= 0XFFC7; //&1111 1111 1100 0111 把D3~D4清零SPI2->CR1 |= SPI_BaudRatePrescaler; //这里是把SPI_BaudRatePrescaler的值与SPI2->CR1中的值按2进制的方式相加//如果SPI_BaudRatePrescaler的值为0x038,二进制数为00111000与1111 1111 1100 0111相或后结果是1111 1111 1111 1111->0XFFFF; SPI_Cmd(SPI2, ENABLE);}

spi.h

#ifndef __spi_h__
#define __spi_h__#include "stm32f10x.h"void SPI2_Init(void) ;//SPI2初始化   主模式
u8  SPI2_ReadWriteByte(u8 dat);
void SPI2_SetSpeed(u8 SPI_BaudRatePrescaler);#endif

spi.c

#include "spi.h"
#include "stm32f10x.h"void SPI2_Init(void)//SPI2初始化   主模式
{SPI_InitTypeDef  SPI_InitStructure;GPIO_InitTypeDef GPIO_InitStructure;/* Enable SPI1 and GPIOA clocks */RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2,ENABLE);/* Configure SPI1 pins: NSS, SCK, MISO and MOSI */GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15;//SCK MOSI GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;//复用推挽                GPIO_Init(GPIOB, &GPIO_InitStructure);GPIO_SetBits(GPIOB,GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15);/* SPI2 configuration */ SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex; //SPI2设置为两线全双工SPI_InitStructure.SPI_Mode = SPI_Mode_Master;                       //设置SPI2为主模式SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;                  //SPI发送接收8位帧结构SPI_InitStructure.SPI_CPOL = SPI_CPOL_High;                          //串行时钟在不操作(空闲)时,时钟为低电平SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;                    //第一个时钟沿开始采样数据(此处为上升沿采集数据)SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;                          //NSS信号由软件(使用SSI位)管理SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_8; //定义波特率预分频的值:波特率预分频值为8,分频后为9MHZSPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;                 //数据传输从MSB位开始  高位SPI_InitStructure.SPI_CRCPolynomial = 7;                          //CRC值计算的多项式SPI_Init(SPI2, &SPI_InitStructure);/* Enable SPI2  */SPI_Cmd(SPI2, ENABLE);                                            //使能SPI1外设
}//SPIx 读写一个字节
//返回值:读取到的字节
//#define SPI_RW  SPI1_ReadWriteByte //代替函数名,以便适用于后面函数u8 SPI2_ReadWriteByte(u8 Data)
{unsigned char t = 0;while(SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_TXE) == RESET){t++;if(t>=200){return 0;}}SPI_I2S_SendData(SPI2, Data);while(SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_RXNE) == RESET){t++;if(t>=200){return 0;}}return SPI_I2S_ReceiveData(SPI2);}void SPI2_SetSpeed(u8 SPI_BaudRatePrescaler)
{assert_param(IS_SPI_BAUDRATE_PRESCALER(SPI_BaudRatePrescaler));SPI2->CR1 &= 0XFFC7; //&1111 1111 1100 0111 把D3~D4清零SPI2->CR1 |= SPI_BaudRatePrescaler; //这里是把SPI_BaudRatePrescaler的值与SPI2->CR1中的值按2进制的方式相加//如果SPI_BaudRatePrescaler的值为0x038,二进制数为00111000与1111 1111 1100 0111相或后结果是1111 1111 1111 1111->0XFFFF; SPI_Cmd(SPI2, ENABLE);}

17. STM32——SPI硬件相关推荐

  1. STM32 SPI 软件NSS和硬件NSS解读

    [导读] SSM可以控制内部NSS引脚与SSI(一个寄存器,软件模式)相连,还是与NSS外部引脚(真正的STM32引脚,硬件模式)相连.真正作用的是内部NSS引脚(内部NSS引脚才真正连接到SPI通信 ...

  2. stm32 spi nss硬件模式配置参考程序

    By: Ailson Jack Date: 2020.11.27 个人博客:http://www.only2fire.com/ 本文在我博客的地址是:http://www.only2fire.com/ ...

  3. STM32 SPI NSS 引脚为不能拉高问题

    使用过 STM32 的SPI 的朋友可能都会发现一个问题,那就是其NSS引脚 在硬件模式下无法自动拉高,可能也因为这个原因致使  .大部分朋友在使用SPI时候都是优先选用软件 控制NSS引脚的工作模式 ...

  4. STM32 SPI难点浅析

    我用的是战舰STM32开发板,两个知识点,一:是STM32 SPI的原理:二:用STM32自带的SPI对外部flash(W25Q64)的读写. 一:STM32 SPI的原理       先上图: 主模 ...

  5. 17章 SPI控制器(XIlinx ZYNQ-7000 SOC UG-585文档)

    第17章 SPI控制器 注:本文为笔者自己翻译的XILINX ZYNQ-7000 SOC UG-585官方文档,文档版本UG585 (v1.12.2) July 1, 2018 文章目录 第17章 S ...

  6. STM32——SPI接口

    STM32--SPI接口 宗旨:技术的学习是有限的,分享的精神是无限的. 一.SPI协议[SerialPeripheral Interface] 串行外围设备接口,是一种高速全双工的通信总线.在ADC ...

  7. stm32 SPI、FLASH

    main.c FLASH:掉电后数据不丢失,U 盘.SD 卡.SSD 固态硬盘.STM32 芯片内部用于存储程序的设备,都是 FLASH 类型的存储器.FLASH芯片(W25Q64)是一种使用 SPI ...

  8. stm32 SPI架构

    STM32 芯片集成了专门用于 SPI 协议通讯的外设. 通讯引脚:SPI 硬件架构从 MOSI.MISO.SCK 及 NSS 线展开:STM32 芯片有多个 SPI 外设,它们的 SPI 通讯信号引 ...

  9. STM32 SPI NSS 作用

    STM32 SPI NSS 作用 原创 2017年06月16日 11:18:14 142 SSM可以控制内部NSS引脚与SSI(一个寄存器,软件模式)相连,还是与NSS外部引脚(真正的STM32引脚, ...

最新文章

  1. Android的Application的生命周期方法
  2. 元宇宙教不会区块链赚钱
  3. CDN视频流中的3个问题以及解决方法
  4. 2021CSP:游记
  5. 防火墙阻止网页连接网络连接_win7电脑打不开网页怎么办 win7电脑打不开网页解决步骤【图文步骤】...
  6. Android开发之AudioManager(音频管理器)详解
  7. 深度学习与计算机视觉教程(17) | 深度强化学习 (马尔可夫决策过程,Q-Learning,DQN)(CV通关指南·完结)
  8. python句柄无效_使用pyinstaller打包,subprocess报“句柄无效”错误的解决方法
  9. 日记 [2006年06月06日] 庞加莱猜想
  10. RW文档翻译学习——RW-BLE-KERNEL核心函数功能
  11. Mysql基础篇(2)—— 单行函数和聚合函数
  12. 群晖emby服务端下载(弃坑,官网已经能顺畅访问)
  13. 国内自由下载jar包的地址
  14. Bootstrap整体架构
  15. 删除文件后,磁盘可用空间并没有释放怎么办?
  16. java 反射为何耗性能_Java反射的性能成本
  17. 如何将一个现有的Vue网页项目封装成electron桌面应用(转载)
  18. 《电路分析导论(原书第12版)》一导读
  19. 高精度加法(C++基础算法)
  20. 拥挤的自动驾驶赛道,谁会成为最终赢家

热门文章

  1. python加速度算位移,计算加速度给定速度
  2. IDEA的Maven Show Dependency使用心得
  3. java基础-Idea的使用和方法
  4. ESP32S2 固件烧录需满足的硬件环境整理
  5. [安卓开发Android][叠层 层叠 卡片效果]RecyclerView与CardView的混合使用
  6. 解决双显卡笔记本安装XP系统后独立显卡无法驱动的问题!Win7双显卡笔记本换XP系统如何安装独立显卡驱动!
  7. 2017计算机应用期末考核,2017年秋季计算机应用基础期末考核作业.pdf
  8. vs使用未初始化的内存怎么解决_C语言内存管理(转载)
  9. Flask(十二)——消息闪现
  10. ps -ef|grep tomcat是啥意思呢?(☆)