STM32开发板学习笔记(一)-- 开篇及STM32按键中断分析

感觉只有边写边看我的思路才会清晰一点。

开发板是老师做的一块,芯片是STM32F103ZET6 。


各种例子。一段一段来分析,最后再来个总结。

第一部分、预定义部分

/* Includes ------------------------------------------------------------------*/
#include "stm32f10x.h"
#include "stm32_eval.h"

#include "stm32f10x_flash.h"
#include 

记得加入stm32f10x_flash.h 是因为除了一个错误,具体错误提示忘了。

一段头文件的编译预处理

#ifdef USE_STM3210B_EVAL
 #include "stm3210b_eval_lcd.h"
#elif defined USE_STM3210E_EVAL
 #include "stm3210e_eval_lcd.h"
#elif defined USE_STM3210C_EVAL
 #include "stm3210c_eval_lcd.h"
#endif

其中EVAL 的意思是 evaluation 评估的意思。另外在stm32_eval.h 中有如下一段,

/**
@code  
 The table below gives an overview of the hardware resources supported by each 
 STM32 EVAL board.
     - LCD: TFT Color LCD (Parallel (FSMC) and Serial (SPI))
     - IOE: IO Expander on I2C
     - sFLASH: serial SPI FLASH (M25Pxxx)
     - sEE: serial I2C EEPROM (M24C08, M24C32, M24C64)
     - TSENSOR: Temperature Sensor (LM75)
     - SD: SD Card memory (SPI and SDIO (SD Card MODE)) 
  =================================================================================================================+
    STM32 EVAL     | LED | Buttons  | Com Ports |    LCD    | IOE  | sFLASH | sEE | TSENSOR | SD (SPI) | SD(SDIO)  |
  =================================================================================================================+
   STM3210B-EVAL   |  4  |    8     |     2     | YES (SPI) | NO   |  YES   | NO  |   YES   |    YES   |    NO     |
  -----------------------------------------------------------------------------------------------------------------+
   STM3210E-EVAL   |  4  |    8     |     2     | YES (FSMC)| NO   |  YES   | NO  |   YES   |    NO    |    YES    |
  -----------------------------------------------------------------------------------------------------------------+
   STM3210C-EVAL   |  4  |    3     |     1     | YES (SPI) | YES  |  NO    | YES |   NO    |    YES   |    NO     |
  -----------------------------------------------------------------------------------------------------------------+
   STM32100B-EVAL  |  4  |    8     |     2     | YES (SPI) | NO   |  YES   | NO  |   YES   |    YES   |    NO     |
  =================================================================================================================+
@endcode
*/

应该是STM 提供了不同的评估板,每块板子的外设结构有所不同,于是在下面有这么一段:

/** 
  * @brief  Uncomment the line corresponding to the STMicroelectronics evaluation
  *   board used in your application.
  *   
  *  Tip: To avoid modifying this file each time you need to switch between these
  *       boards, you can define the board in your toolchain compiler preprocessor.    
  */ 
#if !defined (USE_STM32100B_EVAL) && !defined (USE_STM3210B_EVAL) &&  !defined (USE_STM3210E_EVAL) &&  !defined (USE_STM3210C_EVAL)
 //#define USE_STM32100B_EVAL
 //#define USE_STM3210B_EVAL
#define USE_STM3210E_EVAL
 //#define USE_STM3210C_EVAL
#endif
叫做 uncomment the line 来指定相应的评估板。这里可以看见我用的这个项目里面 uncomment 的行是 也就是说老师所做的板子是对应于 E 型的评估板,而根据上面所提供的的 overview ,这种型号的评估板应该包含

* 4 个 led ,这个确实有,而且算上那些指示灯,还不止4 个,不过应该不用算只是灯。

* 8 个按键, 这个没有,只有一个复位键和四个不明按键。

* 串口两个 确实有

* LCD 这个有,2.8寸 TFT 触摸屏

* sFLASH , 这个还不知道有米有   :TAG MARK

* TSENSOR , 温度传感器,这个应该有,不确定。  :TAG MARK

* SD ,这个有。不过SPI 和SDIO 有什么区别? :TAG MARK

继续下面的,上面另外的问题先留着,免得一件事都没整完。继续贴代码

/** @addtogroup Template_Project
  * @{
  */

/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
#ifdef USE_STM3210B_EVAL
  #define MESSAGE1   "STM32 Medium Density" 
  #define MESSAGE2   " Device running on  " 
  #define MESSAGE3   "   STM3210B-EVAL    " 
