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

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

[复制链接]

该用户从未签到

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

EDA365欢迎您登录!

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

x
  之前一直对SPI通信一知半解,所以想抽空把它搞得明白一些。考虑到之前是结合Flash芯片来学的,十分不直观,而且主要把时间和精力都花在Flash芯片的datasheet和驱动上了,SPI通信也没学好。所以这次就考虑用4位数码管显示模块,模块是直接买的现成的,如下图所示,这样可以简化操作,把精力聚焦到学习的核心–SPI通信本身上来。
1 h% F; J& B' t+ Z/ l  该模块是用2片74HC595串联驱动的,一片用来控制数码管的位选(U1),一片用来控制数码管的段选(U2)。接口比较简单,总共5个引脚,2个引脚分别接VCC和GND,DIO用来接收串行数据的输入,SCLK用来接收同步时钟,每个SCLK上升沿74HC595内部的移位寄存器会移一位,RCLK用来控制数据的输出,每个RCLK上升沿74HC595内部的移位寄存器的数据会被放进存储寄存器并输出到外部引脚QA~QH上。而QH’是串行输出引脚,该引脚会接收最高位的溢出,从而实现多片74HC595的级联。
1 S1 k4 d, x1 ?* ^; q
  当两片74HC595串联时,先发八位数据用于段选,再发八位数据用于位选,然后RCLK上升沿,就可以驱动某位数码管显示某个字符,通过动态扫描数码管,由于人眼的视觉暂停效果,就可以实现4位数码管的同时显示。先用通用I/O来实现该数码管的驱动,程序如下:
