首先,需要熟悉下一些重要的杂散的知识。/ F s! R" O t* D- U8 M
, l5 e/ ~) }3 ?$ G+ L
6 t: z5 [1 h+ k$ `' ?! c
3 n1 Q+ P' a, {& `( M( K上图是一个标准的GPIO配置过程。
: {) @* D) e! l9 l3 A; A, l5 P9 y8 f6 c5 `; P" F# ?5 N x- z" M
GPIO_InitTypeDef是一个结构体,
% |$ Y& h& r8 B# j
. Q7 ]1 E+ F3 `4 V" g" a& ^4 y0 g
4 w3 v2 o& ^+ ?; s# b$ {5 U8 J
+ d; q; J* C1 ^0 A$ a
% l; l/ G' ?& X2 h& f# k# N
& q" U0 P& @, H# S可以看出,CRL寄存器的每4位控制一个GPIO的工作状态。
& G. X; s% t$ ^5 c0 |( R( d4 ~: [
1 |( b. u/ ~6 F! b' V( w1 w
6 Q( O B% t. V- E6 r) W上面的枚举类型设计得很巧妙,其用低四位代表具体输入/输出模式,低四位右移两位即是对应的寄存器配置,如下:- T- j% u8 K$ g
5 u# _/ D3 ?" e# e- E! e
- (GPIO_Mode_AIN & 0X0F) >> 2 = 00B
* U+ k# N6 @6 _/ l: h* ? - (GPIO_Mode_Out_PP & 0X0F) >> 2 = 00B
复制代码
0 V/ u; J8 B! d. H+ `0 W! `+ q
5 f9 m2 @4 O2 x1 ?' q0 c# Z
2 i7 H8 d. W- g& i! Q$ I3 J- (GPIO_Mode_IN_FLOATING & 0X0F) >> 2 = 01B( V6 Z0 \: P% }* I) H7 V
- (GPIO_Mode_Out_OD & 0X0F) >> 2 = 01B
( z) r0 B+ c- K( `8 g0 X( h+ u$ V
复制代码
; J! O: a7 x( F7 f' v+ `6 f
$ g7 r& K3 R) W
( M* s( a: ]! F; n: ?0 w* k p$ x. c% T z3 A
- (GPIO_Mode_IPD & 0X0F) >> 2 = 10B
* N( p9 ^" x$ [* O) P - (GPIO_Mode_IPU & 0X0F) >> 2 = 10B
* d {. g, e$ w2 @2 E# s - (GPIO_Mode_AF_PP & 0X0F) >> 2 = 10B
复制代码
+ F/ ^* K/ I" d/ I* F( q+ Y5 _2 h
! P& y+ O5 f( z z2 C. U& C" s# S+ X% T+ {! R; `/ d
通过上述操作,可以从GPIOMode_TypeDef枚举类型的变量中得到配置具体输入、输出所需要的寄存器参数。" |. g+ d0 U0 g! ^2 D! {1 r
: J$ q: @. w* a1 l W! g, u
; Q7 E4 o1 S2 ?( p
7 W, s: c* M$ o, z" ?* T
而之所以将GPIOMode_TypeDef类型变量的低四位后两位空出来(怎么看出来后两位空出来了呢?是因为该变量的低四位是0/4/8/C,后两位都是0),是为了在程序中与GPIOSpeed_TypeDef类型变量相或,最终得到以4位为单位的CRL/CRH寄存器配置参数。1 U9 ]) a0 F1 b1 W2 m* g
7 x0 A: x g) x9 G0 O# F# w2 ]% IGPIOMode_TypeDef类型变量的第5位表示输入还是输出。
2 J3 V3 g9 A6 V
7 T" s0 ]& k0 i0 c. C+ o5 ~- #define GPIO_Pin_0 ((uint16_t)0x0001) /*!< Pin 0 selected */* Y$ a1 W( e4 P6 z. Z
- #define GPIO_Pin_1 ((uint16_t)0x0002) /*!< Pin 1 selected */
7 d! ~" n) I0 y - #define GPIO_Pin_2 ((uint16_t)0x0004) /*!< Pin 2 selected */. C4 v; `( G8 E1 j8 H/ o; [" f' X
- #define GPIO_Pin_3 ((uint16_t)0x0008) /*!< Pin 3 selected */
8 _4 E& I) ?1 t* C7 i+ V - #define GPIO_Pin_4 ((uint16_t)0x0010) /*!< Pin 4 selected */, A) Y+ N7 v, m( R' s- L5 l
- #define GPIO_Pin_5 ((uint16_t)0x0020) /*!< Pin 5 selected */
! n0 Z. m8 d0 |# G$ r/ I - #define GPIO_Pin_6 ((uint16_t)0x0040) /*!< Pin 6 selected */
8 U, A3 E3 W7 m0 z - #define GPIO_Pin_7 ((uint16_t)0x0080) /*!< Pin 7 selected */
. g: H9 B$ Q5 M0 K - #define GPIO_Pin_8 ((uint16_t)0x0100) /*!< Pin 8 selected */
" R& r" b0 N9 d9 d; o( y - #define GPIO_Pin_9 ((uint16_t)0x0200) /*!< Pin 9 selected */6 E+ {0 M: H2 c
- #define GPIO_Pin_10 ((uint16_t)0x0400) /*!< Pin 10 selected */
" E2 v4 |. A% i- ` - #define GPIO_Pin_11 ((uint16_t)0x0800) /*!< Pin 11 selected */( _ V! L5 ?! n6 A
- #define GPIO_Pin_12 ((uint16_t)0x1000) /*!< Pin 12 selected */2 _, L: M( F% B
- #define GPIO_Pin_13 ((uint16_t)0x2000) /*!< Pin 13 selected */
: [7 r* x( E! ]& m2 [0 C. Q, i - #define GPIO_Pin_14 ((uint16_t)0x4000) /*!< Pin 14 selected */
6 ^ H6 G, p* b5 b - #define GPIO_Pin_15 ((uint16_t)0x8000) /*!< Pin 15 selected */2 A: D d& }. X
- #define GPIO_Pin_All ((uint16_t)0xFFFF) /*!< All pins selected */
复制代码 ' u7 \( S! j2 A( U I
以上是GPIO_Pin的宏定义。
, R Q5 E, I I4 F
; p1 X: t* U8 t+ R! w下面是GPIO_Init函数的详细注释,+ C4 b) i. G; C1 d
! @ u& j2 r; k' y6 ~
- void GPIO_Init(GPIO_TypeDef* GPIOx, GPIO_InitTypeDef* GPIO_InitStruct)2 v* P$ e0 y2 J
- {
4 @2 J( ?: U I+ G" h# H* |9 { - uint32_t currentmode = 0x00, currentpin = 0x00, pinpos = 0x00, pos = 0x00;
& Q, u$ f- e/ \2 _3 t" J+ R3 T - uint32_t tmpreg = 0x00, pinmask = 0x00;6 w+ ^7 _9 Q+ A3 f# r
- /* Check the parameters */& i ]: ]5 H$ X3 R" r0 N
- assert_param(IS_GPIO_ALL_PERIPH(GPIOx));
# |( L1 e5 o4 f3 v - assert_param(IS_GPIO_MODE(GPIO_InitStruct->GPIO_Mode));
; C0 ?( y& L- \3 e2 s. x( s - assert_param(IS_GPIO_PIN(GPIO_InitStruct->GPIO_Pin));
g% \/ q; ^8 i% G. z) Q) r* ^ - / Y3 [5 m+ m+ `. v7 A7 z
- /*---------------------------- GPIO Mode Configuration -----------------------*/
; B# f7 t5 _* h% ^ - //此处只取 GPIO_Mode 的低四位,GPIO_Mode 低四位代表了输入或输出的具体模式3 A+ n2 f+ L W- u% U) b; ~
- currentmode = ((uint32_t)GPIO_InitStruct->GPIO_Mode) & ((uint32_t)0x0F);
( u$ j+ x( |# X2 E8 i - if ((((uint32_t)GPIO_InitStruct->GPIO_Mode) & ((uint32_t)0x10)) != 0x00)//在这里获取GPIO的工作速度 因此GPIO_Mode的第5位代表了是输入还是输出,判断为输出时才设定工作速度
n* a8 \) U. r# S* l; r I5 R8 y% v - { & A6 z/ b( S& f4 R
- //GPIO_Mode第5位为1,说明是输出模式,现在设置工作速度
# M8 K3 Z: G# J/ e0 Q - /* Check the parameters */9 Q3 h V4 H, p' b; Z% H+ V
- assert_param(IS_GPIO_SPEED(GPIO_InitStruct->GPIO_Speed));; m% ^4 e; T8 |' S/ ~0 }$ L* f4 j
- /* Output mode */
! l* P$ f \6 R/ X. I* W - //在此,currentmode已经是可以写入的寄存器参数了6 {7 D$ N( z# j6 {) z
- currentmode |= (uint32_t)GPIO_InitStruct->GPIO_Speed;! R3 w3 t) `; c' T# J5 V7 o
- }1 a) x# S# G( G; r, f& q! |
- /*---------------------------- GPIO CRL Configuration ------------------------*/
' J: T" Q7 W7 I2 H1 g - /* Configure the eight low port pins */
: ~0 s' F: }8 ^2 f( s7 W - //下面确定currentmode具体写入到哪一个GPIO口的配置位中9 x' H( h; K3 T. I
- if (((uint32_t)GPIO_InitStruct->GPIO_Pin & ((uint32_t)0x00FF)) != 0x00)//判断需要设置的GPIO是不是0-7
4 o, P6 W0 W+ k& r+ L/ V - {
$ V7 @+ u3 d4 ], J3 v4 F* | - tmpreg = GPIOx->CRL;//将CRL寄存器值读出8 C6 O6 I: P! W* O3 a& i, b
- for (pinpos = 0x00; pinpos < 0x08; pinpos++)5 G+ o7 q9 o0 e
- {# p( F. S- b- g8 H2 x
- pos = ((uint32_t)0x01) << pinpos;
/ i- h5 L: C9 ?0 h4 Q+ v - /* Get the port pins position */
8 a0 T; l# \ o% m6 B - currentpin = (GPIO_InitStruct->GPIO_Pin) & pos;// 得到当前正在配置的Pin 并且确保本次操作只有一个Pin需要配置. s2 H O' y8 f3 ~2 C' @
- if (currentpin == pos)
; w3 a9 i, i! Y5 J - {
% B2 O. w, g9 E p9 p - pos = pinpos << 2;//右移两位相当于位数乘4,每一个GPIO口的配置占位4个,所以GPIO n的最低配置位就是 nx4
; j) m! A/ L7 Q' x5 N& | - /* Clear the corresponding low control register bits */
' E+ I1 ^' i& g- _7 P5 N+ T - pinmask = ((uint32_t)0x0F) << pos;//获取对应配置位的掩码
& P3 C. I# w+ G) S4 ? - tmpreg &= ~pinmask;//清除对应配置位
, w+ k# h& {" l7 v- H3 w - /* Write the mode configuration in the corresponding bits */! M4 b+ h6 f2 J& P, Y
- tmpreg |= (currentmode << pos);//将currentmode写入临时寄存器值中
4 J6 e+ f' N F6 o - /* Reset the corresponding ODR bit */
0 j: p v7 ^ x9 d, U - if (GPIO_InitStruct->GPIO_Mode == GPIO_Mode_IPD)
* O2 ~ |, I+ x5 J' b$ ?, ? - {
/ V2 c; ^8 s1 h4 Q$ z3 N( {, s - GPIOx->BRR = (((uint32_t)0x01) << pinpos);
. W: `% I# _4 f$ t, H7 }! @ - }: x; M4 M7 ^( [. F
- else
- N5 F! G; S) |3 [. Y6 Z$ o D - {
4 p9 r, {5 A8 y5 j) W - /* Set the corresponding ODR bit */
# e9 ^! g* h0 t8 s1 ]: t- i. Y - if (GPIO_InitStruct->GPIO_Mode == GPIO_Mode_IPU)
2 x8 E" Z/ i- F7 B - {. t, r+ c2 e5 Q! _( V$ }. L- y
- GPIOx->BSRR = (((uint32_t)0x01) << pinpos);
; |8 L& Q( U& l$ D, h! W4 l* J. t - }
8 r4 F# y! A* Q6 ] - }
) r* M Z0 W( n t% T# q - }
0 I1 d7 [, I0 B - }
5 _/ K6 {; p M& ?7 F8 G! j - GPIOx->CRL = tmpreg;//更新寄存器值5 G. V7 s2 O% {, h B) a! d+ R
- }/ B/ B5 M' K7 K4 u, _
- /*---------------------------- GPIO CRH Configuration ------------------------*/
( ]+ q3 ?# K* r5 e! ] - /* Configure the eight high port pins */, `6 h+ L3 _ p0 m* H1 T! R
- if (GPIO_InitStruct->GPIO_Pin > 0x00FF)//判断需要配置的脚是否大于7* I% g' h9 J( m. ]3 s! O! K
- {
* j5 v5 g; m9 [( F3 Z' C - tmpreg = GPIOx->CRH;+ ~- T* T ^* b! w( u# y6 u) @. f
- for (pinpos = 0x00; pinpos < 0x08; pinpos++)
4 q* f5 g& S$ B! f) D7 a! } - {
8 e! ?8 N7 o( t+ m - pos = (((uint32_t)0x01) << (pinpos + 0x08));
8 h' k) D, M/ _0 d, J- G - /* Get the port pins position */
0 e1 m/ g1 s7 \& P0 h y2 T, t s - currentpin = ((GPIO_InitStruct->GPIO_Pin) & pos);4 w2 L7 n- D' F) s/ b' {- A
- if (currentpin == pos)* I# e6 K7 g9 W( i. g
- {" U$ f1 j. G9 A2 t& D, N
- pos = pinpos << 2;7 I* P. Y8 r1 \6 I
- /* Clear the corresponding high control register bits */) y8 x7 _/ w6 X* x$ F; m4 V9 ^7 b) ]
- pinmask = ((uint32_t)0x0F) << pos;- @3 a! x$ R# e5 O( |9 T9 t7 C+ ?
- tmpreg &= ~pinmask;
; @9 J3 P9 T4 A4 c# `3 D5 x - /* Write the mode configuration in the corresponding bits */: Z1 a" d; n6 J7 k
- tmpreg |= (currentmode << pos);
+ {# o( _2 k3 O) U9 X" ~ - /* Reset the corresponding ODR bit */0 j4 |( \" z }% o! R T0 N, r
- if (GPIO_InitStruct->GPIO_Mode == GPIO_Mode_IPD)
# ]2 _. S1 C7 ? - {( _! j5 H, R3 L* R! b6 b' h
- GPIOx->BRR = (((uint32_t)0x01) << (pinpos + 0x08));9 p/ q, O7 d4 h; `$ {0 c% h7 U' V
- }4 x& x9 V2 J+ ]
- /* Set the corresponding ODR bit */; U) x" _, f. k
- if (GPIO_InitStruct->GPIO_Mode == GPIO_Mode_IPU)
# f v4 B8 j# N. D- {- s$ G - {
/ h9 O z2 J) \* D l' q - GPIOx->BSRR = (((uint32_t)0x01) << (pinpos + 0x08));, \7 v% q8 ]: m5 _$ |% |$ W0 ~
- }
" q d- S+ T2 v' }2 S3 G4 q - }
7 u | b2 W% I; c6 x - }
3 S( i& `+ b3 X5 g; y* a, w - GPIOx->CRH = tmpreg;4 o* g. I& g( C! X5 Q: i- o2 d% g
- }
" q4 @, J% T) S7 v, ]) Y - }+ C( ^4 `% |+ M$ h9 d
9 g1 R o! R/ D# U8 a4 D1 J2 U2 R
复制代码
- q0 l2 a) _( i* P( L% ] |