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

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

[复制链接]

该用户从未签到

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

EDA365欢迎您登录!

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

x
  之前一直对SPI通信一知半解,所以想抽空把它搞得明白一些。考虑到之前是结合Flash芯片来学的,十分不直观,而且主要把时间和精力都花在Flash芯片的datasheet和驱动上了,SPI通信也没学好。所以这次就考虑用4位数码管显示模块,模块是直接买的现成的,如下图所示,这样可以简化操作,把精力聚焦到学习的核心–SPI通信本身上来。
" ?  `: t- K& ^- J* R+ g  该模块是用2片74HC595串联驱动的,一片用来控制数码管的位选(U1),一片用来控制数码管的段选(U2)。接口比较简单,总共5个引脚,2个引脚分别接VCC和GND,DIO用来接收串行数据的输入,SCLK用来接收同步时钟,每个SCLK上升沿74HC595内部的移位寄存器会移一位,RCLK用来控制数据的输出,每个RCLK上升沿74HC595内部的移位寄存器的数据会被放进存储寄存器并输出到外部引脚QA~QH上。而QH’是串行输出引脚,该引脚会接收最高位的溢出,从而实现多片74HC595的级联。: X* S" `3 e" R7 ^, w
  当两片74HC595串联时,先发八位数据用于段选,再发八位数据用于位选,然后RCLK上升沿,就可以驱动某位数码管显示某个字符,通过动态扫描数码管,由于人眼的视觉暂停效果,就可以实现4位数码管的同时显示。先用通用I/O来实现该数码管的驱动,程序如下:
6 `& {* ~6 L1 Q2 ]& K  头文件74HC595.h
# i* ~- Y* ]& e- P7 ~! x$ ~2 ]% r6 _
  1.  #ifndef __74HC595_H__! f  z' a  `6 g" v) d; D& S
  2. 6 ^; S3 K2 r9 [8 \. k5 I
  3.   #define __74HC595_H__
    2 ?( F& }  y$ h3 U

  4. ' [$ K2 F2 a8 l. I# J
  5.   #include"stm32f10x_lib.h" //包含所有的头文件
    & _, O4 S9 P# h' V7 ~) b
  6. 0 j' Y6 p2 e3 p: \. y7 Q2 n
  7.   #include: ^. f3 v  W: q9 X
  8. 0 d3 a" e3 p+ u1 ]# w" Q
  9.   // 4-Bit LED Digital Tube Module. s+ c7 N* f' A6 W

  10. & F7 G1 K, I" ~5 M# s+ J
  11.   #define HC595_SCLK_PIN GPIO_Pin_5 // SPI1_SCK PA5
    , l. p0 G" [$ v

  12. 6 {3 t4 e0 f# o5 n6 ~/ z
  13.   #define HC595_RCLK_PIN GPIO_Pin_12 // SPI1_NSS PA4/ q& p" I8 y* a. y: o
  14. ) M. L0 J* E0 b
  15.   #define HC595_DIO_PIN GPIO_Pin_7 // SPI1_MOSI PA7* z! u7 n* P  X- t8 s5 q# q$ y1 y) k
  16. + X8 j5 {6 O/ T8 P
  17.   #define HC595_GPIO GPIOA
    6 h6 Q4 Q5 i7 [

  18. : V  M; B  O+ e  `( M
  19.   #define HC595_RCLK_GPIO GPIOB" T8 G9 w0 x5 j6 k6 Q; i& R
  20. ; s7 ^/ }/ |) f
  21.   #define HC595_RCC RCC_APB2Periph_GPIOA
    2 `8 I9 c* k) w3 R- M& i6 c1 ?

  22. . k. `8 h; q. u  h( }3 K' s
  23.   #define HC595_RCLK_RCC RCC_APB2Periph_GPIOB
    - q. @- d& m' R3 n" \
  24. 7 F( ?# g8 E- r4 A9 z3 m
  25.   void HC595_Init(void);& ?- K) z7 {* [; L8 u  T! E
  26. # M4 \% z0 B5 P( T
  27.   void HC595_SendByte(u8 data);
    ) {7 Y3 `& W/ w( A) r
  28. ! ~/ n& v% B7 d5 Q) G
  29.   u8 HC595_Display(u16 num, u8 dp);3 ?; l9 c9 R2 D; i& j9 G1 S

  30. ) Q: n2 b" R- o. Q2 _9 v
  31.   #endif9 U3 \+ w) R/ h0 O& O
  32. 3 ^. |( m  ?) |% C, u
  33.   源文件74HC595.c
    # j; t5 B; k$ @  I
  34. + A5 G6 U5 X/ ~' _7 h
  35.   // 用于HC595实现的4Bit-LED Digit Tube Module
    # g( e5 u: x% z7 b

  36. : V! [) N! X  O, y+ I% T( j
  37.   // 注意:该4位数码管是共阳的!
    2 t- A2 y9 c, e
  38. ) v. R& K, ~$ ]8 C4 W( T5 q
  39.   #include "74HC595.h"3 p# G+ H; N1 Y5 ~. K" I/ `, O5 o
  40. + e) i/ Z: _* S: C$ p
  41.   // 码表& x4 [2 Z, {4 ]. H4 v* e- S9 G

  42. ) k/ ]9 n7 r: H0 I1 t
  43.   const u8 digitTable[] =; Q7 D$ r8 {6 `0 Q- c  O
  44. . U) j" _7 X7 J3 t7 r
  45.   {/ B3 i# N7 |+ C6 l' H+ J% q9 V- M6 \. Y

  46. 4 Z: z+ B# n( E- O( [1 C0 _9 H
  47.   // 0 1 2 3 4 5 6 7 8 9' q- t* p% K5 o

  48. ! D& G% ^$ R: ~, V  k6 X
  49.   0xC0, 0xF9, 0xA4, 0xB0, 0x99, 0x92, 0x82, 0xF8, 0x80, 0x90,
    & G! B7 q4 k1 c& @' H; n# z
  50. / X& B+ g; J& k2 I8 V
  51.   // A b C d E F -: H1 g. r" Y) i4 Z9 T5 K! G7 d
  52. ; c1 A9 {& w5 F# @/ L/ r% `$ H
  53.   0x8C, 0xBF, 0xC6, 0xA1, 0x86, 0xFF, 0xbf
    3 P4 E4 V8 s, t, w: ?4 T0 Y& _
  54. : q3 T6 ^  f1 J. z1 l
  55.   };" M9 D  t  H# n' e" `
  56. 3 F8 t/ X2 x3 e# q$ c6 G8 f
  57.   /*******************************************************************************& y5 O" C! s1 k
  58. 6 F2 H% ?8 ]+ a8 X& {8 r6 v; k9 I2 |
  59.   * Function Name : HC595_Init
    . @! k) z, j1 [5 j8 \% ]
  60. + {  j0 q5 \, ]9 I" t  A
  61.   * Description : 初始化HC595# j% u+ x6 K, w( _

  62. " r! w5 J9 p& `7 F: }' `3 n3 s
  63.   * Input : None
    9 y; U& J. q. W+ r

  64. 6 I. I9 i8 s5 M) e! u* d5 t5 j
  65.   * Output : None9 k4 r- N# {+ R$ C2 q3 a
  66. % y/ K/ P  x! `* v( i: y% ^4 C
  67.   * Return : None' e; l8 J* b7 R  s4 l1 }$ `5 N9 u
  68. % k! X2 G, ?5 ~+ q# J& [; l4 E* K
  69.   *******************************************************************************/( j) I( Z' \4 i1 v+ S
  70. 8 |# ?  f, h; j
  71.   void HC595_Init(void)- n; n, N4 b. @
  72. + K; ]- D" m' L4 i+ _- B
  73.   {
    $ J0 Q! a3 S+ V* ]  G# j) G  C* Q! s7 g

  74. * ~* X& e5 j' A7 I/ F% n. C4 M* R" S
  75.   GPIO_InitTypeDef GPIO_InitStructure; //声明一个结构体变量1 W* @4 J2 S) S* ?1 q3 y
  76. 4 f2 g- {0 ~2 k7 g" W
  77.   RCC_APB2PeriphClockCmd(HC595_RCC | HC595_RCLK_RCC, ENABLE); //使能HC595的时钟
    9 Z. u; e5 K& P$ j
  78. & O% [* b# R% c9 _9 ?
  79.   //74HC595, SCLK RCLK DIO 推挽输出
    8 G- B" t4 A4 f
  80. + ~/ R' I0 _: o
  81.   GPIO_InitStructure.GPIO_Pin = HC595_SCLK_PIN| HC595_DIO_PIN;. r! z; s3 \* w: H. U

  82. : a$ A6 h2 N/ S2 x
  83.   GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //管脚频率为50MHZ2 W0 O% A; I) Y' D
  84. 9 c$ f0 {. y* x/ ?1 v9 X
  85.   GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //输出模式为推挽输出
    ( `* {! a  b) D4 k

  86. # l5 u- Y& p' y5 [9 k) D8 ?
  87.   GPIO_Init(HC595_GPIO, &GPIO_InitStructure); //初始化寄存器
      w" @0 ^; i* o' X# H
  88. + ]! k( T) M( k: g9 l1 ]$ X
  89.   GPIO_InitStructure.GPIO_Pin = HC595_RCLK_PIN;' T, ?8 a( D; @" V

  90. " {0 H# E! i/ M. a6 s
  91.   GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //管脚频率为50MHZ
    # ]' i/ ]! {  x+ G1 ~  x8 ?9 k; u

  92. 3 z  E, g4 X5 l/ O% e
  93.   GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //输出模式为推挽输出0 G/ U+ d! T! j: L
  94. 2 T" v1 h: c2 o: O" }
  95.   GPIO_Init(HC595_RCLK_GPIO, &GPIO_InitStructure); //初始化寄存器1 R1 n& ~( w" l+ Y
  96. 8 w$ H( G& O/ Q$ A! Q
  97.   }/ T" W: \- i1 q. D! k* l
  98. 2 p$ `) `7 S; g# R1 V0 T) S7 s9 s& ?
  99.   /*******************************************************************************
    ( R9 s7 W; Y/ ]/ `, E4 [% H( y: Y! L
  100. % m+ B/ ?8 `& O( |2 g
  101.   * Function Name : HC595_SendByte: N  S8 e$ [6 m" X9 v9 H
  102. 0 W  @+ f( x3 Z; ]8 x
  103.   * Description : 发送一个字节
    9 z, K9 r; h4 f( |

  104.   M, P) r8 p+ g# p  o
  105.   * Input : data! F3 P4 b% V# x. u! ]8 m9 H5 R
  106. 5 B; G0 `* p& v; ]! V
  107.   * Output : None
    4 Y' y5 k0 R- p" e  r  i# _
  108. & ]2 X4 p' U2 A" Y
  109.   * Return : None! l$ H* R; M1 }5 s# c" O5 g" J

  110. 3 s6 r: G0 n# ^8 C5 v
  111.   *******************************************************************************/
    ! V! x/ \& Z) i- [$ W' o

  112. ( n$ @9 c& u' y9 K7 q
  113.   void HC595_SendByte(u8 data)
    ' m/ ~, b  M1 F! N/ h
  114. - p. k5 q8 A# p( }. o9 R/ \
  115.   {
    0 h* l8 L/ m! `/ U3 Z1 ~/ ~
  116. % L* \0 G& J( i5 A! c
  117.   u8 i;
    ) z2 E" T; l( [
  118. + t" |: n6 R  a+ U, Y
  119.   for (i=8; i>=1; i--), X! j+ G  ?% f- O/ X0 v# J
  120. 5 u' ~; T% a- X2 f! O$ o
  121.   {) q/ c: y" J% `0 P
  122. 0 M0 v5 P- m) F; ~9 ~& n+ r2 [$ f
  123.   // 高位在前# v( W8 }; z. t7 P2 l. Q
  124. * Z: o. B" n& x: P* k! G. C
  125.   if (data&0x80)
      U6 i4 p: F( Z. {* i5 ~
  126. , v4 Z4 I) o5 V! M- [% \& |# H
  127.   GPIO_SetBits(HC595_GPIO, HC595_DIO_PIN);
    . y4 ~) B2 E3 w/ m4 ~; R
  128. ' _# W, q* D: p: k. C+ G- |' z
  129.   else
    7 U5 a$ I  D5 U# g3 s' G
  130. $ Q: H1 J+ o( F8 \8 \
  131.   GPIO_ResetBits(HC595_GPIO, HC595_DIO_PIN);
    + v) H/ o7 a( U# h. A% i- P; g2 n

  132. ( `9 g- P/ P3 Z; S) z) Z
  133.   data <<= 1;8 T5 c: J  T8 e# Z9 t
  134. , X$ p1 m, C7 v
  135.   // SCLK上升沿# @) \: p7 G+ ^4 h; R0 I0 b9 a

  136. 3 r0 C: H3 o) ^& x" |) k3 b" P$ B
  137.   GPIO_ResetBits(HC595_GPIO, HC595_SCLK_PIN);
    2 ]/ Z$ r) Z* k- |6 V- R
  138. % [  A- [5 ]  u3 u  I( H
  139.   GPIO_SetBits(HC595_GPIO, HC595_SCLK_PIN);$ ]( d7 h/ l, D- k  A
  140. 7 O4 `/ N5 R, C% w' ^$ k  H" Q! ~. ~3 Q
  141.   }$ X) }  k+ Y2 P( k  X+ _9 M. R

  142. - L6 a' k+ S6 a; I2 Q8 s
  143.   }
    + X( O. W. S0 s" `) ?5 t
  144. - a! d' i) d' A' g- [6 l, `
  145.   /*******************************************************************************
    # r3 H& i% r: L( c- g5 m6 H
  146. 1 T& h- M: [$ a/ y4 J4 G/ t
  147.   * Function Name : HC595_Display
    3 _/ o& a2 D' ]4 c4 u/ R

  148. 4 u6 h6 d3 y/ f; a3 S% a
  149.   * Description : 显示4位数字(包括小数点)$ f8 C. T& H  p9 n% @

  150. 1 F: O( Q  p9 p! Y; ?; g- I
  151.   * Input : num: 0000 - 9999" d5 P7 b" w2 _5 x0 s4 a& ^: Y

  152. : v; [6 ?) q# r
  153.   * dp: 小数点的位置1-4
    9 V4 C' C/ a. c) c6 i7 o% E5 Y" q
  154. - U' q9 ^2 I3 W" u
  155.   * Output : None
    1 }4 a6 M+ d3 @+ z$ v/ A

  156. * Z2 e4 G- z! W
  157.   * Return : 正常返回0,错误返回1  T" b" h  ^- k6 s

  158. 2 c& N( u/ @; Q! r. L! j7 ]
  159.   *******************************************************************************/# Q+ C8 N+ G" L( W
  160. 8 N  {# p* n* Y9 j9 w
  161.   u8 HC595_Display(u16 num, u8 dp)
    - ]7 [0 ?. l. p& c

  162. 3 {9 x' q! d4 L1 ^
  163.   {
    6 _6 k8 T& y! y, ~' P4 `
  164. ; h% X) U! z# O4 v# b4 e
  165.   u8 qian = 0, bai = 0, shi = 0, ge = 0;8 w+ ~( b0 d& z* w5 {
  166. 1 U% Y# k3 ?& r, N1 \6 F
  167.   // 对显示的参数范围进行检查
    2 k5 j$ Q3 j& X" [* N5 o: A' C  U

  168. $ G* x' M3 y& M5 e0 c# X. ?! x2 V
  169.   if (num > 9999 || dp > 4)" j* f7 X, E+ D6 R. |
  170. 6 V4 Q1 \# w' J3 y% N: o, w
  171.   //报错
    " M5 `, H9 h7 \% S

  172. ) d( L4 D4 c# X6 _# @
  173.   return 1;
    9 M; M. \3 }: _" i& o1 Q- {/ w& w

  174. 3 n7 J6 |! Y  e  w' _7 o( e
  175.   // 对num进行分解
    # w9 R& z: y: ~- C' w; ?$ `
  176. ; b2 b8 \, X$ `) x& K/ E) m
  177.   qian = num / 1000;0 H, A. q  p" q
  178. ' L: K3 O- \7 M3 {2 n
  179.   bai = num % 1000 / 100;1 |3 p( r$ }- D7 T! m- G8 S
  180. + F' [' p( R* X' I1 O5 E
  181.   shi = num % 100 / 10;
    3 d# J; i8 n: a. B: |4 `

  182. # T; ?! n. c6 j/ r. o% ?
  183.   ge = num % 10;
    % Z1 p  z6 m! j

  184. , Y: D. t) U; p1 I
  185.   // 千位
    & z6 d) E- L: E
  186. ' U" o1 I6 o1 h( B3 e5 {& l) e
  187.   if(dp == 1)
    8 i  j8 H: H1 t, A% [1 l: y3 F
  188. 9 t- ]2 l1 g8 i1 F9 I
  189.   HC595_SendByte(digitTable[qian] & 0x7F);5 g' P" L1 B! L* `+ c( E
  190. 9 p" Q" p5 s: t
  191.   else
    0 o1 S, j/ J7 U2 N' ^: \  X/ e4 v* [

  192. 4 Z' E* e6 X# U; ^( X
  193.   HC595_SendByte(digitTable[qian]);
    $ |; ^  C* n( P  g0 `- r: H
  194. 6 w, h1 A' z& }+ o  c- _  \
  195.   HC595_SendByte(0x08);
    ; v- g: R: ~% ^3 S5 F

  196. + i" F0 i7 Q8 y% e; B$ V5 \
  197.   GPIO_ResetBits(HC595_RCLK_GPIO, HC595_RCLK_PIN);; T3 ^0 W2 X4 T6 k. L

  198. 8 ]) T- ~, E1 ?. {2 s
  199.   GPIO_SetBits(HC595_RCLK_GPIO, HC595_RCLK_PIN);  @2 F7 a2 {: m" s

  200. 1 i+ I) ~$ r3 ~' H
  201.   // 百位& y' q; {. x; {& j! d% b. C

  202. * o2 R* w% F- P# `0 b
  203.   if(dp == 2)9 H6 {8 P6 X8 p9 v
  204. , H2 \$ o8 Z: \5 a7 |* E5 Y1 X4 B
  205.   HC595_SendByte(digitTable[bai] & 0x7F);
    ( J. U  ?- }! ]  S: f% d

  206. - Q& I# d3 x5 p0 N! B7 c# b
  207.   else
    * D) {0 \/ F/ {# G

  208. ' e4 a2 `+ e' J
  209.   HC595_SendByte(digitTable[bai]);7 ~7 i5 p( [7 u7 V9 G' E. ]2 U  z

  210.   I  g7 X7 T) w! c
  211.   HC595_SendByte(0x04);
    8 F  k' A" p- q( X* U; i( |  ~

  212. 9 @1 _1 L, W3 e& {" E8 d
  213.   GPIO_ResetBits(HC595_RCLK_GPIO, HC595_RCLK_PIN);
    & w$ C* l7 U) X1 V6 G. y# z

  214. ! ?" W$ J7 A' Z3 K
  215.   GPIO_SetBits(HC595_RCLK_GPIO, HC595_RCLK_PIN);$ F9 G- [! ~. J' u. @$ r
  216. 4 v  j/ q4 C) u/ U9 n) V& k
  217.   // 十位! z  L' R3 b4 {, f$ w: g+ N* ?
  218. ; h! }+ k' v& J2 G$ `' Q
  219.   if(dp == 3)  D; k1 G$ m5 F+ h) s
  220. 8 m; B2 @" e4 l) e6 }1 {
  221.   HC595_SendByte(digitTable[shi] & 0x7F);+ W' L: n( X& l5 R- J: v
  222. # B: c; p5 F! `  l$ ?
  223.   else
    * D0 s2 z  H% r- y- x; C3 H8 w

  224. " G% s/ x- y- n/ c- c
  225.   HC595_SendByte(digitTable[shi]);
    3 z% w0 m- u; i9 t& ^) _; B
  226.   i* o! m3 B2 G5 ~2 u2 J
  227.   HC595_SendByte(0x02);6 Q5 j6 d8 k% l- P% W' D9 I8 G% ^% O

  228. 3 b( [6 P7 x/ ^1 l! i7 S
  229.   GPIO_ResetBits(HC595_RCLK_GPIO, HC595_RCLK_PIN);) ]6 f; h& p9 ?9 J0 I) `
  230. 9 o3 _5 \/ O$ i
  231.   GPIO_SetBits(HC595_RCLK_GPIO, HC595_RCLK_PIN);
    " T. z* i# f7 N3 X/ |# Q

  232. $ I$ G/ K) `. O. W
  233.   // 个位
    2 @$ x# x+ e+ U" O6 j

  234. 4 @; M5 e" F7 i7 g: u( Q
  235.   if(dp == 4): Z+ W* k1 u1 K& N1 ?( x0 ]3 g) }
  236. : i9 I; R) C$ y2 _
  237.   HC595_SendByte(digitTable[ge] & 0x7F);
    + u  g- X( M: k/ j" d
  238. 2 Q- p4 F+ |1 r6 R) N' {8 G0 w
  239.   else$ z, x  @8 s$ f* _7 l  J
  240. ( L! r- D, E4 C$ a$ c5 s
  241.   HC595_SendByte(digitTable[ge]);
    ) b1 H8 R) J) H4 O% ?4 }- ]
  242. $ [4 _% W! A% j0 I- L# K! `7 V" l4 c
  243.   HC595_SendByte(0x01);
    ( G0 T; K: w. D' ?
  244. " ^1 A4 v# u! V: h
  245.   GPIO_ResetBits(HC595_RCLK_GPIO, HC595_RCLK_PIN);9 O1 f' q' x: N" Z' \4 O
  246. + ?& ?/ M/ Z8 \* _  M8 j5 ^
  247.   GPIO_SetBits(HC595_RCLK_GPIO, HC595_RCLK_PIN);/ _1 A# n! K. B

  248. 4 T2 K3 y1 m9 J/ V' I4 O
  249.   return 0;
    $ R9 a* K; D# p3 A
  250. # W; A" C, U6 L; j# k2 o3 B, }- r2 k
  251.   }
复制代码

7 |3 T" r  Z) B3 K" e2 M/ v2 u* H  接下来就可以把重心都放在STM32的SPI外设上了,首先需要读一下STM32F10x的参考手册的SPI(串行外设接口)部分,这样对SPI就可以有较好的理解,比较重要的是要看懂SPI的结构框图和主从机通信的示意图,如下:
# s/ q5 S2 }9 h* t1 i
  这个理解以后,我们就可以参考《STM32F103XX固件库用户手册》的SPI部分来实现STM32的SPI外设配置和收发数据了,具体代码如下:7 w  n6 B2 G- H
  头文件74HC595_SPI.h1 w0 P4 w" @9 H* ~) k. |

' k* o3 V, C4 Z
  1.  #ifndef __74HC595_SPI_H__
    3 M: z+ K8 Y+ O

  2. 6 V+ ^% g6 `9 J# i" h6 S
  3.   #define __74HC595_SPI_H__
    + }' F  I* D8 E7 S3 u

  4. 9 Q8 i% V+ S2 Q: o1 ?% F
  5.   #include"stm32f10x_lib.h" //包含所有的头文件
    1 z8 Q* ~6 ~: \: u4 B& h
  6. # t6 ]6 I( b% J- {9 v
  7.   #include
    ! A( E: @! ?. q4 `
  8. 0 a0 H+ c5 |# t; _8 S
  9.   // 4-Bit LED Digital Tube Module
    6 J" N3 s) W& ?" {9 x

  10. " n) y3 g( R8 P# O+ |
  11.   // 引脚 // SPI1 4位数码管5 F6 r  Y1 z. n0 `* S& F4 A1 j6 |
  12. : v- ~3 c4 e; q9 T( d* }% f
  13.   #define HC595_NSS_PIN GPIO_Pin_4 // SPI1_NSS 未用
    - p+ q' p$ l& s' E& @% Q
  14. 1 I$ _9 Z$ I- R* {/ ~+ @2 v) K
  15.   #define HC595_SCK_PIN GPIO_Pin_5 // SPI1_SCK SCLK+ T. x, `/ D5 O/ x+ D

  16. . v: Q* T, w% P$ _) g) l
  17.   #define HC595_MISO_PIN GPIO_Pin_6 // SPI1_MISO 未用" @0 @; e3 G: b) v: v' t8 Y" a
  18. . V! v+ D; P; `' ^6 _
  19.   #define HC595_MOSI_PIN GPIO_Pin_7 // SPI1_MOSI DIO4 g- F; V, x3 P) ^! H, Q
  20. ! j; y0 q1 ~: R8 j: r, C' \
  21.   #define HC595_RCLK_PIN GPIO_Pin_12 // RCLK
    % e; r7 y  K8 V
  22. ; Q" b* d7 s4 F. I; L* d2 P
  23.   // 端口" I1 t" y9 I- q) C
  24. / L0 ]" }$ q/ _  q; E
  25.   #define HC595_SPI1_GPIO GPIOA* y/ d4 o9 ^  C7 G' z
  26. ' u9 ^  \4 d6 Z5 i7 `7 M4 O
  27.   #define HC595_RCLK_GPIO GPIOB
    ' }' ^- L! U5 T. D
  28. % J' N  y1 Q: M# w
  29.   // 时钟! @: Y) R" S! B: H6 ^
  30. ! s; O' ]0 u: W- }( \
  31.   #define HC595_SPI1_RCC RCC_APB2Periph_GPIOA  y3 T0 M8 D6 C+ {  E  K
  32. # s8 s4 y5 |* g2 b9 K
  33.   #define HC595_RCLK_RCC RCC_APB2Periph_GPIOB6 E$ O: o0 b' T/ f. Q

  34. 4 [, n# B: E* a7 q6 S
  35.   void HC595_Init(void);" m3 e7 o' p" |, h: I

  36. ( O# A) ^, z8 q/ z2 `! d
  37.   void HC595_SendByte(u8 data);
    . s* d# [; y: ?. q

  38. 5 j; j4 {% F. {5 i$ [
  39.   u8 HC595_Display(u16 num, u8 dp);
    8 ?: ]8 d) F* A8 S

  40. & ~3 v  v3 w  @1 ?6 }0 O4 C* V4 D
  41.   #endif% m6 ~% ~3 g& U1 Z% H* C
  42. ) d2 X; w* b" g9 ]. A
  43.   源文件74HC595_SPI.c
    1 A0 I/ _+ ]& ^5 K% ]+ i1 C
  44. 0 N  H8 c2 P; }5 y9 b3 s/ I
  45.   /************************省略部分代码见(74HC595.c)************************/" W* b* |: o7 f. ?# Y7 ~$ P
  46. & e' t7 H' M( |: a6 `, t
  47.   /*******************************************************************************% w7 d8 D2 Z: H" m) ^9 l* r

  48. , x+ [5 s+ _0 N1 q
  49.   * Function Name : HC595_Init2 m# A2 _5 }/ _" J

  50. 9 q0 ~: _- v3 H6 [/ K. Q2 C" V
  51.   * Description : 初始化HC595) e- V# ?6 }- [) {  W
  52. ) S3 O8 t; ]6 B) v! i
  53.   * Input : None% G) }% ?1 E! Z9 ^' T

  54. ; c8 }( ?( _, t  T
  55.   * Output : None3 x, a" I% ~/ W5 Z) V, X

  56. + J8 s+ N. [& W  t1 R. }0 R# \
  57.   * Return : None' H; n/ g# x, _3 s7 V+ y. I' X
  58. 9 A- ?5 v# u! q/ A
  59.   *******************************************************************************/' ]+ c- X+ W: X$ t3 V+ E3 d

  60. , k% b: M) S+ U. ~
  61.   void HC595_Init(void)" n0 [/ |( |, Z
  62. 2 j* P$ o7 o+ d3 w6 m0 i" k8 h
  63.   {5 y$ G2 X- H6 i1 ?% M4 t

  64. $ t3 S& |4 Q, \  b5 ?0 b. I
  65.   GPIO_InitTypeDef GPIO_InitStructure;
    2 C( G3 r/ ?' J/ ]$ P8 _

  66. : J! x5 }. ]- _  w- ^
  67.   SPI_InitTypeDef SPI_InitStructure; // 声明一个结构体变量
    + v! w/ {! E: i* h6 B, B

  68. 9 _( V  r8 c9 J$ l! S
  69.   // 不需要开启AFIO时钟6 F8 @5 e9 s1 ?# n/ Y# j+ i

  70. ( A: @% r1 X0 P2 B& ^
  71.   RCC_APB2PeriphClockCmd(HC595_SPI1_RCC | HC595_RCLK_RCC | RCC_APB2Periph_SPI1, ENABLE); // 使能HC595及SPI1的时钟
    * K3 `8 G6 n  l; Y+ F
  72.   p* H) f2 C/ q' ]. ]. u" c
  73.   //74HC595, SPI1_NSS、SPI1_SCK、SPI1_MOSI
    0 n# Q- {4 q& D

  74. - D! P0 ^* r* A% Q
  75.   GPIO_InitStructure.GPIO_Pin = HC595_NSS_PIN | HC595_SCK_PIN |HC595_MOSI_PIN;& r% S4 T0 e8 R& f! ]0 k( d8 u* s0 V

  76. " y- |6 j3 `" G0 d
  77.   GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; // 管脚频率为50MHZ6 ~) y$ h4 y% z
  78. " O) l8 J5 N; K7 a* _2 ~1 V
  79.   GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; // 输出模式为复用推挽输出. r8 L' F, `- \7 k) K
  80. 5 D$ Y; ~- w7 ^9 M( x
  81.   GPIO_Init(HC595_SPI1_GPIO, &GPIO_InitStructure); // 初始化寄存器- a5 q' i; R% t# j0 z2 u
  82. + H7 }5 \' C1 p- n$ {0 B  o
  83.   //74HC595, SPI1_MISO
    2 I- R' q9 q, y" s% i) Q+ m
  84. . L& e" S6 f  V8 g9 d+ Q7 z7 ~
  85.   GPIO_InitStructure.GPIO_Pin = HC595_MISO_PIN;# p/ m% q* H5 a
  86. ( V3 _- P6 D3 j8 A! y8 g
  87.   GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; // 输入模式为浮空输入
    + y' ^8 U* \$ D7 y: Q% S
  88. % M7 T7 V0 [( y( H2 G0 Y9 x
  89.   GPIO_Init(HC595_SPI1_GPIO, &GPIO_InitStructure); // 初始化寄存器
    1 u: U; P/ r0 g/ r2 y2 }/ ~8 Q0 l1 i

  90. / p  C, c( J! D8 g
  91.   //74HC595, RCLK
    9 h% z1 ^$ a8 S: R. D0 j
  92. ) o, c. K& b- p3 T# J! t0 B; y: P2 h
  93.   GPIO_InitStructure.GPIO_Pin = HC595_RCLK_PIN;
    , }7 B. \/ s3 H* R- H% q
  94. ' X2 m0 ^" l( K$ z  m
  95.   GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; // 管脚频率为50MHZ8 A# G3 s2 K! Z) L
  96. 9 k  ?5 y. y5 s% {! R- V, `5 H
  97.   GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; // 输出模式为复用推挽输出
    0 w" s8 L/ z  g% N1 V
  98. + |2 ^( }: @6 G* N' z) s
  99.   GPIO_Init(HC595_RCLK_GPIO, &GPIO_InitStructure); // 初始化寄存器
    6 Z6 V* b- ~- `9 k

  100. , b! Y$ y) z/ N8 W% t
  101.   /* Initialize the SPI1 according to the SPI_InitStructure members */5 g/ P* S* _6 n- Q. X* u- h9 E

  102. / g  s( j/ _2 J5 w7 v
  103.   SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
    ' l! J; U! N2 L% o. p6 w0 Z

  104. * m  w$ H0 R3 n; _' e/ F1 ]
  105.   // 第一步:设置主从模式和通信速率4 ]! A/ u" p. K) [3 ^
  106. 3 e/ Y0 `/ K4 ?
  107.   SPI_InitStructure.SPI_Mode = SPI_Mode_Master;
    1 E, t3 }7 c, d1 n5 j; x+ k# L

  108. / i' ]2 l3 R  \2 J' \
  109.   // SPI_NSS_Hard时需要外部电路把NSS接VCC, SPI_NSS_Soft时SPI外设会将SSM和SSI置位
    8 S& |$ O3 ~9 `2 ^. Z) ~

  110. & z( u0 ^9 o$ Z
  111.   SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;
    & w& \7 d8 y0 }: o
  112. - \& f1 u, ~( y7 r* D
  113.   // 实测波特率最低为SPI_BaudRatePrescaler_8,否则出错+ E, V' ~9 g0 L" k9 r
  114. ) b6 Y: w+ k; c8 d3 B
  115.   SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_4;9 k6 j2 R8 ]0 C! n/ c- P
  116. 6 t4 {! ^0 {. H
  117.   // 第二步:设置数据格式5 m" d7 c. Y+ O; T  o
  118. 7 s% I7 t0 b8 G4 V: U
  119.   SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;" l4 e8 @, y8 g, K$ D; D% P

  120. ' \+ U! s  s$ B$ J
  121.   // MSB在前还是LSB在前要根据码表和数码管与74HC595的接法来定
    9 T. _0 r5 S% ^/ R! A3 f% W

  122. 2 z5 z' q+ G3 P3 q) s
  123.   SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;: q5 P$ \! j$ Y- I
  124. 7 C! M6 Z, r; Y1 ~
  125.   // 第三步:设置时钟和极性$ j8 c6 W) T+ J1 k& I
  126. " b  {  t9 ?# n
  127.   // 当SPI_CPOL_Low且SPI_CPHA_2Edge出错
    ; e) |2 G/ H7 G6 x' M0 i1 H

  128.   e+ C" Y% u& C
  129.   SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;, p* k6 `$ a7 N4 K0 E/ t1 ]

  130. . @4 E% h  z. U8 T0 [( t( Y/ g
  131.   SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge;# m0 q/ Q5 [/ b8 B; J
  132. 8 ^* a1 m: w% W: q# X
  133.   //第四步:其它,CRC校验,可靠通信,这步可以不设置8 x* g9 C/ o. q& M- k
  134. $ [. m' C" g* |4 Y! v! C- N, O; y
  135.   SPI_InitStructure.SPI_CRCPolynomial = 7;
    1 m9 H0 B3 t% L) _9 y+ t$ A9 R% G0 ^

  136. . q- k4 V6 w& [) ^9 U- l
  137.   SPI_Init(SPI1, &SPI_InitStructure);
    / G8 }/ p- g# c; i
  138. & F# Y' T! k7 m; a- w1 R6 |
  139.   /* Enable SPI1 */0 J0 Q  L7 u! Y  }, p

  140. 4 `$ Q( G, L; _
  141.   SPI_Cmd(SPI1, ENABLE);- u% |! R$ v5 b- U# ^) l

  142. 0 g  M$ ~2 ?# G% k+ P) b$ k. c  i
  143.   }/ X* l7 K  ]/ S* }+ |
  144. 5 f. _/ m6 X0 f7 w4 _8 N7 h
  145.   /*******************************************************************************% `2 r7 t6 V! c8 F5 u: l
  146. 9 Q) g+ \. m: V+ t
  147.   * Function Name : HC595_SendByte
      S% P$ h3 J: V% F( b
  148. 5 b8 J+ Y+ I- t- W0 O% m
  149.   * Description : 发送一个字节: R$ t: g, Z  H

  150. 1 ]. u  F. N8 l" f' _
  151.   * Input : data
    4 n) y$ C. V) B; e! u: X

  152. ' X9 P- j0 Q. \* \6 {* m3 h& I2 k
  153.   * Output : None# p" q( [" R4 m/ X$ T5 V
  154. : p9 Z2 }! k. {8 l% E! n6 t& l
  155.   * Return : None7 t# ?; x7 t% e' w1 u5 R7 q
  156. 0 y- x; E5 {& u  P. |$ R; O9 |  ^
  157.   *******************************************************************************/
    5 Z  C+ k5 I/ ^0 ^) G! i" L

  158. 4 w/ \% g2 p9 K' p2 T6 j, s! f
  159.   void HC595_SendByte(u8 data)
    + v, P8 D5 E* B+ p9 _# _
  160. 8 b4 r& y! X8 Q. K. Z
  161.   {, b$ C7 Y" U: p( ]$ n" C

  162. 0 o" u& W5 e* o: P
  163.   SPI_I2S_SendData(SPI1, data);% q( F. P/ |. f9 t8 j

  164. 6 i3 k/ Y: F$ R' w) x9 K' G# [% }
  165.   while(!SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE));5 R4 \! i" `' ~! k8 M

  166. + f# Z/ G0 {* q% W
  167.   }8 X# X8 V2 ?- x+ I
  168. + c& K% h1 X, r8 D  C  L! u8 O7 c. J
  169.   /************************省略部分代码(见74HC595.c)************************/
复制代码
' M+ {& X% u% j5 ]* j
  这样就大工告成啦,STM32的SPI外设还是比较简单的,尤其是通过库函数来调用。用数码管模块这种简单的可视化工具,我们就可以更好的研究通信协议本身的特性啦,后续我还会用这种方式来学习其它的通信协议。
& S( N4 Z% n4 F5 C  }" p6 N& A9 Z# X, K; @% K: T$ u6 y  n
, ]0 T; m2 K. Y4 l/ F

3 c" h7 I/ q7 F; u3 v9 e: E4 B9 y2 d9 J1 }3 _

该用户从未签到

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

本版积分规则

关闭

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

EDA365公众号

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

GMT+8, 2025-8-21 22:19 , Processed in 0.125000 second(s), 27 queries , Gzip On.

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

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

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