1 r4 b: ^) B  z: v; o  头文件74HC595.h7 P$ z+ [! J9 ~$ T& m
9 V" g. @  F3 z' [& Y
  1.  #ifndef __74HC595_H__
    . l. x7 Y' M5 ^3 G0 m6 A( Q' g. D
  2. & L3 I2 f  U1 }' L: l# U
  3.   #define __74HC595_H__* x% z1 M  B/ }3 G% W

  4. " {7 C! Q- f5 Z
  5.   #include"stm32f10x_lib.h" //包含所有的头文件  h  {4 y/ Q* D4 l) D& w7 C

  6. , h4 Q  K% m- l) a2 U! J
  7.   #include
    7 @2 ?& N# M9 H+ p4 @1 |5 T

  8. : Z6 E" ~- a7 {- z6 m% ^* w
  9.   // 4-Bit LED Digital Tube Module/ S% X. e5 S4 X- J: i, t6 d
  10. / b% r$ C& A9 V) }8 R4 S, N; n. d
  11.   #define HC595_SCLK_PIN GPIO_Pin_5 // SPI1_SCK PA5
    1 r4 u% C6 l, x* r* y' A6 U

  12. " X- b/ y0 E3 V. V0 Q" v
  13.   #define HC595_RCLK_PIN GPIO_Pin_12 // SPI1_NSS PA4
    # K- ^, z: m6 I& s2 T) p8 E" a

  14. 5 k; W6 N* i: ~# n& T
  15.   #define HC595_DIO_PIN GPIO_Pin_7 // SPI1_MOSI PA7
    ( U& _3 f* C, h7 ]

  16. ) X) b4 o! Z& X
  17.   #define HC595_GPIO GPIOA
    # [0 P% s, I2 ^4 q  e& \

  18. # ?& Q: a3 R; O; T( k& N
  19.   #define HC595_RCLK_GPIO GPIOB
    0 k. C/ [/ Z! w! S! I- a
  20. ! `. `% S8 a0 f+ T% S
  21.   #define HC595_RCC RCC_APB2Periph_GPIOA
    3 l+ m8 r  n* ?1 S: l8 p( v' u

  22.   u* e5 l7 |* ]8 V+ n
  23.   #define HC595_RCLK_RCC RCC_APB2Periph_GPIOB
    # u8 ]* K+ Y9 P9 k7 \" s" [: `
  24. $ f- v! s& A, s; Q
  25.   void HC595_Init(void);% y' [: T( H# ]/ y) v" u) r

  26. ( u/ `/ d- k/ |6 x6 n
  27.   void HC595_SendByte(u8 data);
    " \6 v1 W$ k& `' i7 R- W

  28. 0 I7 e7 C  @% g
  29.   u8 HC595_Display(u16 num, u8 dp);
    6 `; t8 r% G3 o$ z

  30. ( |1 B+ M# d7 g# ~
  31.   #endif8 [) Y8 m* u# g4 P2 c# p

  32. , p. x8 j# C, ~1 G) Z. z
  33.   源文件74HC595.c
    ( I: i1 R7 o6 Y

  34. 9 M- X6 ~# ?! U- J1 a+ A
  35.   // 用于HC595实现的4Bit-LED Digit Tube Module
    * q0 Y, ?" B- g7 S0 K' _8 E

  36. , {1 h( _$ @2 C; R6 B
  37.   // 注意:该4位数码管是共阳的!
    4 e3 P( O' T; \& |4 y

  38. 0 \, Q. M3 d" d; X. a4 r
  39.   #include "74HC595.h"
    9 X7 r; o4 \: Y" r* t

  40. * ]- d. [( @7 d3 a- x1 s0 d1 ?5 a
  41.   // 码表. T4 Y  \  r) t$ [6 X
  42. / ~7 I9 h7 X; h# }* F8 |
  43.   const u8 digitTable[] =
    6 x! p" Q  d% U/ S  ]- o
  44. 7 {) M; |. P+ c/ {4 {
  45.   {
    5 s" b  E# z  Q
  46. . V2 C% |1 d# I& p. f. _+ i
  47.   // 0 1 2 3 4 5 6 7 8 9
    ' r! I% t* a' ~" i% b9 b

  48. ) K; M9 z4 ^" L5 y4 y0 U
  49.   0xC0, 0xF9, 0xA4, 0xB0, 0x99, 0x92, 0x82, 0xF8, 0x80, 0x90,
    8 e4 m4 _- ?6 N" b1 m4 p% l; V
  50. % E& h, \" N2 u& x7 e5 D1 y) |
  51.   // A b C d E F -
    & F6 E6 P6 ?5 P, r
  52. & x' j: K9 @. o2 ~/ [
  53.   0x8C, 0xBF, 0xC6, 0xA1, 0x86, 0xFF, 0xbf
    ' L# _6 m- E* Z. I5 Y& V

  54. 5 o# J/ d. D: U$ X( a
  55.   };7 C, i" b1 E3 y" d( i

  56. 4 Z, d: ]& d9 J! i, x
  57.   /*******************************************************************************6 _% u! `( o3 v7 }! {

  58.   e$ a" T! g9 @& m1 c$ m* `
  59.   * Function Name : HC595_Init# z! w: z. Z" ?1 W7 b

  60. 3 h( x/ N; o. o- k- b! m
  61.   * Description : 初始化HC595
    ! k4 |7 K4 O8 E& Z5 B, V
  62. ' W$ ~; q/ ~% A5 l. I
  63.   * Input : None8 v& K2 q% E5 s& i

  64. - S% a1 w! }( @
  65.   * Output : None" a' b/ F2 x% V! s/ S

  66. / r6 ^4 a8 |$ q8 {
  67.   * Return : None, k2 c7 E, U0 j- b: h: o* b
  68. ' Q. a* T" J% r+ i  a/ F# y( O
  69.   *******************************************************************************/" D+ g; i: [" \* [; ^+ T9 Y

  70. ( T: W! V9 C6 o, y& X
  71.   void HC595_Init(void), d  Y8 K4 |& u* h5 ?" n+ b
  72. 6 P3 M0 C4 r5 Q* Z
  73.   {6 f9 D" R% f* J6 B
  74. ) B/ }5 q7 k  o9 B2 l, X: Z' a
  75.   GPIO_InitTypeDef GPIO_InitStructure; //声明一个结构体变量
    4 H' q; h3 Q  n* N. k# \
  76. 8 j  n7 b0 y. K
  77.   RCC_APB2PeriphClockCmd(HC595_RCC | HC595_RCLK_RCC, ENABLE); //使能HC595的时钟0 S% K# \2 H1 ?  b8 a; E
  78. , s5 K* h1 s7 N; w9 Q
  79.   //74HC595, SCLK RCLK DIO 推挽输出
      J: e; W2 j4 e2 }3 y" k/ q% j

  80.   Z0 o* `) L# Q2 `/ k' w, t% r" O
  81.   GPIO_InitStructure.GPIO_Pin = HC595_SCLK_PIN| HC595_DIO_PIN;
    7 Q4 y2 G! Z8 A3 Z' W& F
  82. , ~  e' W* \3 ?& y# M, r
  83.   GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //管脚频率为50MHZ* Q" v, W; t( n. a
  84. ) O) Q8 L4 g* j! E( e
  85.   GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //输出模式为推挽输出
    ; C9 U; d! q% x( j8 q0 h

  86.   Z! J" r) }# a2 a  x& @' u/ ~1 x
  87.   GPIO_Init(HC595_GPIO, &GPIO_InitStructure); //初始化寄存器2 @/ z4 V6 ]6 @7 O

  88. 7 j) K- S+ C5 n/ @
  89.   GPIO_InitStructure.GPIO_Pin = HC595_RCLK_PIN;; e4 C3 U) |1 N! }  E2 N7 y9 M. H

  90. . h; q  I* C8 v$ F* d5 u; n
  91.   GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //管脚频率为50MHZ
      p; a5 k1 I  b& V, ~. y

  92. 7 l8 q7 w6 D) w) ^' a
  93.   GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //输出模式为推挽输出
    . P6 s6 ?+ S0 h9 p# t" b; |8 h

  94. 5 t& G. ?2 ~( [/ s: l4 O
  95.   GPIO_Init(HC595_RCLK_GPIO, &GPIO_InitStructure); //初始化寄存器
    7 @& x8 F  a/ n/ P1 ~
  96. + w( y# ]! E( ~8 b. R
  97.   }8 w. @) }5 Y: ?# W3 k1 Q1 M
  98. 3 W' \' a: u  F: @/ c
  99.   /*******************************************************************************
      }; i6 I  I! P! L
  100. : U: H; m; m; r% N6 P2 y
  101.   * Function Name : HC595_SendByte) \) j- }1 T3 K+ N% H
  102. & k. Z' y" X# v) W, u
  103.   * Description : 发送一个字节
      t2 p: G+ q* C: P: a, R

  104. / E/ d- P  R+ R, t8 _" W0 f
  105.   * Input : data
    5 Z9 q) x4 a+ m
  106. % x/ j6 ^. c7 G! a9 o7 ^* ~
  107.   * Output : None0 {; v* U2 l+ A9 V# c; i9 d  |/ r

  108. 5 |$ p( O$ Z) Q3 t
  109.   * Return : None
    . @$ w) ^& _8 v6 l' n0 \7 L8 O& T% L
  110. 4 w* j+ o( }% @2 H2 t0 [
  111.   *******************************************************************************/
    5 C7 ^% b' I; m

  112. : a0 m* N0 s4 w( {* Q9 Y
  113.   void HC595_SendByte(u8 data)* I! A* {5 G/ v  d9 g. |

  114. / }) r( d! @- S2 Z( K
  115.   {
    , ]0 U0 D. x2 A& @1 n, x, f/ Y4 ]

  116. 6 Y1 I2 V( a# [" k
  117.   u8 i;+ M) M5 d& B. b9 G* w, @
  118. 9 k% q4 W" |0 K2 i. q8 i4 v0 I! T( R
  119.   for (i=8; i>=1; i--)5 m, G- e7 G( F3 ]/ t- A1 T

  120. : d. X6 `0 k) V. N/ _8 R) B
  121.   {
    # @3 f/ j$ s3 p/ m* B3 j
  122. $ [- [* r* V) g7 u9 ]
  123.   // 高位在前
    : m6 T- u  k2 o( _& A% w5 W* w! b
  124. * j; e" d# J9 |& x
  125.   if (data&0x80)& ~# d  K/ U4 ^
  126. : [2 w  l. G* |# W. U1 @4 P
  127.   GPIO_SetBits(HC595_GPIO, HC595_DIO_PIN);
    ' ?) _& D$ h7 u" M* F; J) ^- j3 b6 J. J
  128. ; u' @) k1 V5 \. m
  129.   else
    : B- J- e5 i3 D- F' ^
  130. 5 z" p. V$ \1 [. N
  131.   GPIO_ResetBits(HC595_GPIO, HC595_DIO_PIN);  `2 |; R. y  I+ r6 W% c

  132. 2 `$ e  W( V4 I# X2 N  z
  133.   data <<= 1;
    - I) c5 d4 H; }* J8 n1 S* [/ @% A
  134. ) ^% q4 S. \% \1 b
  135.   // SCLK上升沿
    9 t/ M  l. Q  e, D" I  o3 _" F

  136. 5 X) n' L! k( J# t
  137.   GPIO_ResetBits(HC595_GPIO, HC595_SCLK_PIN);
      q; o% l) T( [* W1 I6 t

  138. ' ~2 m" }- E* h# g3 R. {
  139.   GPIO_SetBits(HC595_GPIO, HC595_SCLK_PIN);  t& N+ _( u$ R! [
  140. , l) Y9 B2 e) E7 W, J- E
  141.   }
    6 X/ ~& I9 D; ~' D$ {! C

  142. 4 @; w9 f( [) R( K. O# N0 L; a
  143.   }% c0 x5 o: v' Q* \. @) S; o

  144. / Y8 K2 g0 b/ |5 l, q& d& R
  145.   /*******************************************************************************. b) t+ _3 W$ V4 @& c4 S) x( }% o
  146. + \- d9 b5 ^; u8 E5 f$ ]% I
  147.   * Function Name : HC595_Display/ H( @" B; m# N

  148. + m; A/ t  B% A: j9 ]  C7 k9 [
  149.   * Description : 显示4位数字(包括小数点)# @9 {1 r% @- S, r7 L- {  u
  150. ! ]! |+ {- I& R$ s# @. ]  U
  151.   * Input : num: 0000 - 9999
    / t& O% ~, p2 `- ^3 n
  152. + u3 y$ [5 r5 g: L
  153.   * dp: 小数点的位置1-4
    4 U% @! p* B" ^. A

  154. ' q/ o3 R! o" B& @% d
  155.   * Output : None
    2 O/ N7 t8 H; X; R

  156. / w# e+ w* T0 n, [6 O& u
  157.   * Return : 正常返回0,错误返回1
    4 v7 g5 X3 |& h/ \) I9 l' N
  158. & b7 W* _# u9 P- ]( E8 f
  159.   *******************************************************************************/
    ' [+ k. M# G; d! C

  160. 9 `7 f; u& o0 |7 T
  161.   u8 HC595_Display(u16 num, u8 dp)2 X/ G; m( T7 ~' @, R

  162. ; x3 w$ S$ A4 y1 J' J) J1 ^+ Y
  163.   {
    ' [! w% W/ f' o% r7 L0 N

  164. : @2 j, s- S( ?: j: }& k! g( r( F
  165.   u8 qian = 0, bai = 0, shi = 0, ge = 0;
    : w  M1 b6 e5 l* {, i6 X

  166. % ~1 `9 K4 P0 n+ |; c: T/ ^% V" u
  167.   // 对显示的参数范围进行检查4 l$ y* ^4 k8 y8 ~# U# k5 _& J
  168. 5 w0 h  g7 A8 T! {
  169.   if (num > 9999 || dp > 4)
    1 G+ Z& _- q6 I" p8 P

  170. $ Z5 o) ]  P  D" s
  171.   //报错( B8 b  h+ _3 R! S' C
  172. 9 ?- G5 ?+ V/ f6 ~" l! \2 ?
  173.   return 1;5 w( r6 C, `. U- D$ ?- M' L  F
  174. 1 T: ]) |+ G' k. q0 k- ]
  175.   // 对num进行分解4 a# @: M% T' W; r- x. }

  176. ( B, i$ C7 G8 }' W; D& o% l! _
  177.   qian = num / 1000;
    4 [  V9 _, p1 b! z

  178. + _/ N3 H" F8 w) O# d3 C% _, j
  179.   bai = num % 1000 / 100;
    1 l- H1 v. y1 \
  180. 9 ]* m4 K4 [) P3 g# A; b1 I
  181.   shi = num % 100 / 10;
    * ?" M4 Y0 b4 I6 K
  182. * o5 F: [2 V% c0 R- m, g' W9 X2 S
  183.   ge = num % 10;
    4 {" v4 L- C) v/ V0 P" r4 S9 N, s

  184. 0 _; _% a$ W* U
  185.   // 千位
    + t- A$ A% [& D4 |7 e  p' \

  186. % ~! m1 V" {- R5 Y) k
  187.   if(dp == 1)' u$ n/ k9 e8 z; L+ g

  188. ! a" Q; o- _6 H" ]# R
  189.   HC595_SendByte(digitTable[qian] & 0x7F);5 u/ ?0 v4 s4 `( ]2 w- Z9 |* E
  190. - S, z9 G' {0 G: u
  191.   else
    : {; c, y1 x8 F1 W. |7 l  ^# g
  192. ) z! A7 O& {9 [4 M5 ?2 u/ t! H
  193.   HC595_SendByte(digitTable[qian]);7 `9 j) [. X3 T" f4 O
  194. # B4 v, J. V2 [; \; B
  195.   HC595_SendByte(0x08);/ Z! t: A! l' Z* L
  196. 7 K$ g& r$ n/ @  I. Q5 r
  197.   GPIO_ResetBits(HC595_RCLK_GPIO, HC595_RCLK_PIN);. Q, R- M) A" M! z7 i$ E; j3 g' n

  198. ( R/ Q* m- P! ~/ ~2 @/ i- {+ k5 j; ~
  199.   GPIO_SetBits(HC595_RCLK_GPIO, HC595_RCLK_PIN);
    9 [! d& b# V# m9 M! F
  200. % W. j* @( y) c$ X; g, o
  201.   // 百位
    4 `- K' W7 m( s5 e/ N4 D; Q' ^1 Q% V

  202. ' |  t/ F: I: n  z, E7 ^8 P
  203.   if(dp == 2)
    " V! W  D$ _  j0 n* P2 Y$ c
  204. 3 P8 Y! G' Z( U
  205.   HC595_SendByte(digitTable[bai] & 0x7F);
    5 N& M9 b0 m& F3 D, @6 O

  206. & A$ {, ?" Z- s  a5 a2 ]- W
  207.   else
    3 ^+ t1 G) o3 ?9 z) ?3 y/ R! G: i. J

  208. 3 h% ^& s8 z9 r  c5 B2 T5 `$ I7 m
  209.   HC595_SendByte(digitTable[bai]);( \( d# y" u; \- E  Y9 e
  210.   K1 ?4 O$ Z& M& V+ l" X7 j
  211.   HC595_SendByte(0x04);
    - j  l/ m8 f6 |! R

  212. 7 V9 x6 P3 M8 u* R, a% g$ N& W4 _
  213.   GPIO_ResetBits(HC595_RCLK_GPIO, HC595_RCLK_PIN);
    : ~. W' ~+ c+ w6 q! {1 s  [
  214. - z8 N4 S+ y1 k& U; ^  a
  215.   GPIO_SetBits(HC595_RCLK_GPIO, HC595_RCLK_PIN);
    : W0 }1 v  B. j% @

  216. ( a; O4 k$ y3 r
  217.   // 十位* g- o0 n8 `. {- a

  218. 9 }; N- T6 q# I. \( d8 j
  219.   if(dp == 3)
    7 h: O9 Z5 v- Z, R4 w' w9 O

  220. . D. w" g* ]- _0 Z! |& f1 w7 g
  221.   HC595_SendByte(digitTable[shi] & 0x7F);
    1 @9 Q- x6 B3 ~
  222. 1 K( F+ C1 T8 {" P
  223.   else  k2 |, H0 n* ?9 U  c! W1 u
  224. " E. `# q9 L* V5 B* ~& g7 M
  225.   HC595_SendByte(digitTable[shi]);" \* ?; n5 u9 m; g
  226. 1 l* b0 J$ I' i9 v
  227.   HC595_SendByte(0x02);
    - q- \" m& ^& |5 ~: Q2 M: ]0 l; H7 k
  228. 6 H; u5 V6 `8 {* j' F0 v+ ~2 H! W5 K
  229.   GPIO_ResetBits(HC595_RCLK_GPIO, HC595_RCLK_PIN);
    ! X) y$ i* ?% G+ k
  230. . m5 y- \. h1 c
  231.   GPIO_SetBits(HC595_RCLK_GPIO, HC595_RCLK_PIN);
    6 ~' X, X+ I% C% p+ `8 ^% M# p

  232. 2 K& _# ^- h3 s4 X+ d$ Z; y
  233.   // 个位, f% ^. B7 J7 e  ~# K: s

  234. 9 S* C5 p" j, x$ |& ?$ U0 x
  235.   if(dp == 4)/ ?3 `% v0 |7 m3 i$ I; g: K8 O
  236. 8 i$ A1 @" T! M9 X1 T! e: P! M
  237.   HC595_SendByte(digitTable[ge] & 0x7F);/ g  \1 h$ v' l8 ?+ j2 s; }4 }
  238. 4 t) j* j! ^% P/ _& H7 ]
  239.   else
    8 `' F# u1 s4 p% E# k1 W7 _

  240. . y$ [/ g/ Z2 W) H% A* C0 Q
  241.   HC595_SendByte(digitTable[ge]);
    5 A2 `+ U5 ?, L! j
  242. - A+ Q* }) z. w1 C
  243.   HC595_SendByte(0x01);
    8 F* f3 m/ G' u9 C+ K

  244. . c% n* |) |0 ^4 q
  245.   GPIO_ResetBits(HC595_RCLK_GPIO, HC595_RCLK_PIN);) @( _: e% r' u/ K/ q$ [
  246. # Q2 q5 s; w- V1 u1 h$ }5 S
  247.   GPIO_SetBits(HC595_RCLK_GPIO, HC595_RCLK_PIN);+ [, b+ I/ \2 A( f) B+ z" d8 C3 g

  248. ! l& s6 w. h) `+ G+ W6 `2 ^8 g+ Z
  249.   return 0;5 p' l& [( R: R, l9 T

  250. + e0 Q( j, f8 z4 l/ l! c3 W, f
  251.   }
复制代码

6 k9 x3 B& W( q& N  接下来就可以把重心都放在STM32的SPI外设上了,首先需要读一下STM32F10x的参考手册的SPI(串行外设接口)部分,这样对SPI就可以有较好的理解,比较重要的是要看懂SPI的结构框图和主从机通信的示意图,如下:! G) A, J0 f9 k
  这个理解以后,我们就可以参考《STM32F103XX固件库用户手册》的SPI部分来实现STM32的SPI外设配置和收发数据了,具体代码如下:7 ?4 y' i) C# Q3 _7 `, \! @
  头文件74HC595_SPI.h
/ f$ l$ v  V+ z- Z# V
$ q" o' H+ E; ~$ @2 C
  1.  #ifndef __74HC595_SPI_H__
    , I4 D4 p# ^1 z2 k) s9 F7 \6 [7 t
  2. ) N. J2 @) P8 v# b0 `9 V0 g" H- [9 M
  3.   #define __74HC595_SPI_H__
    6 b4 p) N; E' R5 c

  4. . g& U. x& K3 e
  5.   #include"stm32f10x_lib.h" //包含所有的头文件  u& F( _% P) |$ }
  6. 8 l5 g% C4 ?( ]# ^( {# ^- [
  7.   #include' P. h8 z, C; E. M8 X
  8. ; Z; _, h) j; {2 M8 B
  9.   // 4-Bit LED Digital Tube Module1 c- Q" A% R. ~6 h( m
  10. 6 ]+ Q; v2 H" f9 _% B0 L4 V+ Q
  11.   // 引脚 // SPI1 4位数码管
    , N3 g1 ^: g- x" @* L, A
  12. 0 ~4 y$ i0 j% h( r* }. n8 Q% Q
  13.   #define HC595_NSS_PIN GPIO_Pin_4 // SPI1_NSS 未用
    & D" p1 v# g1 t  g

  14. ( _9 a9 Q: y; U; Y& h
  15.   #define HC595_SCK_PIN GPIO_Pin_5 // SPI1_SCK SCLK  W2 K5 K0 {8 G. L8 m6 p

  16. 6 Q6 y: H" l7 U6 P: s
  17.   #define HC595_MISO_PIN GPIO_Pin_6 // SPI1_MISO 未用6 D' Y& `+ R+ v! q( T% E) ~

  18. 3 t# w. _% j% h; G; x
  19.   #define HC595_MOSI_PIN GPIO_Pin_7 // SPI1_MOSI DIO6 p4 A% M7 B" |9 H; @( \0 T
  20. : l1 Q1 W6 i! k
  21.   #define HC595_RCLK_PIN GPIO_Pin_12 // RCLK
    , o% }6 H% u+ V* E3 {3 }# b* g; Q

  22. * J8 ~% i; ~% Y" b8 o+ H
  23.   // 端口
    # D& r3 b& l; Y/ z8 V/ o7 ~
  24. # E+ L+ y6 L$ l% M2 W
  25.   #define HC595_SPI1_GPIO GPIOA
    ( }( O+ L0 [! H& `' Z9 ~

  26. 6 {* s. x. f/ C" Q7 Q
  27.   #define HC595_RCLK_GPIO GPIOB( k" F5 x. _/ f! q' d4 n
  28. , Z1 V" G: q3 r$ E; J
  29.   // 时钟
    3 J& H4 y+ h' O6 `: J8 r, ?! ]
  30.   T; `4 y5 p+ E" B* C/ o1 _
  31.   #define HC595_SPI1_RCC RCC_APB2Periph_GPIOA4 @  p- `% T0 D% c; Q
  32. # H! S( Q) l8 h8 W9 r4 h6 j
  33.   #define HC595_RCLK_RCC RCC_APB2Periph_GPIOB/ S& l# P" R( _7 v

  34. * P0 a* t' |: ?  u
  35.   void HC595_Init(void);
    $ P8 H* J4 K" G: i5 m5 P

  36. & N1 G( t9 I9 ?
  37.   void HC595_SendByte(u8 data);+ D+ u! z1 v; v

  38. 9 I0 ^% Z, |6 s$ d$ w. n% ]
  39.   u8 HC595_Display(u16 num, u8 dp);
    ' M! c# d# {. T$ e

  40. 9 `, M. q( L4 c1 G8 H
  41.   #endif
    $ {4 C+ t6 Q) @- S* {

  42. : k0 s( \% G1 G) a( L+ b5 o& B# j7 h
  43.   源文件74HC595_SPI.c
    : h' i5 D' O) q, o# l! M, U

  44. * }* M6 W7 U) M( r" {+ }& z1 Z* V
  45.   /************************省略部分代码见(74HC595.c)************************/
    ' S/ H) U& o' [% n* C; O& y" ^
  46. 7 i3 }/ ^! z& g2 r% \0 s. l
  47.   /*******************************************************************************
    * G( g: P+ x+ h( P! K$ M5 }
  48. / P6 y. l$ v2 Y. B$ o/ G" {% a
  49.   * Function Name : HC595_Init8 j) d: t9 f" c% C, q3 D0 a
  50. 5 c$ `- u4 W5 I! Z, y) r  d* ]
  51.   * Description : 初始化HC595- d9 ~6 r  @+ _& Y8 l- C
  52. 2 z1 P% S9 ~! e+ O. N' G, c8 {9 G
  53.   * Input : None
    * r$ u6 a, c  K# N* j

  54. ' u4 X; @5 u* I- _& e+ v
  55.   * Output : None
    , _2 t8 J  W1 L1 Z. f% A
  56. $ E- m4 r* y- Y$ @/ S0 T
  57.   * Return : None
    % H) P5 u. a! r
  58. 3 a" C6 h$ C) N2 w5 p, c8 Z- ]
  59.   *******************************************************************************/( V. p+ v( o3 Q
  60. ' y# V% A$ i, G% Q3 R
  61.   void HC595_Init(void)4 s8 i1 P6 r" L) W6 B

  62. 5 a9 Q7 S9 ?% V; `! o! D
  63.   {
    6 w" ~. d, z  c

  64. + s. H: s: D& K5 U: m
  65.   GPIO_InitTypeDef GPIO_InitStructure;% R% @/ b3 t1 E9 t& B/ f& ]. G

  66. ' R5 I/ K! h" R0 I9 j7 n
  67.   SPI_InitTypeDef SPI_InitStructure; // 声明一个结构体变量
    # N8 K; X, X8 H- ~3 L9 A& c, F

  68. ; L. N' f9 J. z
  69.   // 不需要开启AFIO时钟) x  a2 a% Z( d  K8 Y8 {& s4 b0 x- S1 U
  70. - ^5 a) A2 p9 _" K+ C$ C" G( a
  71.   RCC_APB2PeriphClockCmd(HC595_SPI1_RCC | HC595_RCLK_RCC | RCC_APB2Periph_SPI1, ENABLE); // 使能HC595及SPI1的时钟
    6 `$ c  P( F; Z7 ]
  72. * F8 T4 A5 a% C
  73.   //74HC595, SPI1_NSS、SPI1_SCK、SPI1_MOSI4 M- v3 z6 X3 `% \* Q6 q
  74. 0 u, ]7 k/ d5 o
  75.   GPIO_InitStructure.GPIO_Pin = HC595_NSS_PIN | HC595_SCK_PIN |HC595_MOSI_PIN;
    ( r; B$ \4 F9 d/ t* k8 P
  76. 7 n8 G7 g7 `2 j1 j8 L8 r- ~
  77.   GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; // 管脚频率为50MHZ
    , U7 z/ h. f( Y( p% k5 d4 y
  78. , k. H. _7 m6 o+ u
  79.   GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; // 输出模式为复用推挽输出
    2 \: f$ ]3 [/ A5 M% S, y# N
  80. ( r2 h5 `. B3 C4 e0 ^& C
  81.   GPIO_Init(HC595_SPI1_GPIO, &GPIO_InitStructure); // 初始化寄存器# G; D1 V+ M+ L6 P' Y

  82. 4 v. Y* ?: w5 m: W
  83.   //74HC595, SPI1_MISO( u! i9 j7 j, Y" q# J6 z' H

  84. 5 }' u! d5 {" q' ~# H
  85.   GPIO_InitStructure.GPIO_Pin = HC595_MISO_PIN;
    " V6 G9 x, D3 c5 y2 p9 }- u
  86. - U% ]& A' T* N6 s# Y# Z
  87.   GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; // 输入模式为浮空输入
    ! H( o9 f  |+ U0 p  H4 q4 Z# _

  88. - W% k( [; {6 E4 |6 T
  89.   GPIO_Init(HC595_SPI1_GPIO, &GPIO_InitStructure); // 初始化寄存器
    0 ^. C( a3 M6 _, o3 C% m: W0 U. _/ Y
  90. " d' Y" [7 [7 n. _  M" @
  91.   //74HC595, RCLK( [5 l. \, s9 \2 ?

  92. / @2 U6 Z6 f% K$ b2 {- J
  93.   GPIO_InitStructure.GPIO_Pin = HC595_RCLK_PIN;
    4 l1 s/ i6 L$ X. B3 Z  K

  94. % h# F2 I( j# |. J) e' P) A" w
  95.   GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; // 管脚频率为50MHZ
    / b+ ?2 Y" k) s7 E# I

  96. + ?6 V. E+ }/ c( A
  97.   GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; // 输出模式为复用推挽输出9 R2 M5 q  y4 F( z
  98. + e. K( T2 }$ n
  99.   GPIO_Init(HC595_RCLK_GPIO, &GPIO_InitStructure); // 初始化寄存器+ l+ P/ h) s5 K* P5 N2 d

  100. ) Z' _1 m9 A, J9 S
  101.   /* Initialize the SPI1 according to the SPI_InitStructure members */
    8 w  U8 B: \7 `& j% }4 T

  102. ) D5 T6 [7 ~2 v! [' g
  103.   SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;3 `! a& P% j1 s
  104. 7 _& e. o; g% l) K
  105.   // 第一步:设置主从模式和通信速率+ O; D& ]8 H, _. b2 Q

  106. + ~) F9 ]* C0 Z4 `% E% n0 c
  107.   SPI_InitStructure.SPI_Mode = SPI_Mode_Master;* f( n. B! Y9 e

  108.   I3 d- ^# H" F% s+ \" F  v* m3 F
  109.   // SPI_NSS_Hard时需要外部电路把NSS接VCC, SPI_NSS_Soft时SPI外设会将SSM和SSI置位
    0 |; O! B7 p$ y1 E9 k: ~" Z
  110. / M& S* w- U8 _! ]' \* O5 @- D1 {
  111.   SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;
    1 M. E) T/ U7 u2 Q( S

  112. ! _" N0 ?  D7 i/ N% g
  113.   // 实测波特率最低为SPI_BaudRatePrescaler_8,否则出错0 f4 i9 v$ m  z% G3 Q' H

  114. ' ^0 k; [0 G) m1 f2 @' T! L& Z
  115.   SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_4;2 `9 a  l& K: V5 t

  116. 6 Y# m+ J0 |5 ~) b) W( J
  117.   // 第二步:设置数据格式3 O" d5 C* X) \  ?& S+ X
  118. 3 W  V3 l7 s7 i& G( t7 \
  119.   SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;
      c8 L1 X6 D8 Q
  120. $ p4 p, v8 F% ?  a' @
  121.   // MSB在前还是LSB在前要根据码表和数码管与74HC595的接法来定$ M: ?8 ~4 b, C' B$ h& J
  122. 0 n- Q9 p2 T9 o9 f- w8 v/ M! v; }
  123.   SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;9 o% `" x$ ^4 L; c

  124.   e' P  Z7 i' B$ z0 ~
  125.   // 第三步:设置时钟和极性
    / e" P& Z+ Y- g& Y8 [4 D

  126. 7 }1 Z7 e7 i- @
  127.   // 当SPI_CPOL_Low且SPI_CPHA_2Edge出错
    $ G+ X3 F8 o3 f1 ]  l
  128. : L4 _0 V2 O' a; B' v+ m' O, z
  129.   SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;
    ; u: z7 _8 G+ Q( @, S- d: h; T
  130. 2 u( d3 }# s( l5 a- }
  131.   SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge;
    ) y& I+ A, z" U2 k5 O0 w
  132. 2 L: _2 X* u, Q% _8 C2 c+ Z" f! f' x. m
  133.   //第四步:其它,CRC校验,可靠通信,这步可以不设置
    6 P7 w$ h" E( N  b2 C) T* v
  134. ; w8 C6 k# y( n5 a: \
  135.   SPI_InitStructure.SPI_CRCPolynomial = 7;
    $ l( h: h# G( t) l+ }

  136. & O4 `9 q& R; J2 k; g
  137.   SPI_Init(SPI1, &SPI_InitStructure);% o8 A* Q9 m8 s1 p& `4 H3 F! k
  138. # K# I9 F) {8 l* }3 }
  139.   /* Enable SPI1 *// V8 ?# G/ A9 {) h$ y( O' g

  140. 2 h" m" O, y7 }# V
  141.   SPI_Cmd(SPI1, ENABLE);
    # u2 B7 [( `. \5 ~

  142. + z' D( _( A7 y; u$ F0 ]
  143.   }7 e3 `9 z' p: O8 {( U) X0 p: Y
  144. 6 J+ t, h% `+ X1 i
  145.   /*******************************************************************************, O# ?# h$ R9 O4 z( ?3 H2 Z( V

  146. # L- Y$ h8 _- @# V+ l
  147.   * Function Name : HC595_SendByte
    1 u5 {- B1 p- n! T9 h& U
  148. 3 @/ H) T5 w5 G
  149.   * Description : 发送一个字节0 _8 J) _1 Z2 r/ b& y/ O  {
  150. ! z( y9 D: X2 b; }0 o; y
  151.   * Input : data
    + x+ L9 k4 q5 k& r

  152. # r: V0 t, }6 r. t
  153.   * Output : None# W; l4 E, D: o% W+ o# d

  154.   x8 |& [' A2 _2 |; `/ `
  155.   * Return : None! H: E! v) M2 Q# R! y

  156. 4 k- ]! a2 v: e9 e& |, M
  157.   *******************************************************************************// ]) K2 b$ s/ f0 I5 D2 N4 K; U% }

  158. + h/ s0 {+ M6 p; k- s
  159.   void HC595_SendByte(u8 data)( ?2 U# h: o- x

  160. 0 l/ ]6 }0 `8 l6 U. O7 v
  161.   {, W0 I! U5 B' b( y& i! @
  162. 2 v  J) [( K( J4 {
  163.   SPI_I2S_SendData(SPI1, data);2 m# q$ i/ c! Y* a* H" p) R

  164. $ X' w5 {7 q$ u+ e7 I$ U1 m, ?
  165.   while(!SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE));7 D, E3 B3 [7 r& O0 ^% r
  166. ; }* O6 \  v# s4 A/ _  W
  167.   }) a/ w, |% }$ Y* g
  168.   V# l& o3 N: E' n2 b0 S
  169.   /************************省略部分代码(见74HC595.c)************************/
复制代码
# v/ n1 T6 Q, T, \8 B  |
  这样就大工告成啦,STM32的SPI外设还是比较简单的,尤其是通过库函数来调用。用数码管模块这种简单的可视化工具,我们就可以更好的研究通信协议本身的特性啦,后续我还会用这种方式来学习其它的通信协议。
" L! w& ~% ]6 c/ v) q' Y% a5 \8 D+ f! s
* s. A7 k. ]: k1 e( h) a
; c* g8 S9 C4 r
5 c0 I+ B4 Y" f) {3 m

该用户从未签到

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

本版积分规则

关闭

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

EDA365公众号

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

GMT+8, 2025-6-28 12:08 , Processed in 0.093750 second(s), 26 queries , Gzip On.

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

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

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