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

STM32CubeMX-HAL库的SPI接口使用

[复制链接]
STMCU-管管 发布时间:2020-10-19 13:37
STM32CubeMX-HAL库的SPI接口使用
, J2 B* l( }5 B  y  a' {
1 i' V2 E7 f4 L1 H2 z' P% k
本文主要介绍STM32的SPI接口、cubeMX软件配置SPI接口和分析SPI相关代码。
2 w$ t$ J) ~+ f- l' FSTM32之SPI简介:
+ D4 i0 }/ }9 B1 o* qSPI协议【Serial Peripheral Interface】& R; z( t' D% K* h6 y5 i" M
    串行外围设备接口,是一种高速全双工的通信总线。主要用在MCU与FLASH\ADC\LCD等模块之间的通信。

  h; D. k& F/ L  Q3 j  `% CSPI信号线
$ Q0 X( V5 b5 ~3 ~  I8 b" U; W: Z! y    SPI 共包含 4 条总线。
9 R' y$ x  u2 q# D6 x* Y" o9 z
SS(Slave Select):片选信号线,当有多个SPI 设备与 MCU 相连时,每个设备的这个片选信号线是与 MCU 单独的引脚相连的,而其他的 SCK、MOSI、MISO 线则为多个设备并联到相同的 SPI 总线上,低电平有效。
3 b6 g1 v' t: t# g4 tSCK (Serial Clock):时钟信号线,由主通信设备产生,不同的设备支持的时钟频率不一样,如 STM32 的 SPI 时钟频率最大为 f PCLK /2。
0 w$ w  L1 ?; t5 c4 X4 TMOSI (Master Output Slave Input):主设备输出 / 从设备输入引脚。主机的数据从这条信号线输出,从机由这条信号线读入数据,即这条线上数据的方向为主机到从机。
$ U, q. X% h3 d$ g% _6 [2 Z" M) x  BMISO(Master Input Slave Output):主设备输入 / 从设备输出引脚。主机从这条信号线读入数据,从机的数据则由这条信号线输出,即在这条线上数据的方向为从机到主机。
. v: J! a  a5 a' N    其中SCK,MOSI,MISO是接在一起的,NSS分别接到不同的IO管脚控制。主器件要和从器件通信就先拉低对应从器件的NSS管脚使能。默认状态IO1,IO2,IO3全为高电平,当主器件和从器件1通信时,拉低IO1管脚使能从器件1。而从器件2,3不使能,不作响应。下图是主器件与多个从器件通信图。
% y' I+ ^- D& B
11.png
* R7 n  N# m8 e" U
SPI特性( r: l, U$ E& |& n& }
    单次传输可选择为 8 或 16 位。波特率预分频系数(最大为 fPCLK/2) 。时钟极性(CPOL)和相位(CPHA)可编程设置。数据顺序的传输顺序可进行编程选择,MSB 在前或 LSB 在前。
& s1 }+ M8 z8 L7 a$ }4 ?
    注:MSB(Most Significant Bit)是“最高有效位”,LSB(Least Significant Bit)是“最低有效位”。
1 X/ b- d. J7 o. E    可触发中断的专用发送和接收标志。可以使用 DMA 进行数据传输操作。下图是STM32的SPI框架图。3 y  g# D- `% x8 s2 H
12.png
0 w% n5 g+ M. Q* G# W6 {6 |
    如上图,MISO数据线接收到的信号经移位寄存器处理后把数据转移到接收缓冲区,然后这个数据就可以由我们的软件从接收缓冲区读出了。当要发送数据时,我们把数据写入发送缓冲区,硬件将会把它用移位寄存器处理后输出到 MOSI数据线。SCK 的时钟信号则由波特率发生器产生,我们可以通过波特率控制位(BR)来控制它输出的波特率。
! \  `2 C' Q/ ~    控制寄存器 CR1掌管着主控制电路,STM32的 SPI模块的协议设置(时钟极性、相位等)就是由它来制定的。而控制寄存器 CR2则用于设置各种中断使能。
) u* m5 ~% |/ p" i    最后为 NSS引脚,这个引脚扮演着 SPI协议中的SS片选信号线的角色,如果我们把 NSS引脚配置为硬件自动控制,SPI模块能够自动判别它能否成为 SPI的主机,或自动进入 SPI从机模式。但实际上我们用得更多的是由软件控制某些 GPIO引脚单独作为SS信号,这个 GPIO引脚可以随便选择。$ B; j) \$ D9 R) B0 W( R
SPI时钟时序
; |, n4 T/ k, P  X) b- I/ c    根据时钟极性(CPOL)及相位(CPHA)不同,SPI有四种工作模式。# F% [7 |- O3 O. Y6 l* ~
    时钟极性(CPOL)定义了时钟空闲状态电平:) [- h1 y+ U0 s. p& c0 h
CPOL=0为时钟空闲时为低电平
- b1 x% Y- M& ]: n5 gCPOL=1为时钟空闲时为高电平: C; ]3 G2 r& P- ?8 k
    时钟相位(CPHA)定义数据的采集时间。
) b9 k* p( I6 V, ]6 c) y& x7 wCPHA=0:在时钟的第一个跳变沿(上升沿或下降沿)进行数据采样。
, r7 W. P& W' f& t4 I: t+ QCPHA=1:在时钟的第二个跳变沿(上升沿或下降沿)进行数据采样。$ b. C& u! h; e4 [0 j# s, X
13.png
/ \3 P9 P1 F% g; s  \! E
CubeMX软件配置SPI:7 |! U% X2 b$ }2 Y# s8 `0 i+ ^+ n$ _
    下面继续介绍cubeMX软件配置STM32L152的SPI接口方法。
) Z0 ^8 B& }$ f9 R1 _! Z
(1)打开软件,选择对应芯片后,配置好时钟源;, `* p6 e9 Z7 R) F9 v' H! T5 Q; e
(2)勾选SPI1为全双工,硬件NSS关闭,如下图:
! I" [$ ^( Y/ Q% T6 y 14.png 4 `* m1 J" U4 R6 W5 k
(3)勾选好后,PA5、PA6、PA7如下图,在配置PA4为普通io口,gpio_output  j( Y9 D$ R3 z8 x" ~) e' ^
15.png
" X6 u: E( R0 k& I+ V(4)SPI1的参数配置选择默认,如下图所示
0 n: {2 E0 b1 G# r 16.png
$ h% h: ^- Z2 A. y1 I/ }- ?' {(5)生成代码,保存即可。/ y0 M. Q. k+ y6 F, `( V2 H
    HAL库的SPI函数分析:
! o! {8 y9 f0 A; `4 Z) O    下面具体分析下生成的SPI函数和函数调用。
% Z0 q8 w! J" n
SPI_HandleTypeDef hspi1; //SPI结构体类定义,下面看其结构体内部的声明。
17.png
( M+ E4 h& h  x. x% q8 s9 J 18.png ( j$ h) |- z) n1 J' ]- m! _3 a

% r, s8 N2 C3 v; M. i  G
下面分析SPI的初始化函数:# ^3 P! a% l5 n. l' A2 a/ w  G% v
+ P- k) X4 H# X
  1. ) ?- H& T) Y, I: a. Q# I" e
  2. void HAL_SPI_MspInit(SPI_HandleTypeDef* hspi)
    / `9 d$ n( s6 W/ U  ^: v
  3. {
    7 h$ I" Y: x5 ]8 _) e
  4. GPIO_InitTypeDef GPIO_InitStruct;! y4 m* ]; B/ r- g; n" [
  5. if(hspi->Instance==SPI1)
    , @" N% H- F; V7 L9 ~9 Y# _
  6. {+ z6 C9 S+ y+ {
  7. /* USER CODE BEGIN SPI1_MspInit 0 */
    ( c. s8 |# v" _, P% @  B/ v# ]
  8. /* USER CODE END SPI1_MspInit 0 */
    3 D+ b$ x: _5 K! a( [" h5 q- X
  9. /* Peripheral clock enable */
      k- @' S- n' Z8 c' U4 E3 f* k
  10. __HAL_RCC_SPI1_CLK_ENABLE();//使能SPI1时钟2 N! C) ?3 }  X1 Q6 |2 C
  11. /**SPI1 GPIO Configuration" ~4 V+ n% e5 J# r3 Y6 S
  12. PA5     ------> SPI1_SCK% L- Z6 [3 O1 K. k& k' S
  13. PA6     ------> SPI1_MISO, {/ [: R( r6 I0 g) A' c
  14. PA7     ------> SPI1_MOSI6 \* i$ Y6 A8 Y6 V, O; x- U
  15. */1 r. P6 d0 Z& f. S+ o2 P
  16. GPIO_InitStruct.Pin = GPIO_PIN_5|GPIO_PIN_6|GPIO_PIN_7;4 Z. w; f0 D' |  k
  17. GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    - A3 l9 C. q- I4 U  F( Y8 k; L
  18. GPIO_InitStruct.Pull = GPIO_NOPULL;
    ' H2 Y$ w7 h. p/ x+ n) |
  19. GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;/ F0 C% w8 \6 j& H, F
  20. GPIO_InitStruct.Alternate = GPIO_AF5_SPI1;4 D/ N3 w& c9 z+ @
  21. HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);//配置SPI的数据线和时钟线, z8 I* }5 R! f! F4 M/ a
  22. /* USER CODE BEGIN SPI1_MspInit 1 */- e! a" ?' C( q. Z7 Q  X
  23. /* USER CODE END SPI1_MspInit 1 */
    : j% V$ x" H  B, @7 L7 G5 v
  24. }
    0 x& L4 h+ _0 g2 e# G7 T6 m/ G
  25. 8 ^* _( P" [: |( n0 ^
  26. static void MX_SPI1_Init(void)$ l5 v2 h) i: |9 F7 |: T. x' L
  27. {! `2 |6 j9 {/ H
  28. hspi1.Instance = SPI1;
    4 Y2 C9 v' C8 P; f' R" w/ y
  29. hspi1.Init.Mode = SPI_MODE_MASTER;//主模式
    ( T1 S+ h: E/ s* P
  30. hspi1.Init.Direction = SPI_DIRECTION_2LINES;//全双工9 t% S4 G$ Y  L% m4 P
  31. hspi1.Init.DataSize = SPI_DATASIZE_8BIT;//数据位为8位0 D! K# P/ o0 t" a. G; Z
  32. hspi1.Init.CLKPolarity = SPI_POLARITY_LOW;//CPOL=0,low
    6 b8 B) g8 Q* Q  e
  33. hspi1.Init.CLKPhase = SPI_PHASE_1EDGE;//CPHA为数据线的第一个变化沿
    ( `( q* z0 _. }' {
  34. hspi1.Init.NSS = SPI_NSS_SOFT;//软件控制NSS' B& l- Q9 w! _9 J
  35. hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_2;//2分频,32M/2=16MHz
      @5 H: ~7 ]" C0 j. z2 e
  36. hspi1.Init.FirstBit = SPI_FIRSTBIT_MSB;//最高位先发送- l  b6 p- O& l: P' o/ I$ i
  37. hspi1.Init.TIMode = SPI_TIMODE_DISABLE;//TIMODE模式关闭
    7 v7 q) p# v5 ]2 `$ p* u. c
  38. hspi1.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;//CRC关闭
    ( I' [: u# Y" _  Q" D  x. I
  39. hspi1.Init.CRCPolynomial = 10;//默认值,无效
    1 `% l3 \- K7 E
  40. if (HAL_SPI_Init(&hspi1) != HAL_OK)//初始化
    " C6 I% {  g2 D6 A. D# z
  41. {$ P5 W1 N5 l  E# K" R
  42. _Error_Handler(__FILE__, __LINE__);
    . r7 X  h$ n% `8 c8 T: ~: N/ v
  43. }' j% X9 O7 H- `' V" g, A% o4 P
  44. }
复制代码

8 S. W5 q  ~% O9 [6 K+ m+ e) @1 V6 {+ N# G5 _
利用SPI接口发送和接收数据主要调用以下两个函数:) I! O0 d; {) D/ s
) q: N5 W. e( |. Z1 l8 Q
  1. 9 d- S( s' u) m6 V
  2. HAL_StatusTypeDef  HAL_SPI_Transmit(SPI_HandleTypeDef *hspi, uint8_t *pData, uint16_t Size, uint32_t Timeout);//发送数据
    9 y9 \. ^7 j- O" ]7 O
  3. HAL_StatusTypeDef  HAL_SPI_Receive(SPI_HandleTypeDef *hspi, uint8_t *pData, uint16_t Size, uint32_t Timeout);//接收数据
复制代码

8 M2 o9 _" |/ ~, Z* n+ W( I0 J, T0 z  @
& ]8 V' g" v( l8 \

5 F7 n8 ?2 G8 {% ?2 l* I/ N
  a* U0 e( b) e0 h" j5 d$ c- Y7 F& j6 J# t+ L' g
1 f2 B" u& W3 F" `
收藏 1 评论0 发布时间:2020-10-19 13:37

举报

0个回答
关于意法半导体
我们是谁
投资者关系
意法半导体可持续发展举措
创新和工艺
招聘信息
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
关注我们
st-img 微信公众号
st-img 手机版