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