你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

STM32F4系列-SPI通讯应用-十

[复制链接]
STMCU小助手 发布时间:2022-10-24 19:02
这一章来说一说SPI通信,同样的很多模块也用到了SPI通信,比如0.96寸的OLED模块。玩过单片机的小伙伴都知道OLED有4针的也有7针的,4针的就是IIC通信,7针的就是SPI通信。- i0 s3 U5 X# U, I0 P/ e

) V2 M% B% H) D& ^% G
一、 SPI 简介
  SPI 是英语 Serial Peripheral interface 的缩写,顾名思义就是串行外围设备接口。是 Motorola首先在其 MC68HCXX 系列处理器上定义的。SPI 接口主要应用在 EEPROM,FLASH,实时时钟,AD 转换器,还有数字信号处理器和数字信号解码器之间。SPI是一种高速的,全双工,同步的通信总线,并且在芯片的管脚上只占用四根线,节约了芯片的管脚,同时为 PCB 的布局上节省空间,提供方便,正是出于这种简单易用的特性,现在越来越多的芯片集成了这种通信协议,STM32 也有 SPI 接口。SPI通讯使用 3 条总线及片选线,3条总线分别为 SCK、MOSI、MISO、SS。
- G# R4 C: O; Z
2 Y/ T6 {& D) ?" B
微信图片_20221024184115.png : n. `. j+ g0 R. y7 F0 {
  (1) SCK (Serial Clock):时钟信号线,用于通讯数据同步。它由通讯主机STM32产生,决定了通讯的速率,不同的设备支持的最高时钟频率不一样,如STM32的SPI 时钟频率最大为fpclk /2,两个设备之间通讯时,通讯速率受限于低速设备。
0 O. D3 U, Y4 J  (2) MOSI (Master Output, Slave Input):主设备STM32输出/从设备输入引脚。STM32的数据从这条信号线输出,从机由这条信号线读入STM32发送的数据,即这条线上数据的方向为STM32到从机。
6 @' f( Y+ B! o0 i, {  E% h  (3) MISO(Master Input,,Slave Output):主设备STM32输入/从设备输出引脚。STM32从这条信号线读入数据,从机的数据由这条信号线输出到STM32,即在这条线上数据的方向为从机到STM32。: G5 p( E3 V. i4 A: r0 S* e' ?" H1 q
  (4) SS( Slave Select):片选信号线,也称为 NSS、CS。当有多个SPI 从设备与 SPI 主机STM32相连时,设备的其它信号线 SCK、MOSI及 MISO同时并联到相同的 SPI总线上,即无论有多少个从设备,都共同只使用这 3 条总线;而每个从设备都有独立的这一条 NSS 信号线,本信号线独占主机的一个引脚,即有多少个从设备,就有多少条片选信号线。I2C 协议中通过设备地址来寻址、选中总线上的某个设备并与其进行通讯;而 SPI 协议中没有设备地址,它使用 NSS 信号线来寻址,当主机要选择从设备时,把该从设备的 NSS 信号线设置为低电平,该从设备即被选中,即片选有效,接着主机开始与被选中的从设备进行 SPI 通讯。所以SPI通讯以 NSS 线置低电平为开始信号,以 NSS 线被拉高作为结束信号。' O: |3 C8 L. D* w0 D% X. C

! E6 I4 p3 @7 L0 g" e( T' @) S二、 具体代码编写
! t# V# q& g* r4 ^1.SPI引脚初始化
  我们使用 STM32 的 SPI1 的主模式,第一步就要是能 SPI1 的时钟,SPI1 的时钟通过 APB2ENR 的第12位来设置。其次要设置 SPI1 的相关引脚为复用输出,这样才会连接到 SPI1 上否则这些 IO 口还是默认的状态,也就是标准输入输出口。这里我们使用的是 PA5、PA6、PA7 这 3 个,所以设置这三个为复用 IO。
  1. void SPI1_Init(void)
    - |% v( B9 k6 ?1 D
  2. {6 W' v; d: f( P* Z$ W0 o6 ~0 E
  3. GPIO_InitTypeDef GPIO_InitStructure;    * X7 G+ }7 o8 e8 {
  4. RCC_APB2PeriphClockCmd(    RCC_APB2Periph_GPIOA|RCC_APB2Periph_SPI1, ENABLE );  
    9 v1 q) ^# u! X  b( }& v
  5. GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7;) b: s4 d1 k2 M% P( U: B! m  j5 O, }
  6. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;  //复用推挽输出
    - K  {1 Q$ \8 [( ~6 Y3 G6 a
  7. GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;6 a. E! P. C% s# R4 d1 M
  8. GPIO_Init(GPIOA, &GPIO_InitStructure);    , z  h3 x* }7 y& {& F6 T
  9. GPIO_SetBits(GPIOA,GPIO_Pin_5|GPIO_Pin_6|GPIO_Pin_7);
    $ u$ D+ {5 Z1 _5 E0 w0 `
  10. }