#elif defined USE_STM3210E_EVAL
  #define MESSAGE1   " STM32 High Density " 
  #define MESSAGE2   " Device running on  " 
  #define MESSAGE3   "   STM3210E-EVAL    " 
#elif defined USE_STM3210C_EVAL
  #define MESSAGE1   " STM32 Connectivity " 
  #define MESSAGE2   " Line Device running" 
  #define MESSAGE3   " on STM3210C-EVAL   " 
#endif
这段说明 E 型开发板用的是 STM32 High Density 的 微控制器,噢,原来如此,不同型的评估板用的微控制型号是不同的。那么 STM32 High Density 是怎样的呢? 查选型手册:

没仔细找 STM32 High Density,找到上面的表。

也就是说:频率 72Mhz , 512KB ROM , 64kb RAM,.........

继续贴代码,LED 定义,

/* Private macro -------------------------------------------------------------*/
/*神州III号LED灯相关定义*/
#define RCC_GPIO_LED                    RCC_APB2Periph_GPIOF    /*LED使用的GPIO时钟*/
#define LEDn                            4                       /*IIILED数量*/
#define GPIO_LED                        GPIOF                   /*IIILED灯使用的GPIO组*/

#define DS1_PIN                         GPIO_Pin_6              /*DS1使用的GPIO管脚*/
#define DS2_PIN                         GPIO_Pin_7				/*DS2使用的GPIO管脚*/
#define DS3_PIN                         GPIO_Pin_8  			/*DS3使用的GPIO管脚*/
#define DS4_PIN                         GPIO_Pin_9				/*DS4使用的GPIO管脚*/

#define GPIO_LED_ALL                                 DS1_PIN |DS2_PIN |DS3_PIN |DS4_PIN 
老师好似借鉴了很多板子啊。查过原理图,对应引脚是这样的。好理解 。

continue ....

/*神州III号按键相关定义*/
#define RCC_KEY1                                    RCC_APB2Periph_GPIOD
#define GPIO_KEY1_PORT                              GPIOD    
#define GPIO_KEY1                                   GPIO_Pin_3

#define RCC_KEY2                                    RCC_APB2Periph_GPIOA
#define GPIO_KEY2_PORT                              GPIOA  
#define GPIO_KEY2                                   GPIO_Pin_8

#define RCC_KEY3                                    RCC_APB2Periph_GPIOC
#define GPIO_KEY3_PORT                              GPIOC    
#define GPIO_KEY3                                   GPIO_Pin_13 

#define RCC_KEY4                                    RCC_APB2Periph_GPIOA
#define GPIO_KEY4_PORT                              GPIOA    
#define GPIO_KEY4                                   GPIO_Pin_0 

#define GPIO_KEY_ANTI_TAMP                          GPIO_KEY3
#define GPIO_KEY_WEAK_UP                            GPIO_KEY4


/* Values magic to the Board keys */
#define  NOKEY  0
#define  KEY1   1
#define  KEY2   2
#define  KEY3   3
#define  KEY4   4

/* LED status */
#define LED_ON 1
#define LED_OFF 0


由此可得,按键对应的引脚是: D3 、A8、C13、A0 


于是问题来了,#define RCC_KEY1                                    RCC_APB2Periph_GPIOD

RCC 的意思是 复位 时钟控制。好吧 先去吃饭了。回来再继续,

此时看得应该是时钟设置,

三种不同的时钟源可被用来驱动系统时钟(SYSCLK) : 
● HSI振荡器时钟   (高速 内部振荡器时钟)
● HSE振荡器时钟   (高速外部振荡器时钟)
● PLL 时钟               (内部PLL 可以用来倍频HSI RC的输出时钟或HSE晶体输出时钟)

这段先到这,后面还有相关。

第二部分、GPIO

看LED——config

void LED_config(void)
{
  GPIO_InitTypeDef GPIO_InitStructure;
  /* Enable GPIOB, GPIOC and AFIO clock */
  RCC_APB2PeriphClockCmd(RCC_GPIO_LED | RCC_APB2Periph_AFIO , ENABLE);  //RCC_APB2Periph_AFIO
  
  /* LEDs pins configuration */
  GPIO_InitStructure.GPIO_Pin = GPIO_LED_ALL;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
  GPIO_Init(GPIO_LED, &GPIO_InitStructure);
}
函数首先定义了一个GPIO_InitTypeDef 类型的变量,其结构如下:

typedef struct
{
  uint16_t GPIO_Pin;             /*!< Specifies the GPIO pins to be configured.
                                      This parameter can be any value of @ref GPIO_pins_define */

  GPIOSpeed_TypeDef GPIO_Speed;  /*!< Specifies the speed for the selected pins.
                                      This parameter can be a value of @ref GPIOSpeed_TypeDef */

  GPIOMode_TypeDef GPIO_Mode;    /*!< Specifies the operating mode for the selected pins.
                                      This parameter can be a value of @ref GPIOMode_TypeDef */
}GPIO_InitTypeDef;
即,引脚, 速度, 和模式。引脚很好理解,速度的可取值有哪些?又有哪些模式可以设置呢?如下:

/** 
  * @brief  Output Maximum frequency selection  
  */

typedef enum
{ 
  GPIO_Speed_10MHz = 1,
  GPIO_Speed_2MHz, 
  GPIO_Speed_50MHz
}GPIOSpeed_TypeDef;
#define IS_GPIO_SPEED(SPEED) (((SPEED) == GPIO_Speed_10MHz) || ((SPEED) == GPIO_Speed_2MHz) || \
                              ((SPEED) == GPIO_Speed_50MHz))

/** 
  * @brief  Configuration Mode enumeration  
  */

typedef enum
{ GPIO_Mode_AIN = 0x0, 			// 模拟输入
  GPIO_Mode_IN_FLOATING = 0x04, 	// 输入浮空
  GPIO_Mode_IPD = 0x28, 		// 输入下拉
  GPIO_Mode_IPU = 0x48, 		// 输入上拉
  GPIO_Mode_Out_OD = 0x14,		// 开漏输出
  GPIO_Mode_Out_PP = 0x10,		// 推挽式输出
  GPIO_Mode_AF_OD = 0x1C,		// 开漏复用功能
  GPIO_Mode_AF_PP = 0x18		// 推挽式复用功能
}GPIOMode_TypeDef;

#define IS_GPIO_MODE(MODE) (((MODE) == GPIO_Mode_AIN) || ((MODE) == GPIO_Mode_IN_FLOATING) || \
                            ((MODE) == GPIO_Mode_IPD) || ((MODE) == GPIO_Mode_IPU) || \
                            ((MODE) == GPIO_Mode_Out_OD) || ((MODE) == GPIO_Mode_Out_PP) || \
                            ((MODE) == GPIO_Mode_AF_OD) || ((MODE) == GPIO_Mode_AF_PP))
可以看到,GPIO 的速度可以取3档,  10mhz  2mhz , 50mhz 。而模式的有很多种,手册上P105 面:设置的寄存器是 端口配置低寄存器(GPIOx_CRL(/H)) (x=A..E) (p114)

─   输入浮空    TAG MARK
─   输入上拉 
─   输入下拉 
─   模拟输入 
─   开漏输出 
─   推挽式输出 
─   推挽式复用功能 
─   开漏复用功能 


看第二行设置时钟:

其中有个 

RCC_APB2Periph_AFIO 

在手册中的APB2 外设时钟使能寄存器了有说明:(P71)

AFIOEN :辅助(翻译的貌似不对,应该是复用)功能IO时钟使能 (Alternate function I/O clock enable) 
由软件置’1’ 或清’0’ 
0:复用功能IO时钟关闭; 
1:复用功能IO时钟开启。 

那么合适需要使能这个时钟呢?

在EXIT 里找到一段:通过AFIO_EXTICRx配置GPIO线上的外部中断/ 事件,必须先使能AFIO时钟。另外有人说:需要用到外设的重映射功能时才需要使能AFIO的时钟

还有手册里的一段:

***************************************************************************************************************

复用功能I/O 和调试配置(AFIO) 
为了优化64脚或100 脚封装的外设数目,可以把一些复用功能重新映射到其他引脚上。设置复用
重映射和调试I/O 配置寄存器(AFIO_MAPR) 实现引脚的重新映射。这时,复用功能不再映射到它
们的原始分配上。

***************************************************************************************************************

还是不太懂 : TAG MARK 


看看RCC 使能的函数:

