找回密码
 注册
关于网站域名变更的通知
查看: 1010|回复: 1
打印 上一主题 下一主题

stm32之SPI通信之学习分析附源码

[复制链接]

该用户从未签到

跳转到指定楼层
1#
发表于 2019-8-29 17:01 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式

EDA365欢迎您登录!

您需要 登录 才可以下载或查看,没有帐号?注册

x
  之前一直对SPI通信一知半解,所以想抽空把它搞得明白一些。考虑到之前是结合Flash芯片来学的,十分不直观,而且主要把时间和精力都花在Flash芯片的datasheet和驱动上了,SPI通信也没学好。所以这次就考虑用4位数码管显示模块,模块是直接买的现成的,如下图所示,这样可以简化操作,把精力聚焦到学习的核心–SPI通信本身上来。+ y! G, c* q' k/ m
  该模块是用2片74HC595串联驱动的,一片用来控制数码管的位选(U1),一片用来控制数码管的段选(U2)。接口比较简单,总共5个引脚,2个引脚分别接VCC和GND,DIO用来接收串行数据的输入,SCLK用来接收同步时钟,每个SCLK上升沿74HC595内部的移位寄存器会移一位,RCLK用来控制数据的输出,每个RCLK上升沿74HC595内部的移位寄存器的数据会被放进存储寄存器并输出到外部引脚QA~QH上。而QH’是串行输出引脚,该引脚会接收最高位的溢出,从而实现多片74HC595的级联。
7 f$ N" N2 [4 i" m" M" D
  当两片74HC595串联时,先发八位数据用于段选,再发八位数据用于位选,然后RCLK上升沿,就可以驱动某位数码管显示某个字符,通过动态扫描数码管,由于人眼的视觉暂停效果,就可以实现4位数码管的同时显示。先用通用I/O来实现该数码管的驱动,程序如下:
