GPIO最经典应用:LED灯。
! U2 ]' f9 }, Q" m& N0 K
4 ^$ q/ k9 ^0 r/ F# {先看电路。声明:参考正点原子战舰开发板。
8 D* N* x& W+ l' V) B) g( I$ k& w2 {$ w4 t9 A1 A& ?% U* N
( S6 H- i1 \8 c7 S& R: _4 \) z/ O, H
6 K* t9 A5 M* E2 X+ `% K. t6 b- H; c% ~
5 w1 @7 R0 C6 H8 i6 u5 Y9 y: s4 l4 G$ Q1 @% r) D6 Q! `2 Q
2 C; H+ h* p k: _$ ?% O: {
与LED串联的电阻称为限流电阻。) t" p* K7 X+ _" ]
& x1 f& {: Q. U0 g' z
限流电阻计算公式:R=(U-LED压降)/20ma。! T4 d' c F9 R
5 }- v' v+ T# X w6 F: ^U为LED工作电压,LED一般最大电流为20ma。5 o* g3 j' x/ H7 L9 B8 }
; e6 ^1 u X3 o4 f6 Y% {/ i在此R=(3.3-0.7)/0.02=130Ω。# U( V' }6 k) u6 R
+ ^% a3 q/ U4 y
因此本次示例中限流电阻阻值大于130Ω,才不会烧坏LED。
5 v; ] O/ E Y0 Z0 Q% R8 u( @' f% V/ x! Z3 R& R6 v
5 X& \, p) [% d5 P再看代码。
0 r# b- I' [* e5 N* [3 T: Y3 N# ^8 u- i) j. \# _ V
GPIO初始化。
! Y. x6 n6 M! M/ |$ _" Y- void LED_Init(void)
2 P, s6 L6 @1 W% r8 \" y f - {
, C: C- b3 }. Y e' U - GPIO_InitTypeDef GPIO_InitStructure;& K- f, Q' k! d% Y2 S
- & Z- S3 N9 N/ ?# P
- RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOE, ENABLE);3 _% |$ e$ ^1 x5 E0 [) P
- 3 m9 j: Q; `: I& o
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;; Y; ~& s9 V1 m" g& I& j
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
2 T. A6 ?3 J; O! n - GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;" n' H; F3 D$ s0 T6 Z
- GPIO_Init(GPIOB, &GPIO_InitStructure);+ C% `# C! p9 O6 M3 a
- GPIO_SetBits(GPIOB, GPIO_Pin_5);
+ f b& @$ z/ b8 J) B - 1 R7 X7 W& @0 ^2 r7 q
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;: Y# C5 ]( Y: G
- GPIO_Init(GPIOE, &GPIO_InitStructure);
2 T0 J& q: f- E: s6 j - GPIO_SetBits(GPIOE, GPIO_Pin_5);
, e, P" N* _! o0 J - }
复制代码
+ ]0 B8 T0 i% W- y% }5 y4 ?LED应用8 {) K" S% [8 R0 q. R5 w
- void HW_Led0_Off(void)
4 z; _/ Z1 G- V. N) }9 I - {
; p8 C0 j C& ^& _0 C' x# Q1 Z6 B - GPIO_SetBits(GPIOB, GPIO_Pin_5); //设置GPIO输出15 B3 B. `" _3 Q! ]7 R1 n
- }
4 a: E- N& `, R - 7 d& Q1 p, a8 T5 C
- void HW_Led0_on(void)7 |7 W l& K5 p
- {
0 d4 C* J m7 J4 ^5 U( S! e - GPIO_ResetBits(GPIOB, GPIO_Pin_5); //设置GPIO输出0, K9 q. e. C9 s6 M7 S; ?( _% ]
- }! `7 V! f- u' a2 w: J/ ^
- " P" c" R5 b( j& `7 s
- void HW_Led1_Off(void)
6 V7 v2 {2 C3 W' I r - {
+ y, M' p2 {4 h( Y" Z( a - GPIO_SetBits(GPIOE, GPIO_Pin_5); //设置GPIO输出1
( D3 X m4 E% W$ n' b$ m+ g - }4 l9 B$ I4 P" J( A& ?0 P% I7 @% \
- : J& k" Y. d2 S/ {; i
- void HW_Led1_on(void)# m ^# t) o6 f% S7 k1 g! G5 J
- {
5 C u( g* s% c# H" F - GPIO_ResetBits(GPIOE, GPIO_Pin_5); //设置GPIO输出04 X1 h l2 z* \' H: i
- }
复制代码
' `! W6 _; o2 `% K7 y, o思考:为什么IO输出低电平时LED亮,而不是输出高电平?
0 {3 c1 \" i. H' n9 p, `" ^3 H0 l) n" u0 n% w; x
思路: S- o r) f' S; s
* d, g' E$ I; F/ e: V
1、由于单片机的I/O口的结构决定了它灌电流能力较强,而拉电流能力比较弱(即IO口的低平驱动能力较强而高电平驱动能力较差);8 r1 n* |: I- M7 m9 n" G
3 e& {3 x! i& w. a3 r5 d0 k 2、为了简化单片机接口的设计。高电平驱动和低电平驱动是同样的效果,另外,低电平驱动也简化了控制代码,避免了单片机上电复位时端口置高电平后对led的影响;: U5 O$ w6 G8 A R- l Z
3 G$ C3 A; o7 B; f* h. }6 I# Q
从STM32中文参考手册内得知,STM32的GPIO可配置为八种模式。
7 W9 D2 S/ l& X* U# h: Q! r( f
% c- A0 U/ U* L6 w% G 1、浮空输入(Input floating); ~" n8 x' o' A- z4 R
) x9 X0 z ~( t! T% f 2、上拉输入(Input pull-up)/ R; z5 v0 {8 ]8 V
3 j/ q, U0 u) z/ K
3、下拉输入(Input pull-down)
2 |0 H/ m: a! A
/ c2 l* ]$ }7 j7 |: y) M, U, W/ _ 4、模拟输入(Analog)" l" {- p# X7 F* w
4 o) t# ~& c" e3 ~ 5、开漏输出(Output open-drain)
6 R. V( F( i3 \$ L ^' @2 b0 ^6 r( n& Q+ ` k0 y9 r9 P
6、推挽式输出(Output push-pull)$ d$ m3 X# h3 P7 K- G3 ?, n6 j
$ `" H/ A" N$ Z9 H# K
7、推挽式复用功能(Alternate function push-pull)* R9 _+ _1 b' X
9 C. l5 V! K; t7 p7 D) |. U 8、开漏复用功能(Alternate function open-drain), a& ^4 z5 ?! [" A) e
# j" Y" Z& S, w) ^: P
- typedef enum
: g7 S1 d- R; u4 j# c! j" y - { ) u, R0 F, j1 C1 n) V6 X0 ]' |" w
- GPIO_Mode_AIN = 0x0,& z3 B0 L7 o6 V* [ N7 F# g
- GPIO_Mode_IN_FLOATING = 0x04,+ [3 ^) P; F- r
- GPIO_Mode_IPD = 0x28,0 g; S# r C/ k- V, {
- GPIO_Mode_IPU = 0x48,2 ~0 Z/ @8 V L
- GPIO_Mode_Out_OD = 0x14,# s1 D! B$ K5 r+ t) M0 `3 v
- GPIO_Mode_Out_PP = 0x10," p5 ?4 O& O, }# D1 u
- GPIO_Mode_AF_OD = 0x1C,8 v8 ], u! X3 C* T; m0 d6 k
- GPIO_Mode_AF_PP = 0x18
/ {' ?0 Y+ [0 S- J( v1 a - }GPIOMode_TypeDef;
复制代码
# Y; y, a+ F( N X/ D驱动LED使用的是推挽输出。推挽电路(push-pull)就是两个不同极性晶体管间连接的输出电路。
R. g' |' ]4 g, y( c2 h, N% l
y7 o, ]& ?. P' `3 b( I( w9 w- ?2 \5 Z- V! w8 s
( E: \9 J) w' L8 L6 X简单理解推挽和开漏的区别:驱动能力不同。推挽驱动能力强。4 a8 w& S L% o' s5 A6 Z, Z# {$ k
+ m7 ]# q/ ^1 O( k. Q$ I复用意思是GPIO不作为普通IO,而是特殊功能使用,比如ADC、USART等。
8 ~- d" \* v6 R N
0 Z0 _. V3 q" D& v& n* l, V引脚输出速度有3种:
1 a$ ^8 ^* E1 k# y- typedef enum
, i! D$ P+ K Q1 r& V5 B( x - {
8 Z" N: w5 d% m+ G7 ?8 [ - GPIO_Speed_10MHz = 1,# y1 S4 I( F3 q" n! f7 Y4 D
- GPIO_Speed_2MHz,
* \/ j h9 F2 b, P( ^ - GPIO_Speed_50MHz( n5 M( T# I6 X+ F) h! J
- }GPIOSpeed_TypeDef;
复制代码
% i; s Q" v$ Z- l! l7 G" PGPIO的速度应该与应用匹配。速度配置越高,噪声越大,功耗越大。 v+ h" V4 K# W0 N
) I# v, a5 D9 Y G1 }: Z; ~7 F比如配置为串口应用,波特率为115200,此时GPIO的速度配置为2MHz就够了,既省电也噪声小。" ]2 u* n7 n3 P) @
$ ?6 p1 k8 v* u7 fI2C接口,400K波特率,若想把余量留大些,可以配置为10MHz。
% y, }6 _& w |2 ^% C
- ]4 J; ?% {) a3 V" @SPI接口,18M或9M需要选用50MHz的GPIO速度。; l& \$ Y8 |. V& f8 E @0 [ z
) N4 ^/ C' f+ e e1 H0 l. L& F/ u: D2 c
|