GPIO最经典应用:LED灯。
: g2 x* r) \) [& V2 a9 m
* g9 s: I& _* N3 ` g, a* i3 i) t2 v先看电路。声明:参考正点原子战舰开发板。
1 b6 q) T! B; a, L
5 f8 K; h- {, I, X: S
! R" b8 G& t% }; ?. Z. N8 d. Q$ H( z: a6 H7 @! k
1 n; G1 W4 J9 I3 {0 M2 Q& h7 T* _3 n4 V W" ]6 S3 ^; ]
0 V3 Y% i3 M }9 W
8 ~: t1 M/ Z) o2 z; Z与LED串联的电阻称为限流电阻。0 C0 W; _% y) w; ^8 h7 C8 e; o6 o
5 V" E3 j9 ~0 R7 K
限流电阻计算公式:R=(U-LED压降)/20ma。
5 o; _. X$ d; [. l5 m6 M' Y# s5 `) X. k9 s
# ^4 q/ f& i3 L/ h* D$ M7 _U为LED工作电压,LED一般最大电流为20ma。8 z: h. n9 _, M
( e& N3 l+ ^" E4 l! }
在此R=(3.3-0.7)/0.02=130Ω。* B8 m0 S8 U' w0 i% c1 O) L- `
1 i d4 g& V( g( u6 k
因此本次示例中限流电阻阻值大于130Ω,才不会烧坏LED。
: c2 S7 @$ E7 P5 u; G: S0 H4 [- N9 u4 W* b: G
U3 P' s2 W8 {7 E! x再看代码。! U) L2 W8 F' P
5 G) o* @ c# G& ^# k( u* F$ pGPIO初始化。
7 ?' {. @! M! W: B( g5 ?2 d4 S, Q- void LED_Init(void)
3 s# W; E: H8 ^8 @. b Y% r - {. J; i4 u+ `! r1 q
- GPIO_InitTypeDef GPIO_InitStructure;0 A& U5 O+ O6 i" K$ A& }8 \& |4 B
-
! W- M, O' h' O. ?3 \- t4 Y - RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOE, ENABLE);" q( C/ b! r+ u5 g& N8 V: \/ [
-
# b) ]) W- A/ C; d& k8 `8 ` - GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;2 C. l- S; q( {9 f6 J* ^( m3 v6 E
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
8 C2 `2 y$ D9 L2 { - GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
# X6 `: C/ `. }- g) [2 k7 m - GPIO_Init(GPIOB, &GPIO_InitStructure);/ I4 R6 Z9 P, X8 h
- GPIO_SetBits(GPIOB, GPIO_Pin_5);
5 e8 Q$ L+ H3 `! V - " c: J, V( ^: t( e+ Z
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;1 c3 f/ G7 |! d0 t. l
- GPIO_Init(GPIOE, &GPIO_InitStructure);
7 n+ P. G5 Y, \7 R - GPIO_SetBits(GPIOE, GPIO_Pin_5);
$ h" v w0 m' H& n- [, c - }
复制代码
! l; f( v; ~( L9 ZLED应用
! Z# N( T6 v( X- void HW_Led0_Off(void)
1 p+ L2 s% [4 A: [8 a# C - {
+ F# Y3 C! l: ` x - GPIO_SetBits(GPIOB, GPIO_Pin_5); //设置GPIO输出1
+ }0 A; \1 ]; v' V8 V1 k$ L - }, d6 V- \6 P8 P: E7 [
- 4 i& j: C. J# W' ^2 [
- void HW_Led0_on(void)
3 p3 A: c0 k: f' r' i# P - {
0 \% G% R7 a2 s( b - GPIO_ResetBits(GPIOB, GPIO_Pin_5); //设置GPIO输出06 q1 ^ p3 p8 H7 _
- }" @) H7 \+ P7 I5 y" L, p+ r
- $ H0 X2 [+ R5 ^" A O( o, N6 E/ @
- void HW_Led1_Off(void); ~( J& l3 Q8 g7 ~- d
- {
! }2 K( z; i/ e - GPIO_SetBits(GPIOE, GPIO_Pin_5); //设置GPIO输出12 b+ l+ ~" b# Q* ]3 Q& s8 v: M
- }2 j9 m9 t) k0 R# S8 N; }
# o, l/ w; d, ~* W! x- void HW_Led1_on(void)* G! h2 n) D2 F
- {& F$ S3 X. i, |6 i/ k/ O1 F8 ?
- GPIO_ResetBits(GPIOE, GPIO_Pin_5); //设置GPIO输出0
+ g6 v- e! k7 t8 F2 ?' p - }
复制代码
/ E+ b L K& `: c- J- x思考:为什么IO输出低电平时LED亮,而不是输出高电平?2 ~- H1 u' Q* u( H/ Q/ z
5 L0 l' ~) m4 a0 B9 Y思路:3 f$ s1 n j( |0 f1 `7 b
, t7 i! P, g. a1 l9 l) ], V
1、由于单片机的I/O口的结构决定了它灌电流能力较强,而拉电流能力比较弱(即IO口的低平驱动能力较强而高电平驱动能力较差);- {; v" H* I7 ^1 `9 G6 D- h
% H! f* M: |+ K2 F3 W2 ~0 ^' c
2、为了简化单片机接口的设计。高电平驱动和低电平驱动是同样的效果,另外,低电平驱动也简化了控制代码,避免了单片机上电复位时端口置高电平后对led的影响;
. Q4 t+ N4 p9 b/ ]1 ^ l* U; X0 S6 Y! W, R6 _! z
从STM32中文参考手册内得知,STM32的GPIO可配置为八种模式。9 i; M+ ~# _* |' E6 ^6 W4 e
3 H$ S L6 F5 X% M! T5 i 1、浮空输入(Input floating)
1 V: N9 m6 }& \) n r& k( k9 Y! I
" }! k5 `/ ~2 |' C; c 2、上拉输入(Input pull-up)
/ o7 X# \4 m" r# F1 a" N$ m+ u' D+ Z8 K1 y9 P* x& f9 M3 s4 F0 O
3、下拉输入(Input pull-down)
) w/ U/ H1 n( o2 P) R+ |' w: n0 N0 J& D# `
4、模拟输入(Analog)( {. Z6 O/ d) `7 ^
+ u: P# k+ ^. W) ` 5、开漏输出(Output open-drain)
* G! L I. u7 V9 O7 {
: X% N8 \! `6 L4 ]6 N& C+ V/ V 6、推挽式输出(Output push-pull)$ S; A3 o: ]. o" A% A: x4 m. \* D- z* }
4 ^8 `% p7 R( l7 {# m6 P 7、推挽式复用功能(Alternate function push-pull)- L; j9 R1 p1 X
: v! U2 ~5 \2 q3 Z- c1 } 8、开漏复用功能(Alternate function open-drain)4 d! p1 ]+ I/ w4 A% H
7 D" J8 [2 _, a- typedef enum- \! J7 ^4 P, }* F
- {
* E% x6 D% K: ~8 J, D& {' e2 Q - GPIO_Mode_AIN = 0x0,
) d& s: V0 `) E5 ~% `4 v. b8 X - GPIO_Mode_IN_FLOATING = 0x04,
) P1 i' l& m0 c2 J - GPIO_Mode_IPD = 0x28, ~+ T( ^' ]) W3 m9 G
- GPIO_Mode_IPU = 0x48,
) H9 z- K4 [. M3 p: D5 l' R - GPIO_Mode_Out_OD = 0x14,
0 W) s) \2 t( N- c - GPIO_Mode_Out_PP = 0x10,
0 I9 p1 c( S6 q/ G - GPIO_Mode_AF_OD = 0x1C,
* M8 F2 U. Z7 M i+ ], x7 a9 ? - GPIO_Mode_AF_PP = 0x182 d( E& d- u! e: V
- }GPIOMode_TypeDef;
复制代码
/ B9 L- s6 S$ K) F驱动LED使用的是推挽输出。推挽电路(push-pull)就是两个不同极性晶体管间连接的输出电路。$ S6 @- E9 Y# E3 j" P8 c
3 A6 ] S7 E% J" X* G# i
/ y; l3 D6 ~+ y. t
0 [9 A: B( R6 U简单理解推挽和开漏的区别:驱动能力不同。推挽驱动能力强。5 Z# e: R7 D6 l% R/ Y- W# s
9 i, T) I0 i- `: G: d- ?
复用意思是GPIO不作为普通IO,而是特殊功能使用,比如ADC、USART等。. _1 R/ `, d6 B
' O$ D5 |! ^ L+ r' i/ N* z3 B引脚输出速度有3种:
# ~. A) J- w' w) J! l- typedef enum6 S5 h; W: ?4 V; w0 R' ^! T
- { 1 c8 w- S: M* L0 R
- GPIO_Speed_10MHz = 1,
5 r, d) v) i$ I+ ] - GPIO_Speed_2MHz, : I, q4 h# C: w" t5 H: r
- GPIO_Speed_50MHz6 O9 k8 r6 t, M- `
- }GPIOSpeed_TypeDef;
复制代码 8 v$ o6 r7 o# l+ D
GPIO的速度应该与应用匹配。速度配置越高,噪声越大,功耗越大。
1 l9 O& c7 F* n$ D8 o- h' s" S% C$ d4 B
比如配置为串口应用,波特率为115200,此时GPIO的速度配置为2MHz就够了,既省电也噪声小。: c- J+ s! ?" {7 s
6 J8 L2 k# ?6 I/ ]- a* oI2C接口,400K波特率,若想把余量留大些,可以配置为10MHz。/ \0 ^, s. s1 u% F
0 k& e" P2 t7 | I# g/ e2 jSPI接口,18M或9M需要选用50MHz的GPIO速度。# e. |+ z2 O. w$ `
) `5 V1 T5 x6 _* o! Y
; l+ w W- j" {% \4 ?- |
|