void RCC_APB2PeriphClockCmd(uint32_t RCC_APB2Periph, FunctionalState NewState)
{
  /* Check the parameters */
  assert_param(IS_RCC_APB2_PERIPH(RCC_APB2Periph));
  assert_param(IS_FUNCTIONAL_STATE(NewState));
  if (NewState != DISABLE)
  {
    RCC->APB2ENR |= RCC_APB2Periph;
  }
  else
  {
    RCC->APB2ENR &= ~RCC_APB2Periph;
  }
}

关于其中的 assert_param 上面的一段英文已经说得很清楚 如果表达式为假,则调用assert——failed 函数去报告源代码里的错误所在文件和行数。

/* Exported macro ------------------------------------------------------------*/

#ifdef  USE_FULL_ASSERT

/**
  * @brief  The assert_param macro is used for function's parameters check.
  * @param  expr: If expr is false, it calls assert_failed function
  *   which reports the name of the source file and the source
  *   line number of the call that failed. 
  *   If expr is true, it returns no value.
  * @retval None
  */
  #define assert_param(expr) ((expr) ? (void)0 : assert_failed((uint8_t *)__FILE__, __LINE__))
/* Exported functions ------------------------------------------------------- */
  void assert_failed(uint8_t* file, uint32_t line);
#else
  #define assert_param(expr) ((void)0)
#endif /* USE_FULL_ASSERT */

再就是GPIO_Init的过程了, 

首先看看GPIO 有哪些寄存器,

Each of the general-purpose I/O ports has two 32-bit configuration registers (GPIOx_CRL, GPIOx_CRH), two 32-bit data registers (GPIOx_IDR, GPIOx_ODR), a 32-bit set/reset register (GPIOx_BSRR), a 16-bit reset register (GPIOx_BRR) and a 32-bit locking register (GPIOx_LCKR).

即两个configuration register ,两个data register (inout 一个 , output 一个),一个复位置位寄存器,还有一个16bit的复位寄存器。加上一个锁寄存器。

如代码中描述:

typedef struct{  

__IO uint32_t CRL;  // 控制寄存器低位  

__IO uint32_t CRH; // 控制寄存器高位 

__IO uint32_t IDR;  // 输入数据寄存器

  __IO uint32_t ODR; // 输出数据寄存器 

  __IO uint32_t BSRR; //端口位设置/清除寄存器 

  __IO uint32_t BRR;  // 端口为清除寄存器

 __IO uint32_t LCKR; //锁存寄存器

} GPIO_TypeDef; 

又到饭点了,应该说都过了饭点了,吃饭了再来继续,刚才又看见不少。

吃了饭回来,写了篇马克思的论文,再蹂躏了几件衣服,就差不多这个时候了,本打算洗洗睡了,没地方洗。就继续看看。

之前我看见,STM32F103ZET6 有 A...G 个GPIO,而每个GPIO 有0...15,号,所以相应的各种寄存器也都有16套。

看GPIO 的初始化 

