你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

【经验分享】STM32-GPIO介绍

[复制链接]
STMCU小助手 发布时间:2022-5-7 11:13
1.概述
) s$ D6 n7 _, ]( PGPIO是STM32最基本的外设之一,下面我们从三个角度来介绍STM32的GPIO,分别是:①GPIO原理、②相关寄存器、③库函数编程
; s. [6 a8 ]; y: v  w. a% _8 ?; s) k2 b" V# l" `
2.GPIO工作原理5 [  I1 z3 ^% X6 o6 s2 s
GPIO是通用输入输出端口(General-purpose input/output)的英文简写,是所有的微控制器必不可少的外设之一,可以由STM32直接驱动从而实现与外部设备通信、控制以及采集和捕获的功能。STM32单片机的GPIO被分为很多组,每组有16个引脚,不同型号的MCU的GPIO个数是不同的,比如STM32F103C8T6只有PA、PB以及个别PC引脚而STM32F103ZET6拥有PA~PG的全部112个引脚。所有的GPIO都有基本的输入输出功能,同时GPIO还可以作为其它的外设功能引脚。
% n8 w' K' C4 Y$ Q2 t5 A5 R9 Z8 @% L# V( G: u6 [  ?
作为STM32最基本的外设,GPIO最基本的输出功能是由STM32控制 引脚输出高低电平,比如可以把GPIO接LED灯来控制其亮灭,也可以接继电器或者三极管,通过继电器或三极管来控制外部大功率电路的通断。
+ G0 s2 ^7 u1 }8 ~5 p/ W$ C! b' m) r  w
GPIO最基本的输入功能是检测外部电平变化,比如把GPIO引脚连接到按键电路,通过电平的高低变化来识别按键是否被按下。
8 O9 y! q$ w; Q7 s0 t" B
7 {/ N& y) V9 f% H XP}D3LWM~CW%QPQ6H5TZ9$B.png
8 Z0 s, h1 m6 w/ x6 g' u  ?8 ^0 V" n4 T) L
这是GPIO的硬件结构框图,可以从这个框图中清晰的了解GPIO外设极其各种应用模式,最右端的I/O引脚就是STM32芯片引出的GPIO引脚,其它的部件都位于芯片内部。
: u6 P8 s: k. h* n: j7 s5 Y) D' R6 }- R) z3 O8 @$ C0 x+ T
2.1 保护二极管及上下拉电阻
( M8 w4 M5 E7 p6 O+ h
为了防止芯片被外部过高或者过低的输入电压烧坏,STM32内置保护二极管,当引脚输入电压高于VDD-FT(FT标识代表可以容忍5V电压,不同的引脚对电压的容忍值不同,需要在芯片数据手册上查找,见下图)时上方的二极管导通,当引脚电压低于Vss时,下方的二极管导通,这样就可以防止不正常的电压引入芯片导致芯片烧毁。
# K% ]: p- i$ e' T' z9 r" z( b$ T# s# P( q9 j
U4Y(1R[KG]`C[P)A3BTMEEY.png CHN@(6OH{3`C`2D+Z$S20.png
2 \" ]2 M" e6 z3 n0 Y5 L& q7 `; X2 G9 D! u9 j5 b' D9 [

- K+ g0 n& C4 Q  q 2.2 GPIO工作模式8 y2 o/ n! {; Y% [* x  ^' n
STM32的GPIO共有8种工作模式,分别是输入模式的模拟输入、上拉输入、下拉输入和浮空输入以及输出模式的推挽输出、开漏输出、推挽复用输出和开漏复用输出8 U7 b$ D; {- d1 X
# A# U1 l/ Z( F" R
为了便于理解,使用结构框图来详细讲解每一种模式:
1 Q1 C$ a8 V& y6 h7 o
( k$ p& C" z6 s' }3 J2.2.1 浮空输入模式$ d' O, P/ ?+ E& f2 h5 R; [( P
}196H6P7()8LDV~PPE7}THR.png

' i- z+ q) V2 R0 X7 }& u% @& S/ T* X* P) O
GPIO工作模式——浮空输入

, e1 K: _& _3 J  m( rGPIO作为输入功能的浮空输入时,电信号使由外部流向内部的,从结构图的右侧往左侧看,信号流经顺序是①端口——②施密特触发器——③输入数据寄存器——④读取
. M& I, w# p" k0 e' p' y% H' t. [2 s6 O0 c3 B8 ^: B
2.2.2 上拉输入模式3 d, P1 |  ~" i8 p" Q2 X7 }
: S8 _6 b  V; ^. F
WR5$$_{PNE7)EHKDSMTSK8C.png

. L1 a* D$ t  X
; P/ u6 h+ V7 a5 n7 k* t
GPIO工作模式——上拉输入

( I! L% s1 |3 c  j0 V9 L 上拉输入和浮空输入的区别就是在第①和第②之间多了一个上拉电阻,这样GPIO在没有连接外部部件时的默认电平是高电平,其它流程和原来一样。! L2 T$ E) i/ v7 [/ q

1 V1 O6 {: {* s: v2.2.3 下拉输入模式
/ k* f; O9 [2 k' c9 z
2 Q' r  O& W" c" K
SCUG@RPOUDOVLT963ACJO`6.png
# d: P4 ]+ @/ o- G7 d; G
- i. ^, S$ ]7 y5 e# [, T
GPIO工作模式——下拉输入
6 C) `# N/ v" p
  下拉输入和浮空输入的区别就是在第①和第②之间多了一个下拉电阻,这样GPIO在没有连接外部部件时的默认电平是低电平,其它流程和原来一样。
7 I4 b/ {( b" W, _. ?+ [
4 H/ H+ z% f6 Q! O4 ^) p2.2.4 模拟输入模式

+ f- u1 P% B2 Q6 ]8 V9 H0 g% }4 X! E3 }/ ?9 x
2E%QRP2CSZ4`LVPF)2@NPJV.png
! N9 C9 H8 F+ J8 [
' B! |' w6 D; V3 }. A. ~
GPIO工作模式——模拟输入

