|
EDA365欢迎您登录!
您需要 登录 才可以下载或查看,没有帐号?注册
x
之前一直对SPI通信一知半解,所以想抽空把它搞得明白一些。考虑到之前是结合Flash芯片来学的,十分不直观,而且主要把时间和精力都花在Flash芯片的datasheet和驱动上了,SPI通信也没学好。所以这次就考虑用4位数码管显示模块,模块是直接买的现成的,如下图所示,这样可以简化操作,把精力聚焦到学习的核心–SPI通信本身上来。
e6 a9 Z0 x Q3 ~5 n" r# b7 u 该模块是用2片74HC595串联驱动的,一片用来控制数码管的位选(U1),一片用来控制数码管的段选(U2)。接口比较简单,总共5个引脚,2个引脚分别接VCC和GND,DIO用来接收串行数据的输入,SCLK用来接收同步时钟,每个SCLK上升沿74HC595内部的移位寄存器会移一位,RCLK用来控制数据的输出,每个RCLK上升沿74HC595内部的移位寄存器的数据会被放进存储寄存器并输出到外部引脚QA~QH上。而QH’是串行输出引脚,该引脚会接收最高位的溢出,从而实现多片74HC595的级联。: H) E+ o% S" L) Y0 ~* w- U0 d
当两片74HC595串联时,先发八位数据用于段选,再发八位数据用于位选,然后RCLK上升沿,就可以驱动某位数码管显示某个字符,通过动态扫描数码管,由于人眼的视觉暂停效果,就可以实现4位数码管的同时显示。先用通用I/O来实现该数码管的驱动,程序如下:. z1 x1 R# [% Q# b! \
头文件74HC595.h
. x& I4 r6 H% V; k- u) @ k* Y2 s- Z
- #ifndef __74HC595_H__! v: L5 V% s$ r% _
- W& h# j5 F, X) P6 A$ i# q- #define __74HC595_H__% k2 H) Q& _- m) r' J* E- Q: ~ F
4 C# u5 v5 `- c8 F! ?1 w! S- #include"stm32f10x_lib.h" //包含所有的头文件6 l2 A# l( ?7 Q' {- G8 h
, I6 P; ?& W5 U' H$ @0 a1 k7 V$ X- #include
' ~8 ^- |# T5 L* Z ^ - & H2 B' e! y9 O; ?- L
- // 4-Bit LED Digital Tube Module
2 R( d1 S+ I c- l: ^( e3 A3 S) E' ` - " ^3 ^- a6 c; Q- X6 s1 B6 u8 o1 e
- #define HC595_SCLK_PIN GPIO_Pin_5 // SPI1_SCK PA5
( A1 O$ L, f$ E7 ]. v: Z: k
8 z4 n2 I; q" G' t- #define HC595_RCLK_PIN GPIO_Pin_12 // SPI1_NSS PA4
8 I, f. S5 ^' U) b0 d: U, T* X$ w
3 g5 m( K! i4 r0 k- e- #define HC595_DIO_PIN GPIO_Pin_7 // SPI1_MOSI PA71 T4 V2 R. o( e4 X
- 8 N( f9 d0 y, n9 J5 o1 Y
- #define HC595_GPIO GPIOA. j8 c. A+ h, f; J
- . J! |1 r; {5 W/ S: o0 h! ]
- #define HC595_RCLK_GPIO GPIOB
% K& n6 T+ O! H e& H( X6 T* e - 4 q+ z, m, b- r- |$ y8 w
- #define HC595_RCC RCC_APB2Periph_GPIOA
2 G( v& h/ |/ O9 e8 m9 r - : c% |0 Y* z" e( H* B9 M* g
- #define HC595_RCLK_RCC RCC_APB2Periph_GPIOB
& x9 Y5 ~8 D1 j- Q) W
' H- Y2 w! F. B8 ^$ }8 E- void HC595_Init(void);
; Q. G+ p& [6 r9 Q: X - 2 T' n+ S, ^5 H& N$ k
- void HC595_SendByte(u8 data);
5 y$ I$ k [ ]
' h' l, w9 Q2 g( P7 l- u8 HC595_Display(u16 num, u8 dp);8 L5 q" \5 L$ f1 Q
' x0 k( f* F8 w' j- #endif" l: S+ h* u& {2 \- Y
- 2 x+ F& @5 Y- q2 S1 e/ R
- 源文件74HC595.c8 i6 N4 q3 W4 O
: O. `9 @+ v! h2 h1 t- // 用于HC595实现的4Bit-LED Digit Tube Module1 `0 ?! X, D( |+ H! J; p+ `, c
! N. M% o9 a( K& Z- // 注意:该4位数码管是共阳的!5 m4 b: v( U) E9 y7 s
- ( |. j- U1 j, s6 w
- #include "74HC595.h"0 O$ x" N# a3 M. d. ]/ A
- * {! Q9 W' L; d- ?
- // 码表
/ C3 [5 ?, b m; ^0 l
8 r. x+ i0 L6 S3 y1 }! l- const u8 digitTable[] =
! ]- d/ j- K( o& q9 V) C4 C- i - * M% p$ T" W1 L" U
- {
* R1 L& x0 m9 u, |, @& g; @; R# Z
* Q+ k5 ~% b+ f: t+ L) t: u- // 0 1 2 3 4 5 6 7 8 90 P5 V) y8 `- ^8 f
- : \! e( ?+ {* A4 A. C5 N% ?
- 0xC0, 0xF9, 0xA4, 0xB0, 0x99, 0x92, 0x82, 0xF8, 0x80, 0x90,
, W! Q# Y6 `& l* S3 k6 U+ h: ?. n
& b; |* \6 d& P! x6 G- l- // A b C d E F -
8 D8 Q0 B: R# D! Z2 ?/ s: ~) K
3 F" H" G3 q1 x8 C- 0x8C, 0xBF, 0xC6, 0xA1, 0x86, 0xFF, 0xbf
; t4 g- D2 w6 F0 k! J+ l
" M& V9 i* Y2 o* f6 S/ M( u- };
7 k$ ^& i0 `! h; e% a3 T/ I# L3 R% j' f0 D - ( I5 F! I$ y. T- Q
- /*******************************************************************************; U K/ Q8 q% A6 J; I
% P/ ~0 j0 h+ C8 r- P- * Function Name : HC595_Init b/ \% t" F1 [, ^' a
! N# g5 ]- r5 z1 M2 v- * Description : 初始化HC595
; {+ g. C! a8 c5 f3 v z. ~
% }$ ?2 V/ Z8 G5 c- * Input : None
6 E# ]2 z: [/ f% d: u
) n, Y, ]7 P. W6 S; F' u" o% s- * Output : None
: B5 V& R6 J9 Y1 x
; X# G1 u( |- J4 b3 A- * Return : None
# ?/ \6 Q3 Z8 e5 M; H7 q
6 \3 N: ^( g; L- *******************************************************************************/
- u8 I! H6 H4 r. ^# I3 R' Q
2 [3 ^. {6 O% x, J# Y" Q- void HC595_Init(void). K& T5 L" ]! G6 n* ?' d
& v- l0 L! x7 D8 v/ W1 y- {
3 ?) G2 \7 ^+ K6 ?% [ - 2 S2 K1 v1 X" b3 V, T' o1 {+ p
- GPIO_InitTypeDef GPIO_InitStructure; //声明一个结构体变量
. g* S5 a5 w( _6 B% {& Q
& P4 x5 F: S" A# G1 A+ s- RCC_APB2PeriphClockCmd(HC595_RCC | HC595_RCLK_RCC, ENABLE); //使能HC595的时钟6 l! \( M& y, |
- : j$ K# j1 t9 h. `9 T8 W, |6 N+ @$ ^( D
- //74HC595, SCLK RCLK DIO 推挽输出
: v6 b1 K1 z7 y$ p" L7 O
% n2 B0 [: [9 K6 ]- GPIO_InitStructure.GPIO_Pin = HC595_SCLK_PIN| HC595_DIO_PIN;% d, I: s4 _2 t! J* x
9 G$ j o- L" V* m6 r/ }- GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //管脚频率为50MHZ7 w6 A4 H! W( X
4 H( \" ]0 D% ~6 i. d @- s2 M- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //输出模式为推挽输出' |- z# y. U# v4 G
* L% H1 v" G* V) o/ e, k2 Z- GPIO_Init(HC595_GPIO, &GPIO_InitStructure); //初始化寄存器
' G3 P0 k, b3 j0 P5 V! h8 k* H+ F
0 a) v F# ]4 Y4 N' b- GPIO_InitStructure.GPIO_Pin = HC595_RCLK_PIN;7 Z: q" E9 W u) s$ R
- 9 [2 X3 f' V3 \4 v! q0 K8 G
- GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //管脚频率为50MHZ
9 _. J9 X0 j9 ]& P$ P
; n! P# @ M9 }0 |1 Y- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //输出模式为推挽输出3 L! b4 S1 h! S
: E$ F; X8 T$ ~' T: ?- GPIO_Init(HC595_RCLK_GPIO, &GPIO_InitStructure); //初始化寄存器( e. ^# \" H( C
- 9 { ^, Y0 Q+ n* P1 Z
- }9 W' G1 s( W% p5 n
; I# o$ `. Y* l4 M$ H" Y4 m4 K- /*******************************************************************************- N. z; E3 V" E( `! Y2 I: ]
- 1 Q9 Y6 L1 g$ q- ]
- * Function Name : HC595_SendByte
& _* X9 a% N* J; ^
, p2 M7 F- Q( w3 g" y& L6 o& R, p- * Description : 发送一个字节
5 S" L5 a' N" A C0 G# e& D- u5 i" g9 } - - ?3 ]3 w; Y* P5 L! b
- * Input : data
: ~0 A+ `) I+ p' S4 E - $ `2 V s$ S* S. N Z
- * Output : None: j& P( U; [$ W. Y# ~, n5 k
0 a3 U/ H4 ~* f/ @; c) F- * Return : None) I# Y/ ] M1 u0 K
( X( s% U( t' Y W- W1 q1 l- *******************************************************************************/
) M9 E& A' X, o. v4 E! c8 q" k - ( @0 E D; Y. n3 Q5 U0 i
- void HC595_SendByte(u8 data)6 G# P5 J( ^% L
+ \8 |0 |3 j. A9 S# ?% C, z4 h0 J- {" o3 r& d" ^' d) q
. u' _/ W; x" E8 h' q* f2 r- v- u8 i;
7 `% J+ ?: q$ v3 J1 o
, h3 }* Q8 r' w# \( v' O: p- for (i=8; i>=1; i--)% m, f3 G- q, Q9 D7 J `9 T" G
5 A3 Y3 d. Q3 M- {+ C9 w/ m! g& ]) y$ S2 G0 t
- $ {/ o' z7 J( d! N0 m
- // 高位在前" L' i' h" |# l0 S) b; U. k
- 1 q) s, {2 K) B5 T9 O$ a( m
- if (data&0x80)# y* i7 ], O6 g4 }& a& A
2 Y$ b. P9 k" K2 W- I8 ~' @- GPIO_SetBits(HC595_GPIO, HC595_DIO_PIN);: o# K( Z! n! ~7 ~" b
% [; S% L, u; ~$ y$ w n2 g- else
7 D W, Q) L; z& j( R - 8 ~9 ], }' u$ z" b ]( k/ s
- GPIO_ResetBits(HC595_GPIO, HC595_DIO_PIN);
n- @8 s: s' S: e; L2 N* s
( L; A9 @' o2 `3 n6 y Y, A- data <<= 1;8 ^" \. o& p/ I& t1 W; C
- ; r1 z& D- u% q3 w
- // SCLK上升沿
4 z2 U/ b! c& A4 n1 e - 5 o" u' M4 `$ V; X
- GPIO_ResetBits(HC595_GPIO, HC595_SCLK_PIN);& i+ c7 ~. a6 D
( O' _5 I; L8 S0 D1 y% l3 W @- GPIO_SetBits(HC595_GPIO, HC595_SCLK_PIN);
n* f' X6 w6 S! ~# D
0 e1 M: j8 A+ V2 P: P# j- } y* S, t2 h5 {: \& M
- : {, C# Z- j# l2 ^) P
- }- y4 F! B2 [8 X4 o: x4 T- c
- - M ?% W5 h4 f& H9 i
- /*******************************************************************************- P: w8 L( U! g; x+ ]) `. j
- - R9 V) A3 Z, v2 j1 N0 ]
- * Function Name : HC595_Display
! }& {2 F1 S" X# n
) q; ~! k' [% U6 ?9 X- * Description : 显示4位数字(包括小数点)
! D- N2 ]& a: G" {" ~, Q6 s2 R7 d
0 m! X3 K/ X* V# S% A5 N" b- * Input : num: 0000 - 9999; Q0 ~+ N3 h2 T9 I
- i! ]. G1 ]0 o3 A- * dp: 小数点的位置1-4
# m, }. c5 j" p" }! E* j - h* D" Z; N( U
- * Output : None
! ~2 h" r1 h) ?3 @ - 4 ?0 f; b1 |9 G' \; w5 w) N
- * Return : 正常返回0,错误返回1
) x, X' ?9 }( B6 x5 i/ A
1 c: [* ^& B8 I: j- C! w3 ?- *******************************************************************************/
- B+ x3 M) M4 I7 t6 `- E# t
{( o! g$ d8 J* x& A- u8 HC595_Display(u16 num, u8 dp)2 \& Y6 U; `' I( ]
; ~ Z& O. l) P# T3 M- {
: G% G1 E$ F: @' h
B/ T' `7 ?5 Y# u+ D2 a3 \+ l- u8 qian = 0, bai = 0, shi = 0, ge = 0;
; s4 Q1 }! u+ T+ z - " M# x) L3 c& B0 H" Q) R
- // 对显示的参数范围进行检查! H: _' a K3 _! t3 \8 ~
3 E R/ W* R6 Z( p- if (num > 9999 || dp > 4)3 s6 n0 u4 C$ C) X3 t
5 _. K9 [% q* f- //报错3 S: ~1 q; U5 _, T; g# ?9 ?
- 5 Q5 ^! I7 T6 ]" o, X
- return 1;
* N) K. y8 t F0 g
: t- {9 w1 W4 G. E- // 对num进行分解
: `& I% ~) c. E0 } - * A4 X2 r ]* w& ~! r
- qian = num / 1000;* x( ?6 [. ]. `2 A$ p$ R
4 B& ~& w, Z5 h' E8 d3 X- bai = num % 1000 / 100;4 a7 b# N4 A8 Y) n1 `7 ?
+ U3 A3 [6 Q' R9 H; H; A& a- shi = num % 100 / 10;
' p B" L1 [+ K6 A9 [& B& ]) C* b - 5 V5 P2 g: h' {& q! A6 b
- ge = num % 10;
# P$ t7 k _2 o7 c0 E, J0 Z4 t
. ~7 ?( ~( r% i$ K- // 千位/ U& n _$ {3 Z5 ^
- 0 G# y9 s, e5 T7 Q `
- if(dp == 1)
# l% x! Z' r+ q+ N5 f: B
" l$ P- e% Y# x/ B# I8 Y- HC595_SendByte(digitTable[qian] & 0x7F);0 b$ |9 Q, b9 b" g
! D0 ]& m$ n& M6 H) z- else6 [5 {& u* z% ~$ h) g l
- ( C$ `3 w3 _6 {' n% [& w; B
- HC595_SendByte(digitTable[qian]);
3 W T8 z; ]/ ]7 c& s- Z - & q8 L4 P2 v5 A) _
- HC595_SendByte(0x08);. B: V+ h5 _" h# e
+ {+ W T( o/ _' a- GPIO_ResetBits(HC595_RCLK_GPIO, HC595_RCLK_PIN);) O3 A6 U+ n9 u
- ( H4 t+ ]' j, ?- T1 G" Y4 i$ v
- GPIO_SetBits(HC595_RCLK_GPIO, HC595_RCLK_PIN);
% r$ A) ?( W: O8 w% [% ?
8 u% K5 q( P8 e# ^- // 百位
) q0 U$ M. u' J$ ^; G4 j# y7 x$ V - 9 `% T9 p7 n' x& C6 ?! u
- if(dp == 2)
# l0 h3 i. O: T' ~# ^
7 Q6 b( n: O: b, \ W- HC595_SendByte(digitTable[bai] & 0x7F);
; R8 ]& w3 |! C2 C" ?& M) ]
( E. e* I8 ~- ]4 T5 r0 L& m$ U- else
( W% M* a$ p. Y9 k' R% q
- W1 K% P5 ~: j+ Y8 u- HC595_SendByte(digitTable[bai]);; p0 [2 `7 i: R" e/ f) X9 F; P; B
/ a/ ^. T* g" N+ Q) M2 @- HC595_SendByte(0x04);
p- _$ B( X0 u# {1 n3 b
8 m. o: y) I8 p- GPIO_ResetBits(HC595_RCLK_GPIO, HC595_RCLK_PIN);
~: j* R- T& I3 v) o9 V. Q) a - / w9 r8 Q5 n+ s" @4 u: t
- GPIO_SetBits(HC595_RCLK_GPIO, HC595_RCLK_PIN);
0 O0 N. O1 `8 w0 _5 @9 O - 7 _: m a$ R7 F- T+ p
- // 十位
5 G0 \6 T; b! l" x; _, l8 I
9 w7 j% N: Z" a$ B/ d' _- if(dp == 3)
1 i+ [) G4 D" |2 v5 H, j$ j8 y
8 z* a; h) W0 e9 R! p. k" s5 \- HC595_SendByte(digitTable[shi] & 0x7F);
6 K1 U7 z! ?9 x* T+ g
5 m$ c: r2 X1 F- else
9 p; |9 q6 ]- n
! O% B8 \( N8 E& d& d- HC595_SendByte(digitTable[shi]);* N1 _. s$ l( q: f5 ^
X& ]3 E# R1 b6 e, G9 N% |- HC595_SendByte(0x02);+ _; d" I4 `+ r* o4 r$ b8 V
- 5 [ }1 g/ o6 _& K
- GPIO_ResetBits(HC595_RCLK_GPIO, HC595_RCLK_PIN);6 g4 [0 O- ?5 M+ @- s J
- - A6 g; J! `* ^! i% O! k8 E* T7 o3 q( d
- GPIO_SetBits(HC595_RCLK_GPIO, HC595_RCLK_PIN);3 n* n q% g5 n4 l4 e
7 E: u& G9 N4 Y- // 个位' u1 }- _! r& R9 W( q* Z: o+ U
- 7 g: e v; F' s: {- M; l" B
- if(dp == 4), @3 W% z! j8 x; T) f. d" e
- # t; R7 ?( r; Q+ \
- HC595_SendByte(digitTable[ge] & 0x7F);$ Y$ `9 b* k2 ]0 o* f; e3 Y
- " f& r4 W S4 g: }) K4 B& ~- ~
- else
1 |5 P1 Y% o n5 {! W - 7 a X, ~3 X7 H& b9 s7 P+ p- J; M# X
- HC595_SendByte(digitTable[ge]);
: s4 q% o! Z% \5 S$ d6 y6 F
4 D$ `/ C! v) A, R9 l; M1 E- HC595_SendByte(0x01);. K( H1 y" k9 W4 G0 L7 y& G2 `
- ) I7 v1 O' |- Z, g
- GPIO_ResetBits(HC595_RCLK_GPIO, HC595_RCLK_PIN);
; a5 G* y) X) a9 O5 t - 3 i2 H9 G! c$ M0 Q% _! B
- GPIO_SetBits(HC595_RCLK_GPIO, HC595_RCLK_PIN);0 c( \) |: q4 S/ v$ d% Q6 m0 n
- 3 I7 q% |+ p3 _; X2 D
- return 0;
3 f6 Q% |9 J! d# ]/ z. E
; G- d |) h \; {! f4 c/ k) L- }
复制代码 8 [8 i: A* }: p. @: Z. C, Z3 M
接下来就可以把重心都放在STM32的SPI外设上了,首先需要读一下STM32F10x的参考手册的SPI(串行外设接口)部分,这样对SPI就可以有较好的理解,比较重要的是要看懂SPI的结构框图和主从机通信的示意图,如下:2 O" d: w5 c) H" V. s0 |8 B
这个理解以后,我们就可以参考《STM32F103XX固件库用户手册》的SPI部分来实现STM32的SPI外设配置和收发数据了,具体代码如下:
9 X7 e! p; a0 O% }$ v n 头文件74HC595_SPI.h# e. h% i; E4 D5 ?8 J5 v1 ^
" z# Z& X- W* K. Z( L/ {3 i/ t9 N
- #ifndef __74HC595_SPI_H__" ^5 v, t# d5 T3 @# \1 A: j! {7 M
3 N. o5 z) V! [5 @+ f- #define __74HC595_SPI_H__
6 y) j! D/ X+ j: o - ; x G3 x; q% Z- z
- #include"stm32f10x_lib.h" //包含所有的头文件
6 c f% C6 g/ N
6 x' m3 x& [- [6 w& [5 j- #include+ C) Q0 P/ N+ ~7 Z1 D2 V
; Z' I- B8 n- h% e* l: y' h2 i* A- // 4-Bit LED Digital Tube Module
. N2 U" r# l/ l- W3 r; ~. e, M% R3 l - 8 r! o0 n. D! [/ Q- p
- // 引脚 // SPI1 4位数码管
# k6 Z! z, t" F: }8 @: j& S
) z0 e# q v7 \, g1 { _- #define HC595_NSS_PIN GPIO_Pin_4 // SPI1_NSS 未用
" |7 n9 Q8 D( ~, j h - - U# s: p$ g: C9 f: j
- #define HC595_SCK_PIN GPIO_Pin_5 // SPI1_SCK SCLK( i1 N: @: g3 F4 K* A3 _
) l4 _1 Z3 e% \ o6 F- e: q5 N- #define HC595_MISO_PIN GPIO_Pin_6 // SPI1_MISO 未用
" e8 @9 \ X- t! a8 r - - F; m$ j; O& c; r" x
- #define HC595_MOSI_PIN GPIO_Pin_7 // SPI1_MOSI DIO& h: ]. E. Y) v J4 P
/ q6 L6 E* `) \; U+ Z ]/ ]5 d% ?- #define HC595_RCLK_PIN GPIO_Pin_12 // RCLK! Y/ [% A; r$ _& G' C) ]
% J0 e; _- }$ E0 J* t( i- // 端口
. s% w6 W0 a( W - + |6 P- b8 C2 q+ T( J
- #define HC595_SPI1_GPIO GPIOA
8 P7 T- w# q, n& U4 ]* m
3 v; L2 Y) L0 Y* @% Q% G! \; Q- #define HC595_RCLK_GPIO GPIOB
% O }, W8 P1 `* w0 Q0 {2 c
8 x" }4 t" e! i# U- // 时钟+ l% L) G. n- o# s- f8 L& D- x
- * `8 _' q8 ?3 J+ {- f
- #define HC595_SPI1_RCC RCC_APB2Periph_GPIOA u; K! Z( W) E( U+ M
- % E7 Y2 s/ `, }* _8 x' V5 U
- #define HC595_RCLK_RCC RCC_APB2Periph_GPIOB
7 v% p6 [; b" T5 d8 s4 b
/ B, M- z$ ^ N: k- void HC595_Init(void);
# O+ h" x7 C! h( }* a" q, ^ - # [5 V, R B+ H: q' n8 N! z! i
- void HC595_SendByte(u8 data);2 J+ i2 R; S; d' G- X! W- x
/ v5 X% v# Y6 Y; ^- u8 HC595_Display(u16 num, u8 dp);
3 J5 j" A# d2 v8 o8 i
# X* K. p( B4 v$ ]- #endif% b- s6 a+ h: T# U6 {* T
& u9 [# M# ?/ E2 g2 I& u/ q- 源文件74HC595_SPI.c) I4 e' [1 S8 G5 ]0 ~
' H" O0 X/ H& R6 H3 ~" U- /************************省略部分代码见(74HC595.c)************************// u8 R; J4 S! T; T# T5 w0 X) H& o
- + M/ x7 v# ^! L' J. [; ~! j
- /*******************************************************************************/ ^! ]- [% D0 q2 R, T3 M4 j
7 L+ X( ` A: M: }9 a( K; I) t- * Function Name : HC595_Init9 A, s& i i! I) H9 M
8 C2 R/ N; _5 ~4 C5 ]" h, W- * Description : 初始化HC5951 x4 o' i. u' A/ L: |$ t
- Q5 N+ W$ z4 D" u4 u n$ V- * Input : None. e: n3 O! }# Z+ P2 u, v( a
- D8 [) _& r* Z$ x0 V% K6 i. D
- * Output : None$ z) ?- r5 s$ c, }: C
- % n4 o1 @* I' {: ]! Z
- * Return : None" V7 F2 F" H9 a1 h; G" M1 e; Y
- ' H. ^1 g$ Z* @
- *******************************************************************************/1 S* w5 A0 }% c$ Q; |$ s" v4 h+ c( N
! K9 y* ^& P0 E& h- void HC595_Init(void)
( G" K9 P4 K9 z# ~( X x4 _" N/ \ - 0 \9 T- T& P/ b0 k* }; K! J
- {
( u9 ?& ~: [1 d/ o% \5 V0 w2 }9 L0 ] - 9 k" Z: I( w* w I* E2 b
- GPIO_InitTypeDef GPIO_InitStructure;- _- k; t- m* c7 [8 S8 Y
- # Z; A5 ~/ W, e: ?4 I* q6 h
- SPI_InitTypeDef SPI_InitStructure; // 声明一个结构体变量
: F6 g) i @4 ]
/ J& K t+ u1 |. m- // 不需要开启AFIO时钟7 i0 N$ d4 Z" X L, C) u8 T9 y2 ^* F$ a
1 R4 ]3 R( L& t. O6 ?2 [- O4 F9 `- RCC_APB2PeriphClockCmd(HC595_SPI1_RCC | HC595_RCLK_RCC | RCC_APB2Periph_SPI1, ENABLE); // 使能HC595及SPI1的时钟
: y3 w( \; N" R* B
; h# d7 {+ A, J, Z6 J: X8 S- //74HC595, SPI1_NSS、SPI1_SCK、SPI1_MOSI, I* m' F) Y: w8 c( h# p
( E1 L7 I: J9 T0 _( q- GPIO_InitStructure.GPIO_Pin = HC595_NSS_PIN | HC595_SCK_PIN |HC595_MOSI_PIN;8 r- r" x+ e# U3 h( s1 K# S
- 5 C9 ]5 \% H8 T6 K0 q( c" C* C% }
- GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; // 管脚频率为50MHZ0 t; G9 C* N0 z
- " S0 R, ~) t& `6 E1 \9 E7 c3 P8 R
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; // 输出模式为复用推挽输出
0 W1 D5 \" B/ L M$ t6 N% e: E - ) l1 S7 N$ [$ i% x7 a
- GPIO_Init(HC595_SPI1_GPIO, &GPIO_InitStructure); // 初始化寄存器8 G( ^; @4 Y! I) c' m! ]4 b D8 _
- ' {3 X8 W" q a- u N& ~
- //74HC595, SPI1_MISO
0 q. a' t8 e6 _' i/ [7 |. O
5 z' W9 [& N3 ^% ~0 N. `' n- GPIO_InitStructure.GPIO_Pin = HC595_MISO_PIN;; i/ ^1 D1 J8 ~3 r0 R- d; s( u
- / h7 A9 n n% k* F
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; // 输入模式为浮空输入
, G @1 f2 M9 ]+ N ?! V/ s - . @" q; `3 A3 `
- GPIO_Init(HC595_SPI1_GPIO, &GPIO_InitStructure); // 初始化寄存器
4 Y7 C8 s( S" i8 }, Q- D
% @5 b6 B/ z; P: A- //74HC595, RCLK
% r* o5 g# J7 G w% h( P5 E. B& Y
$ A: F) D' j" t; Q( |3 f: h8 |- GPIO_InitStructure.GPIO_Pin = HC595_RCLK_PIN;
$ y* R/ Z$ c8 s, V& X( b8 i - & H: q5 ~2 u+ e) Z8 k6 C+ v2 n
- GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; // 管脚频率为50MHZ
0 Q) |2 a. K; |4 {1 s. R* G
$ `" e* z3 r) i/ H7 ?- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; // 输出模式为复用推挽输出
' a/ V# L ^; y& D
1 ~9 |' A# t9 n$ }- GPIO_Init(HC595_RCLK_GPIO, &GPIO_InitStructure); // 初始化寄存器
+ C, e2 [" J" b* }3 `0 a
6 d) W( w/ j* O7 ?# _- I2 X. }- /* Initialize the SPI1 according to the SPI_InitStructure members */( L4 M- @- J* o/ c2 k0 W
) L) _% g: p |, n: R- SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
' L- a* X" V2 @6 [7 \+ v1 v - - i) \& Q4 t- B/ } f2 _
- // 第一步:设置主从模式和通信速率
! Q; c, ~& p* w8 Q9 e* H( N* h
- L' t( R" I1 h3 b) V1 E5 y- SPI_InitStructure.SPI_Mode = SPI_Mode_Master;) h9 t! C& V" ]9 d
4 s& X7 w( B9 C+ |% y* K$ M- // SPI_NSS_Hard时需要外部电路把NSS接VCC, SPI_NSS_Soft时SPI外设会将SSM和SSI置位3 i2 k6 s: }: u% Z5 _7 D
- ; s, ?5 v# |& \/ O( G
- SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;$ a/ ^- \7 Z9 _
- . p! F3 D/ ]3 G* ?7 Y. a" u
- // 实测波特率最低为SPI_BaudRatePrescaler_8,否则出错: L) F, E/ L0 N! H. a; |
- $ J Y7 Q- S3 @- W; t& h
- SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_4;
/ R3 j) l" V; f$ w$ r5 c8 L6 [8 N
1 O+ @) J1 s5 S/ ]5 N3 ^' i; y- // 第二步:设置数据格式9 Y% _9 Z& s' x
r$ b' o, L: k; O4 p& g; N1 U, t- SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;- M, |" q! L0 ^& H1 J/ T( {" v
; S3 L+ d# \( ]/ U- // MSB在前还是LSB在前要根据码表和数码管与74HC595的接法来定 ~3 X! ]$ _2 y
' i W' ~2 f+ i8 d! Y) Y7 g: I+ \' i- SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
7 o! l C' \2 L2 r: x; r - ! T7 X Y, D9 \8 k1 x; L3 X. ~
- // 第三步:设置时钟和极性) S3 }' O, S6 a4 Z
- 0 I: r$ z$ I; C) K" p1 o. a
- // 当SPI_CPOL_Low且SPI_CPHA_2Edge出错' D7 Z: |7 G9 N+ R; K: ]. U
" j0 r! g0 T. a. K- i; q0 I- SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;/ u) R- p+ Y* m0 D5 e: A5 U4 b
+ D5 D: c- \- q$ m) j; `/ _+ |- SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge;2 r; @ q# m* D2 c- r0 Q4 V
5 j+ G: b1 n* m% M9 G+ z- //第四步:其它,CRC校验,可靠通信,这步可以不设置# K& `9 {4 a9 r( T- }4 ^0 v) @
$ p3 X+ e' |* z& ^- SPI_InitStructure.SPI_CRCPolynomial = 7;2 H: @2 F" {- X9 X K% W
5 D3 j+ m/ b" W% m# Q- SPI_Init(SPI1, &SPI_InitStructure);7 E) T9 k C: F. N) D3 G
- $ [9 l4 g6 K' J* v7 a2 \
- /* Enable SPI1 */
8 h+ i, D6 b7 `% \ - # j& {8 a; D( p+ C1 c& w
- SPI_Cmd(SPI1, ENABLE);& L- x- |7 _2 _! ]0 j/ l
# z" ]0 J; S1 s& h; N) M5 k/ @5 G: w- }
: v: I3 ]) y/ f, x( e
+ k S2 `) P! e# w- /*******************************************************************************8 ?* a" E f, z r8 k
5 v: }% z% Y: i# n- * Function Name : HC595_SendByte
# ^, {7 h/ ~, P; h
4 f2 \7 p) k4 v& U" C3 Y- * Description : 发送一个字节
- I- h: K8 j o* Y
) T Q: C+ r+ B* x$ b& c- * Input : data9 f9 B! u7 a3 G, V% U2 Z6 F* \2 P
- 8 C) A" x5 B2 ^. v
- * Output : None9 J. P! _& x9 j! Q3 s& u# h
$ ?9 q+ e8 ~- ~$ |2 M$ m- * Return : None3 B( ?/ B4 \% o* R. b% G
- & s9 F# A6 f8 h6 ^3 b3 g
- *******************************************************************************/
" X; b. m( f; J, ] f* _
1 o4 K" {4 Z8 |# r C* W [- void HC595_SendByte(u8 data)
/ H! \. {/ a# t( o( h3 V; j
5 a1 h+ K' a' z( h$ u1 s( R _- {5 ?8 _0 g5 M; x2 h0 f" r+ n! d+ D
- 7 P- a3 m4 x0 Z- I2 q
- SPI_I2S_SendData(SPI1, data);
b" ?3 [, K, x+ X
3 N) _, s" ]7 |+ u- b, e- while(!SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE));
4 d9 |( q# ^% E/ { r( U! O - , N6 C) K1 _' b9 L
- }
8 M" p- W7 @6 v+ N' N. m% A/ h
3 ?6 P! s& i% o$ f/ |- /************************省略部分代码(见74HC595.c)************************/
复制代码
5 ~7 @' z- d3 a7 u 这样就大工告成啦,STM32的SPI外设还是比较简单的,尤其是通过库函数来调用。用数码管模块这种简单的可视化工具,我们就可以更好的研究通信协议本身的特性啦,后续我还会用这种方式来学习其它的通信协议。
/ m4 `" T, ]5 Q% ]1 d2 i
: ^' e, C) E4 ~$ Q6 Z7 W# Y! _+ \* l* J& k- V, E6 Y3 U" f- {% R
v7 }$ x# \ T6 @* R8 d/ Y6 l6 ^2 U) b" A
|
|