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

【经验分享】STM32之IO口模拟SPI

[复制链接]
STMCU小助手 发布时间:2022-2-1 18:00
本文介绍如何使用STM32标准外设库的GPIO端口模拟SPI,本例程使用PA5、PA6和PA7模拟一路SPI。SPI有4种工作模式,模拟SPI使用模式0,即空闲时SCK为低电平,在奇数边沿采样。
本文适合对单片机及C语言有一定基础的开发人员阅读,MCU使用STM32F103VE系列。

$ N0 {; H4 d: I6 k- q/ c7 ?1.   简介
SPI 协议是由摩托罗拉公司提出的通讯协议(Serial Peripheral Interface),即串行外围设备接口,是一种高速全双工的通信总线。它被广泛地使用在要求通讯速率较高的场合。SPI用于多设备之间通讯,分为主机Master和从机Slave,主机只有一个,从机可以有多个,通过片选信号对从机进行选择,一次只能选择一个从机。通讯只能由主机发起,支持的操作分为读取和写入,即主机读取从机的数据,以及向从机写入数据。
SPI一般有4根线,分别是片选线SS、时钟线SCK、主设备输出\从设备输入MOSI、主设备输入\从设备输出MISO,其中除MISO对于主机为输入引脚外,其他引脚对于主机均为输出引脚。因为有独立的输入和输出引脚,因此SPI支持全双工工作模式,即可以同时接收和发送。
2.    总线传输信号
  • 空闲状态:片选信号SS低电平有效,那么空闲状态片选信号SS为高。
  • 开始信号及结束信号:开始信号需要将片选信号SS拉低,结束信号需要将片选信号SS拉高。
  • 通讯模式:SPI有4种通讯模式,分别为0、1、2、3,根据时钟极性和时钟相位确定,时钟极性分别为空闲低电平和空闲高电平,时钟相位分别为SCK奇数边沿采样和偶数边沿采样。常用的模式为模式0和模式3。
    9 t- o; [. Y; i. J
SPI模式
时钟极性(空闲时SCK时钟)
时钟相位(采样时刻)
0
低电平
奇数边沿
1
低电平
偶数边沿
2
高电平
奇数边沿
3
高电平
偶数边沿
! m+ o" K3 p$ Q) M0 q
: m# L* _, e. d, }& K
3.    时序说明
以模式0举例说明:
  • 空闲状态:片选信号SS为高,SCK输出低电平。
  • 开始信号:片选信号SS变低,SCK输出低电平。
  • 结束信号:片选信号SS变高,SCK输出低电平。
  • 读取:SCK由低变高之后,读取MISO引脚信号。
  • 写入:SCK输出低电平,MOSI引脚输出相应的电平,然后SCK输出高电平。
  • 一个时钟周期同时读取和写入:SCK输出低电平,主设备控制MOSI输出相应电平,从设备控制MISO输出相应电平,然后SCK输出高电平,从设备读取MOSI引脚电平,主设备读取MISO引脚电平。即无论主设备还是从设备,均在SCK为低电平时输出信号,在SCK为高电平时读取信号。
    " g! J& a) u$ L) `( c
4.    初始化
初始化跟普通GPIO类似,SCK和MOSI设置为推挽输出,而MISO设置为浮空输入。
GPIO初始化完成之后,SCK置为低电平,进入空闲状态。
5.    模拟信号
由于SPI支持一个周期内同时读取和写入,因此读取和写入操作可以用一个函数实现,而单独的读取函数和写入函数可以通过调用该读写函数实现。

$ p& j1 a2 c- J  t$ y9 n" X/ V完整代码(仅自己编写的部分)
( G6 O8 o2 J  b2 |# l5 g/ c
  1. #define SPI_SCK_1    GPIO_SetBits(GPIOA, GPIO_Pin_5)            /* SCK = 1 */: _/ z  y& |8 C2 \0 W9 G3 n
  2. #define SPI_SCK_0    GPIO_ResetBits(GPIOA, GPIO_Pin_5)        /* SCK = 0 */
    . S$ [) e* q$ I/ Y" B7 n; O

  3. 9 g* R5 [1 [0 x: I. d9 i
  4. #define SPI_MOSI_1    GPIO_SetBits(GPIOA, GPIO_Pin_7)            /* MOSI = 1 */8 ^/ `* ^+ ^' e+ L8 J7 A
  5. #define SPI_MOSI_0    GPIO_ResetBits(GPIOA, GPIO_Pin_7)        /* MOSI = 0 */
    # k6 y& T; t* L9 `3 c. p# A# m, N4 y
  6. 8 U$ P3 ]( ^' t. V" q9 q/ y) F
  7. #define SPI_READ_MISO    GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_6)    /* 读MISO口线状态 */
    # T! P# K2 D9 O4 U3 n
  8. # B  ?0 J) S) c9 |3 |
  9. #define Dummy_Byte    0xFF    //读取时MISO发送的数据,可以为任意数据, B: r/ S4 }. F' E* |

  10. . j1 `  `! b0 o6 {

  11. $ w4 F( m: R0 n
  12. //初始化SPI
    : \( e) e3 L$ u
  13. void SPI_IoInit(void)
    ( ^9 ^. u5 N; }& Y% A
  14. {- }) m3 y0 [- _+ t# ]; ^# t4 I
  15.     GPIO_InitTypeDef GPIO_InitStructure;
    * K+ g2 b' V0 R
  16. ! o  ?4 P! k2 T4 `8 ^) B' B8 e
  17.     RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOC, ENABLE);
    + L2 _, ~% n, T) t+ F3 b# w

  18. 0 [! w3 b5 ~( R& h, t' ^* z
  19.     //CS引脚初始化
    * p6 q7 q0 K, A' ~- X
  20.     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;! X; X  B% ?; X' ^  G/ ^; ?1 d4 V
  21.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP ;           //推挽输出. G, J! L  J; \9 F  C' K+ D4 c2 F/ A
  22.     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    " q: |; Q$ g6 X1 L
  23.     GPIO_Init(GPIOC, &GPIO_InitStructure);! F* I. N  f8 K: B9 d1 A
  24. " w- Z# l" I3 U1 b& N7 g9 ^5 ?
  25.     //SCK和MOSI引脚初始化
    6 x! {0 k% B" ?+ o
  26.     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5|GPIO_Pin_7;0 f$ z( O' E4 J2 N8 r7 ]
  27.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP ;           //推挽输出
    % z& F, j( m0 {, B
  28.     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    8 Z" n: R* }3 t# S8 y
  29.     GPIO_Init(GPIOA, &GPIO_InitStructure);: e; |* |7 @% H  z7 S
  30. & p: D6 s. {- R" I; A2 v
  31.     //MISO引脚初始化
    0 h! {4 k3 o- I5 }0 [9 A( R
  32.     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;$ P7 j0 U5 P1 H# h2 }! A
  33.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU ;               //浮空输入6 H/ F( L! v9 O+ X. V6 c+ A
  34.     GPIO_Init(GPIOA, &GPIO_InitStructure);+ E- g4 @2 v+ M! s

  35.   N7 p( O* {$ p
  36.     SPI_CS_1;
    / {6 [5 O+ Y8 Z/ F" @
  37.     SPI_SCK_1;
    " p  }3 `' `7 [" C8 S1 x
  38. }  U: {$ T5 p# w; q2 I8 t+ j- f; q
  39. $ X+ j1 Q5 i9 w2 P9 I
  40. //SPI可以同时读取和写入数据,因此一个函数即可满足要求3 A' _+ `& ^* j
  41. uint8_t SPI_ReadWriteByte(uint8_t txData)
    * U7 v: ~$ K, m: j: P# l
  42. {3 u# U. N+ v( \1 ]0 R
  43.     uint8_t i;
    ) |4 n. v4 \, @$ V- e# F
  44.     uint8_t rxData = 0;
    / v' ]# y, v* @
  45. + V$ ^& t1 d3 Y4 w
  46.     for(i = 0; i < 8; i++)
    - m# E( t% p- [6 o7 w6 i; J+ u0 N
  47.     {3 _4 k1 [/ P' w! J" L% Z
  48.         SPI_SCK_0;, ~, _' |& k( ~2 k$ @0 e
  49.         delay_us(1);, o0 X# J4 t. k. _* P) x0 |2 F
  50.         //数据发送+ i$ e8 G, r" ^. F. e7 x
  51.         if(txData & 0x80){
    3 z) U6 M# K* z" [. p5 z
  52.             SPI_MOSI_1;( e9 {. {( A2 Q6 U8 A8 a
  53.         }else{1 \4 M+ `3 z3 o8 u: @
  54.             SPI_MOSI_0;7 h2 W. _0 L4 p( ~
  55.         }
    2 `1 r2 {$ S, {- A& i5 c; \8 R# f
  56.         txData <<= 1;1 Y, Z( V; k6 ~4 V, `
  57.         delay_us(1);% I, e( F& D4 G  U9 Y
  58. ' |- {& e. z, P5 b" k! V; w
  59.         SPI_SCK_1;5 N' e2 m1 q4 n0 O
  60.         delay_us(1);
    4 n4 l* Z, `( A- T* o! Q2 e
  61.         //数据接收
    ( O8 _2 f+ R$ ]1 S7 u& B  M
  62.         rxData <<= 1;8 i4 ~! ~7 q3 v+ U' ]/ @
  63.         if(SPI_READ_MISO){
    # E; T% J) A7 [/ k- ^
  64.             rxData |= 0x01;
    7 j, Y* y! L) N& w# r0 G
  65.         }  m/ S! |! n0 |. Y
  66.         delay_us(1);' x7 o8 N4 O- n. R, E
  67.     }" J3 _2 R! K0 S4 W6 `& q; G
  68.     SPI_SCK_0;& \, m, v: L8 p  R9 X  t

  69. ' U& [4 x8 R3 m) U
  70.     return rxData;
    * A! W0 O# ?. B. \
  71. }, K4 T) X2 U0 I! g4 y0 x+ c) W0 T

  72. ' x  T2 ]1 w5 {  n
  73. uint8_t SPI_ReadByte(void)
    , w5 @1 N+ ]4 a% S! U
  74. {/ W/ O/ v* b8 k4 u) M9 v) D  x5 I4 I
  75.     return SPI_ReadWriteByte(Dummy_Byte);$ t; e5 `5 J" ^% `2 C
  76. }
    & m7 H7 I2 U( {% a3 T

  77. 0 O" E2 q8 T& h# h2 G5 }
  78. void SPI_WriteByte(uint8_t txData)0 g/ d  W- q+ D+ K8 d
  79. {: P1 k6 ~! m5 f) b
  80.     (void)SPI_ReadWriteByte(txData);
    4 O0 I9 [8 D( Z7 R# ~" N/ y, {2 S1 u0 O
  81. }
复制代码
9 {; R( v; M& T( a0 F& x

. _8 i# s; Q/ C4 g
收藏 评论0 发布时间:2022-2-1 18:00

举报

0个回答

所属标签

相似分享

官网相关资源

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