& S0 I9 w! \- V" | 模拟输入模式和其它三种输入模式不同,它的外部电平信号没有流入输入数据寄存器,而是直接流入模拟输入部分。模拟输入一般是用来ADC读取和转换的。
* v8 v, [4 \3 z: U# Z% i7 B: S# B- b  R- ^( f/ T
2.2.5 开漏输出模式. U, {. m  D) Q9 x; k

: i; i$ m# L: w3 s
R[OP5~(I3527005`}{7D)RP.png
( G8 }7 k! l) c! J
" b- f% f- d1 _7 j8 q/ h0 o
GPIO工作模式——开漏输出

8 N- R' H, g" D2 o# r( U; I) h GPIO 的输出模式比输入模式复杂,首先看开漏输出模式,电平信号由STM32内部流出引脚,因此流向是①写(包括位设置/清除寄存器、输出数据寄存器)——②输出控制电路——③N-MOS管——④I/O端口2 Q  b- L, w+ }* i

5 n4 |1 ]; t/ g8 k+ S位设置/清除寄存器写入的值会映射到输出数据寄存器,最终到达输出控制电路,如果写入的是1,则N-MOS管关闭,由于N-MOS管截止,所以最后输出的电平不会由写入的1来决定,因此此时的输出为高阻态(类似浮空状态),真正的输出电压由外部的上下拉电阻来决定。它具有“线与”特性,也就是说,若有很多个开漏模式引脚连接到一起时,只有当所有引脚都输出高阻态,才由上拉电阻提供高电平,此电平的电压为外部上拉电阻所接的电源的电压。若其中一个引脚为低电平,那线路就相当于短路接地,使得整条线路都为低电平0伏。若写入0,则N-MOS管处于开启状态,输出电流被拉到VSS,因此可以输出强低电平。输出的电平信号可以被输入数据寄存器读取。3 `* b7 ^9 ^5 _/ a

) \* S" I6 }2 o5 Z+ Q2.2.6 开漏复用输出模式
& E. s; ?! W. O& m9 |/ h
+ ?+ Y: m& |+ H& e: |( ]0 g' M
VOM08~}Y~WWO]F44GRk0J.png

