|
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 _
- #ifndef __74HC595_H__! f z' a `6 g" v) d; D& S
- 6 ^; S3 K2 r9 [8 \. k5 I
- #define __74HC595_H__
2 ?( F& } y$ h3 U
' [$ K2 F2 a8 l. I# J- #include"stm32f10x_lib.h" //包含所有的头文件
& _, O4 S9 P# h' V7 ~) b - 0 j' Y6 p2 e3 p: \. y7 Q2 n
- #include: ^. f3 v W: q9 X
- 0 d3 a" e3 p+ u1 ]# w" Q
- // 4-Bit LED Digital Tube Module. s+ c7 N* f' A6 W
& F7 G1 K, I" ~5 M# s+ J- #define HC595_SCLK_PIN GPIO_Pin_5 // SPI1_SCK PA5
, l. p0 G" [$ v
6 {3 t4 e0 f# o5 n6 ~/ z- #define HC595_RCLK_PIN GPIO_Pin_12 // SPI1_NSS PA4/ q& p" I8 y* a. y: o
- ) M. L0 J* E0 b
- #define HC595_DIO_PIN GPIO_Pin_7 // SPI1_MOSI PA7* z! u7 n* P X- t8 s5 q# q$ y1 y) k
- + X8 j5 {6 O/ T8 P
- #define HC595_GPIO GPIOA
6 h6 Q4 Q5 i7 [
: V M; B O+ e `( M- #define HC595_RCLK_GPIO GPIOB" T8 G9 w0 x5 j6 k6 Q; i& R
- ; s7 ^/ }/ |) f
- #define HC595_RCC RCC_APB2Periph_GPIOA
2 `8 I9 c* k) w3 R- M& i6 c1 ?
. k. `8 h; q. u h( }3 K' s- #define HC595_RCLK_RCC RCC_APB2Periph_GPIOB
- q. @- d& m' R3 n" \ - 7 F( ?# g8 E- r4 A9 z3 m
- void HC595_Init(void);& ?- K) z7 {* [; L8 u T! E
- # M4 \% z0 B5 P( T
- void HC595_SendByte(u8 data);
) {7 Y3 `& W/ w( A) r - ! ~/ n& v% B7 d5 Q) G
- u8 HC595_Display(u16 num, u8 dp);3 ?; l9 c9 R2 D; i& j9 G1 S
) Q: n2 b" R- o. Q2 _9 v- #endif9 U3 \+ w) R/ h0 O& O
- 3 ^. |( m ?) |% C, u
- 源文件74HC595.c
# j; t5 B; k$ @ I - + A5 G6 U5 X/ ~' _7 h
- // 用于HC595实现的4Bit-LED Digit Tube Module
# g( e5 u: x% z7 b
: V! [) N! X O, y+ I% T( j- // 注意:该4位数码管是共阳的!
2 t- A2 y9 c, e - ) v. R& K, ~$ ]8 C4 W( T5 q
- #include "74HC595.h"3 p# G+ H; N1 Y5 ~. K" I/ `, O5 o
- + e) i/ Z: _* S: C$ p
- // 码表& x4 [2 Z, {4 ]. H4 v* e- S9 G
) k/ ]9 n7 r: H0 I1 t- const u8 digitTable[] =; Q7 D$ r8 {6 `0 Q- c O
- . U) j" _7 X7 J3 t7 r
- {/ B3 i# N7 |+ C6 l' H+ J% q9 V- M6 \. Y
4 Z: z+ B# n( E- O( [1 C0 _9 H- // 0 1 2 3 4 5 6 7 8 9' q- t* p% K5 o
! D& G% ^$ R: ~, V k6 X- 0xC0, 0xF9, 0xA4, 0xB0, 0x99, 0x92, 0x82, 0xF8, 0x80, 0x90,
& G! B7 q4 k1 c& @' H; n# z - / X& B+ g; J& k2 I8 V
- // A b C d E F -: H1 g. r" Y) i4 Z9 T5 K! G7 d
- ; c1 A9 {& w5 F# @/ L/ r% `$ H
- 0x8C, 0xBF, 0xC6, 0xA1, 0x86, 0xFF, 0xbf
3 P4 E4 V8 s, t, w: ?4 T0 Y& _ - : q3 T6 ^ f1 J. z1 l
- };" M9 D t H# n' e" `
- 3 F8 t/ X2 x3 e# q$ c6 G8 f
- /*******************************************************************************& y5 O" C! s1 k
- 6 F2 H% ?8 ]+ a8 X& {8 r6 v; k9 I2 |
- * Function Name : HC595_Init
. @! k) z, j1 [5 j8 \% ] - + { j0 q5 \, ]9 I" t A
- * Description : 初始化HC595# j% u+ x6 K, w( _
" r! w5 J9 p& `7 F: }' `3 n3 s- * Input : None
9 y; U& J. q. W+ r
6 I. I9 i8 s5 M) e! u* d5 t5 j- * Output : None9 k4 r- N# {+ R$ C2 q3 a
- % y/ K/ P x! `* v( i: y% ^4 C
- * Return : None' e; l8 J* b7 R s4 l1 }$ `5 N9 u
- % k! X2 G, ?5 ~+ q# J& [; l4 E* K
- *******************************************************************************/( j) I( Z' \4 i1 v+ S
- 8 |# ? f, h; j
- void HC595_Init(void)- n; n, N4 b. @
- + K; ]- D" m' L4 i+ _- B
- {
$ J0 Q! a3 S+ V* ] G# j) G C* Q! s7 g
* ~* X& e5 j' A7 I/ F% n. C4 M* R" S- GPIO_InitTypeDef GPIO_InitStructure; //声明一个结构体变量1 W* @4 J2 S) S* ?1 q3 y
- 4 f2 g- {0 ~2 k7 g" W
- RCC_APB2PeriphClockCmd(HC595_RCC | HC595_RCLK_RCC, ENABLE); //使能HC595的时钟
9 Z. u; e5 K& P$ j - & O% [* b# R% c9 _9 ?
- //74HC595, SCLK RCLK DIO 推挽输出
8 G- B" t4 A4 f - + ~/ R' I0 _: o
- GPIO_InitStructure.GPIO_Pin = HC595_SCLK_PIN| HC595_DIO_PIN;. r! z; s3 \* w: H. U
: a$ A6 h2 N/ S2 x- GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //管脚频率为50MHZ2 W0 O% A; I) Y' D
- 9 c$ f0 {. y* x/ ?1 v9 X
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //输出模式为推挽输出
( `* {! a b) D4 k
# l5 u- Y& p' y5 [9 k) D8 ?- GPIO_Init(HC595_GPIO, &GPIO_InitStructure); //初始化寄存器
w" @0 ^; i* o' X# H - + ]! k( T) M( k: g9 l1 ]$ X
- GPIO_InitStructure.GPIO_Pin = HC595_RCLK_PIN;' T, ?8 a( D; @" V
" {0 H# E! i/ M. a6 s- GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //管脚频率为50MHZ
# ]' i/ ]! { x+ G1 ~ x8 ?9 k; u
3 z E, g4 X5 l/ O% e- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //输出模式为推挽输出0 G/ U+ d! T! j: L
- 2 T" v1 h: c2 o: O" }
- GPIO_Init(HC595_RCLK_GPIO, &GPIO_InitStructure); //初始化寄存器1 R1 n& ~( w" l+ Y
- 8 w$ H( G& O/ Q$ A! Q
- }/ T" W: \- i1 q. D! k* l
- 2 p$ `) `7 S; g# R1 V0 T) S7 s9 s& ?
- /*******************************************************************************
( R9 s7 W; Y/ ]/ `, E4 [% H( y: Y! L - % m+ B/ ?8 `& O( |2 g
- * Function Name : HC595_SendByte: N S8 e$ [6 m" X9 v9 H
- 0 W @+ f( x3 Z; ]8 x
- * Description : 发送一个字节
9 z, K9 r; h4 f( |
M, P) r8 p+ g# p o- * Input : data! F3 P4 b% V# x. u! ]8 m9 H5 R
- 5 B; G0 `* p& v; ]! V
- * Output : None
4 Y' y5 k0 R- p" e r i# _ - & ]2 X4 p' U2 A" Y
- * Return : None! l$ H* R; M1 }5 s# c" O5 g" J
3 s6 r: G0 n# ^8 C5 v- *******************************************************************************/
! V! x/ \& Z) i- [$ W' o
( n$ @9 c& u' y9 K7 q- void HC595_SendByte(u8 data)
' m/ ~, b M1 F! N/ h - - p. k5 q8 A# p( }. o9 R/ \
- {
0 h* l8 L/ m! `/ U3 Z1 ~/ ~ - % L* \0 G& J( i5 A! c
- u8 i;
) z2 E" T; l( [ - + t" |: n6 R a+ U, Y
- for (i=8; i>=1; i--), X! j+ G ?% f- O/ X0 v# J
- 5 u' ~; T% a- X2 f! O$ o
- {) q/ c: y" J% `0 P
- 0 M0 v5 P- m) F; ~9 ~& n+ r2 [$ f
- // 高位在前# v( W8 }; z. t7 P2 l. Q
- * Z: o. B" n& x: P* k! G. C
- if (data&0x80)
U6 i4 p: F( Z. {* i5 ~ - , v4 Z4 I) o5 V! M- [% \& |# H
- GPIO_SetBits(HC595_GPIO, HC595_DIO_PIN);
. y4 ~) B2 E3 w/ m4 ~; R - ' _# W, q* D: p: k. C+ G- |' z
- else
7 U5 a$ I D5 U# g3 s' G - $ Q: H1 J+ o( F8 \8 \
- GPIO_ResetBits(HC595_GPIO, HC595_DIO_PIN);
+ v) H/ o7 a( U# h. A% i- P; g2 n
( `9 g- P/ P3 Z; S) z) Z- data <<= 1;8 T5 c: J T8 e# Z9 t
- , X$ p1 m, C7 v
- // SCLK上升沿# @) \: p7 G+ ^4 h; R0 I0 b9 a
3 r0 C: H3 o) ^& x" |) k3 b" P$ B- GPIO_ResetBits(HC595_GPIO, HC595_SCLK_PIN);
2 ]/ Z$ r) Z* k- |6 V- R - % [ A- [5 ] u3 u I( H
- GPIO_SetBits(HC595_GPIO, HC595_SCLK_PIN);$ ]( d7 h/ l, D- k A
- 7 O4 `/ N5 R, C% w' ^$ k H" Q! ~. ~3 Q
- }$ X) } k+ Y2 P( k X+ _9 M. R
- L6 a' k+ S6 a; I2 Q8 s- }
+ X( O. W. S0 s" `) ?5 t - - a! d' i) d' A' g- [6 l, `
- /*******************************************************************************
# r3 H& i% r: L( c- g5 m6 H - 1 T& h- M: [$ a/ y4 J4 G/ t
- * Function Name : HC595_Display
3 _/ o& a2 D' ]4 c4 u/ R
4 u6 h6 d3 y/ f; a3 S% a- * Description : 显示4位数字(包括小数点)$ f8 C. T& H p9 n% @
1 F: O( Q p9 p! Y; ?; g- I- * Input : num: 0000 - 9999" d5 P7 b" w2 _5 x0 s4 a& ^: Y
: v; [6 ?) q# r- * dp: 小数点的位置1-4
9 V4 C' C/ a. c) c6 i7 o% E5 Y" q - - U' q9 ^2 I3 W" u
- * Output : None
1 }4 a6 M+ d3 @+ z$ v/ A
* Z2 e4 G- z! W- * Return : 正常返回0,错误返回1 T" b" h ^- k6 s
2 c& N( u/ @; Q! r. L! j7 ]- *******************************************************************************/# Q+ C8 N+ G" L( W
- 8 N {# p* n* Y9 j9 w
- u8 HC595_Display(u16 num, u8 dp)
- ]7 [0 ?. l. p& c
3 {9 x' q! d4 L1 ^- {
6 _6 k8 T& y! y, ~' P4 ` - ; h% X) U! z# O4 v# b4 e
- u8 qian = 0, bai = 0, shi = 0, ge = 0;8 w+ ~( b0 d& z* w5 {
- 1 U% Y# k3 ?& r, N1 \6 F
- // 对显示的参数范围进行检查
2 k5 j$ Q3 j& X" [* N5 o: A' C U
$ G* x' M3 y& M5 e0 c# X. ?! x2 V- if (num > 9999 || dp > 4)" j* f7 X, E+ D6 R. |
- 6 V4 Q1 \# w' J3 y% N: o, w
- //报错
" M5 `, H9 h7 \% S
) d( L4 D4 c# X6 _# @- return 1;
9 M; M. \3 }: _" i& o1 Q- {/ w& w
3 n7 J6 |! Y e w' _7 o( e- // 对num进行分解
# w9 R& z: y: ~- C' w; ?$ ` - ; b2 b8 \, X$ `) x& K/ E) m
- qian = num / 1000;0 H, A. q p" q
- ' L: K3 O- \7 M3 {2 n
- bai = num % 1000 / 100;1 |3 p( r$ }- D7 T! m- G8 S
- + F' [' p( R* X' I1 O5 E
- shi = num % 100 / 10;
3 d# J; i8 n: a. B: |4 `
# T; ?! n. c6 j/ r. o% ?- ge = num % 10;
% Z1 p z6 m! j
, Y: D. t) U; p1 I- // 千位
& z6 d) E- L: E - ' U" o1 I6 o1 h( B3 e5 {& l) e
- if(dp == 1)
8 i j8 H: H1 t, A% [1 l: y3 F - 9 t- ]2 l1 g8 i1 F9 I
- HC595_SendByte(digitTable[qian] & 0x7F);5 g' P" L1 B! L* `+ c( E
- 9 p" Q" p5 s: t
- else
0 o1 S, j/ J7 U2 N' ^: \ X/ e4 v* [
4 Z' E* e6 X# U; ^( X- HC595_SendByte(digitTable[qian]);
$ |; ^ C* n( P g0 `- r: H - 6 w, h1 A' z& }+ o c- _ \
- HC595_SendByte(0x08);
; v- g: R: ~% ^3 S5 F
+ i" F0 i7 Q8 y% e; B$ V5 \- GPIO_ResetBits(HC595_RCLK_GPIO, HC595_RCLK_PIN);; T3 ^0 W2 X4 T6 k. L
8 ]) T- ~, E1 ?. {2 s- GPIO_SetBits(HC595_RCLK_GPIO, HC595_RCLK_PIN); @2 F7 a2 {: m" s
1 i+ I) ~$ r3 ~' H- // 百位& y' q; {. x; {& j! d% b. C
* o2 R* w% F- P# `0 b- if(dp == 2)9 H6 {8 P6 X8 p9 v
- , H2 \$ o8 Z: \5 a7 |* E5 Y1 X4 B
- HC595_SendByte(digitTable[bai] & 0x7F);
( J. U ?- }! ] S: f% d
- Q& I# d3 x5 p0 N! B7 c# b- else
* D) {0 \/ F/ {# G
' e4 a2 `+ e' J- HC595_SendByte(digitTable[bai]);7 ~7 i5 p( [7 u7 V9 G' E. ]2 U z
I g7 X7 T) w! c- HC595_SendByte(0x04);
8 F k' A" p- q( X* U; i( | ~
9 @1 _1 L, W3 e& {" E8 d- GPIO_ResetBits(HC595_RCLK_GPIO, HC595_RCLK_PIN);
& w$ C* l7 U) X1 V6 G. y# z
! ?" W$ J7 A' Z3 K- GPIO_SetBits(HC595_RCLK_GPIO, HC595_RCLK_PIN);$ F9 G- [! ~. J' u. @$ r
- 4 v j/ q4 C) u/ U9 n) V& k
- // 十位! z L' R3 b4 {, f$ w: g+ N* ?
- ; h! }+ k' v& J2 G$ `' Q
- if(dp == 3) D; k1 G$ m5 F+ h) s
- 8 m; B2 @" e4 l) e6 }1 {
- HC595_SendByte(digitTable[shi] & 0x7F);+ W' L: n( X& l5 R- J: v
- # B: c; p5 F! ` l$ ?
- else
* D0 s2 z H% r- y- x; C3 H8 w
" G% s/ x- y- n/ c- c- HC595_SendByte(digitTable[shi]);
3 z% w0 m- u; i9 t& ^) _; B - i* o! m3 B2 G5 ~2 u2 J
- HC595_SendByte(0x02);6 Q5 j6 d8 k% l- P% W' D9 I8 G% ^% O
3 b( [6 P7 x/ ^1 l! i7 S- GPIO_ResetBits(HC595_RCLK_GPIO, HC595_RCLK_PIN);) ]6 f; h& p9 ?9 J0 I) `
- 9 o3 _5 \/ O$ i
- GPIO_SetBits(HC595_RCLK_GPIO, HC595_RCLK_PIN);
" T. z* i# f7 N3 X/ |# Q
$ I$ G/ K) `. O. W- // 个位
2 @$ x# x+ e+ U" O6 j
4 @; M5 e" F7 i7 g: u( Q- if(dp == 4): Z+ W* k1 u1 K& N1 ?( x0 ]3 g) }
- : i9 I; R) C$ y2 _
- HC595_SendByte(digitTable[ge] & 0x7F);
+ u g- X( M: k/ j" d - 2 Q- p4 F+ |1 r6 R) N' {8 G0 w
- else$ z, x @8 s$ f* _7 l J
- ( L! r- D, E4 C$ a$ c5 s
- HC595_SendByte(digitTable[ge]);
) b1 H8 R) J) H4 O% ?4 }- ] - $ [4 _% W! A% j0 I- L# K! `7 V" l4 c
- HC595_SendByte(0x01);
( G0 T; K: w. D' ? - " ^1 A4 v# u! V: h
- GPIO_ResetBits(HC595_RCLK_GPIO, HC595_RCLK_PIN);9 O1 f' q' x: N" Z' \4 O
- + ?& ?/ M/ Z8 \* _ M8 j5 ^
- GPIO_SetBits(HC595_RCLK_GPIO, HC595_RCLK_PIN);/ _1 A# n! K. B
4 T2 K3 y1 m9 J/ V' I4 O- return 0;
$ R9 a* K; D# p3 A - # W; A" C, U6 L; j# k2 o3 B, }- r2 k
- }
复制代码
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- #ifndef __74HC595_SPI_H__
3 M: z+ K8 Y+ O
6 V+ ^% g6 `9 J# i" h6 S- #define __74HC595_SPI_H__
+ }' F I* D8 E7 S3 u
9 Q8 i% V+ S2 Q: o1 ?% F- #include"stm32f10x_lib.h" //包含所有的头文件
1 z8 Q* ~6 ~: \: u4 B& h - # t6 ]6 I( b% J- {9 v
- #include
! A( E: @! ?. q4 ` - 0 a0 H+ c5 |# t; _8 S
- // 4-Bit LED Digital Tube Module
6 J" N3 s) W& ?" {9 x
" n) y3 g( R8 P# O+ |- // 引脚 // SPI1 4位数码管5 F6 r Y1 z. n0 `* S& F4 A1 j6 |
- : v- ~3 c4 e; q9 T( d* }% f
- #define HC595_NSS_PIN GPIO_Pin_4 // SPI1_NSS 未用
- p+ q' p$ l& s' E& @% Q - 1 I$ _9 Z$ I- R* {/ ~+ @2 v) K
- #define HC595_SCK_PIN GPIO_Pin_5 // SPI1_SCK SCLK+ T. x, `/ D5 O/ x+ D
. v: Q* T, w% P$ _) g) l- #define HC595_MISO_PIN GPIO_Pin_6 // SPI1_MISO 未用" @0 @; e3 G: b) v: v' t8 Y" a
- . V! v+ D; P; `' ^6 _
- #define HC595_MOSI_PIN GPIO_Pin_7 // SPI1_MOSI DIO4 g- F; V, x3 P) ^! H, Q
- ! j; y0 q1 ~: R8 j: r, C' \
- #define HC595_RCLK_PIN GPIO_Pin_12 // RCLK
% e; r7 y K8 V - ; Q" b* d7 s4 F. I; L* d2 P
- // 端口" I1 t" y9 I- q) C
- / L0 ]" }$ q/ _ q; E
- #define HC595_SPI1_GPIO GPIOA* y/ d4 o9 ^ C7 G' z
- ' u9 ^ \4 d6 Z5 i7 `7 M4 O
- #define HC595_RCLK_GPIO GPIOB
' }' ^- L! U5 T. D - % J' N y1 Q: M# w
- // 时钟! @: Y) R" S! B: H6 ^
- ! s; O' ]0 u: W- }( \
- #define HC595_SPI1_RCC RCC_APB2Periph_GPIOA y3 T0 M8 D6 C+ { E K
- # s8 s4 y5 |* g2 b9 K
- #define HC595_RCLK_RCC RCC_APB2Periph_GPIOB6 E$ O: o0 b' T/ f. Q
4 [, n# B: E* a7 q6 S- void HC595_Init(void);" m3 e7 o' p" |, h: I
( O# A) ^, z8 q/ z2 `! d- void HC595_SendByte(u8 data);
. s* d# [; y: ?. q
5 j; j4 {% F. {5 i$ [- u8 HC595_Display(u16 num, u8 dp);
8 ?: ]8 d) F* A8 S
& ~3 v v3 w @1 ?6 }0 O4 C* V4 D- #endif% m6 ~% ~3 g& U1 Z% H* C
- ) d2 X; w* b" g9 ]. A
- 源文件74HC595_SPI.c
1 A0 I/ _+ ]& ^5 K% ]+ i1 C - 0 N H8 c2 P; }5 y9 b3 s/ I
- /************************省略部分代码见(74HC595.c)************************/" W* b* |: o7 f. ?# Y7 ~$ P
- & e' t7 H' M( |: a6 `, t
- /*******************************************************************************% w7 d8 D2 Z: H" m) ^9 l* r
, x+ [5 s+ _0 N1 q- * Function Name : HC595_Init2 m# A2 _5 }/ _" J
9 q0 ~: _- v3 H6 [/ K. Q2 C" V- * Description : 初始化HC595) e- V# ?6 }- [) { W
- ) S3 O8 t; ]6 B) v! i
- * Input : None% G) }% ?1 E! Z9 ^' T
; c8 }( ?( _, t T- * Output : None3 x, a" I% ~/ W5 Z) V, X
+ J8 s+ N. [& W t1 R. }0 R# \- * Return : None' H; n/ g# x, _3 s7 V+ y. I' X
- 9 A- ?5 v# u! q/ A
- *******************************************************************************/' ]+ c- X+ W: X$ t3 V+ E3 d
, k% b: M) S+ U. ~- void HC595_Init(void)" n0 [/ |( |, Z
- 2 j* P$ o7 o+ d3 w6 m0 i" k8 h
- {5 y$ G2 X- H6 i1 ?% M4 t
$ t3 S& |4 Q, \ b5 ?0 b. I- GPIO_InitTypeDef GPIO_InitStructure;
2 C( G3 r/ ?' J/ ]$ P8 _
: J! x5 }. ]- _ w- ^- SPI_InitTypeDef SPI_InitStructure; // 声明一个结构体变量
+ v! w/ {! E: i* h6 B, B
9 _( V r8 c9 J$ l! S- // 不需要开启AFIO时钟6 F8 @5 e9 s1 ?# n/ Y# j+ i
( A: @% r1 X0 P2 B& ^- RCC_APB2PeriphClockCmd(HC595_SPI1_RCC | HC595_RCLK_RCC | RCC_APB2Periph_SPI1, ENABLE); // 使能HC595及SPI1的时钟
* K3 `8 G6 n l; Y+ F - p* H) f2 C/ q' ]. ]. u" c
- //74HC595, SPI1_NSS、SPI1_SCK、SPI1_MOSI
0 n# Q- {4 q& D
- D! P0 ^* r* A% Q- 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
" y- |6 j3 `" G0 d- GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; // 管脚频率为50MHZ6 ~) y$ h4 y% z
- " O) l8 J5 N; K7 a* _2 ~1 V
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; // 输出模式为复用推挽输出. r8 L' F, `- \7 k) K
- 5 D$ Y; ~- w7 ^9 M( x
- GPIO_Init(HC595_SPI1_GPIO, &GPIO_InitStructure); // 初始化寄存器- a5 q' i; R% t# j0 z2 u
- + H7 }5 \' C1 p- n$ {0 B o
- //74HC595, SPI1_MISO
2 I- R' q9 q, y" s% i) Q+ m - . L& e" S6 f V8 g9 d+ Q7 z7 ~
- GPIO_InitStructure.GPIO_Pin = HC595_MISO_PIN;# p/ m% q* H5 a
- ( V3 _- P6 D3 j8 A! y8 g
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; // 输入模式为浮空输入
+ y' ^8 U* \$ D7 y: Q% S - % M7 T7 V0 [( y( H2 G0 Y9 x
- GPIO_Init(HC595_SPI1_GPIO, &GPIO_InitStructure); // 初始化寄存器
1 u: U; P/ r0 g/ r2 y2 }/ ~8 Q0 l1 i
/ p C, c( J! D8 g- //74HC595, RCLK
9 h% z1 ^$ a8 S: R. D0 j - ) o, c. K& b- p3 T# J! t0 B; y: P2 h
- GPIO_InitStructure.GPIO_Pin = HC595_RCLK_PIN;
, }7 B. \/ s3 H* R- H% q - ' X2 m0 ^" l( K$ z m
- GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; // 管脚频率为50MHZ8 A# G3 s2 K! Z) L
- 9 k ?5 y. y5 s% {! R- V, `5 H
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; // 输出模式为复用推挽输出
0 w" s8 L/ z g% N1 V - + |2 ^( }: @6 G* N' z) s
- GPIO_Init(HC595_RCLK_GPIO, &GPIO_InitStructure); // 初始化寄存器
6 Z6 V* b- ~- `9 k
, b! Y$ y) z/ N8 W% t- /* Initialize the SPI1 according to the SPI_InitStructure members */5 g/ P* S* _6 n- Q. X* u- h9 E
/ g s( j/ _2 J5 w7 v- SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
' l! J; U! N2 L% o. p6 w0 Z
* m w$ H0 R3 n; _' e/ F1 ]- // 第一步:设置主从模式和通信速率4 ]! A/ u" p. K) [3 ^
- 3 e/ Y0 `/ K4 ?
- SPI_InitStructure.SPI_Mode = SPI_Mode_Master;
1 E, t3 }7 c, d1 n5 j; x+ k# L
/ i' ]2 l3 R \2 J' \- // SPI_NSS_Hard时需要外部电路把NSS接VCC, SPI_NSS_Soft时SPI外设会将SSM和SSI置位
8 S& |$ O3 ~9 `2 ^. Z) ~
& z( u0 ^9 o$ Z- SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;
& w& \7 d8 y0 }: o - - \& f1 u, ~( y7 r* D
- // 实测波特率最低为SPI_BaudRatePrescaler_8,否则出错+ E, V' ~9 g0 L" k9 r
- ) b6 Y: w+ k; c8 d3 B
- SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_4;9 k6 j2 R8 ]0 C! n/ c- P
- 6 t4 {! ^0 {. H
- // 第二步:设置数据格式5 m" d7 c. Y+ O; T o
- 7 s% I7 t0 b8 G4 V: U
- SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;" l4 e8 @, y8 g, K$ D; D% P
' \+ U! s s$ B$ J- // MSB在前还是LSB在前要根据码表和数码管与74HC595的接法来定
9 T. _0 r5 S% ^/ R! A3 f% W
2 z5 z' q+ G3 P3 q) s- SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;: q5 P$ \! j$ Y- I
- 7 C! M6 Z, r; Y1 ~
- // 第三步:设置时钟和极性$ j8 c6 W) T+ J1 k& I
- " b { t9 ?# n
- // 当SPI_CPOL_Low且SPI_CPHA_2Edge出错
; e) |2 G/ H7 G6 x' M0 i1 H
e+ C" Y% u& C- SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;, p* k6 `$ a7 N4 K0 E/ t1 ]
. @4 E% h z. U8 T0 [( t( Y/ g- SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge;# m0 q/ Q5 [/ b8 B; J
- 8 ^* a1 m: w% W: q# X
- //第四步:其它,CRC校验,可靠通信,这步可以不设置8 x* g9 C/ o. q& M- k
- $ [. m' C" g* |4 Y! v! C- N, O; y
- SPI_InitStructure.SPI_CRCPolynomial = 7;
1 m9 H0 B3 t% L) _9 y+ t$ A9 R% G0 ^
. q- k4 V6 w& [) ^9 U- l- SPI_Init(SPI1, &SPI_InitStructure);
/ G8 }/ p- g# c; i - & F# Y' T! k7 m; a- w1 R6 |
- /* Enable SPI1 */0 J0 Q L7 u! Y }, p
4 `$ Q( G, L; _- SPI_Cmd(SPI1, ENABLE);- u% |! R$ v5 b- U# ^) l
0 g M$ ~2 ?# G% k+ P) b$ k. c i- }/ X* l7 K ]/ S* }+ |
- 5 f. _/ m6 X0 f7 w4 _8 N7 h
- /*******************************************************************************% `2 r7 t6 V! c8 F5 u: l
- 9 Q) g+ \. m: V+ t
- * Function Name : HC595_SendByte
S% P$ h3 J: V% F( b - 5 b8 J+ Y+ I- t- W0 O% m
- * Description : 发送一个字节: R$ t: g, Z H
1 ]. u F. N8 l" f' _- * Input : data
4 n) y$ C. V) B; e! u: X
' X9 P- j0 Q. \* \6 {* m3 h& I2 k- * Output : None# p" q( [" R4 m/ X$ T5 V
- : p9 Z2 }! k. {8 l% E! n6 t& l
- * Return : None7 t# ?; x7 t% e' w1 u5 R7 q
- 0 y- x; E5 {& u P. |$ R; O9 | ^
- *******************************************************************************/
5 Z C+ k5 I/ ^0 ^) G! i" L
4 w/ \% g2 p9 K' p2 T6 j, s! f- void HC595_SendByte(u8 data)
+ v, P8 D5 E* B+ p9 _# _ - 8 b4 r& y! X8 Q. K. Z
- {, b$ C7 Y" U: p( ]$ n" C
0 o" u& W5 e* o: P- SPI_I2S_SendData(SPI1, data);% q( F. P/ |. f9 t8 j
6 i3 k/ Y: F$ R' w) x9 K' G# [% }- while(!SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE));5 R4 \! i" `' ~! k8 M
+ f# Z/ G0 {* q% W- }8 X# X8 V2 ?- x+ I
- + c& K% h1 X, r8 D C L! u8 O7 c. J
- /************************省略部分代码(见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 _
|
|