GPIO最经典应用:LED灯。
1 P: x- c/ U8 _* E4 m. B. E5 U! |" D K! y& }
先看电路。声明:参考正点原子战舰开发板。
- R" Y6 z, x: e5 x' C2 @! o+ ~; b7 E. n7 s4 B2 a, b! N
: p/ h" a' Q. }9 {: {
/ I& ]+ x5 Q4 X$ s$ \
: x+ t& M! [% ^( \, u
7 @- Y# J* R* Z4 e1 I" D$ X3 r) ^; j& g1 Q# `9 q
$ t! i, q- I1 @; a3 E+ d* w; ^与LED串联的电阻称为限流电阻。
) X2 ?" l4 K/ s, z8 p& c6 C8 y0 t& a3 c/ p1 z3 o# [
限流电阻计算公式:R=(U-LED压降)/20ma。* B' ^& ?1 \0 w; ^, W
( [# q/ \# Q! H$ G4 g
U为LED工作电压,LED一般最大电流为20ma。
& w; F. X7 G8 i& \3 s6 G2 J2 M1 ^7 `) B5 t0 R3 y7 A
在此R=(3.3-0.7)/0.02=130Ω。( r! n- {4 c6 v
5 ~$ m& u3 n9 i1 p" X- h" n" V因此本次示例中限流电阻阻值大于130Ω,才不会烧坏LED。
6 j) }* `# c( i" C. _
9 Z K( }5 Z" W& J1 b0 B& M9 V
* d8 X4 [! V, |7 F! F" v再看代码。) @4 _* T; W9 d4 ]1 ~5 b
+ j2 {& X+ Z9 Y+ gGPIO初始化。& U1 g8 M& d3 b; t
- void LED_Init(void)
6 r" i4 m- E! r: v) L: K - {( y( g3 l# v" s& d! g1 Q& r
- GPIO_InitTypeDef GPIO_InitStructure;
\6 ?" l5 l3 i# h1 J7 P" U- _ - 6 _: z& n. S+ U" S8 Y
- RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOE, ENABLE);
$ F8 n/ |9 B" i -
# W. k4 ?, U# L. Q* r( T" m - GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;
/ H- L4 b4 i% y3 b9 p& G9 i - GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;) z! [# l% Y5 i- e
- GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
5 m" W3 R# k+ F+ Z2 P, a - GPIO_Init(GPIOB, &GPIO_InitStructure);
2 _* K- K. C% v& b2 I" w - GPIO_SetBits(GPIOB, GPIO_Pin_5);
: }) i: L( K$ v$ v6 F* R7 P9 ^, h - 8 y- Z' f' r3 Q" H; P
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;! N! k( H+ Z0 T" o. r, p3 @. |' c
- GPIO_Init(GPIOE, &GPIO_InitStructure);& I3 Z! ~: W' Z8 H7 x$ S
- GPIO_SetBits(GPIOE, GPIO_Pin_5); : b7 X; l' s0 ]# Z8 [7 J
- }
复制代码 # }: a; N. B5 ~& W. t1 C
LED应用- G. R2 z- L5 |* T$ d! q
- void HW_Led0_Off(void)
* ?& |7 h7 T! t, x - {
2 d. k, V- F9 y - GPIO_SetBits(GPIOB, GPIO_Pin_5); //设置GPIO输出1: w$ A; }1 f# e, `: i
- }
# g5 T# }! z' Y6 m - 6 N2 V" a. Q0 T" V; e6 h
- void HW_Led0_on(void)0 e' g7 m$ I9 [0 x0 m" w
- {: Z" x, `$ z5 n7 p
- GPIO_ResetBits(GPIOB, GPIO_Pin_5); //设置GPIO输出0/ f, r3 Z0 Z) Z& x$ W$ p, Q! S
- }
2 E; A/ ?* u g) T' ^( j: a Q - - b! {7 O) k$ `
- void HW_Led1_Off(void)' M! U2 K! z. l3 _5 _: V* }. F c+ I5 T
- {8 R$ J( C7 x0 J3 W/ \' C
- GPIO_SetBits(GPIOE, GPIO_Pin_5); //设置GPIO输出1
! H. N* c# v3 ~: y4 ?* i - }
5 A, {/ k3 T6 g7 N4 K1 k& U1 q - , M5 J- M2 O$ Z* R9 ~# \2 M. [2 B
- void HW_Led1_on(void) S$ E( p; K+ k2 n2 y
- {
" q" D% s. A6 w3 j8 Y - GPIO_ResetBits(GPIOE, GPIO_Pin_5); //设置GPIO输出0
0 @6 H5 d2 O! d3 r, m4 X - }
复制代码 8 I* V$ H% U1 U* d8 V
思考:为什么IO输出低电平时LED亮,而不是输出高电平?
& P3 V) G2 f. t; }, t9 A' X2 ?* W6 F# \" m2 l( U/ O! o6 p
思路:' ]& W+ r5 U: n( _
& M$ A" w3 _$ f0 V- s
1、由于单片机的I/O口的结构决定了它灌电流能力较强,而拉电流能力比较弱(即IO口的低平驱动能力较强而高电平驱动能力较差);, n* I( m% n# @8 i7 M
# M+ i: ?; K9 b/ Y
2、为了简化单片机接口的设计。高电平驱动和低电平驱动是同样的效果,另外,低电平驱动也简化了控制代码,避免了单片机上电复位时端口置高电平后对led的影响;+ [7 z6 k, q: t6 I; b' @) x
1 _6 M. |4 t7 B# J4 _& C* {
从STM32中文参考手册内得知,STM32的GPIO可配置为八种模式。
. k, O, @% V! U5 r- K
5 m3 c: d6 v" O* j* Y% b; X$ k1 a& s 1、浮空输入(Input floating)) p' I: G# s* I4 O: k5 Y
+ A8 l4 H( t1 T9 ^, N Z' N 2、上拉输入(Input pull-up)$ y+ x/ N/ z3 [ @$ n
{7 w8 i' g1 J$ ]4 D( \1 k
3、下拉输入(Input pull-down)4 G* \3 A# t# o( ~0 \/ u, T
# S/ Y$ b7 C% c$ Y$ S
4、模拟输入(Analog)
& _9 Q5 ^3 k+ l" y% y# S9 g1 n
+ E# c6 z$ t: y0 Q3 B 5、开漏输出(Output open-drain)2 O. H0 ~: z# ^: u9 J
: b* ]) b7 i8 j" @ 6、推挽式输出(Output push-pull)
7 T& ~% a' Q% A [
! Q+ w/ u" R! W" j0 T 7、推挽式复用功能(Alternate function push-pull)' q8 `; ], {/ |2 Q/ ?4 [
9 u2 u2 ~3 K& X$ w; {
8、开漏复用功能(Alternate function open-drain)
9 |" ]3 h7 T! F3 f
, V5 D. v' t2 z' @; e6 b- typedef enum
' S% m8 W- k$ s$ q- V - {
. `- f1 B! m5 g9 H1 m) y - GPIO_Mode_AIN = 0x0,
; ~! h8 x3 C7 \3 q4 _- | - GPIO_Mode_IN_FLOATING = 0x04,$ [4 [) w" @1 [: \6 c, r2 S; p k9 ?. ~
- GPIO_Mode_IPD = 0x28,
/ K2 g& x8 }- r7 _+ Z7 x - GPIO_Mode_IPU = 0x48,
, E& r h1 C1 f- Q - GPIO_Mode_Out_OD = 0x14,8 R' M9 ~& {' s& l9 V% |1 Q1 Z
- GPIO_Mode_Out_PP = 0x10,7 e5 n6 P& S8 B" C" r" l
- GPIO_Mode_AF_OD = 0x1C,
; [9 Y4 p. p8 _/ ` - GPIO_Mode_AF_PP = 0x18
1 l1 ?$ M* l, P - }GPIOMode_TypeDef;
复制代码 : G |' e8 F: D8 }- u6 d
驱动LED使用的是推挽输出。推挽电路(push-pull)就是两个不同极性晶体管间连接的输出电路。" `7 I' U f% a. u$ j
( u& F) x( A% i! ^2 U$ i* ~9 _! n3 }! {6 l) h
+ K* A9 \& C8 F. G
简单理解推挽和开漏的区别:驱动能力不同。推挽驱动能力强。* ]2 n; u' U7 X
3 \& V" a9 @9 a$ f; m: M1 E0 ~* j复用意思是GPIO不作为普通IO,而是特殊功能使用,比如ADC、USART等。
( g# C( T' f `, F+ r# ?$ @) L" o6 S* a% j9 _5 U
引脚输出速度有3种:
5 d' A1 O% {# [7 x7 z- typedef enum) b) b; G4 A) O
- { 6 j6 h* `* b/ ? k9 _3 Q. U
- GPIO_Speed_10MHz = 1,
( u& t, G. X$ D - GPIO_Speed_2MHz,
, D# v+ L p, _ - GPIO_Speed_50MHz
5 g# x7 ?1 D$ u& i& Q4 ?. U% I: r - }GPIOSpeed_TypeDef;
复制代码 4 I5 ~# `! D u8 `! V$ d. ?6 ^ y2 C3 }
GPIO的速度应该与应用匹配。速度配置越高,噪声越大,功耗越大。. d: N) x% \0 i
( q5 @, n& f8 C$ M: B1 `% U/ d比如配置为串口应用,波特率为115200,此时GPIO的速度配置为2MHz就够了,既省电也噪声小。4 ?9 D+ f9 F" U, w3 W) J
+ T! i* L5 N, w2 @3 H7 p+ R
I2C接口,400K波特率,若想把余量留大些,可以配置为10MHz。0 ^+ A& k! X& _
( v x$ r. c2 c; F& _) P9 Q. aSPI接口,18M或9M需要选用50MHz的GPIO速度。
$ W1 T( T* V3 N* Q6 `' _, q$ a9 ~$ u7 c! r0 w) `
/ e8 o& O/ O+ N1 U; q1 |$ y6 p& @ |