void GPIO_Init(GPIO_TypeDef* GPIOx, GPIO_InitTypeDef* GPIO_InitStruct)
{
  uint32_t currentmode = 0x00, currentpin = 0x00, pinpos = 0x00, pos = 0x00;
  uint32_t tmpreg = 0x00, pinmask = 0x00;
  /* Check the parameters */
  assert_param(IS_GPIO_ALL_PERIPH(GPIOx));
  assert_param(IS_GPIO_MODE(GPIO_InitStruct->GPIO_Mode));
  assert_param(IS_GPIO_PIN(GPIO_InitStruct->GPIO_Pin));  
  
/*---------------------------- GPIO Mode Configuration -----------------------*/
  currentmode = ((uint32_t)GPIO_InitStruct->GPIO_Mode) & ((uint32_t)0x0F);
  if ((((uint32_t)GPIO_InitStruct->GPIO_Mode) & ((uint32_t)0x10)) != 0x00)
  { 
    /* Check the parameters */
    assert_param(IS_GPIO_SPEED(GPIO_InitStruct->GPIO_Speed));
    /* Output mode */
    currentmode |= (uint32_t)GPIO_InitStruct->GPIO_Speed;
  }
/*---------------------------- GPIO CRL Configuration ------------------------*/
  /* Configure the eight low port pins */
  if (((uint32_t)GPIO_InitStruct->GPIO_Pin & ((uint32_t)0x00FF)) != 0x00)
  {
    tmpreg = GPIOx->CRL;
    for (pinpos = 0x00; pinpos < 0x08; pinpos++)
    {
      pos = ((uint32_t)0x01) << pinpos;
      /* Get the port pins position */
      currentpin = (GPIO_InitStruct->GPIO_Pin) & pos;
      if (currentpin == pos)
      {
        pos = pinpos << 2;
        /* Clear the corresponding low control register bits */
        pinmask = ((uint32_t)0x0F) << pos;
        tmpreg &= ~pinmask;
        /* Write the mode configuration in the corresponding bits */
        tmpreg |= (currentmode << pos);
        /* Reset the corresponding ODR bit */
        if (GPIO_InitStruct->GPIO_Mode == GPIO_Mode_IPD)
        {
          GPIOx->BRR = (((uint32_t)0x01) << pinpos);
        }
        else
        {
          /* Set the corresponding ODR bit */
          if (GPIO_InitStruct->GPIO_Mode == GPIO_Mode_IPU)
          {
            GPIOx->BSRR = (((uint32_t)0x01) << pinpos);
          }
        }
      }
    }
    GPIOx->CRL = tmpreg;
  }
/*---------------------------- GPIO CRH Configuration ------------------------*/
  /* Configure the eight high port pins */
  if (GPIO_InitStruct->GPIO_Pin > 0x00FF)
  {
    tmpreg = GPIOx->CRH;
    for (pinpos = 0x00; pinpos < 0x08; pinpos++)
    {
      pos = (((uint32_t)0x01) << (pinpos + 0x08));
      /* Get the port pins position */
      currentpin = ((GPIO_InitStruct->GPIO_Pin) & pos);
      if (currentpin == pos)
      {
        pos = pinpos << 2;
        /* Clear the corresponding high control register bits */
        pinmask = ((uint32_t)0x0F) << pos;
        tmpreg &= ~pinmask;
        /* Write the mode configuration in the corresponding bits */
        tmpreg |= (currentmode << pos);
        /* Reset the corresponding ODR bit */
        if (GPIO_InitStruct->GPIO_Mode == GPIO_Mode_IPD)
        {
          GPIOx->BRR = (((uint32_t)0x01) << (pinpos + 0x08));
        }
        /* Set the corresponding ODR bit */
        if (GPIO_InitStruct->GPIO_Mode == GPIO_Mode_IPU)
        {
          GPIOx->BSRR = (((uint32_t)0x01) << (pinpos + 0x08));
        }
      }
    }
    GPIOx->CRH = tmpreg;
  }
}
真长, 慢慢看吧。其实下午看的时候我就没懂,现在又想起前面写的几个字,就忽然懂了。有时候不一定要“从代码去懂理论”,也可以从“理论去懂代码”

说 有两个32位的控制寄存器,一个叫CRL, 一个叫CRH ,其中CRL中控制的是 0~7号引脚 , CRH 控制的是 8~15号引脚,每一个有四位去控制,四位分为两种,一个叫MODEy[1..0],控制引脚的输入输出状态,输入状态有一种,输出状态则有三种不同的速率,前面已经碰到,而对应于 输入和输出的MODE , 还有另外两位是 CNF,是更加具体的输入输出模式设置,如什么 pp ipd ipu 啥的(这个我不是太懂。)好吧扯得有点远了。回来继续分析:

第一句:currentmode = ((uint32_t)GPIO_InitStruct->GPIO_Mode) & ((uint32_t)0x0F); 意思就是将mode 设为传进来mode的低四位的值,如上所述,设置一个引脚的状态方式只需要四位,而STM 对mode 的定义是八位,如下:

/** 
  * @brief  Configuration Mode enumeration  
  */

typedef enum
{ GPIO_Mode_AIN = 0x0,
  GPIO_Mode_IN_FLOATING = 0x04,
  GPIO_Mode_IPD = 0x28,
  GPIO_Mode_IPU = 0x48,
  GPIO_Mode_Out_OD = 0x14,
  GPIO_Mode_Out_PP = 0x10,
  GPIO_Mode_AF_OD = 0x1C,
  GPIO_Mode_AF_PP = 0x18
}GPIOMode_TypeDef;

#define IS_GPIO_MODE(MODE) (((MODE) == GPIO_Mode_AIN) || ((MODE) == GPIO_Mode_IN_FLOATING) || \
                            ((MODE) == GPIO_Mode_IPD) || ((MODE) == GPIO_Mode_IPU) || \
                            ((MODE) == GPIO_Mode_Out_OD) || ((MODE) == GPIO_Mode_Out_PP) || \
                            ((MODE) == GPIO_Mode_AF_OD) || ((MODE) == GPIO_Mode_AF_PP))
