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

STM32CubeMX-HAL库的SPI接口使用

[复制链接]
STMCU-管管 发布时间:2020-10-19 13:37
STM32CubeMX-HAL库的SPI接口使用

. l2 W  V- Z! y
. B! L2 O0 |. l. k$ L0 |9 s/ V3 p
本文主要介绍STM32的SPI接口、cubeMX软件配置SPI接口和分析SPI相关代码。
, r( \6 \; B# ]STM32之SPI简介:
, P' ^7 C) O6 J8 M/ d5 q3 aSPI协议【Serial Peripheral Interface】
6 c3 p, g$ h; Q/ A4 A" Q+ r' _    串行外围设备接口,是一种高速全双工的通信总线。主要用在MCU与FLASH\ADC\LCD等模块之间的通信。

/ m6 h2 G0 ^$ n  GSPI信号线/ e5 ]; ~+ ?% R( t9 [
    SPI 共包含 4 条总线。

+ }2 I$ o. f# }. c  d( ~: hSS(Slave Select):片选信号线,当有多个SPI 设备与 MCU 相连时,每个设备的这个片选信号线是与 MCU 单独的引脚相连的,而其他的 SCK、MOSI、MISO 线则为多个设备并联到相同的 SPI 总线上,低电平有效。" Y3 j) s4 E3 _9 Z
SCK (Serial Clock):时钟信号线,由主通信设备产生,不同的设备支持的时钟频率不一样,如 STM32 的 SPI 时钟频率最大为 f PCLK /2。
9 r5 L8 x3 x/ j8 s) F& sMOSI (Master Output Slave Input):主设备输出 / 从设备输入引脚。主机的数据从这条信号线输出,从机由这条信号线读入数据,即这条线上数据的方向为主机到从机。3 \; Y9 o  i0 \$ k: g
MISO(Master Input Slave Output):主设备输入 / 从设备输出引脚。主机从这条信号线读入数据,从机的数据则由这条信号线输出,即在这条线上数据的方向为从机到主机。
$ G$ B. m( I3 N% D$ x    其中SCK,MOSI,MISO是接在一起的,NSS分别接到不同的IO管脚控制。主器件要和从器件通信就先拉低对应从器件的NSS管脚使能。默认状态IO1,IO2,IO3全为高电平,当主器件和从器件1通信时,拉低IO1管脚使能从器件1。而从器件2,3不使能,不作响应。下图是主器件与多个从器件通信图。
2 ]$ M; r+ j9 Z; ^6 H0 ~) P
11.png
( l- j. [  L4 e: d$ B: I- z7 P
SPI特性2 Y0 O" y. D* _9 E3 m( U# |, c" o
    单次传输可选择为 8 或 16 位。波特率预分频系数(最大为 fPCLK/2) 。时钟极性(CPOL)和相位(CPHA)可编程设置。数据顺序的传输顺序可进行编程选择,MSB 在前或 LSB 在前。
" g0 N8 i+ F& S! ~& H( o
    注:MSB(Most Significant Bit)是“最高有效位”,LSB(Least Significant Bit)是“最低有效位”。8 [4 g/ D; `. p9 }
    可触发中断的专用发送和接收标志。可以使用 DMA 进行数据传输操作。下图是STM32的SPI框架图。
( [' c( o$ `: Q3 {3 P0 D/ M7 W
12.png % B; ]; B# y' l; R7 C) y
    如上图,MISO数据线接收到的信号经移位寄存器处理后把数据转移到接收缓冲区,然后这个数据就可以由我们的软件从接收缓冲区读出了。当要发送数据时,我们把数据写入发送缓冲区,硬件将会把它用移位寄存器处理后输出到 MOSI数据线。SCK 的时钟信号则由波特率发生器产生,我们可以通过波特率控制位(BR)来控制它输出的波特率。
$ f. g& X5 @3 t1 t& k    控制寄存器 CR1掌管着主控制电路,STM32的 SPI模块的协议设置(时钟极性、相位等)就是由它来制定的。而控制寄存器 CR2则用于设置各种中断使能。% {: k: |1 O3 t! U$ \, M3 W
    最后为 NSS引脚,这个引脚扮演着 SPI协议中的SS片选信号线的角色,如果我们把 NSS引脚配置为硬件自动控制,SPI模块能够自动判别它能否成为 SPI的主机,或自动进入 SPI从机模式。但实际上我们用得更多的是由软件控制某些 GPIO引脚单独作为SS信号,这个 GPIO引脚可以随便选择。
* }$ h* e( j, y' @SPI时钟时序5 [: N* D# ^8 P0 p, y% J
    根据时钟极性(CPOL)及相位(CPHA)不同,SPI有四种工作模式。
( P. S: S( Y6 q+ S" P9 K" J' T7 J  T    时钟极性(CPOL)定义了时钟空闲状态电平:5 C- y, Q7 R! G- z" D/ M- M
CPOL=0为时钟空闲时为低电平, D5 m9 G7 |5 A8 u6 M9 U8 J
CPOL=1为时钟空闲时为高电平
& U& c; u  n. g    时钟相位(CPHA)定义数据的采集时间。
+ \- l7 j* F0 b9 [% R! t* HCPHA=0:在时钟的第一个跳变沿(上升沿或下降沿)进行数据采样。
$ ]- E. Q; Q" a9 j3 ~, e( m$ ]CPHA=1:在时钟的第二个跳变沿(上升沿或下降沿)进行数据采样。2 l# U5 n- s! ~3 R" D: J! u
13.png
6 X3 M! T' p# l) k
CubeMX软件配置SPI:- _9 t1 U$ H9 ]" f
    下面继续介绍cubeMX软件配置STM32L152的SPI接口方法。
7 ]. Q8 Q( ?: [! z( w+ n8 L4 ?
(1)打开软件,选择对应芯片后,配置好时钟源;
- u0 }8 t  G5 x6 l, W# u/ \(2)勾选SPI1为全双工,硬件NSS关闭,如下图:
5 A1 L7 q+ a( g0 D 14.png
! |1 Y4 |( [, R$ f; n& }9 z0 [) u(3)勾选好后,PA5、PA6、PA7如下图,在配置PA4为普通io口,gpio_output
$ L' c+ H' w% `- e  l5 L 15.png ) ~" ^  o5 r! C* {/ S# c
(4)SPI1的参数配置选择默认,如下图所示/ `' n+ @' {* s9 p/ M- g5 D
16.png 4 w6 O2 E+ T, u& U2 `3 n1 x
(5)生成代码,保存即可。2 m7 l/ b% t4 W2 w" a1 c
    HAL库的SPI函数分析:
9 V; t7 }. o5 ^$ ?: f: C    下面具体分析下生成的SPI函数和函数调用。
1 @/ g: z- h5 A. p  N  W
SPI_HandleTypeDef hspi1; //SPI结构体类定义,下面看其结构体内部的声明。
17.png 2 p; Z. i. ]  V6 \" q, Q( k* h1 j" s4 _
18.png
: ^- U. A8 ]( C& v3 @* y* b0 n1 O; }
下面分析SPI的初始化函数:
) u9 l* u& X0 V/ w% W& z. I
6 U! H* `8 r6 W

  1. 9 [( f" \2 o" H* w* `  D5 T
  2. void HAL_SPI_MspInit(SPI_HandleTypeDef* hspi)7 h( H) T0 o2 G4 z& {( M6 E
  3. {
    ' G% I  L9 H5 e
  4. GPIO_InitTypeDef GPIO_InitStruct;$ o  u4 e" T' k5 S6 C6 F
  5. if(hspi->Instance==SPI1)
    # n' o! H9 A9 S8 A! I( `3 K
  6. {' ]* V. P4 U* x4 D" I6 R) }
  7. /* USER CODE BEGIN SPI1_MspInit 0 */
    ! }( N; c) a: |7 A' o
  8. /* USER CODE END SPI1_MspInit 0 */
    / Z+ H9 v3 t6 G9 {0 t& V- I! o
  9. /* Peripheral clock enable */* N1 W4 i6 |( m' [8 I5 p
  10. __HAL_RCC_SPI1_CLK_ENABLE();//使能SPI1时钟/ O7 f: N) X# z% m9 r! K: m% _: w' _7 [
  11. /**SPI1 GPIO Configuration
    & t$ H8 K- I0 F) ~8 t7 X
  12. PA5     ------> SPI1_SCK
    0 ^5 b% k+ }1 A
  13. PA6     ------> SPI1_MISO3 ?6 X1 A; K" F; h
  14. PA7     ------> SPI1_MOSI& j  v! K' j0 z( v
  15. */
    : K/ W: F0 M, J  ]: f6 D0 z( z
  16. GPIO_InitStruct.Pin = GPIO_PIN_5|GPIO_PIN_6|GPIO_PIN_7;9 ]$ i* j, Z1 S2 Y6 L0 f/ |
  17. GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;9 H/ \# M  e9 S* |
  18. GPIO_InitStruct.Pull = GPIO_NOPULL;3 |0 Z, d9 F# a; `  S* h( G* A6 S
  19. GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    / |6 e6 D) M/ p7 i" w& v
  20. GPIO_InitStruct.Alternate = GPIO_AF5_SPI1;/ B$ Q5 G  f& M1 F9 v* W
  21. HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);//配置SPI的数据线和时钟线7 B) t& |9 U3 i
  22. /* USER CODE BEGIN SPI1_MspInit 1 */! s3 x9 T) O2 |8 r2 O: Y  s7 ^/ o3 B
  23. /* USER CODE END SPI1_MspInit 1 */! F& A/ z* t! Y
  24. }. ?2 r" Q: t7 N. I, N" x

  25. * T! x* D# f- ^* ?. w: C: |' a& u
  26. static void MX_SPI1_Init(void)
    ) N) v6 N, l& v
  27. {
      C5 _% X3 H( \/ k5 y
  28. hspi1.Instance = SPI1;
    % j, k- |/ k. R4 d( {0 o* ?* e
  29. hspi1.Init.Mode = SPI_MODE_MASTER;//主模式
    4 r9 }6 `4 W+ \' `
  30. hspi1.Init.Direction = SPI_DIRECTION_2LINES;//全双工
    5 Z4 b0 u9 [+ M9 }9 @3 ^
  31. hspi1.Init.DataSize = SPI_DATASIZE_8BIT;//数据位为8位+ G6 E0 J; p) d* m, c
  32. hspi1.Init.CLKPolarity = SPI_POLARITY_LOW;//CPOL=0,low
    ' a) S- y& R) f6 w  X$ u
  33. hspi1.Init.CLKPhase = SPI_PHASE_1EDGE;//CPHA为数据线的第一个变化沿
    % @( q2 p) h# D5 {" a
  34. hspi1.Init.NSS = SPI_NSS_SOFT;//软件控制NSS
    - l" G/ f3 H! |* z0 D
  35. hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_2;//2分频,32M/2=16MHz# V# u$ _- H; U7 M9 n# `$ E) x
  36. hspi1.Init.FirstBit = SPI_FIRSTBIT_MSB;//最高位先发送
      N2 {  t' ~2 Z- S
  37. hspi1.Init.TIMode = SPI_TIMODE_DISABLE;//TIMODE模式关闭) d2 I0 x! n7 e/ ?3 H- I& H. n
  38. hspi1.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;//CRC关闭
    4 y: c& n6 i/ p$ q* x1 i
  39. hspi1.Init.CRCPolynomial = 10;//默认值,无效7 v# [2 W% c3 s# d7 N" k
  40. if (HAL_SPI_Init(&hspi1) != HAL_OK)//初始化" P6 H) S' i, e. P9 ?
  41. {3 }5 K* I0 h8 i1 ]1 u
  42. _Error_Handler(__FILE__, __LINE__);
    " N+ e: }2 C3 [6 N- q
  43. }- D0 U8 J8 a- M6 q8 X% _( c1 F
  44. }
复制代码
* i3 I+ T& S1 s1 O4 j( D+ b, y
  |# r/ ^  u  [6 g4 G
利用SPI接口发送和接收数据主要调用以下两个函数:
8 m' _* r2 f5 ]& K+ E) C0 Y- L1 M$ X6 J$ A7 n5 u

  1. 0 ~/ P" N1 Y5 Y' e
  2. HAL_StatusTypeDef  HAL_SPI_Transmit(SPI_HandleTypeDef *hspi, uint8_t *pData, uint16_t Size, uint32_t Timeout);//发送数据5 @: [1 r5 O/ \+ R4 ?0 ?
  3. HAL_StatusTypeDef  HAL_SPI_Receive(SPI_HandleTypeDef *hspi, uint8_t *pData, uint16_t Size, uint32_t Timeout);//接收数据
复制代码
% f! ~+ E2 p$ _4 J$ l
6 I3 h) `8 [% K- ~
) w. Q5 B+ R% W
  [1 n8 {* V: z0 b) R6 l" p

; e7 c6 P8 Y$ P7 F9 |+ @5 ~( _; h  F8 J: j9 P

0 [, @+ r8 X3 y6 z
收藏 1 评论0 发布时间:2020-10-19 13:37

举报

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