GPIO最经典应用:LED灯。2 M% B0 |% _8 U8 q7 z, s
/ {" D, V, d2 @. Q- h先看电路。声明:参考正点原子战舰开发板。
1 i0 v8 a4 x3 ~6 n
& G0 O2 u$ [( U8 o
& M7 v) T* V1 n4 k" j& f
0 E$ [! ]5 ^7 T6 `' O7 g6 [ N2 P- b$ _6 j4 L( Y Y; E7 A
2 a, j+ ?; v4 D0 |/ A _6 c
, f/ u5 s' L/ _+ ?
4 i+ z" p# r8 R7 z与LED串联的电阻称为限流电阻。
, Q" z8 |2 j/ n- O8 u) o0 p/ S& L' [& a* D) k( y
限流电阻计算公式:R=(U-LED压降)/20ma。
8 \& B9 O/ f- m3 ?! c5 F) y3 p) X0 ^$ K7 ~) H, d/ ?" f
U为LED工作电压,LED一般最大电流为20ma。- @" q+ b( [/ M4 O; j
- A4 k. R2 L8 L, H3 ]; @
在此R=(3.3-0.7)/0.02=130Ω。
2 h# C9 f: C7 A8 P7 k2 J" |* g7 H( A+ x7 P/ B1 W( }" M
因此本次示例中限流电阻阻值大于130Ω,才不会烧坏LED。- o- f* O- M% Y `" H
f3 K$ x0 d# T6 j E8 f# |6 T
% ~! x+ o4 ~3 z \ X- O) T" `再看代码。7 j5 \6 N8 e) N6 |# t; z
0 `, v% w# f9 M% F/ \+ X
GPIO初始化。
, d/ V" i: O# k6 z8 \9 {5 S5 \3 K- void LED_Init(void)
2 O4 V6 e( ?" o - {
: {3 _# ]1 H, w/ E1 D - GPIO_InitTypeDef GPIO_InitStructure;
: ?" a+ z* ^& Y5 u1 A! P; _0 u& ~ - ! f' i/ E$ B H/ ^/ A
- RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOE, ENABLE);
0 z( N5 i, v" D/ a! b/ [7 v' I - - e* d6 J9 y$ }) {3 s
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;; K5 T( a; x2 [% W" N; y* T
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;. j1 M4 ~$ I0 d3 v x+ J0 v; i
- GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
# g: t. f8 c2 s5 `! c6 F7 { - GPIO_Init(GPIOB, &GPIO_InitStructure);
9 H' I9 P1 L/ x - GPIO_SetBits(GPIOB, GPIO_Pin_5);
3 m. b8 `2 t0 x+ a0 E7 P- ^' x8 | - * K! P5 h6 z: }- D- T/ S7 ?0 \
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;
% \/ ]( u' @. p s# G9 f/ u - GPIO_Init(GPIOE, &GPIO_InitStructure);5 z& y1 a3 {0 F& A
- GPIO_SetBits(GPIOE, GPIO_Pin_5); 1 l1 ?4 j' T: a
- }
复制代码
; H' `4 c1 U" iLED应用
s7 \* M' M& w V; z- void HW_Led0_Off(void)
0 [! z! ?% W7 l! ^. Q$ ?; f - {
# p: b- o: H% @2 }% @% t - GPIO_SetBits(GPIOB, GPIO_Pin_5); //设置GPIO输出1
$ }$ A( q% n& _( } - }% _9 G. o* W8 }) M* O4 T& y
- 9 S" Y/ a! D9 ~5 |% J; O. I) v) T
- void HW_Led0_on(void)3 j/ q7 K8 d x6 V
- {
/ H8 f& U+ Y x; m - GPIO_ResetBits(GPIOB, GPIO_Pin_5); //设置GPIO输出01 g: {& w! m; r, R' W7 t
- }
1 ~3 g; g3 Q, p+ p, N0 U4 H - & Y8 A+ Z+ ?: _) G
- void HW_Led1_Off(void)
+ J1 e+ R5 X j; c6 B: M - {5 c! x1 q0 c, n4 B3 s7 t
- GPIO_SetBits(GPIOE, GPIO_Pin_5); //设置GPIO输出1+ v, `) x8 A4 J
- }# V) F" a: q6 {6 A6 b$ |- c
1 b8 y3 [/ q& ^. x8 S5 N6 e8 I9 y- void HW_Led1_on(void): b3 ~3 L5 `2 `; ^
- {" v5 Y% ^1 i9 c! q- J
- GPIO_ResetBits(GPIOE, GPIO_Pin_5); //设置GPIO输出0
; w2 h) _% k0 }0 X# w - }
复制代码
8 U" L1 |8 d+ T \% Y思考:为什么IO输出低电平时LED亮,而不是输出高电平?! g4 m* u; G+ \$ B1 }! T
% e: L% i* y5 u' ]6 ?' S( H! ]
思路:7 M! G7 O" K6 J& F; ~
! A0 H' [5 _2 w; t! i$ H! l! \
1、由于单片机的I/O口的结构决定了它灌电流能力较强,而拉电流能力比较弱(即IO口的低平驱动能力较强而高电平驱动能力较差);
2 f) j E# w0 u( ~7 H" K! \) b7 d3 X% c8 X+ c* |
2、为了简化单片机接口的设计。高电平驱动和低电平驱动是同样的效果,另外,低电平驱动也简化了控制代码,避免了单片机上电复位时端口置高电平后对led的影响;. m* ?4 Z8 o$ n4 z: \, I# I
8 } `, `, T: K/ A. g
从STM32中文参考手册内得知,STM32的GPIO可配置为八种模式。1 M5 H0 a5 I2 V+ o
9 K) a; {6 Y8 g8 h3 @. _' f
1、浮空输入(Input floating)
2 a( v+ L6 F5 Y1 U* w7 `( V: b8 d0 m p- p T [* j8 H
2、上拉输入(Input pull-up)" ~" M/ ]: t9 N- k) d
; G0 n/ h% S$ W9 c* f
3、下拉输入(Input pull-down)
! |. K6 F/ D% `$ l5 f* V! }2 z* `* P4 A! y+ K2 H
4、模拟输入(Analog)
; h! G; S9 u1 U' s; u% V
) J9 t. i" z6 P: E 5、开漏输出(Output open-drain)) H4 n8 c- G5 H! Z+ Z1 d
: c$ n2 K7 Y- a7 `9 h 6、推挽式输出(Output push-pull)
' K, N+ Y7 J; C' R/ f
: |. f5 ]% Z% F# K7 ?8 g 7、推挽式复用功能(Alternate function push-pull)
# C) ^0 l p/ F1 |6 W. T' }% P. l' a) I4 x8 |9 T
8、开漏复用功能(Alternate function open-drain)
4 x l4 G3 j" a2 h% u( l2 ?
8 z! z, F# S' d% M3 T- typedef enum
3 ^7 w( a! }+ v- N - {
; F- m$ u9 ]5 J3 @* |- R% }' z - GPIO_Mode_AIN = 0x0,
9 N; l0 C! A- Z - GPIO_Mode_IN_FLOATING = 0x04,
2 W2 h/ `" g0 H. @. i: `- J. f - GPIO_Mode_IPD = 0x28,
; e3 I2 n; s5 k% q9 J - GPIO_Mode_IPU = 0x48,! r9 `5 h1 s1 D1 X/ X \( D
- GPIO_Mode_Out_OD = 0x14, O- ]: m2 `6 t0 M; |3 F3 v
- GPIO_Mode_Out_PP = 0x10,
) o1 Y( h1 V5 a; s7 t - GPIO_Mode_AF_OD = 0x1C,
5 e' o1 P3 Q; g9 D7 e$ M- l0 t - GPIO_Mode_AF_PP = 0x18! Y' I. t: y3 h$ B; G
- }GPIOMode_TypeDef;
复制代码
0 \! ?- j) ^7 v( x, G1 x7 W t5 o& s% o驱动LED使用的是推挽输出。推挽电路(push-pull)就是两个不同极性晶体管间连接的输出电路。* s2 O, h/ F: Q8 }7 i
% P4 G+ H: j4 [
* n) S4 }3 }& z! k7 [
5 q* F( I+ e7 Z' n! r' R简单理解推挽和开漏的区别:驱动能力不同。推挽驱动能力强。" }6 {; T' v2 n0 i
0 O) T7 {8 r8 l/ u( {# H* d7 T: u4 _复用意思是GPIO不作为普通IO,而是特殊功能使用,比如ADC、USART等。6 ~5 l4 y. K$ O, L* Z4 w( X! m
! U3 m# g; q! s( s- l! ]2 h
引脚输出速度有3种:; ?0 _8 _! i n8 p% |4 g2 `
- typedef enum
$ x7 ^5 q; |( { - {
! ]1 Q& z6 J( Q G: g6 h4 Q - GPIO_Speed_10MHz = 1,9 r5 z1 Y9 Q$ O0 B0 \* B4 q
- GPIO_Speed_2MHz, # U4 T7 w/ o( O; u" d P5 `3 ^
- GPIO_Speed_50MHz) _% u1 k; o+ Z, F2 H
- }GPIOSpeed_TypeDef;
复制代码
% h9 c- s" C1 ~+ K& i+ u$ r! UGPIO的速度应该与应用匹配。速度配置越高,噪声越大,功耗越大。5 D* Z0 K8 V* e K2 A5 N
& s8 ^" j5 l6 e( y7 b" F比如配置为串口应用,波特率为115200,此时GPIO的速度配置为2MHz就够了,既省电也噪声小。0 N8 Y. G. k9 g* G
, m/ p+ c- `0 n2 d% d6 n
I2C接口,400K波特率,若想把余量留大些,可以配置为10MHz。+ |, Y; N/ o; X3 B' D
7 L- k6 Z- Y. a' U, y6 M) q% PSPI接口,18M或9M需要选用50MHz的GPIO速度。# \, X- Z1 Q% B# M
, f) T8 c R: S+ _
r( }# [. i, ^2 q+ j |