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

【经验分享】STM32F103固件库源码解析——GPIO配置

[复制链接]
STMCU小助手 发布时间:2022-5-2 09:23
首先,需要熟悉下一些重要的杂散的知识。/ F  s! R" O  t* D- U8 M
, l5 e/ ~) }3 ?$ G+ L
20210206141642133.png 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 20210206141658208.png
4 w3 v2 o& ^+ ?; s# b$ {5 U8 J
+ d; q; J* C1 ^0 A$ a 20210206141710961.png % l; l/ G' ?& X2 h& f# k# N

& q" U0 P& @, H# S可以看出,CRL寄存器的每4位控制一个GPIO的工作状态。
& G. X; s% t$ ^5 c0 |( R( d4 ~: [
20210206141725790.png 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
  1. (GPIO_Mode_AIN & 0X0F) >> 2 = 00B
    * U+ k# N6 @6 _/ l: h* ?
  2. (GPIO_Mode_Out_PP & 0X0F) >> 2 = 00B
复制代码

0 V/ u; J8 B! d. H+ `0 W! `+ q JI8DXY_B]))3TWOV]51CFM1.png 5 f9 m2 @4 O2 x1 ?' q0 c# Z

2 i7 H8 d. W- g& i! Q$ I3 J
  1. (GPIO_Mode_IN_FLOATING & 0X0F) >> 2 = 01B( V6 Z0 \: P% }* I) H7 V
  2. (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 LRYCHR@~}RYR3)J840Z[JSF.png
( M* s( a: ]! F; n: ?0 w* k  p$ x. c% T  z3 A
  1. (GPIO_Mode_IPD & 0X0F) >> 2 = 10B
    * N( p9 ^" x$ [* O) P
  2. (GPIO_Mode_IPU & 0X0F) >> 2 = 10B
    * d  {. g, e$ w2 @2 E# s
  3. (GPIO_Mode_AF_PP & 0X0F) >> 2 = 10B
复制代码

+ F/ ^* K/ I" d/ I* F( q+ Y5 _2 h `KY64`M8V}S}WUKVQ_KU4JO.png
! 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
ZTIC[APjTIC4SNGRR6W.png ; 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 ~
  1. #define GPIO_Pin_0                 ((uint16_t)0x0001)  /*!< Pin 0 selected */* Y$ a1 W( e4 P6 z. Z
  2. #define GPIO_Pin_1                 ((uint16_t)0x0002)  /*!< Pin 1 selected */
    7 d! ~" n) I0 y
  3. #define GPIO_Pin_2                 ((uint16_t)0x0004)  /*!< Pin 2 selected */. C4 v; `( G8 E1 j8 H/ o; [" f' X
  4. #define GPIO_Pin_3                 ((uint16_t)0x0008)  /*!< Pin 3 selected */
    8 _4 E& I) ?1 t* C7 i+ V
  5. #define GPIO_Pin_4                 ((uint16_t)0x0010)  /*!< Pin 4 selected */, A) Y+ N7 v, m( R' s- L5 l
  6. #define GPIO_Pin_5                 ((uint16_t)0x0020)  /*!< Pin 5 selected */
    ! n0 Z. m8 d0 |# G$ r/ I
  7. #define GPIO_Pin_6                 ((uint16_t)0x0040)  /*!< Pin 6 selected */
    8 U, A3 E3 W7 m0 z
  8. #define GPIO_Pin_7                 ((uint16_t)0x0080)  /*!< Pin 7 selected */
    . g: H9 B$ Q5 M0 K
  9. #define GPIO_Pin_8                 ((uint16_t)0x0100)  /*!< Pin 8 selected */
    " R& r" b0 N9 d9 d; o( y
  10. #define GPIO_Pin_9                 ((uint16_t)0x0200)  /*!< Pin 9 selected */6 E+ {0 M: H2 c
  11. #define GPIO_Pin_10                ((uint16_t)0x0400)  /*!< Pin 10 selected */
    " E2 v4 |. A% i- `
  12. #define GPIO_Pin_11                ((uint16_t)0x0800)  /*!< Pin 11 selected */( _  V! L5 ?! n6 A
  13. #define GPIO_Pin_12                ((uint16_t)0x1000)  /*!< Pin 12 selected */2 _, L: M( F% B
  14. #define GPIO_Pin_13                ((uint16_t)0x2000)  /*!< Pin 13 selected */
    : [7 r* x( E! ]& m2 [0 C. Q, i
  15. #define GPIO_Pin_14                ((uint16_t)0x4000)  /*!< Pin 14 selected */
    6 ^  H6 G, p* b5 b
  16. #define GPIO_Pin_15                ((uint16_t)0x8000)  /*!< Pin 15 selected */2 A: D  d& }. X
  17. #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 ~
  1. void GPIO_Init(GPIO_TypeDef* GPIOx, GPIO_InitTypeDef* GPIO_InitStruct)2 v* P$ e0 y2 J
  2. {
    4 @2 J( ?: U  I+ G" h# H* |9 {
  3.   uint32_t currentmode = 0x00, currentpin = 0x00, pinpos = 0x00, pos = 0x00;
    & Q, u$ f- e/ \2 _3 t" J+ R3 T
  4.   uint32_t tmpreg = 0x00, pinmask = 0x00;6 w+ ^7 _9 Q+ A3 f# r
  5.   /* Check the parameters */& i  ]: ]5 H$ X3 R" r0 N
  6.   assert_param(IS_GPIO_ALL_PERIPH(GPIOx));
    # |( L1 e5 o4 f3 v
  7.   assert_param(IS_GPIO_MODE(GPIO_InitStruct->GPIO_Mode));
    ; C0 ?( y& L- \3 e2 s. x( s
  8.   assert_param(IS_GPIO_PIN(GPIO_InitStruct->GPIO_Pin));  
      g% \/ q; ^8 i% G. z) Q) r* ^
  9. / Y3 [5 m+ m+ `. v7 A7 z
  10. /*---------------------------- GPIO Mode Configuration -----------------------*/
    ; B# f7 t5 _* h% ^
  11.   //此处只取 GPIO_Mode 的低四位,GPIO_Mode 低四位代表了输入或输出的具体模式3 A+ n2 f+ L  W- u% U) b; ~
  12.   currentmode = ((uint32_t)GPIO_InitStruct->GPIO_Mode) & ((uint32_t)0x0F);
    ( u$ j+ x( |# X2 E8 i
  13.   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
  14.   { & A6 z/ b( S& f4 R
  15.     //GPIO_Mode第5位为1,说明是输出模式,现在设置工作速度
    # M8 K3 Z: G# J/ e0 Q
  16.     /* Check the parameters */9 Q3 h  V4 H, p' b; Z% H+ V
  17.     assert_param(IS_GPIO_SPEED(GPIO_InitStruct->GPIO_Speed));; m% ^4 e; T8 |' S/ ~0 }$ L* f4 j
  18.     /* Output mode */
    ! l* P$ f  \6 R/ X. I* W
  19.     //在此,currentmode已经是可以写入的寄存器参数了6 {7 D$ N( z# j6 {) z
  20.     currentmode |= (uint32_t)GPIO_InitStruct->GPIO_Speed;! R3 w3 t) `; c' T# J5 V7 o
  21.   }1 a) x# S# G( G; r, f& q! |
  22. /*---------------------------- GPIO CRL Configuration ------------------------*/
    ' J: T" Q7 W7 I2 H1 g
  23.   /* Configure the eight low port pins */
    : ~0 s' F: }8 ^2 f( s7 W
  24.   //下面确定currentmode具体写入到哪一个GPIO口的配置位中9 x' H( h; K3 T. I
  25.   if (((uint32_t)GPIO_InitStruct->GPIO_Pin & ((uint32_t)0x00FF)) != 0x00)//判断需要设置的GPIO是不是0-7
    4 o, P6 W0 W+ k& r+ L/ V
  26.   {
    $ V7 @+ u3 d4 ], J3 v4 F* |
  27.     tmpreg = GPIOx->CRL;//将CRL寄存器值读出8 C6 O6 I: P! W* O3 a& i, b
  28.     for (pinpos = 0x00; pinpos < 0x08; pinpos++)5 G+ o7 q9 o0 e
  29.     {# p( F. S- b- g8 H2 x
  30.       pos = ((uint32_t)0x01) << pinpos;
    / i- h5 L: C9 ?0 h4 Q+ v
  31.       /* Get the port pins position */
    8 a0 T; l# \  o% m6 B
  32.       currentpin = (GPIO_InitStruct->GPIO_Pin) & pos;//  得到当前正在配置的Pin  并且确保本次操作只有一个Pin需要配置. s2 H  O' y8 f3 ~2 C' @
  33.       if (currentpin == pos)
    ; w3 a9 i, i! Y5 J
  34.       {
    % B2 O. w, g9 E  p9 p
  35.         pos = pinpos << 2;//右移两位相当于位数乘4,每一个GPIO口的配置占位4个,所以GPIO n的最低配置位就是 nx4
    ; j) m! A/ L7 Q' x5 N& |
  36.         /* Clear the corresponding low control register bits */
    ' E+ I1 ^' i& g- _7 P5 N+ T
  37.         pinmask = ((uint32_t)0x0F) << pos;//获取对应配置位的掩码
    & P3 C. I# w+ G) S4 ?
  38.         tmpreg &= ~pinmask;//清除对应配置位
    , w+ k# h& {" l7 v- H3 w
  39.         /* Write the mode configuration in the corresponding bits */! M4 b+ h6 f2 J& P, Y
  40.         tmpreg |= (currentmode << pos);//将currentmode写入临时寄存器值中
    4 J6 e+ f' N  F6 o
  41.         /* Reset the corresponding ODR bit */
    0 j: p  v7 ^  x9 d, U
  42.         if (GPIO_InitStruct->GPIO_Mode == GPIO_Mode_IPD)
    * O2 ~  |, I+ x5 J' b$ ?, ?
  43.         {
    / V2 c; ^8 s1 h4 Q$ z3 N( {, s
  44.           GPIOx->BRR = (((uint32_t)0x01) << pinpos);
    . W: `% I# _4 f$ t, H7 }! @
  45.         }: x; M4 M7 ^( [. F
  46.         else
    - N5 F! G; S) |3 [. Y6 Z$ o  D
  47.         {
    4 p9 r, {5 A8 y5 j) W
  48.           /* Set the corresponding ODR bit */
    # e9 ^! g* h0 t8 s1 ]: t- i. Y
  49.           if (GPIO_InitStruct->GPIO_Mode == GPIO_Mode_IPU)
    2 x8 E" Z/ i- F7 B
  50.           {. t, r+ c2 e5 Q! _( V$ }. L- y
  51.             GPIOx->BSRR = (((uint32_t)0x01) << pinpos);
    ; |8 L& Q( U& l$ D, h! W4 l* J. t
  52.           }
    8 r4 F# y! A* Q6 ]
  53.         }
    ) r* M  Z0 W( n  t% T# q
  54.       }
    0 I1 d7 [, I0 B
  55.     }
    5 _/ K6 {; p  M& ?7 F8 G! j
  56.     GPIOx->CRL = tmpreg;//更新寄存器值5 G. V7 s2 O% {, h  B) a! d+ R
  57.   }/ B/ B5 M' K7 K4 u, _
  58. /*---------------------------- GPIO CRH Configuration ------------------------*/
    ( ]+ q3 ?# K* r5 e! ]
  59.   /* Configure the eight high port pins */, `6 h+ L3 _  p0 m* H1 T! R
  60.   if (GPIO_InitStruct->GPIO_Pin > 0x00FF)//判断需要配置的脚是否大于7* I% g' h9 J( m. ]3 s! O! K
  61.   {
    * j5 v5 g; m9 [( F3 Z' C
  62.     tmpreg = GPIOx->CRH;+ ~- T* T  ^* b! w( u# y6 u) @. f
  63.     for (pinpos = 0x00; pinpos < 0x08; pinpos++)
    4 q* f5 g& S$ B! f) D7 a! }
  64.     {
    8 e! ?8 N7 o( t+ m
  65.       pos = (((uint32_t)0x01) << (pinpos + 0x08));
    8 h' k) D, M/ _0 d, J- G
  66.       /* Get the port pins position */
    0 e1 m/ g1 s7 \& P0 h  y2 T, t  s
  67.       currentpin = ((GPIO_InitStruct->GPIO_Pin) & pos);4 w2 L7 n- D' F) s/ b' {- A
  68.       if (currentpin == pos)* I# e6 K7 g9 W( i. g
  69.       {" U$ f1 j. G9 A2 t& D, N
  70.         pos = pinpos << 2;7 I* P. Y8 r1 \6 I
  71.         /* Clear the corresponding high control register bits */) y8 x7 _/ w6 X* x$ F; m4 V9 ^7 b) ]
  72.         pinmask = ((uint32_t)0x0F) << pos;- @3 a! x$ R# e5 O( |9 T9 t7 C+ ?
  73.         tmpreg &= ~pinmask;
    ; @9 J3 P9 T4 A4 c# `3 D5 x
  74.         /* Write the mode configuration in the corresponding bits */: Z1 a" d; n6 J7 k
  75.         tmpreg |= (currentmode << pos);
    + {# o( _2 k3 O) U9 X" ~
  76.         /* Reset the corresponding ODR bit */0 j4 |( \" z  }% o! R  T0 N, r
  77.         if (GPIO_InitStruct->GPIO_Mode == GPIO_Mode_IPD)
    # ]2 _. S1 C7 ?
  78.         {( _! j5 H, R3 L* R! b6 b' h
  79.           GPIOx->BRR = (((uint32_t)0x01) << (pinpos + 0x08));9 p/ q, O7 d4 h; `$ {0 c% h7 U' V
  80.         }4 x& x9 V2 J+ ]
  81.         /* Set the corresponding ODR bit */; U) x" _, f. k
  82.         if (GPIO_InitStruct->GPIO_Mode == GPIO_Mode_IPU)
    # f  v4 B8 j# N. D- {- s$ G
  83.         {
    / h9 O  z2 J) \* D  l' q
  84.           GPIOx->BSRR = (((uint32_t)0x01) << (pinpos + 0x08));, \7 v% q8 ]: m5 _$ |% |$ W0 ~
  85.         }
    " q  d- S+ T2 v' }2 S3 G4 q
  86.       }
    7 u  |  b2 W% I; c6 x
  87.     }
    3 S( i& `+ b3 X5 g; y* a, w
  88.     GPIOx->CRH = tmpreg;4 o* g. I& g( C! X5 Q: i- o2 d% g
  89.   }
    " q4 @, J% T) S7 v, ]) Y
  90. }+ C( ^4 `% |+ M$ h9 d

  91. 9 g1 R  o! R/ D# U8 a4 D1 J2 U2 R
复制代码

- q0 l2 a) _( i* P( L% ]
赞 收藏 评论0 发布时间:2022-5-2 09:23

举报

0个回答

所属标签

相似技术帖

官网相关资源

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