7 f1 y0 B! `+ R8 X- M: a  头文件74HC595.h7 w) h7 M, f  o
6 O' C" o) z2 k1 \) T# u
  1.  #ifndef __74HC595_H__, E* p4 @8 \, r
  2. 5 r) k7 u* \: w* `/ y
  3.   #define __74HC595_H__
    ; C/ B% X* [6 v0 {$ N4 G

  4. 4 W% |+ |" F8 n* n6 y9 o
  5.   #include"stm32f10x_lib.h" //包含所有的头文件
    * o0 J2 e# b: [' p# U

  6. 0 Q! [  p6 X4 b2 ^! o9 w4 P3 x! g6 h5 a
  7.   #include
    6 a. q4 H  @4 s: f( |
  8. ' Z! L& ^4 ?; P  G' T
  9.   // 4-Bit LED Digital Tube Module
    8 E3 e. y4 E: I
  10. # E) X! S7 k( Y1 p8 P5 [5 W. V6 Q( f
  11.   #define HC595_SCLK_PIN GPIO_Pin_5 // SPI1_SCK PA5
    5 x$ C4 e+ l6 f( o1 @8 h

  12. % @& P4 ^5 g: X. P- v  U% k
  13.   #define HC595_RCLK_PIN GPIO_Pin_12 // SPI1_NSS PA4) l# W. u0 p4 C

  14.   E; f5 w5 M/ Y
  15.   #define HC595_DIO_PIN GPIO_Pin_7 // SPI1_MOSI PA7; m7 j. P7 V4 y' f% x
  16. : d, i: H, G0 E* R
  17.   #define HC595_GPIO GPIOA/ F( r5 i  p7 m' l  E: k

  18. - f: o- t& ^- \; E- D
  19.   #define HC595_RCLK_GPIO GPIOB+ Q$ D; T5 f8 Y0 Q- w5 i3 K/ M

  20. ' J- P, q5 _4 _
  21.   #define HC595_RCC RCC_APB2Periph_GPIOA
    ) H) R5 X6 Q% b- {% \5 P
  22. # W: K: z  K, u# W  Y
  23.   #define HC595_RCLK_RCC RCC_APB2Periph_GPIOB- f- B4 f2 U  |& ?; P& U

  24. # o: H2 v3 N$ b; ?3 }+ _" m& K
  25.   void HC595_Init(void);' d  r. w& h9 t2 M0 m
  26. + f1 u% `" D2 S; `" m5 A
  27.   void HC595_SendByte(u8 data);
    $ N3 ?- F7 M" e

  28. ) @( \+ Z/ j0 z8 X9 ?# V
  29.   u8 HC595_Display(u16 num, u8 dp);
    & L& z2 e! y; x0 h- d, K. F. f* Z: `

  30. 6 _, @6 r1 Q, `* K6 J! P, N  Y
  31.   #endif
    + ?! {7 P& @1 D% n9 _6 q$ q
  32. : l$ M. y& g. h6 n1 P7 B
  33.   源文件74HC595.c
    , L$ t) Y) o/ O5 _6 b

  34. 2 ]7 a4 M. M. V' Y' i7 g
  35.   // 用于HC595实现的4Bit-LED Digit Tube Module" y4 ]( T. `6 Z8 ]& @
  36. - h0 F, U- q3 i. f3 ^
  37.   // 注意:该4位数码管是共阳的!
    0 j5 M* T" p* d4 K) c* l

  38. 0 o; u9 _6 m4 R) ~3 w$ g; b5 q" S
  39.   #include "74HC595.h"
    * O0 D) C2 }, I
  40. ; \- I9 |% b+ L: n! j$ F4 l
  41.   // 码表
    - V- S( e( D% Y, \9 ^$ D# U, f+ k: g4 m

  42. ( A0 r: q6 \3 g' q* ~5 U8 w+ W; o
  43.   const u8 digitTable[] =4 Y) c" E$ V$ z3 E

  44. ! L! ]: v3 {: W3 B0 [
  45.   {* K  O/ |0 }2 G  V* F* D

  46. - @$ l* y4 H. B8 c7 Q) P9 Y" n% k
  47.   // 0 1 2 3 4 5 6 7 8 9
    ! G$ k: Q# n2 W! Z

  48. ( O# k  A7 \4 f
  49.   0xC0, 0xF9, 0xA4, 0xB0, 0x99, 0x92, 0x82, 0xF8, 0x80, 0x90,
    7 Y  y% \  {% G* m; W. ~$ v2 c
  50. 7 r& h. G, Q) j: J9 s% m, Y+ J
  51.   // A b C d E F -
    " _  D  ~# z9 F# d
  52. - t5 B3 _1 y! x" }! l1 }
  53.   0x8C, 0xBF, 0xC6, 0xA1, 0x86, 0xFF, 0xbf
    2 T% X8 i4 U5 c  J
  54. 1 d+ P) s9 H8 a  v; _* g* x5 U$ v
  55.   };! V, X- A. L8 a' {2 f- Y, ^( y
  56. . K1 Z/ t$ }0 l) `3 B6 x
  57.   /*******************************************************************************! W. p  c& a3 c. g$ ?
  58. % F2 E5 X" w' i7 ?( F
  59.   * Function Name : HC595_Init" L7 H0 |8 z. X* x* D# d+ j
  60. / g( l/ |4 x7 A& [) t
  61.   * Description : 初始化HC595
    1 s& g' ]5 w' @2 ?
  62. * ]7 X( ^0 d9 O- M# f' N- G
  63.   * Input : None
    4 m% \3 p8 d" G5 l" l
  64. ( L9 \! @6 V, S9 \# ?7 u
  65.   * Output : None
    6 f8 G% @1 m# E5 x  F- u7 U% c
  66. + W$ n3 `9 l2 M" o% j: E. l
  67.   * Return : None) n( p; k; B6 t  C+ z# h2 j

  68. 0 j* S$ l/ H, [$ d3 W! O7 M7 @' S
  69.   *******************************************************************************/- Z! ^4 E7 y1 S& _
  70. $ D0 i2 U% D, F& x. E/ n
  71.   void HC595_Init(void)
    / M. r5 {4 }4 L1 T1 [9 E

  72. 5 |$ U# U6 S( G) h; N6 ?- O
  73.   {
      b: I9 ]# `0 i$ R

  74.   {4 x) I, d2 z/ ?7 w
  75.   GPIO_InitTypeDef GPIO_InitStructure; //声明一个结构体变量2 J! O5 c  D7 w
  76. ' @4 O. c$ L- H8 f2 a! y
  77.   RCC_APB2PeriphClockCmd(HC595_RCC | HC595_RCLK_RCC, ENABLE); //使能HC595的时钟6 `# C+ D+ E% ^; |8 k
  78. ' O$ l' @, Y2 U5 f
  79.   //74HC595, SCLK RCLK DIO 推挽输出
    4 }# E5 r; ~7 a9 Q- d& H

  80. 6 r2 f; T$ n6 A5 H" w
  81.   GPIO_InitStructure.GPIO_Pin = HC595_SCLK_PIN| HC595_DIO_PIN;: d! p5 D& y: s/ S" n

  82. % x9 h8 u; z5 f' Y
  83.   GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //管脚频率为50MHZ
    " o! f6 m! N( Y6 q
  84. 0 y8 f7 M. m& E& D
  85.   GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //输出模式为推挽输出
    : V9 v# V/ p- X5 H0 h. K
  86. . ?7 N" t# h" S% S7 Q
  87.   GPIO_Init(HC595_GPIO, &GPIO_InitStructure); //初始化寄存器
    % T$ d) \: l: G2 o! A
  88. ; n- }3 e3 _+ b# ]8 U0 W' P
  89.   GPIO_InitStructure.GPIO_Pin = HC595_RCLK_PIN;
    7 t- F- x- q2 @9 i
  90. 4 ?4 |! n$ s+ Y4 y. [
  91.   GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //管脚频率为50MHZ( F! o2 F* [% g6 d9 `

  92. ' E5 M& p# n- J" |' j7 ~7 K
  93.   GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //输出模式为推挽输出
    % N( L+ h$ K7 A: I1 ^5 X2 W
  94. # A7 }. ~( l" m' B" u
  95.   GPIO_Init(HC595_RCLK_GPIO, &GPIO_InitStructure); //初始化寄存器
    & R/ `2 D, w8 s- s6 H+ n

  96. $ s+ Q* |0 K  z6 j' n: d
  97.   }: Q' I6 G+ \: K/ q. h5 R, E8 J
  98. 8 o+ j4 S0 X; z) e
  99.   /*******************************************************************************" e8 H7 p  k0 ]; y* H" y

  100. # S! V" v- \) l# u! ^% f9 g0 V' I$ u
  101.   * Function Name : HC595_SendByte
    9 y% n  [, d7 Q# P! X3 a5 {

  102. " C4 j8 ]& r3 V  d; T* _
  103.   * Description : 发送一个字节
    " w5 ?2 }9 \. Q% A, j0 Q$ Q
  104. ) N, Z8 B# N* i; X& ~8 }5 S2 H
  105.   * Input : data+ U7 o4 z. x$ X0 f, _- r( v6 z; _: {9 A

  106. 0 ~. p& L( {8 ~- N9 T0 ?
  107.   * Output : None2 x- J/ p$ @" C" N# b2 _

  108. * U8 O/ ^& V/ z6 e: l
  109.   * Return : None8 ]# P. R4 V# g& t* \7 i7 U! c
  110. % x; ]. D6 q7 {, L% R
  111.   *******************************************************************************/
    7 C- C$ |( }1 E
  112. & n2 Z5 r" d/ ^/ A
  113.   void HC595_SendByte(u8 data)
    + [1 Q5 f: Y! B4 B

  114. $ t' }% I2 [- h" V+ b* p3 \5 U- V4 }
  115.   {
    " I* i: r! y  P: f' ^

  116. . N! H6 H- I1 J8 R5 e* h) O: d
  117.   u8 i;5 b0 v0 o" B0 ^9 X, {" O; R8 `
  118. ; z2 t4 B" Z5 t
  119.   for (i=8; i>=1; i--)
    * l  d4 d2 \" |  w# A

  120. 9 ^( d1 ?) Q5 s
  121.   {
      h2 u- A+ f9 ~

  122. ; x. E/ @0 j# i1 t! }4 s
  123.   // 高位在前
    9 G1 }" L7 M- X$ p

  124. % e: R, D: V' h1 M
  125.   if (data&0x80)
    ( D  _* m+ ]" o1 o

  126. / U& c+ }5 C! D8 K5 B) ^
  127.   GPIO_SetBits(HC595_GPIO, HC595_DIO_PIN);
    ) Z( a7 b) _- s
  128. . f: P* Q3 K/ C1 o' i
  129.   else/ Y3 ]& V+ X; r" X5 N

  130. + k$ L0 x! F) G% a) m" Z, M7 o( f
  131.   GPIO_ResetBits(HC595_GPIO, HC595_DIO_PIN);
    . ?$ a! g  H* u8 U: d
  132. 3 n. z0 ^1 g# Q8 o  ^+ s
  133.   data <<= 1;
    - \  K3 l* t- G
  134. ( g3 r& U7 Y: m# j+ i/ q
  135.   // SCLK上升沿
    " I/ o: v, Z; B0 w. W, B

  136. , A) E. ^4 i7 @: @
  137.   GPIO_ResetBits(HC595_GPIO, HC595_SCLK_PIN);! A% p* ~0 ]0 O- Q

  138. + Q4 [9 M$ l6 x7 Z/ V
  139.   GPIO_SetBits(HC595_GPIO, HC595_SCLK_PIN);
    1 N; z  C6 c" Q- Y# B2 I) z

  140. ) e$ Q' Y( T6 f8 `! W9 z; U
  141.   }2 b$ c2 T$ z' U( ^" b7 E

  142. ' p0 z: J! V0 \6 }
  143.   }4 B) c. a' E- C7 E$ B
  144. 6 K' {# b5 H; C7 a: A# [0 |% S
  145.   /*******************************************************************************$ H  F7 K, T" ~6 s

  146. 7 B" k% R3 t! `- k6 ~! p, h5 r0 G
  147.   * Function Name : HC595_Display
    & Y6 c6 X# v& N) x
  148. , a0 j* m4 z  |
  149.   * Description : 显示4位数字(包括小数点); l# x: i1 B/ Y% _, X0 E

  150. 4 q5 _6 M; Z' I* P0 v
  151.   * Input : num: 0000 - 99991 n/ E- D% |- L& ^5 W
  152. ' E# C9 X7 p* ?8 j& K, E; B. D) d
  153.   * dp: 小数点的位置1-4: L0 V" `& A  F3 z$ d
  154. + j3 m2 p5 v8 C% ~3 K% [
  155.   * Output : None3 y4 ]" c1 b( L; c0 g: a
  156. ! h6 [! g$ `% c
  157.   * Return : 正常返回0,错误返回1
    0 s8 k1 t+ S/ x0 v6 \! r4 H$ G
  158. ; n  U1 j# a. {7 E! }6 r  Z# D
  159.   *******************************************************************************/
    ) K0 A- Z6 n- R7 D6 ~* |, I6 i

  160. : N% D" y: z" A5 \: K1 v
  161.   u8 HC595_Display(u16 num, u8 dp)  q( k2 [( q8 c2 W. ^" |, x1 u

  162. # n% U) F% t# @+ @; @7 U9 t
  163.   {
    & b4 z$ L1 Q- F
  164. & E1 D+ [& w6 v/ ?6 N3 w$ }
  165.   u8 qian = 0, bai = 0, shi = 0, ge = 0;
    9 l- l; K% W& g& i2 v* q
  166. 8 M* n$ @7 K+ z, e. [5 {5 D
  167.   // 对显示的参数范围进行检查
    / `* \! E3 t) ]  E( E+ W

  168.   G; k2 _+ I" E; `5 g, h
  169.   if (num > 9999 || dp > 4)
    # {  N. P8 U6 A. H% r
  170. 5 y  F; U" J0 M
  171.   //报错$ ^2 ~5 c2 J0 T
  172. ; x- l$ U) P1 l' r8 m& @& n
  173.   return 1;, h  d+ v- ]& ^9 {
  174. # S+ Y8 N) V" [0 I. m  x; U
  175.   // 对num进行分解- u, |5 J* c& h; P9 {) X

  176. * @( C& T  W7 x, a1 N, l" B  A7 U' q9 l
  177.   qian = num / 1000;
    + @6 o1 h# B1 X  ]2 r' j6 s
  178. 0 b& a0 r3 P6 j
  179.   bai = num % 1000 / 100;
    + [$ q- ~3 C; l8 O" l
  180. 9 r& U! \. K! u3 p- |. i. v* A& D7 E
  181.   shi = num % 100 / 10;
    2 J2 i2 c) N" J. x6 I- @4 W
  182. ! _' }% H: e5 M* H6 l
  183.   ge = num % 10;, M8 y7 d- J* d0 `1 Q) a7 k% e
  184. ( R6 o6 v" b! B& Q
  185.   // 千位4 k3 l* G! r8 v1 @. N0 Z2 S

  186. ; C2 z! }( s$ l# Q7 f0 J
  187.   if(dp == 1)
    , o6 K! \, w: K& X
  188. 8 ~1 L* ^5 M5 ?# U
  189.   HC595_SendByte(digitTable[qian] & 0x7F);' e+ v4 G& M7 L+ t

  190. . t$ H) R! U& w% O& C6 X) H) |# D
  191.   else4 ^; u/ l+ ?6 H- b+ x$ O

  192. * n! _0 \' i! c
  193.   HC595_SendByte(digitTable[qian]);# v2 Q  V; |6 P. Y, W

  194. / H, A. ]' e% P* N
  195.   HC595_SendByte(0x08);
    7 ~( ]: h' _) m) e3 \! W' z4 B' F

  196. ( f% p" Z9 T9 o# _7 ?3 v7 X
  197.   GPIO_ResetBits(HC595_RCLK_GPIO, HC595_RCLK_PIN);
    : M2 _4 @+ u! m5 L' T5 I4 ?

  198. : V1 F) j1 [  y; }. Q, @  b
  199.   GPIO_SetBits(HC595_RCLK_GPIO, HC595_RCLK_PIN);5 j4 X5 s, N* i4 e. u4 R2 L, z# T

  200. 5 E! w7 S$ U: p6 l
  201.   // 百位
    8 Q- A+ l. N; h! ]

  202. / b1 Y0 ?; h" r
  203.   if(dp == 2)2 N! _- [- J7 `; ]

  204. , f  u4 _' e! }1 h( p( p; ~- A
  205.   HC595_SendByte(digitTable[bai] & 0x7F);% C7 g2 s. R( e: \
  206. - @$ d; m4 m- o3 @" i
  207.   else
    7 r  O( e" O5 R" J; Q

  208. , n1 H4 H: O% S' \& C& T
  209.   HC595_SendByte(digitTable[bai]);
    # w4 n$ l; T8 h2 E

  210. # R- h* F  N$ V: }- h" t! |
  211.   HC595_SendByte(0x04);) D( n0 H- c2 x# y7 Z% v! l" ~

  212. 4 o1 y! a2 k3 t0 u( C4 U8 m
  213.   GPIO_ResetBits(HC595_RCLK_GPIO, HC595_RCLK_PIN);/ ?9 H) J' c4 x6 u) Y: N3 I9 [# E3 H
  214. 6 O4 p, H7 b1 B3 z( r) R
  215.   GPIO_SetBits(HC595_RCLK_GPIO, HC595_RCLK_PIN);
    # i, ?% K0 o' v# e0 E. Y

  216. ; E: l& Y. {) \2 V. \
  217.   // 十位0 k$ ?3 A3 P4 {1 R7 L# q  |

  218. 0 d1 t# y2 T2 s( a8 p
  219.   if(dp == 3)
    & a5 X' z4 L( g( K
  220. ) o9 ^8 m$ s( g. p4 H& {
  221.   HC595_SendByte(digitTable[shi] & 0x7F);
    5 u) ?& u* z( }8 N2 B- y

  222. ( d2 F9 d, l  B; z3 s4 G
  223.   else- R' C7 ~, \" v3 m6 W! @) t

  224. ! a! l6 o7 K) C8 T! A: _7 |
  225.   HC595_SendByte(digitTable[shi]);
    9 l" h! {  C* o/ h2 f; E$ |

  226. / M7 R$ u$ k- S7 t! R" e
  227.   HC595_SendByte(0x02);: J8 k6 o4 O, l7 r0 q, C( _& V. n: W

  228. $ Z4 E* S8 T% h
  229.   GPIO_ResetBits(HC595_RCLK_GPIO, HC595_RCLK_PIN);0 j0 g) ~% p  P( j0 Z6 v1 U
  230.   o" C, [  @8 k; g
  231.   GPIO_SetBits(HC595_RCLK_GPIO, HC595_RCLK_PIN);& P4 L) N+ |6 |- ^9 J5 W6 b

  232. + j8 B" W$ v- u
  233.   // 个位  t" ?0 K0 z5 X. R! u6 g% f& a8 f  l

  234. 1 x- a% E4 v) e! a7 m+ @5 q
  235.   if(dp == 4)$ Y% a; ?& A" Y
  236. 4 W8 _- ?- c4 }) }# J& n
  237.   HC595_SendByte(digitTable[ge] & 0x7F);& S( M3 L9 G& V/ p1 k

  238. ! R) {" B0 |% f5 }- l2 \
  239.   else) v1 }, Y  n3 |$ I
  240. ( F5 @( N% L; X2 X
  241.   HC595_SendByte(digitTable[ge]);1 K2 y& ~6 `, y0 I& G; o
  242. & {/ U- t* W4 V% J6 k1 y
  243.   HC595_SendByte(0x01);: A( _' m1 R/ u9 t; P! o
  244. 2 i' ~4 r/ l4 s3 Y" y! C
  245.   GPIO_ResetBits(HC595_RCLK_GPIO, HC595_RCLK_PIN);, x1 V. a* |# O6 v! z" X
  246. ' R% I9 W+ D5 m) b% ?
  247.   GPIO_SetBits(HC595_RCLK_GPIO, HC595_RCLK_PIN);
    7 E- C+ s9 G5 r( D; f% r

  248. 3 N" `( j' T1 g' A# P$ ]
  249.   return 0;
    1 H$ }5 A6 {  Q' M3 O0 Y* W' S

  250. : v8 x6 M1 l2 T1 `4 n
  251.   }
复制代码

, k, l# k* y) P7 b7 |1 I1 {  接下来就可以把重心都放在STM32的SPI外设上了,首先需要读一下STM32F10x的参考手册的SPI(串行外设接口)部分,这样对SPI就可以有较好的理解,比较重要的是要看懂SPI的结构框图和主从机通信的示意图,如下:
7 Z; D1 Y4 Z/ y
  这个理解以后,我们就可以参考《STM32F103XX固件库用户手册》的SPI部分来实现STM32的SPI外设配置和收发数据了,具体代码如下:
  f. N+ Q- Z: Q+ X: S  头文件74HC595_SPI.h
) ^$ h4 a2 g. ]7 \2 h( ]: o
1 a) B0 v  V- m: `+ g$ ?: I
  1.  #ifndef __74HC595_SPI_H__
    & \6 z9 U$ |% F/ |4 V; y
  2. ) V. e' O1 Y2 C3 y! J& d
  3.   #define __74HC595_SPI_H__
    6 w8 i: c0 f+ b6 C, {& D! e
  4. 5 B% f& |3 d1 I: m: U3 ]# e
  5.   #include"stm32f10x_lib.h" //包含所有的头文件; T8 R* U# o4 X; b0 Q+ T: k

  6. 6 G& c- e7 p" w+ O% z9 A' u
  7.   #include9 h. A2 P! I' _9 h1 k8 U
  8. ' @4 j& {0 G% H* e/ h0 i
  9.   // 4-Bit LED Digital Tube Module0 a7 {( G8 Q! Z% z$ N2 O# Q. Z
  10. 8 z5 J2 U0 j1 W
  11.   // 引脚 // SPI1 4位数码管: P% \  c1 |. d; P
  12. " I' j! c/ Y* ~0 C- P& s5 Z. x% W( N6 M
  13.   #define HC595_NSS_PIN GPIO_Pin_4 // SPI1_NSS 未用
    9 |: e) Z6 p4 ?( k$ f1 W  |; Y

  14. - p. V+ |" _, z, R. G
  15.   #define HC595_SCK_PIN GPIO_Pin_5 // SPI1_SCK SCLK1 i( |' G" i6 m0 q7 E* l* \: O3 e

  16. / P  v$ Z) S4 [. i
  17.   #define HC595_MISO_PIN GPIO_Pin_6 // SPI1_MISO 未用3 e, Z) ]0 z; [6 U0 n7 ?
  18. ! F) R) [9 B1 K9 ^/ y6 B
  19.   #define HC595_MOSI_PIN GPIO_Pin_7 // SPI1_MOSI DIO3 [5 w# ^9 x+ N6 N) X% m

  20. & z8 m, k8 J% q- H2 z' b( Y/ e: ?
  21.   #define HC595_RCLK_PIN GPIO_Pin_12 // RCLK! H/ d% A9 P& n% G# ]# p* S
  22. * Y) r% E( I8 k# t' v" i
  23.   // 端口
    % e- q+ O5 g+ j* i
  24. / \0 D5 O9 m" C6 D7 s0 n% d9 O
  25.   #define HC595_SPI1_GPIO GPIOA2 L9 [6 P+ `  e6 s9 Z

  26. 0 `2 y4 @! L0 \  w2 v& D* E
  27.   #define HC595_RCLK_GPIO GPIOB. w" ]! k: P. m; v2 @
  28. ! Y6 a: K7 M! i; R! ~
  29.   // 时钟
    * e( R3 v) d7 {9 x: e
  30.   V* E. F% ?% v8 d+ P+ @1 f' \0 O8 r
  31.   #define HC595_SPI1_RCC RCC_APB2Periph_GPIOA
    6 _8 k& d7 }3 C& Z: y0 c& d: F) N

  32. ! G- J3 V0 j1 C% T8 }4 p
  33.   #define HC595_RCLK_RCC RCC_APB2Periph_GPIOB
    6 q5 j3 _: _1 Z; p# c

  34. 6 m1 s; V/ n. R
  35.   void HC595_Init(void);
    8 |1 Y- N2 {8 m) C
  36. ; x1 R! q# t& P$ G
  37.   void HC595_SendByte(u8 data);
    " E$ J0 h0 a: h6 J5 B: K

  38. 3 G1 R9 f( y# ~# ]' }: j" X" S
  39.   u8 HC595_Display(u16 num, u8 dp);
    % H% T4 X4 n. Q- E+ k$ {
  40. - w+ ^* k0 U" g& ?  ?9 e1 {3 R
  41.   #endif
    3 D$ E9 o  y1 ]- Q* w

  42. , U  {9 J  m6 f: Z7 }
  43.   源文件74HC595_SPI.c! ]* F' O- D  i( L) o6 Z
  44. " v1 H7 r! x( H. P0 K5 u9 X3 z
  45.   /************************省略部分代码见(74HC595.c)************************/
    + W% Q5 I: @+ v/ H$ E' S
  46. 4 C  q8 K1 a! E1 C* y
  47.   /*******************************************************************************
    7 }) J  s. ~4 h  d" v' W2 P4 p8 ?

  48.   J- w( N6 A8 }6 g' c. l: U+ `0 Z7 }
  49.   * Function Name : HC595_Init
    " E( l! t5 ~+ g5 X% w

  50. $ T% Q  n6 {. _2 q& ?( k) d
  51.   * Description : 初始化HC595  K2 H0 A& k& z, E  n
  52. & Y. V# {$ n) U* w+ v" q
  53.   * Input : None7 a' _# n( p( A, M9 l
  54. 5 z) k. d; A. N/ Y' V! u) I5 s9 k  k
  55.   * Output : None# a6 |, O' F  [: A% Y

  56. 0 f- m0 n; R( F9 Z0 G* h
  57.   * Return : None
    6 _  r4 r% l' B4 _& m" ?  [) {
  58. # I; Z: Y* g9 O% C: o' w
  59.   *******************************************************************************/& f! R9 d( R$ l" ]  x. K- _
  60. 9 k$ ~2 w( E6 R+ L/ y1 F
  61.   void HC595_Init(void)! [. S, }5 R! l
  62.   {" i5 i  {2 l0 g  ]' a
  63.   {# ^% Q0 r! ?! |* P

  64. ' l) e$ Z1 \5 B% a  a* `; |
  65.   GPIO_InitTypeDef GPIO_InitStructure;8 D% U! Z7 L# }: t

  66. # [. P0 j" M2 T3 |" `
  67.   SPI_InitTypeDef SPI_InitStructure; // 声明一个结构体变量. T3 R3 S" C* @4 t' e/ _" V# Y
  68. 2 ?; C; ?3 w- ?( c1 U% C
  69.   // 不需要开启AFIO时钟
    7 S/ S9 L- t6 c

  70. & l& d8 x$ d% M4 T- P, L3 B
  71.   RCC_APB2PeriphClockCmd(HC595_SPI1_RCC | HC595_RCLK_RCC | RCC_APB2Periph_SPI1, ENABLE); // 使能HC595及SPI1的时钟" `: n3 h* p5 d0 @4 I9 s' ^9 k
  72. 1 W0 \- \4 V  F0 e# O: u& \* ]
  73.   //74HC595, SPI1_NSS、SPI1_SCK、SPI1_MOSI
    ! Q* ?* h; Q/ _- m# u0 Y
  74. ; h6 O' c; L4 B" }) |5 g
  75.   GPIO_InitStructure.GPIO_Pin = HC595_NSS_PIN | HC595_SCK_PIN |HC595_MOSI_PIN;
    * z  b/ i4 T* P( h; ~1 s3 w
  76. * O$ [. W: d1 T/ ]/ h! b
  77.   GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; // 管脚频率为50MHZ
    " i& q0 `" l  V9 H9 z

  78. - ]: d4 P. E+ [) Q( s
  79.   GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; // 输出模式为复用推挽输出
      J9 [) J1 ^8 q: _3 N
  80. # e! `+ ~! a, _& N3 m8 A) `
  81.   GPIO_Init(HC595_SPI1_GPIO, &GPIO_InitStructure); // 初始化寄存器2 S: m/ r( o7 Y" _$ E

  82. $ V; t0 S. V4 W
  83.   //74HC595, SPI1_MISO% y  n, H5 B: Q/ e, X% B' Y6 ?

  84. ; G# F+ ]5 P/ q; m
  85.   GPIO_InitStructure.GPIO_Pin = HC595_MISO_PIN;9 ]6 Y9 T6 C. X' @/ @+ P

  86. - d4 ^7 q6 B* |+ V% Z+ N
  87.   GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; // 输入模式为浮空输入' J9 A  D- G) _6 Y* Q6 A0 ^+ l

  88. 8 I' V; [  s. L' }
  89.   GPIO_Init(HC595_SPI1_GPIO, &GPIO_InitStructure); // 初始化寄存器$ O' G9 H" }; T3 V0 j3 {: U
  90. 0 ]# |+ g  _  w) J' l
  91.   //74HC595, RCLK( O- a' E1 r4 E0 J9 N( L! u- k

  92. $ B2 a; r% V1 b  }5 ^% n( s
  93.   GPIO_InitStructure.GPIO_Pin = HC595_RCLK_PIN;
    & ~8 d- M' m+ q) m4 O8 G
  94. 0 Q. \# A( p! H, O/ z$ w0 C0 ]
  95.   GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; // 管脚频率为50MHZ: [5 b0 y% @7 }9 c0 c
  96. , s5 c1 |9 B! F* {
  97.   GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; // 输出模式为复用推挽输出; _- w% S  c5 ^5 [- \6 H
  98. . ^! m. S/ T- G7 k; b! ~
  99.   GPIO_Init(HC595_RCLK_GPIO, &GPIO_InitStructure); // 初始化寄存器
    9 G! |0 ^% V5 S% t
  100. 0 F3 Y5 E2 M. i
  101.   /* Initialize the SPI1 according to the SPI_InitStructure members */6 J9 \- M; O; ]( n& v
  102. ! H4 c& f" ]* d0 v) j  R- C
  103.   SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
    : x: W. s# D  }  S) c2 @% w! H4 t- ]
  104. + k3 u9 h( `- l% ?8 k% H2 _
  105.   // 第一步:设置主从模式和通信速率
    " Q/ J8 s! g4 U! _" }9 Y( k
  106. 2 v" A# N& I' S  ?' D7 t$ G
  107.   SPI_InitStructure.SPI_Mode = SPI_Mode_Master;" j* ?; V* ]' R' W
  108. 8 K2 E" }/ e" n& v- R
  109.   // SPI_NSS_Hard时需要外部电路把NSS接VCC, SPI_NSS_Soft时SPI外设会将SSM和SSI置位8 K; d! L# y1 P* h

  110. 0 G+ ^% `7 V! R7 D+ I- \
  111.   SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;& q5 q. p8 L4 x- V
  112. ' c# h' G2 p8 z* [, Q* z0 K4 {
  113.   // 实测波特率最低为SPI_BaudRatePrescaler_8,否则出错
    & x' q+ g" a2 K5 X- S! X
  114. . {. v7 g% m. @3 O3 U* Q+ b
  115.   SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_4;* w. t: L. k6 H3 ]: A. ~
  116. 3 K) |3 [- n' Q' \" h
  117.   // 第二步:设置数据格式# |; c9 `  E* h3 g

  118. 5 x$ z- k1 N0 V( |& |  w- @
  119.   SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;
    7 v2 Q2 T1 a! u3 V+ K' _7 w
  120. 9 c( t3 S# h+ [% W$ g$ d7 n5 L
  121.   // MSB在前还是LSB在前要根据码表和数码管与74HC595的接法来定0 y+ e" w' J" l6 R' o

  122. 2 z1 ~  X+ L5 H, U
  123.   SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;3 M- x9 l) z* k% `/ M7 [
  124. / ?/ e9 `7 r2 b6 C
  125.   // 第三步:设置时钟和极性1 Y( k1 y0 M9 P

  126. 1 L7 C+ R  h  d$ ~1 q/ S- Q6 Y
  127.   // 当SPI_CPOL_Low且SPI_CPHA_2Edge出错
    $ Q) V- \; e6 A7 B0 D4 ?

  128. 4 a. m0 M8 Y/ Y/ [  t0 P7 O, Y
  129.   SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;
    9 Y! j0 `6 [5 O/ R
  130. ! _! W; J* \! d) R
  131.   SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge;3 u# u- k% P0 n) }6 y- m# m

  132. + j# R7 Z; J8 R: C( f: Z/ o" K
  133.   //第四步:其它,CRC校验,可靠通信,这步可以不设置6 L5 u# J$ Z, B# X5 P

  134. ) s3 y: z( y) c5 Z5 n' o4 n
  135.   SPI_InitStructure.SPI_CRCPolynomial = 7;4 [0 P" L1 Q; Q7 [

  136. 6 h9 X$ c" k! h9 ^3 a# d
  137.   SPI_Init(SPI1, &SPI_InitStructure);( O1 E  N9 ]  I7 t3 v& B
  138. ! P, ]  }, c0 c3 d) _& h# h
  139.   /* Enable SPI1 */
    $ d  e7 p! H; p" p& g& y! E& u

  140. ( P* d5 Z7 C8 d0 F5 l" [
  141.   SPI_Cmd(SPI1, ENABLE);! k6 B- C- d2 t( ?

  142. % U3 u! M# D' }! F1 [
  143.   }. c- Z6 |7 M5 k" q- c5 y8 A2 f& W
  144. : o$ A8 m0 y. N0 E- k* X' m% Z
  145.   /*******************************************************************************
    # F* Z4 q9 I. D. ^+ ^) `  o$ h

  146.   \: L) H/ Y" T: S$ ~
  147.   * Function Name : HC595_SendByte! Q9 e9 N6 ~# }7 ]" S" l7 C' b4 ~
  148. ) b% C" W1 ~* B! I3 j
  149.   * Description : 发送一个字节' p  o  F9 U; }! f
  150. ' x! K7 p( X: \2 W5 G  C$ _
  151.   * Input : data
    9 z" i9 E& c8 z$ {: o0 K
  152. & K+ \" w, e/ B: s8 V9 s
  153.   * Output : None, S: y) W& l9 k6 e$ u
  154. & y! K4 j3 y, L7 I
  155.   * Return : None. K6 q. m' R8 }8 y6 q( T- e

  156. : V  T- o& K: J. ~% F
  157.   *******************************************************************************/
    / w7 `( m( n! A2 D

  158. 7 M& h% S0 Z; R: Q4 X" r6 w7 M3 \
  159.   void HC595_SendByte(u8 data)6 F4 R* S+ B+ _3 `2 J; d: @$ ^$ g
  160. ' d3 @2 X! j! m( Z% c  i
  161.   {; X  ^# A* ^' y0 ~% l! u5 q+ b5 z) f
  162. + D  W6 y# V+ w
  163.   SPI_I2S_SendData(SPI1, data);
    1 G- ^: Q2 K- d+ ~( K
  164. 9 m  W+ s3 W( J, ]/ ?/ S
  165.   while(!SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE));, ]1 H7 W1 W/ H" I  {# M/ |( R

  166. 0 S' I  a4 N! i/ P. n) f, J
  167.   }
    $ ?8 L2 F2 |/ q

  168. $ e$ ~. K2 o6 |( T8 R
  169.   /************************省略部分代码(见74HC595.c)************************/
复制代码
4 }4 V1 I" K& x8 N9 m4 t+ z0 C* n1 m
  这样就大工告成啦,STM32的SPI外设还是比较简单的,尤其是通过库函数来调用。用数码管模块这种简单的可视化工具,我们就可以更好的研究通信协议本身的特性啦,后续我还会用这种方式来学习其它的通信协议。+ h1 `8 K6 {/ h

, f+ u( A$ s- }) E( t/ [2 \. E2 x& O% T% S! w6 F7 x
, ~4 ^' v4 w, [/ O
1 {6 T7 i! R  J) ^- D

该用户从未签到

2#
发表于 2019-8-29 17:27 | 只看该作者
好文章,值得收藏
您需要登录后才可以回帖 登录 | 注册

本版积分规则

关闭

推荐内容上一条 /1 下一条

EDA365公众号

关于我们|手机版|EDA365电子论坛网 ( 粤ICP备18020198号-1 )

GMT+8, 2025-6-21 22:58 , Processed in 0.093750 second(s), 26 queries , Gzip On.

深圳市墨知创新科技有限公司

地址:深圳市南山区科技生态园2栋A座805 电话:19926409050

快速回复 返回顶部 返回列表