GPIO最经典应用:LED灯。
" J6 ~3 ~+ Q9 H
* t& }5 Q( g) v& |8 D# V先看电路。声明:参考正点原子战舰开发板。
( \6 {1 ~ K' @ A' O5 ^, T. m0 Z2 Q( T
* c/ w# k( ^( l# v5 t* q: L" I% a6 @! x: _7 N* x4 V
& r* u: m2 Y- y, S/ g
6 U1 h/ c7 p+ z2 u ]* O8 C5 `. J' v- f0 d9 r3 F6 n
$ I0 |" b+ S4 o' D* @: C( f8 ?
! s& @) F) L5 e2 |9 ~3 g( C- U与LED串联的电阻称为限流电阻。
* l# m. s% B6 l' i# f2 F0 |
" t+ j! D) r5 Z; B1 V& s6 d" p限流电阻计算公式:R=(U-LED压降)/20ma。$ f3 e- Z6 N. l* r
2 s) o! {/ g. K- H
U为LED工作电压,LED一般最大电流为20ma。
# A0 G2 m4 n; O1 ^$ t) k" j [1 t( {: O
在此R=(3.3-0.7)/0.02=130Ω。! l A& ?* T* T2 m h+ q
1 H& C1 \; |' D因此本次示例中限流电阻阻值大于130Ω,才不会烧坏LED。
# [1 x" [/ M! T A5 d7 |' J2 J r+ M
$ N! \( ~" d. |) M( R" f& K' b再看代码。
8 s5 c1 s) Y2 p+ |3 b3 w* U2 b5 u A
GPIO初始化。% |5 k8 F1 X- a" R: ~( J% Y
- void LED_Init(void)! {# d. m* q+ `7 A5 X
- {
, U+ s6 l* `" A - GPIO_InitTypeDef GPIO_InitStructure;7 S# H. G7 H5 ]1 E" r
- ! Z; y: U O0 a# @0 @6 Q
- RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOE, ENABLE);
8 t& ]' A, d5 N: _. U! F - 1 x% ]3 O: D8 [% I6 ~2 |
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;
0 f r8 F! d' @) d- m - GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;( ]4 C+ E* E1 Q" T. T2 W2 J3 Q
- GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;9 c% s/ j- f+ E
- GPIO_Init(GPIOB, &GPIO_InitStructure);" C8 ?6 X8 i! `( o# g# u
- GPIO_SetBits(GPIOB, GPIO_Pin_5);
" c' M6 @! D' Q, `( r, s# v( | - % g4 y9 u' B$ b( p& m( W+ i& f/ J8 S
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;4 |1 j+ [# @( }: C3 J
- GPIO_Init(GPIOE, &GPIO_InitStructure);$ }; K; _# q4 j' @ u; @! h! j9 e' t
- GPIO_SetBits(GPIOE, GPIO_Pin_5);
7 j# ~( r* q* T. H4 p9 R3 h( \$ f - }
复制代码
+ X- T: d1 P# @/ i) GLED应用8 ^3 q9 m% H2 I& z E
- void HW_Led0_Off(void)
' X: j0 \1 M2 F" L - {! Q" f! b/ @7 {5 A" a$ f( G
- GPIO_SetBits(GPIOB, GPIO_Pin_5); //设置GPIO输出1
: m0 q' Q; \6 B' M) A9 r' R - }! t5 h9 n" ~* O" x
2 V* G% X9 S) b% N2 f1 b- void HW_Led0_on(void)8 T x+ R& q4 ?
- {
G7 I- x" `/ |! E) Q - GPIO_ResetBits(GPIOB, GPIO_Pin_5); //设置GPIO输出05 n+ N2 P7 c2 Y
- }
3 b! v* R4 j" a* w- P' W
& A# I0 Q5 v) y! L& _- void HW_Led1_Off(void)5 q1 \6 r' X6 i! Q2 ^
- {/ H' \* m' y% ]+ t
- GPIO_SetBits(GPIOE, GPIO_Pin_5); //设置GPIO输出1
, |8 N- Z5 A7 X6 i3 S3 e - }
5 g+ r: A, ~0 J+ M7 i' E
0 T) e0 H9 S5 V, x' c% [3 {- Y- void HW_Led1_on(void) o- x! w( g. g% @' m4 b
- {
$ w2 Y4 P, ^# |8 P - GPIO_ResetBits(GPIOE, GPIO_Pin_5); //设置GPIO输出04 v) Y! ^3 {2 f G" T+ f& ?6 s
- }
复制代码
: B% U5 H5 M# _8 a2 l* g思考:为什么IO输出低电平时LED亮,而不是输出高电平?0 ]7 x. }: P% _5 R7 u' I# u( U4 x
4 C5 q8 s' w, m: [$ N5 b4 T
思路:
, a4 `3 w. z$ }/ [* [* U1 X4 Z& f0 ~7 f
1、由于单片机的I/O口的结构决定了它灌电流能力较强,而拉电流能力比较弱(即IO口的低平驱动能力较强而高电平驱动能力较差);/ V+ B* R% N2 G% y* m: s. j$ R
! b2 |6 f2 J. [* N6 `8 y* @
2、为了简化单片机接口的设计。高电平驱动和低电平驱动是同样的效果,另外,低电平驱动也简化了控制代码,避免了单片机上电复位时端口置高电平后对led的影响;$ }" i7 ^: {( S2 u5 L
- f; E) o" y+ L) V/ o( i
从STM32中文参考手册内得知,STM32的GPIO可配置为八种模式。
; L5 x0 {( _. D8 I. x) c: R5 P8 L; M, l- P
1、浮空输入(Input floating)
& F: o2 H; I( @* N; s7 S* u _8 t, r) [ P& C: c, q
2、上拉输入(Input pull-up)
/ L2 w) F' S$ ]) r3 f
/ k$ u/ J* i( {2 G( m% J 3、下拉输入(Input pull-down)- w( j2 s4 i- D/ c) |1 x+ d* W
* E8 u, c) Q, H8 U* X 4、模拟输入(Analog)# ? y% i- D- D+ A
1 H3 L ^, X4 b0 M% ? 5、开漏输出(Output open-drain)$ U9 S# Z- K. B* p% {! c
1 L. I# B1 r+ l, S
6、推挽式输出(Output push-pull)
& R- y' r3 U( o2 U
, J, g- _6 ]* W4 U6 q! o0 C 7、推挽式复用功能(Alternate function push-pull)
) Y$ N: k( N; U3 c! S4 S/ Q' K: M+ F# g0 c3 U
8、开漏复用功能(Alternate function open-drain)
# O, {6 K; g* |" p& N7 ]( n0 H, f- Q G
! b2 O& e* }& O) m+ ^) r c& Y- typedef enum1 w! G+ O! i, T5 f/ \7 ` `2 G
- { % A7 ?! G' p. x) Q- u
- GPIO_Mode_AIN = 0x0,% L: x }& j# B0 Z0 F
- GPIO_Mode_IN_FLOATING = 0x04,$ A! j4 h* A4 c4 A6 ~6 S8 g Z4 }
- GPIO_Mode_IPD = 0x28,
" H+ N7 E/ @- w' u - GPIO_Mode_IPU = 0x48,
: U) l, \& B, Y3 l+ Q; l - GPIO_Mode_Out_OD = 0x14,1 \0 M6 J/ b, S. D
- GPIO_Mode_Out_PP = 0x10,
Z$ r7 R* L, V' K$ t, p - GPIO_Mode_AF_OD = 0x1C,
3 b; @( E$ z9 y: s# E1 H - GPIO_Mode_AF_PP = 0x18; Q0 \# J6 ?* v& j* G
- }GPIOMode_TypeDef;
复制代码 8 p9 Z0 r7 N0 _- C; k
驱动LED使用的是推挽输出。推挽电路(push-pull)就是两个不同极性晶体管间连接的输出电路。& F9 E9 r: k/ {8 ]' b
. e; t( U( z+ H; B- d
5 U1 t8 }- v7 F1 u
$ O2 n. G5 V& I& F( D简单理解推挽和开漏的区别:驱动能力不同。推挽驱动能力强。
( [" j/ q% H5 k: p% v+ S" H! w$ A2 `9 C9 R3 j! b9 }& O
复用意思是GPIO不作为普通IO,而是特殊功能使用,比如ADC、USART等。) n, d }. C) c, {7 c! G
; x! D, z7 K* a2 Q! V' w引脚输出速度有3种:
8 r7 J4 _0 _% I- typedef enum
: i. Q- B- e, l4 q - { ( k0 M+ d0 j; Z! `) ?( e4 x* @
- GPIO_Speed_10MHz = 1,
9 o5 p, L: t! j - GPIO_Speed_2MHz, 1 y7 D' t* \8 Z
- GPIO_Speed_50MHz
* A K/ l9 T" r& Z6 V0 S; U& } - }GPIOSpeed_TypeDef;
复制代码 }3 L! V& C5 a+ w/ x2 R
GPIO的速度应该与应用匹配。速度配置越高,噪声越大,功耗越大。
: V q6 ]4 U, B. z( g2 m2 Q
4 g5 P& l+ k* g4 g. l6 I Y2 r比如配置为串口应用,波特率为115200,此时GPIO的速度配置为2MHz就够了,既省电也噪声小。
3 s3 c( r, p/ @' y" `
+ ^4 Z. N3 r# u0 h$ YI2C接口,400K波特率,若想把余量留大些,可以配置为10MHz。
" S! \0 N6 A" [. V$ @8 s3 f
2 O+ M; W$ H! M0 C4 X! {" kSPI接口,18M或9M需要选用50MHz的GPIO速度。
* h3 b; X9 R! O3 Q; o2 K$ f
7 e% l5 [9 b6 f0 S6 L4 [0 M
6 F: F" U" l/ G |