GPIO最经典应用:LED灯。- v4 g' t" O. W9 n( L
' x, V9 `8 q2 L4 V$ r先看电路。声明:参考正点原子战舰开发板。
' O+ r8 d% D+ N- c, |, D/ s* K# ^/ t2 K4 O. u; N2 c: e
+ D p) \4 V5 a/ Q3 x' W
, C" k0 n$ e) g1 \7 t7 t' T
D# W3 m) W9 ]0 _2 }
( B+ m; u3 @0 [' K k4 I8 O3 P9 j' Q9 x
' U4 E9 A! C- n6 ~. m+ ^
与LED串联的电阻称为限流电阻。
0 T* b4 `; I5 P: ^" K- W/ W3 ~. n. j& k
限流电阻计算公式:R=(U-LED压降)/20ma。
' O! z5 B P8 O, x) N0 D; x8 e! s5 B h% _
U为LED工作电压,LED一般最大电流为20ma。
0 {" C. T; V; g+ ]0 m- ?) j) K/ L/ ?+ t g, E6 ?
在此R=(3.3-0.7)/0.02=130Ω。0 X$ R% F5 p* y _7 R, O& q" S( m
) @* u4 b# g1 ]: }! `3 K& q
因此本次示例中限流电阻阻值大于130Ω,才不会烧坏LED。. ~. e1 S% G9 S3 D' O* e
9 D& |9 X2 O) l4 n# L7 h
3 u* d6 L5 V6 w1 N: G8 R5 K' D再看代码。 j/ | T1 f6 \" _
9 a P y( H c" J$ R. I
GPIO初始化。9 @+ G- l$ L# J! A2 |' V+ g
- void LED_Init(void)$ s* X# F' Y4 h$ c6 P
- {- v7 A! M: ?- U
- GPIO_InitTypeDef GPIO_InitStructure;! z6 A% V8 O! l8 D: y f0 |. ^9 a/ M
-
) [ n0 t7 Y1 c1 l: o - RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOE, ENABLE);
7 g6 U0 a" s' N$ }3 x# Z: h: W6 S -
2 @- D5 i: ~! V Y - GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;
1 S/ q: B4 K) e& C- W - GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
/ ]5 s6 _" q$ Y0 T& N ~ - GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
4 W5 W7 k1 v" `1 U - GPIO_Init(GPIOB, &GPIO_InitStructure);
+ C$ c, S; x6 r9 i5 f2 T& n( `+ F - GPIO_SetBits(GPIOB, GPIO_Pin_5);/ D( m7 P( y B
- % B! z1 r2 U' [8 t* [
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;6 [9 x9 K* V# b% V& L: [
- GPIO_Init(GPIOE, &GPIO_InitStructure);
6 @$ f% `6 n$ i8 n/ e$ _ - GPIO_SetBits(GPIOE, GPIO_Pin_5); $ L' ^8 Z4 x2 X( n; K! _2 Q; ^
- }
复制代码
; F- c& }; L1 E* _5 e# {LED应用
4 O. X3 g; O! S" R* ?- M7 T7 N1 X- void HW_Led0_Off(void)2 e1 i: F* E4 t0 Z
- {4 z1 T4 m/ S n8 H
- GPIO_SetBits(GPIOB, GPIO_Pin_5); //设置GPIO输出1+ e- j8 T+ @; L
- }/ P* s2 a5 X: h6 k5 A" f' T
- * Y3 r) s- L1 u6 ~, h" L
- void HW_Led0_on(void)2 e. p4 f( I Q3 \/ q. i$ I% ]9 {% s
- {. |$ \5 v' G# w' D
- GPIO_ResetBits(GPIOB, GPIO_Pin_5); //设置GPIO输出0
9 K6 `0 G1 U% t& M5 K; [, a4 X1 ^, C - }, n) a4 M) Y2 K, Z. w
1 Y) U( Z- Z% {9 n- void HW_Led1_Off(void)
0 q1 N* W& j5 g+ W1 V- O' p2 T0 U - {
/ }0 r" U0 q1 W0 z - GPIO_SetBits(GPIOE, GPIO_Pin_5); //设置GPIO输出1* W7 u7 T. c; ~
- }
5 p- a2 V6 w, S1 k
1 F% ?) D1 }8 ]4 J- void HW_Led1_on(void)# J& u [" Q2 b2 X1 d: Q
- {
- [% ]+ h' U. J8 H6 t' [# ?+ x - GPIO_ResetBits(GPIOE, GPIO_Pin_5); //设置GPIO输出0& E, u1 q. v2 @2 r6 ~: w, {
- }
复制代码 5 n* S( S. }* F& r, T
思考:为什么IO输出低电平时LED亮,而不是输出高电平?" R6 L# I3 M6 ]1 N& v
" K0 ]) J& U2 r' i思路:. ^. D+ N* V0 E8 F# f
% C% L t t i& o N- Y! t, z 1、由于单片机的I/O口的结构决定了它灌电流能力较强,而拉电流能力比较弱(即IO口的低平驱动能力较强而高电平驱动能力较差);
, ?5 W' g) x& R$ f# ^5 l" |1 A7 n- u
2、为了简化单片机接口的设计。高电平驱动和低电平驱动是同样的效果,另外,低电平驱动也简化了控制代码,避免了单片机上电复位时端口置高电平后对led的影响;
" k1 [6 `$ l; n2 d9 J+ ?" t- A: x' |5 e4 J! K% l% P% a
从STM32中文参考手册内得知,STM32的GPIO可配置为八种模式。& R+ t2 e @ |5 `3 k' T
: K9 [# C2 Q; n2 Y7 m0 |' Y v- D
1、浮空输入(Input floating)+ y U: X2 p9 m8 Z! n4 s9 @
% K4 ?, e% u' w8 x F0 t
2、上拉输入(Input pull-up)
6 x- Y6 w' h7 \9 |4 W& e
% j6 }7 O+ f0 g. i: q% H 3、下拉输入(Input pull-down)# P" Z( b7 ?# }
; W, v- I/ g0 p* h7 x- V' A
4、模拟输入(Analog)( h" r4 o+ {! d* G" ^1 x7 J( N
8 I, E) n! I) Y
5、开漏输出(Output open-drain)3 X$ Z7 ^ U" \, }% F$ \5 t
9 K6 m7 K; I$ {& u: L% X, k4 R 6、推挽式输出(Output push-pull). e9 h3 x; u' B
; _8 E4 v8 i. X0 u7 x 7、推挽式复用功能(Alternate function push-pull)
% `# s8 v* h. a0 K7 u" a
5 O. b/ A8 k7 x& }# s0 y 8、开漏复用功能(Alternate function open-drain)
8 B* j- o5 I+ x* h p4 n; ^6 e
: l2 q& O' k) T8 g3 P- \- typedef enum0 H! e5 S7 H9 d
- { 1 v4 Q$ B1 h8 C0 ]
- GPIO_Mode_AIN = 0x0,
' Z* a* x; Z$ u4 y& |$ M) x: C! V - GPIO_Mode_IN_FLOATING = 0x04,. P5 {2 p2 N1 _- F5 z+ W
- GPIO_Mode_IPD = 0x28,
3 z4 H7 T) J! c/ ^; x - GPIO_Mode_IPU = 0x48,
5 b" Z; c/ Z% n - GPIO_Mode_Out_OD = 0x14,
3 V- c) m0 h# H - GPIO_Mode_Out_PP = 0x10,% n; S* q" n% B/ @
- GPIO_Mode_AF_OD = 0x1C,4 K% z2 u g/ P, j
- GPIO_Mode_AF_PP = 0x18' j1 @. Y' i+ N1 Y
- }GPIOMode_TypeDef;
复制代码 5 K2 f8 T$ }: }; N
驱动LED使用的是推挽输出。推挽电路(push-pull)就是两个不同极性晶体管间连接的输出电路。2 l' k# n7 S) P% K+ h& `7 X
' J8 F7 o( H+ ~3 Y( b. x
4 Z" k) m; U% }! f+ w. m( I
. W8 N9 W8 Z( U. K1 g8 x/ F
简单理解推挽和开漏的区别:驱动能力不同。推挽驱动能力强。 I& o' U3 }9 y* m7 \3 ~* b8 o
1 Z7 ], w( D3 W6 q5 }9 L+ t
复用意思是GPIO不作为普通IO,而是特殊功能使用,比如ADC、USART等。/ @2 k; x) O* s; D, f
% z7 I( p3 P; P( S4 Y
引脚输出速度有3种:
3 m$ Q; }6 U% V, L5 @6 `- typedef enum+ W. U* m1 V) Q1 B7 \
- { 2 @0 M+ o: X9 i" A; l: H7 ]' S
- GPIO_Speed_10MHz = 1,
0 N7 N$ J+ L9 ^' F0 Q8 ?( w - GPIO_Speed_2MHz,
3 w2 V3 O4 X/ I3 V# f5 i Z - GPIO_Speed_50MHz
% I. k% i9 l8 I7 J: I" K5 Z - }GPIOSpeed_TypeDef;
复制代码 4 v) p8 @" T& d) t5 {. Z* j
GPIO的速度应该与应用匹配。速度配置越高,噪声越大,功耗越大。
6 f0 r+ e- c+ | D$ D9 Y( }% N0 P' X
比如配置为串口应用,波特率为115200,此时GPIO的速度配置为2MHz就够了,既省电也噪声小。' o% |& G# ^( }( \) A" G
0 Z& z: h6 M7 ^/ m4 Z9 }* [
I2C接口,400K波特率,若想把余量留大些,可以配置为10MHz。, f! Y* @# H7 K4 Y2 K3 B! C
, }, A, R2 r/ U2 @6 W4 F1 p dSPI接口,18M或9M需要选用50MHz的GPIO速度。# n/ d/ M% E7 P( G/ f
8 z- D; F1 j5 W: d3 e# {* U# t' w
% j8 Q5 f. n5 }% A ? |