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