复制代码

: `- E; M; U; R2.设置SPI1工作模式
  接下来我们要初始化 SPI1,这在库函数中是通过 SPI_Init 函数来实现的,和STM32的其他外设一样同样需要配置这些参数,使用中我们不需要关心这些具体的设置。设置 SPI1 为主机模式,设置数据格式为 8 位,然设置 SCK 时钟极性及采样方式。并设置 SPI1 的时钟频率(最大 18Mhz),以及数据的格式(MSB 在前还是LSB 在前)。这在库函数中是通过 SPI_Init 函数来实现的。
SPI_InitTypeDef  SPI_InitStructure;( N* _) T7 h. E0 N$ w4 @1 G
SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;//设置SPI单向或者双向的数据模式:SPI设置为双线双向全双工) ]+ {' a! y6 n8 l# F, q9 ]" J! e0 a
  1. SPI_InitStructure.SPI_Mode = SPI_Mode_Master;//设置SPI工作模式:设置为主SPI
    - ^2 h( B0 G6 Q$ o& R2 l; {
  2. SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;//设置SPI的数据大小:SPI发送接收8位帧结构1 P7 L0 L9 T6 H: y5 ?' w
  3. SPI_InitStructure.SPI_CPOL = SPI_CPOL_High;//选择了串行时钟的稳态:时钟悬空高# T* i; P% n. q7 ^; E) r
  4. SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;//数据捕获于第二个时钟沿
    - [# k% c5 d4 }; b! S1 F! [$ G
  5. SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;//NSS信号由硬件(NSS管脚)还是软件(使用SSI位)管理:内部NSS信号有SSI位控制2 P$ Y8 S6 Y. K# u9 h# t. I& P
  6. SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_256;//定义波特率预分频的值:波特率预分频值为256
    0 n# O5 o, y/ T2 V6 P2 N  A: K, V, w
  7. SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;//指定数据传输从MSB位还是LSB位开始:数据传输从MSB位开始
    ) c7 {8 u6 N1 m/ a9 G, O2 M
  8. SPI_InitStructure.SPI_CRCPolynomial = 7;//CRC值计算的多项式
    ! l) F  |/ B/ d. W) \
  9. SPI_Init(SPI1, &SPI_InitStructure); //根据SPI_InitStruct中指定的参数初始化外设SPIx寄存器
复制代码
) _/ w' J8 b6 t, E5 Y
3.使能SPI1
初始化完成之后接下来是要使能 SPI1 通信了,在使能 SPI1 之后,我们就可以开始 SPI 通讯了。
  1. SPI_Cmd(SPI1, ENABLE); //使能SPI外设
复制代码

4 @1 x. f% }, _! j! g
- r/ k2 T; T0 b/ \4.使用SPI读写一个字节

- H: `' C9 x& p, p1 k
  1. u8 SPI1_ReadWriteByte(u8 TxData)
    1 }% J. p' |; K
  2. {          V; F3 ~7 M7 m3 i
  3.     u8 retry=0;                 + H! s& f( q% u  z
  4.     while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET)//检查指定的SPI标志位设置与否:发送缓存空标志位
    ' E1 T: e! G3 W. `% q
  5.     {; D/ z9 f( I  H7 z( p! {9 q
  6.         retry++;
    5 v% [: A$ i7 o! s' p" }
  7.         if(retry>200)return 0;7 ~% p3 ^3 V3 h5 z/ J" p
  8.     }            
      N( O8 r* a4 A( l- R( n
  9.     SPI_I2S_SendData(SPI1, TxData);//通过外设SPIx发送一个数据
    " t) g1 S7 n" _; e6 w% _/ Z7 ]; Y
  10.     retry=0;
    " P- \3 A' j& n* q2 ?' `; @- q
  11.     while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) == RESET)//检查指定的SPI标志位设置与否:接受缓存非空标志位1 K0 ~7 X) ^4 U- C: k  l5 k; {
  12.     {: \. N3 X( Z/ r
  13.         retry++;* u/ r  I( n$ d" v$ F/ Q
  14.         if(retry>200)return 0;
    ! n7 ?  M1 ~7 J2 s+ M' A
  15.     }                              
    % J3 Y/ m& s; ~' A8 G  \
  16.     return SPI_I2S_ReceiveData(SPI1); //返回通过SPIx最近接收的数据                     
    $ t& S$ y7 K4 t3 u* e
  17. }
复制代码

3 U1 P6 y7 Z- T8 p
  本函数中不包含 SPI 起始和停止信号,只是收发的主要过程,所以在调用本函数前后要做好起始和停止信号的操作;
. {) @# Z5 n4 p7 }& x  循环调用库函数SPI_I2S_GetFlagStatus 检测事件,若检测到事件,则进入通讯的下一阶段,若未检测到事件则停留在此处一直检测,当检测200次都还没等待到事件则认为通讯失败,退出通讯;
" E, m# R* q7 j. \. F2 j# t8 ]0 Q% p; v  通过检测TXE标志,获取发送缓冲区的状态,若发送缓冲区为空,则表示可能存在的上一个数据已经发送完毕;等待至发送缓冲区为空后,调用库函数 SPI_I2S_SendData 把要发送的数据“TxData”写入到 SPI的数据寄存器 DR,写入 SPI数据寄存器的数据会存储到发送缓冲区,由 SPI外设发送出去;1 g, d3 A1 K/ p7 Q
  写入完毕后通过循环200次等待RXNE 事件,即接收缓冲区非空事件。由于 SPI 双线全双工模式下MOSI 与 MISO 数据传输是同步的,当接收缓冲区非空时,表示上面的数据发送完毕,且接收缓冲区也收到新的数据;
) X$ F5 y+ o4 [. a, r  等待至接收缓冲区非空时,通过调用库函数 SPI_I2S_ReceiveData 读取 SPI 的数据寄存器 DR,就可以获取接收缓冲区中的新数据了。代码中使用关键字“return”把接收到的这个数据作为SPI_SendByte 函数的返回值。9 S- [* B' D1 K' Z
  以上的步骤我们就搞定了SPI 的基本收发单元,还需要了解如何对FLASH 芯片进行读写。FLASH 芯片自定义了很多指令,我们通过控制 STM32 利用 SPI 总线向 FLASH 芯片发送指令,FLASH芯片收到后就会执行相应的操作。而这些指令,对主机端(STM32)来说,只是它遵守最基本的 SPI 通讯协议发送出的数据,但在设备端(FLASH 芯片)把这些数据解释成不同的意义,所以才成为指令。查看FLASH 芯片的数据手册可了解各种它定义的各种指令的功能及指令格式。这里我就不过多的将写了。
* b1 L' [3 ?" W) ]1 N: {

/ z- g. f( K3 d7 v( m转载自: 果果小师弟
' Q2 J& |8 U: m/ T" X# G- V
' a7 p0 [. A- Z" [* G
收藏 评论0 发布时间:2022-10-24 19:02

举报

0个回答
关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版