: H4 @5 E: h3 V  T* y
8 m% {1 Z; f# j+ y
GPIO模式——开漏复用输出

" U( W5 h0 O5 ~, v6 K
# E- S0 H+ m" G- B: I( A) z1 u2 \ 开漏复用输出和开漏输出的区别在于信号来源,复用的来源不是内部直接通过输出数据寄存器写的,而是由复用功能的外设决定的。
9 l6 i- v! L) k8 s4 Z
) b' h, m9 e, }3 B# l' U2 ]* l+ `0 Z2.2.7 推挽输出模式
7 c6 P. ^- k' s7 F8 U8 {5 W/ b8 S5 X. r3 g9 d
4UX8PS5{(R~M2W3O2%DHHOR.png
3 ^' F$ D# H7 |+ c0 Q, C! U

/ Y/ q6 L) {- R' e! S
GPIO工作模式——推挽输出

: q2 ^# Z) \0 ]6 e5 E7 G 推挽输出模式和开漏输出模式有一定的区别,其控制输出的寄存器是一样的,但是②部分的写1有效,即输出控制电路输出1的时候,P-MOS管导通,N-MOS管截止,这样I/O口电平就会被P-MOS管拉高,输出强高电平;相反,当输出控制电路输出0时,P-MOS管截止,N-MOS管导通,I/O端口电平被N-MOS管拉低,输出强低电平。同样,输出的电平信号可以被输入数据寄存器读取。
" c5 v" q/ U! W" V7 K
* y/ f. C: l7 a5 i& a2.2.8 推挽复用输出模式9 k4 i* i% u9 \/ d7 B
+ @  t# R! M2 W6 t; y: M
955$ZON3)6[(1IE0FCEU5EN.png
. t1 S: A' }; G9 D: v
2 h  f9 m! E& q0 g8 ?7 Q
GPIO工作模式——推挽复用输出

8 h3 m- c5 b& g0 p+ [8 Z  R" C 推挽复用输出和推挽输出的区别在于信号来源,其信号来源是由复用功能相关的通信通道来控制。1 n1 f1 h  s+ \( m- e, r
% D+ A+ q3 `7 A$ d$ c
2.3 注意事项
4 n, s% h/ Q& b, z
注意:
6 }* @- q4 u% N7 o, G- @8 [$ j& P8 |' M- I$ P$ O
推挽输出可以输出强高低电平(高电平为3.3V),一般用来连接数字器件。在STM32的应用中,除了必须用开漏模式的场合,我们都习惯使用推挽输出模式。: P0 Q! Z( [, s/ y: C

. J+ f  t7 o0 U! z4 r. ^开漏输出只可输出强低电平,高电平需要靠外部电阻拉高。输出端相当于三极管的集电极;要得到高电平状态需要上拉电阻才行。适合于做电流型的驱动,其吸收电流的能力相对强(一般20ma以内)。开漏输出一般应用在I2C、SMBUS通讯等需要“线与”功能的总线电路中。除此之外,还用在电平不匹配的场合,如需要输出5伏的高电平,就可以在外部接一个上拉电阻,上拉电源为5伏,并且把GPIO设置为开漏模式,当输出高阻态时,由上拉电阻和电源向外输出5伏电平。
1 E$ `; Z# r5 L5 }+ s( C
0 ]- K8 c, f) i# H$ k. p$ f/ M2.4 GPIO端口复用
% R" O% e# n' Q7 V1 ?3 k为了最大限度的利用端口资源,STM32的大部分端口都具有复用功能。
! e. k9 Q1 `0 f+ l- E
3 [9 B& C9 f) D. l所谓复用,就是一些端口不仅仅可以做为通用IO口,还可以复用为一些外设引脚,比如PA9,PA10可以复用为STM32的串口1引脚。复用情况可以查找数据手册,如下表所示:
: A7 S# i( w" ^' p( u! W/ l- c4 f1 @2 X' T1 g" Z* Y
(5TM0%HSL2I_IVCE[2D]W6P.png
3 o  D  B; B& O7 @* K/ G& U2 D/ T: ~6 e$ ^$ K# q
从表格种可以看出,PA9和PA10引脚不仅可以作为GPIO还可以作为串口1的收发引脚使用。
7 }$ N2 n5 o7 d- B1 T3 Z
2 |" g) A4 n7 }/ I* h6 z2.5 GPIO端口重映射
9 R5 r" s/ @  T  M7 l为了方便布线  ,STM32配有端口重映射功能,所谓重映射就是可以把某些功能引脚映射到其他引脚。比如串口1默认引脚是PA9,PA10可以通过配置重映射映射到PB6,PB7。
, i8 m$ C  }# |1 h1 w/ a! K& c3 \
* o9 |7 ^+ N7 v5 C' g3 W0 P端口的映射情况也可以通过查找数据手册来获得,如下表所示:# R1 t' l* O7 m$ q. L  K: z- S3 ?6 J
$ ^* }( E% B# _6 o

" q! c& E+ ^8 l( [) b9 @9 D8 Q AKT7LA9_4[{N57M1)RI@TNM.png + l. _3 p- j- J

" k7 w) A' I8 O( F4 u0 J5 Y& P) v- B2 ~8 y- b  h  ]- X
3.GPIO相关寄存器
( R( J1 J5 R; S/ m1 c& aSTM32的每组GPIO都包含7个寄存器,分别是:
/ k$ @) g2 D5 P/ W, H- p1 @1 H) R9 }( {
        -  GPIOx_CRL :端口配置低寄存器
- ]: C1 S) H" J' l+ L$ K: l
" a$ e% {* Y% W6 B/ Y        - GPIOx_CRH:端口配置高寄存器
: u; X- D8 g& H: J, d# h0 H4 J) T2 C& G+ m; o
        - GPIOx_IDR:端口输入寄存器4 I4 p" O1 V2 ]9 S" V" _

/ I+ q( R8 R$ `9 q        - GPIOx_ODR:端口输出寄存器
" K+ [5 d- [/ z- h# ?9 ]1 |9 C5 x
        - GPIOx_BSRR:端口位设置/清除寄存器! m1 S' G& O+ ~; w

8 R4 z- `  a' X2 f        - GPIOx_BRR :端口位清除寄存器
! a) i8 D: q- \( G& ^( }# {$ ?3 D
9 i. \( D: v& A  X' ^" i$ q7 n0 t6 K        - GPIOx_LCKR:端口配置锁存寄存器
4 b4 y+ e0 @& A  i8 o1 M7 _! p8 U' p- c0 P" d$ Z- O" w# X
每个I/O端口位可以自由编程,然而I/O端口寄存器必须按32位字被访问(不允许半字或字节访问) 。
' M, ^" {6 w; g2 P4 w" w- m5 I* u9 O% c% h
3.1 端口配置低寄存器(GPIOx_CRL )
( _# Y6 K5 O* c" u: I% K8 t  s! h5 p2 U' i5 E' v
~3MM2ONO3V9GYF`DDE}Y06N.png   ?9 `  Z* i0 k2 P9 Y
0 ?& O, `( G( ?& _5 D
QO9XWQWOT0AE1W4U2M)%(}D.png
" O6 H' V% Q# U0 C) [2 M$ ?. R; t
! f& E. {; p+ u; U& A
9 f' K7 _% [* n 3.2 端口配置高寄存器(GPIOx_CRH )+ Z1 R% s2 g2 w, m  E6 z, @: J7 v
+ L' t$ n4 R; C, h0 U4 h
UJZAE19)%BWV97__C)I@$CO.png
9 \, J1 `( V. t. \# x. |; K
0 V7 u( s1 I6 I: Q6 q 3.3 端口输入数据寄存器(GPIO_IDR)8 R3 d( i/ w9 I/ _, a
  N4 H! l1 I' v9 {
S4X@~]0BTSCXH2Z%U}TIL_1.png
/ x+ k% W( a4 f& t$ K* F
! e+ F2 p3 d  ^1 V7 n  3.4 端口输出数据寄存器(GPIO_ODR)
6 C3 Q5 J3 I5 _, \3 `
: R  X; a9 i  d+ [& g# j (4@~WQY2XBK2{}Y5]H8O]Q0.png
( B# Q9 L6 g3 w0 T' }2 h  g
1 e) R$ g1 e( S! m 3.5 端口位设置/清除寄存器(GPIO_BSRR)
$ T' c0 l# a* E1 o' i) z+ p
2 Y" H* |- G% w8 M% V JNPC$C%]}WYTO8VZF6G}M6K.png
( P, K% p& j! V+ |6 Y; R3 Y8 Z( ?1 U2 F+ W, V: p$ y6 N8 t
  3.6 端口位清除寄存器(GPIO_BRR)& i/ D$ P( Z8 F: B8 W: a: R5 A$ B+ l

/ h3 h$ Y! O! q' _. r# ]! R, Q' l/ ^9 X (MPGH0SBU[88U@WPYTWF(95.png 6 V- V0 V8 n3 a- P  p8 O( x2 d
% J, E5 m  ?& o% |
4.GPIO库函数配置
8 [) V$ h; T" [; q6 X4.1 重要函数

" p" e( Z0 }- j) G* c初始化函数:
) n0 H2 k2 b; F5 Q3 n+ J7 e  w
  1. void GPIO_Init(GPIO_TypeDef* GPIOx, GPIO_InitTypeDef* GPIO_InitStruct);
复制代码

4 t, s$ e, S# E# l, i2个读取输入电平函数:
9 c  N1 ^& Q+ S5 }
  1. uint8_t GPIO_ReadInputDataBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);! J; b+ X2 |0 W: w6 N2 M+ P' r

  2. 0 w3 x/ r: I& x2 V/ k
  3. uint16_t  GPIO_ReadInputData(GPIO_TypeDef* GPIOx);
复制代码
8 d( U- r' ]# A5 D2 x3 H4 v3 Z
2个读取输出电平函数:( C) l, @' u; u0 c9 B& L0 l
  1. uint8_t  GPIO_ReadOutputDataBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);5 n- l1 r" `9 k$ i2 b6 O

  2. # w% k% |1 P: v8 `
  3. uint16_t  GPIO_ReadOutputData(GPIO_TypeDef* GPIOx);
复制代码
) Y- r/ P# c* W- s
4个设置输出电平函数:
; E3 @3 l) o6 F3 Y# r+ l/ `5 l
  1. void GPIO_SetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);: C% {% A8 i% G- q7 f
  2. 2 X! q1 }2 n5 t+ }# X  L
  3. void GPIO_ResetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);8 k, U5 p: P4 u8 e

  4. 1 o' X+ L) o- d4 X8 M2 N0 R8 c* [
  5. void GPIO_WriteBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin, BitAction BitVal);
    5 S# Z  C9 u( ]8 T( @

  6. % m/ D7 U8 s. `4 ~7 S; k3 n! c" z0 q
  7. void GPIO_Write(GPIO_TypeDef* GPIOx, uint16_t PortVal);
复制代码
# @# g, `, U1 U
4.2 初始化函数& m. {. _7 j  V6 O$ g
  1. void GPIO_Init(GPIO_TypeDef* GPIOx, GPIO_InitTypeDef* GPIO_InitStruct);
复制代码

, b! _4 n" V4 u7 t+ b* b作用:初始化一个或者多个IO口(同一组)的工作方式和速度。
! y0 I9 M) A+ _* m7 R5 Q) B5 x$ d- a7 L) v; Q
           该函数主要是操作GPIO_CRL(CRH)寄存器,在上拉或者下拉的  L/ @9 Z: D4 Y. {
3 ~6 d7 Q( I/ O
           时候有设置BSRR或者BRR寄存器3 j: L  A3 k/ K1 n
# q; d* }8 {' x; U9 L
   GPIOx: GPIOA~GPIOG0 F$ i1 a. a, }* g1 Y0 \7 u
# K, i' e7 v" q9 ^
GPIO_InitTypeDef结构体:9 C' U$ G$ p9 \* r% P

& |( X4 g5 B; w  H/ E0 e
  1. typedef struct    {( x3 i) s9 F- u5 [4 i# ?

  2. - T7 Y* \; g3 r
  3. uint16_t GPIO_Pin;                           //指定要初始化的IO口     
    ; h; U* f8 I  Y4 F  q
  4. ; w5 Z9 }9 E7 ]* D
  5. GPIOSpeed_TypeDef GPIO_Speed; //设置IO口输出速度    , e) u1 w9 q9 i5 h

  6. 1 l3 N6 {. n" r$ q: A0 {6 o
  7. GPIOMode_TypeDef GPIO_Mode;    //设置工作模式:8种中的一个   2 N0 @4 S2 o, d) @2 j8 j

  8. 1 a9 z; |( K( m) ~& N
  9. }
复制代码
% g  r* L0 h  l' X1 d
注意:外设(包括GPIO)在使用之前,几乎都要先使能对应的时钟。
9 G$ P9 S& f/ L1 O# h5 r
: O3 F8 Z' ?! CRCC_APB2PeriphColckCmd();( N& s) r( z" o* @3 ?. d0 P

9 z0 {% l4 H: w- t! l; NGPIO输出速度:
) r) ~% ?2 z3 v2 x. m
  1. 0 f/ F' r/ {; ~- ?
  2. typedef enum {6 c! y, d  v7 a8 e# a. @
  3. 8 {' {, ]3 E) l+ Y3 ~
  4. GPIO_Speed_10MHz,
    : Q+ y) @( F# O/ T: h

  5. # Y8 R, U7 m% F
  6. GPIO_Speed_2MHz,
    ; O" q- J" X' k/ Z0 E2 P( g

  7. & f% V' `# I4 r& `
  8. GPIO_Speed_50MHz1 O6 H# ]! U  Y, o
  9. 9 F' n9 c9 z  j1 ^3 N
  10. }( Y$ e+ W% c4 n) x9 @$ H

  11. ( g8 c* C2 z3 ~" a- i$ u
  12. GPIOSpeed_TypeDef;
复制代码
5 y, |' x# Z- U& L  T' ?
* g7 o8 s% v% k5 w& v" s; \5 s2 M
GPIO模式:: |% Y4 k; W& l. M/ u
2 h* h4 z8 a9 x! V
  1. typedef enum
    8 o: S7 Z. n0 O
  2.   t0 F  h3 O9 k; R8 E
  3. { GPIO_Mode_AIN = 0x0, //模拟输入
    " o) A" w4 H9 B- i1 X
  4. ; P% D' S9 Y  b9 l
  5. GPIO_Mode_IN_FLOATING = 0x04, //浮空输入
    & q: C5 `" X. F

  6. ( E# B$ l5 v1 z7 U5 g
  7. GPIO_Mode_IPD = 0x28, //输入下拉& k- E1 {, w* \2 Y! A* l3 w+ H

  8. . ^* }" V  y) w* |, x0 x, g7 L! W+ P# x
  9. GPIO_Mode_IPU = 0x48, //输入上拉
    - |0 _) w7 c  K" A  z) x% z5 j
  10. 2 ?* Y' t0 ]8 t9 @
  11. GPIO_Mode_Out_OD = 0x14, //开漏输出
    * G" ~, W' W- U/ i5 N

  12. : u9 z7 J$ ^( k. M3 e% J; F  n
  13. GPIO_Mode_Out_PP = 0x10, //推挽输出& y7 L) ~: X' J; b2 g9 O& j
  14. $ T6 J3 q% J7 o% x0 {
  15. GPIO_Mode_AF_OD = 0x1C, //开漏复用输出
      L, P6 @% g+ X  j& b; s
  16. & \) M& y* R2 V0 D3 V
  17. GPIO_Mode_AF_PP = 0x18 //推挽复用输出9 G, s" Q; g! e; m5 d7 D
  18. 5 a$ E9 ^) ?- T2 s+ g/ c& G. `
  19. }GPIOMode_TypeDef;
复制代码
3 O5 t% y: l# P4 o7 d- Z
4 x, E1 m- b, R6 [6 d
GPIO_Init函数初始化样例:
4 r  ~. Y) d4 t: \- U/ [! @0 M+ x  s: q( v& p% H( b5 O" b8 q- Y
  1. GPIO_InitTypeDef  GPIO_InitStructure;  # ^) x# F4 ]$ t1 v) |5 e- l/ b! W' R
  2.   }! l% Q7 Q3 C5 |3 b
  3. GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5; //LED0-->PB.5 端口配置  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;  //推挽输出  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //IO口速度为50MHz  GPIO_Init(GPIOB, &GPIO_InitStructure);  //根据设定参数初始化GPIOB.5
复制代码
) `+ G2 |% X' f' w$ u! v5 T

" D! H( A! c% [) Z) p, Q可以一次初始化一个IO组下的多个IO,前提是这些IO口的配置方式一样。! d; e$ i% d  N4 ^8 _& I
" w' _$ y9 {% z; j1 D* N9 {/ i* }
4.3 两个读取输入电平函数:. {2 u6 {" s- G4 Y
uint8_t GPIO_ReadInputDataBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin); GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_5);//读取GPIOA.5的输入电平
/ q  @  z+ u- [( d9 ?0 D. ?3 ~- a" R6 G( V: }9 ^& G( R
作用:读取某组GPIO的输入电平。实际操作的是GPIOx_IDR寄存器。6 d# g5 k9 m) u; c5 K" L/ Y
& A4 d( Z0 B& z' U/ J
4.3 四个设置输出电平函数:* {4 ~3 o  Y2 X
void GPIO_SetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
( U- @5 G0 o  y
# {" x8 T9 H- i& u5 r作用:设置某个IO口输出为高电平(1)。实际操作BSRR寄存器
; [. Q% w7 w. X  n6 h; i3 D# _2 J1 P4 \/ z' `9 E
void GPIO_ResetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
, D3 |! J' `: |# }& x# [5 p/ O
$ r  O1 Q" I: }" j0 i9 Y  Y作用:设置某个IO口输出为低电平(0)。实际操作的BRR寄存器。4 Q* b" r/ @3 M- q) Y

: D3 a5 ~' v" N5 Nvoid GPIO_WriteBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin, BitAction BitVal);
( {3 K- s: H: G0 l$ d, l( k2 `, c& i
void GPIO_Write(GPIO_TypeDef* GPIOx, uint16_t PortVal);, \1 \1 V" O+ K  ]' X! o

+ r7 Z. u! K9 e% Z这两个函数不常用,也是用来设置IO口输出电平。+ u. H1 w# j# J* U
  V- }/ ?: n( L8 D. Y6 l# h
4.4 库函数配置程序示例
3 b5 H; H. z" Z- ^0 h- |下面我们以流水灯案件为例,把整个GPIO的库函数配置过程展现出来:7 [8 }3 c, g0 C9 J1 d" b+ o. _

# b  ~% }+ K* F/ c" l% q
  1. //led.h头文件
    1 u" p- `6 ~4 T% C) V
  2. #ifndef __LED_H
    " k  v  m( o& v
  3. #define __LED_H3 k1 ^4 V1 T, ^, ~
  4. #include "sys.h"- u" i! G. X: A2 G3 p
  5. ! s% ?5 x, T* k1 q9 n- _
  6. void LED_Init(void);8 B# s: g9 o% j/ g; l9 ^" ]
  7. + k% G) j( g4 q6 S/ Y
  8. #endif
复制代码
  1. //led.c源文件* W, m+ p  H1 a
  2. #include "led.h"2 }# q8 @1 T; ^7 Z/ D0 W& U
  3. #include "stm32f10x.h"1 }$ D/ l6 G" ^) l
  4. void LED_Init(void)
    4 b2 F8 r# q# P' d2 H' w- z
  5. {6 G7 `3 |# O- i9 [; ]* Q
  6.         GPIO_InitTypeDef GPIO_InitStructure;  Q: Y% R$ ]0 }! e% z% u, L; J
  7.         0 [7 @8 d* B+ j9 M: g
  8.         RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB|RCC_APB2Periph_GPIOE, ENABLE);//使能GPIOB和E2 @9 j' D5 u( g/ f
  9.         3 W5 h. m; W" G. X/ o* J
  10.         GPIO_InitStructure.GPIO_Pin=GPIO_Pin_5;
    3 `# z4 W2 E: |1 P+ O
  11.         GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
    ; {$ Y* X  O/ t# E
  12.         GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP;' g- k# W5 n2 J+ e/ B9 S
  13.         5 L% _6 N; j) K! f( ^, _
  14.         GPIO_Init(GPIOB, &GPIO_InitStructure);$ f) }6 X( X: X' l. ~0 M3 w1 X+ d- x
  15.         GPIO_SetBits(GPIOB, GPIO_Pin_5);
    % e9 ^$ C6 J7 U. ]* u6 b5 V, r
  16. & l' T9 p% R: C8 V: Z0 ]
  17.         GPIO_Init(GPIOE, &GPIO_InitStructure);
    5 a% h8 K; L9 i1 C1 i4 f* w1 g
  18.         GPIO_SetBits(GPIOE, GPIO_Pin_5);        2 G8 R. j  A: [% E; p
  19. }
复制代码
  1. //main.c主程序
    : Q( L2 U, P& y5 T# l  n
  2. #include "stm32f10x.h", z9 K  L2 [  \; ~9 r9 p5 |
  3. #include "led.h"
    2 H9 g" E4 Q7 |& v# }+ c& |  U5 O
  4. #include "delay.h"
    1 O1 c5 J9 q6 }% d  g

  5. # f; ~' u# D/ z) q5 |3 G/ \
  6. int main(void)
    4 ~' e+ g8 r* L9 }+ b, N
  7. {
    ; Z3 W; L9 {" @( K
  8. delay_init();$ H5 d( q4 K5 y  `* x  a
  9. LED_Init();
    2 \  a7 f& P* j7 i1 N$ ~  d
  10.         " n* t" N: m3 V  S, `0 ?8 S
  11. while(1){
    / x" w4 [" r% ~4 {: h
  12.      GPIO_ResetBits(GPIOB, GPIO_Pin_5); //LED0即DS0亮
    9 f5 l/ |; K7 t6 ^# A/ V% Q
  13.      GPIO_SetBits(GPIOE, GPIO_Pin_5);   //LED1即DS1灭" V) E; n, w& B  _" A
  14.           delay_ms(500);2 {: n7 J' c) k0 V/ L, E
  15.         
    . @9 {9 A: }  y$ C. d
  16.             GPIO_SetBits(GPIOB, GPIO_Pin_5);   //LED0即DS0灭0 D6 h) u4 x; F9 B
  17.           GPIO_ResetBits(GPIOE, GPIO_Pin_5); //LED1即DS1亮  B- _: w3 U8 ~/ I
  18.           delay_ms(500);
    # w8 f  ]# L# Y
  19. }
    3 V: c/ e" I6 f  m: M$ S
  20. }
复制代码
7 l7 d; q& e* d( g" z
" ^6 ^, Y7 C7 ?5 n# e
5. GPIO寄存器配置
9 J5 v* b& k$ D4 q, G库函数的优点在于移植性好、便于理解、方便学习,是我们一般编程常常使用的。但是如果只会用库函数编程,寄存器内部工作原理不闻不问,当你拿到一份带有寄存器配置片段的程序时就会一头雾水。因此,理解寄存器的配置对于更深一步的学习掌握STM32这个MCU以及在真正的工程总运用也是尤为重要的。
0 f9 W4 ~  R. U# [  C+ K5 O; r
4 Q8 ^1 ?  C* c( A) q2 d- P5.1 寄存器配置程序示例' t: `. ~3 o: u$ _$ G1 B/ L" i
下面是流水灯例程的寄存器版本程序,其中led.h和库函数一样的,这里就不展示了。' B! H9 N) v3 m% c. b
- @' ~2 {& M7 t
  1. //led.c源文件3 ]9 C: _4 ]6 W4 Z
  2. #include "led.h"6 X5 e( {  i1 G: ?- D" Q
  3. #include "stm32f10x.h"
    4 ~5 r+ u& V# `& U
  4. * g' O9 f- Z4 l% ~+ Q3 Z
  5. void LED_Init(void){
    4 f" f5 \3 N$ j3 Z8 O' P
  6.         
    1 F4 V- X2 O4 I* h6 a, W
  7.         RCC->APB2ENR|=1<<3;* Q, @2 m! }3 x3 Z! B6 }* o; |0 U
  8.         RCC->APB2ENR|=1<<6;
    2 Q2 D" |  C. F+ M" u

  9. 2 R- D9 b4 b  X! ]. l, h
  10.         //GPIOB.5
    ' \5 c& @6 [" F
  11.         GPIOB->CRL&=0xFF0FFFFF;//与运算,使GPIOB的CRL寄存器第20~23位(PB5)清零: L  ~9 g$ u  f. j; L, A
  12.         GPIOB->CRL|=0x00300000;//或运算,使GPIOB的CRL寄存器第20~23位置位0011,即设置为推挽输出、速率为50MHz
    7 c1 E  K4 S  T% B: _0 R
  13.         GPIOB->ODR|=1<<5;//或运算,使GPIOB的输出数据寄存器ODR第5位置1即PB5输出高电平9 @6 N0 b8 J( {; |8 s
  14.         0 J2 k" v" b) P; B% f
  15.         GPIOE->CRL&=0xFF0FFFFF;//与运算,使GPIOE的CRL寄存器第20~23位(PE5)清零
    6 k" u2 X1 H- p1 ]2 a8 ?2 J
  16.         GPIOE->CRL|=0x00300000;//或运算,使GPIOE的CRL寄存器第20~23位置位0011,即设置为推挽输出、速率为50MHz
    , r3 T1 m# C. E& q
  17.         GPIOE->ODR|=1<<5;//或运算,使GPIOE的输出数据寄存器ODR第5位置1即PE5输出高电平
    ! J. [3 w- O3 G) W
  18.         //GPIOE.5- w8 k; s4 w5 {& p2 G/ ]1 F0 `
  19. }
复制代码
  1. //main.c主程序
    + {3 q$ F% j* d: H4 ~* d! [: p
  2. #include "sys.h"! \4 J  ~( Z" r6 ?6 `, I3 g
  3. #include "usart.h"                ; h0 {) }9 @8 H% W- y
  4. #include "delay.h"         
    : g4 i8 s# U& j( i  o' Q
  5. #include "led.h"
    ( L5 @- U. }3 O5 g+ V

  6. $ x- k, u4 ^6 n4 L0 x
  7. int main(void)
    - r. K; T. q3 U" [  D/ ~  a
  8. {                                 
    ; r7 W7 {" }9 u, m$ ]% ]* E7 Y# L
  9.         # d8 P" y: D' I, o  ?& y) e
  10.         while(1){0 |2 R5 f# m9 o* p
  11.                 GPIOB->ODR|=1<<5;//或运算,使GPIOB的输出数据寄存器ODR第5位置1即PB5输出高电平. u! q: F4 }5 r$ ^. n
  12.                 GPIOE->ODR|=1<<5;//或运算,使GPIOE的输出数据寄存器ODR第5位置1即PE5输出高电平" p6 g8 v; k- W  T
  13.                 delay_ms(500);( Q8 t5 V# w+ ]+ d8 M# |8 _: C
  14.                
    5 v* n9 ~+ i, m0 r1 L
  15.                 GPIOB->ODR&=~(1<<5);//与运算,使GPIOB的输出数据寄存器ODR第5位置0即PB5输出低电平
    8 N8 [9 d& l' E
  16.                 GPIOE->ODR&=~(1<<5);//与运算,使GPIOE的输出数据寄存器ODR第5位置0即PE5输出低电平
    $ `$ o. z+ I# n+ w* l! h
  17.                 delay_ms(500);
    0 Z: ?5 Q+ c+ R0 n
  18.         }" V7 P) z0 t0 p: i4 T$ x4 `
  19. }
    4 |' w9 D* T0 j" m
复制代码
. G" w3 l& K8 ]& U' f: L8 q

5 P+ b/ P( U8 m: K
* `! [1 G! r# i& B
赞 收藏 评论0 发布时间:2022-5-7 11:13

举报

0个回答

所属标签

相似技术帖

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
人形机器人运动控制、感知与智能配电
半导体创新技术与应用方向
EE架构与软件定义汽车
12V/48V 汽车智能配电(SPD)
区域控制单元(ZCU)与分区架构
关注我们
st-img 微信公众号
st-img 手机版