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

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

[复制链接]
STMCU小助手 发布时间:2022-2-1 18:00
本文介绍如何使用STM32标准外设库的GPIO端口模拟SPI,本例程使用PA5、PA6和PA7模拟一路SPI。SPI有4种工作模式,模拟SPI使用模式0,即空闲时SCK为低电平,在奇数边沿采样。
本文适合对单片机及C语言有一定基础的开发人员阅读,MCU使用STM32F103VE系列。
5 H) \6 K/ x1 L9 K1 [) W) I) r
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。% B- J/ ^# D1 l8 ~" _( G2 T, l
SPI模式
时钟极性(空闲时SCK时钟)
时钟相位(采样时刻)
0
低电平
奇数边沿
1
低电平
偶数边沿
2
高电平
奇数边沿
3
高电平
偶数边沿

; h* p0 x$ L- a( D4 j
6 |3 n7 h9 h0 B( ~+ v3.    时序说明
以模式0举例说明:
  • 空闲状态:片选信号SS为高,SCK输出低电平。
  • 开始信号:片选信号SS变低,SCK输出低电平。
  • 结束信号:片选信号SS变高,SCK输出低电平。
  • 读取:SCK由低变高之后,读取MISO引脚信号。
  • 写入:SCK输出低电平,MOSI引脚输出相应的电平,然后SCK输出高电平。
  • 一个时钟周期同时读取和写入:SCK输出低电平,主设备控制MOSI输出相应电平,从设备控制MISO输出相应电平,然后SCK输出高电平,从设备读取MOSI引脚电平,主设备读取MISO引脚电平。即无论主设备还是从设备,均在SCK为低电平时输出信号,在SCK为高电平时读取信号。4 e4 E  D8 D5 J' x5 Y/ j9 v5 u
4.    初始化
初始化跟普通GPIO类似,SCK和MOSI设置为推挽输出,而MISO设置为浮空输入。
GPIO初始化完成之后,SCK置为低电平,进入空闲状态。
5.    模拟信号
由于SPI支持一个周期内同时读取和写入,因此读取和写入操作可以用一个函数实现,而单独的读取函数和写入函数可以通过调用该读写函数实现。

4 k) B0 ]) z, q8 [完整代码(仅自己编写的部分)+ I2 w  x! n# D7 h9 ^
  1. #define SPI_SCK_1    GPIO_SetBits(GPIOA, GPIO_Pin_5)            /* SCK = 1 */; C  W6 [8 ~4 _
  2. #define SPI_SCK_0    GPIO_ResetBits(GPIOA, GPIO_Pin_5)        /* SCK = 0 */
    6 p( i2 H5 m/ X3 p& ?0 L

  3. , F# ]/ X6 y# r  i7 j( J
  4. #define SPI_MOSI_1    GPIO_SetBits(GPIOA, GPIO_Pin_7)            /* MOSI = 1 */' v, h8 }& S' b8 T# z
  5. #define SPI_MOSI_0    GPIO_ResetBits(GPIOA, GPIO_Pin_7)        /* MOSI = 0 */
      k% T' e$ s( b, B

  6. - @. I( L  R% N# r% A: Z- w: y* e% N
  7. #define SPI_READ_MISO    GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_6)    /* 读MISO口线状态 */5 Y3 d* G3 g& I# l

  8. & ^  g' }2 r# t5 z7 e4 t
  9. #define Dummy_Byte    0xFF    //读取时MISO发送的数据,可以为任意数据2 M1 N0 V' N: Z* Z5 G3 o
  10. 8 M- K3 v* r: C/ x* q& W. p! r! l

  11. : }0 X% x8 R, h8 E$ k! g
  12. //初始化SPI
    . g* G! D' ?+ e5 M& g. p
  13. void SPI_IoInit(void)
    & [8 X& w& L- q, `  ?2 l0 n
  14. {( X3 ~/ P8 D3 {
  15.     GPIO_InitTypeDef GPIO_InitStructure;
    $ i. ]3 Q% N# l: }( u' O

  16. # O) \# r. h- s; h$ @0 V8 b
  17.     RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOC, ENABLE);
    4 _/ O3 r% F) T( D# F& Q1 K

  18. : u' l0 |3 z0 o6 a8 ?
  19.     //CS引脚初始化
    % f- [0 x/ J7 r) k0 j
  20.     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
    6 O. I2 n* c$ j1 F4 O6 Y" M0 K
  21.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP ;           //推挽输出
    : l$ g5 i% R, B; ^/ A0 M
  22.     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    - l& L. c1 j. ], H/ x
  23.     GPIO_Init(GPIOC, &GPIO_InitStructure);
    # ]  N2 @; i4 B; |9 C+ B
  24. 8 s3 w9 n3 l, H
  25.     //SCK和MOSI引脚初始化
    $ y+ _& r8 U. Y( F- \# f" a- x
  26.     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5|GPIO_Pin_7;( k7 H7 r# C# e3 Z) G( r9 N
  27.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP ;           //推挽输出# Z! P& n8 {1 R& q+ Z) X9 ?& j/ C
  28.     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;$ e) J# ]3 v. D
  29.     GPIO_Init(GPIOA, &GPIO_InitStructure);
    2 r& R. G; e% S; N, D

  30. " ?* ?4 n/ f: x6 f6 }# L2 {8 |
  31.     //MISO引脚初始化
    " c# c+ P  u& _# j; j2 r6 K: R
  32.     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
    ! S+ p2 S& f+ _9 j
  33.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU ;               //浮空输入4 S! ?# m8 q/ q
  34.     GPIO_Init(GPIOA, &GPIO_InitStructure);' N' f3 o0 c" S" R

  35. - R1 _5 m. H4 m7 i$ V
  36.     SPI_CS_1;3 P! p, K( k- [/ g! z, T, v2 C
  37.     SPI_SCK_1;9 o5 ~9 x/ b# Y2 Q8 J
  38. }+ Q% V( |, t0 X, w
  39. / c4 g8 C& z$ x; [, M6 y
  40. //SPI可以同时读取和写入数据,因此一个函数即可满足要求
    " N& Y1 _% `$ ]: k0 V/ K- V% k( H0 [
  41. uint8_t SPI_ReadWriteByte(uint8_t txData)/ D: o7 A5 T+ f  n
  42. {7 b" f! K3 }8 K3 c; z
  43.     uint8_t i;
    9 S) |; I5 X8 J
  44.     uint8_t rxData = 0;8 |1 X5 x: \# e, O/ C! ^

  45. % y) `& I% }4 H: Z
  46.     for(i = 0; i < 8; i++)
    . r, |4 h: V  h7 U- c6 w( p
  47.     {
    - ~% i, [3 i( ]6 B  D
  48.         SPI_SCK_0;! W5 U& z4 H# @6 k3 ^+ n; g
  49.         delay_us(1);
    + L( G9 ?) c( @; l3 ~* x* c
  50.         //数据发送
    : J2 P4 w( X/ i8 c! |
  51.         if(txData & 0x80){# {# F& q+ k6 V
  52.             SPI_MOSI_1;
    9 O, t! z/ ]3 j) z' k0 o
  53.         }else{
    9 f4 B% \5 B8 |( N
  54.             SPI_MOSI_0;: _# `* c/ y# Y
  55.         }- Y) \, T7 \# h" `+ h3 v
  56.         txData <<= 1;& P$ D+ Y; E* m# a# T- g
  57.         delay_us(1);, L5 k( j) w. \$ l
  58. 3 ?6 W- {" e  K; q- u; q7 [% ]
  59.         SPI_SCK_1;3 }6 d* U9 H9 K1 e2 q
  60.         delay_us(1);
    * p) c& _9 o6 t' L+ |$ y/ ]! X
  61.         //数据接收
    % y/ g2 _# O' V# h8 \8 ?: |
  62.         rxData <<= 1;3 o# I: C$ C9 B( m+ W' j
  63.         if(SPI_READ_MISO){
    ' Z  b6 [& `  \8 n3 C8 L; r
  64.             rxData |= 0x01;1 \, |( f- ]+ H# V( c* u$ z# n
  65.         }  o$ C2 Y: V5 X; [9 w/ C- \/ z5 M
  66.         delay_us(1);! U( a7 B: c& z
  67.     }
    9 }3 ?  h6 y+ s6 u+ i" R$ E
  68.     SPI_SCK_0;' k# ~: b# D2 t( G

  69. 0 N$ D; r. x! k$ x2 F
  70.     return rxData;0 s( i8 J8 |+ t4 P
  71. }* U5 S. A" ^2 N' |

  72. 2 I2 Q8 i$ h& P; g
  73. uint8_t SPI_ReadByte(void)2 D) W, B1 w& S  {/ v, n
  74. {
    + f# T) ]" W# a' l8 ]; N7 G
  75.     return SPI_ReadWriteByte(Dummy_Byte);# [, q) Y6 e+ q2 L* E
  76. }4 A! b1 H4 W+ \5 `5 D
  77. ) @; k4 ]# L4 V! p3 ~
  78. void SPI_WriteByte(uint8_t txData)
    ' a2 @) N5 O7 g3 o  y- b
  79. {. k+ w9 {2 Y7 w) A4 ?8 Z3 l  _
  80.     (void)SPI_ReadWriteByte(txData);" n' j5 V7 q, O" g, M
  81. }
复制代码

! j( l# }4 [  n* ^# b& B+ I" u1 n9 e+ D' Z( j
收藏 评论0 发布时间:2022-2-1 18:00

举报

0个回答

所属标签

相似分享

官网相关资源

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