那么我肯定就要问了,那么它的 0x28, 0x48是什么意思?看手册知道 输入上拉/下拉 的CNFy[1..0] 设置其实是一起的 ,如下:

在输入模式(MODE[1:0]=00): 
00:模拟输入模式 
01:浮空输入模式(复位后的状态
10:上拉/ 下拉输入模式 
11:保留 

那么这个2 和 4 有什么意思呢?就我目前浅薄的见识来看,没什么意思,没什么作用。但是下面的输出状态高位填的1 却是有作用的,看GPIO_Init 的第二句:

if ((((uint32_t)GPIO_InitStruct->GPIO_Mode) & ((uint32_t)0x10)) != 0x00)
 我在总结前一篇位掩码时想到这种干是判断,判断什么呢?判断传入的8位的MODE的高四位是否为1 ,也就是说 判断 mode是否为输出模式,因为输出模式要设置速度。

在输出模式时,CNF的两位可以设置输出方式(通用推挽(00),通用开漏(01),复用推挽(10),复用开漏(11)),但是MODE的值确是来设定速度的,于是输的mode 的8位的低四位即本来应该对应 CNFy[1..0] 和 MODEy[1..0]的四位只取了CNFy[1..0]的值,而将mode留空,如

通用推挽(00 00),   ...

通用开漏(01 00), 即得到GPIO_Mode_Out_OD = 0x14, 的 4

复用推挽(10 00),...

复用开漏(11 00)  ...

在通过附加在mode的一个高位 的 1 判断出是输出模式后,再利用 GPIO_InitTypeDef 结构体里面的 GPIO_Speed 去设置输出速率,也就是下面这句话所做的事。

currentmode |= (uint32_t)GPIO_InitStruct->GPIO_Speed;


接下来就是配置到具体的引脚了,注意 刚才的 currentmode 只是一个变量。还要把它装入到寄存器的相应位中才能设置模式,可是不知道哪个引脚要怎么设呢?于是接下来就开始判断。

 好吧后面的一段由于太晚我已经没什么耐心了。反正就是通过各种位操作,判断出是哪个引脚,然后将相应的设置装入的寄存器的相应位。


准备在下面总结下GPIO,不得不提一提之前看得一点关于系统总线的:

系统总线的图示:

STM32开发板学习笔记(一)-- 开篇及STM32按键中断分析_第1张图片

(这手册比较老,GPIO少了几个)。注:此图不对应互联型产品。

从图上看得也算清楚,再结合手册说明,总线的组成如下:

四个驱动单元:(也就是接入在总线矩阵左边的)

Cortex-M3 内核驱动DCode总线, System 总线

DMA1 和 DMA2

四个被动单元:也比较清楚。

FLASH

SRAM

FSNC   : TAG MARK

AHB 到 APB 总线桥。

其实我要说的就是第四个被动单元:AHB 到 APB 总线桥。因为要说到GPIO。

首先看查到的一些资料,给我的印象就是 AHB 就相当于 微机 里的系统总线,用于连接高速设备,而APB 则相当于用户总线,用以连接低速设备。

查到了 ARM 的AMBA (高级微控制器总线体系),简单的看看:

包括:

1. AHB  -- 高级高性能总线

2. ASB -- 高级系统总线

3. APB -- 高级外设总线

APB 一般包装为 AHB 总线的一个外设,如图可见。而APB 一般连接外设,如图中连接的一堆。在APB2上面就连接有 GPIOy 。


GPIO 小结

上面讲的貌似都是GPIO 先就上面的小结一下吧。

一般的东西要工作,都得给个时钟,时钟是什么了,目前还没有那么尖锐的理解。而 GPIO 是连接在 APB2上的,所以呢,GPIO 的初始化中时钟使能是调用的函数 RCC_APB2PeriphClockCmd,(至于APB连接在AHB 上,那么是不是要先调用AHB 的时总使能呢?)。那么通用 GPIO 的使用过程应该可以总结如下:

1. 调用 RCC_APB2PeriphClockCmd 使能相应引脚时钟

2. 设置引脚模式。若是输出模式,则还需要设置 速率。

3. 调用 GPIO_Init 将设置装入到相应的寄存器。

其中还有问题的地方: TAG MARK 

1. 各种输出、输入模式是是什么意思?

2. AFIO






































你可能感兴趣的:(STM32开发板学习笔记(一)-- 开篇及STM32按键中断分析)