STM32之GPIO

来源:互联网 发布:Ubuntu Gnome 16.04.3 编辑:程序博客网 时间:2024/05/17 06:21

1、GPIO介绍

  • 每个通用IO口都有四个32位的配置寄存器,分别是
- GPIOx_MODER   : 模式设置- GPIOx_OTYPER  :类型设置- GPIOx_OSPEEDR :速度选择- GPIOx_PUPDR   :上拉下拉
  • 两个32位的数据寄存,分别是
- GPIOx_IDR  : 输入数据寄存器- GPIOx_ODR  :输出数据寄存器
  • 一个32位的设置/复位寄存器
- GPIOx_BSRR
  • 一个32位的锁存器
- GPIOx_LCKR
  • 两个附加功能选择寄存器
- GPIOx_AFRH : 高32位- GPIOx_AFRL :低32位

每个GPIO段都有16个引出引脚以供使用,引脚标号是Px0~Px15,这点与K60有区别

2、主要电气特性

  • 输出状态: 上拉下拉,全推挽输出,开漏
  • 从数据输出寄存器(GPIOx_ODR)或者外围设备(alternate function output)输出数据到IO引脚
  • 每个IO口可选时钟速度
  • 输入状态: 浮点,上拉下拉,逻辑
  • 从数据输入寄存器(GPIOx_IDR)或者外围设备(alternate function input)输入数据到IO引脚
  • 位操作寄存器(GPIOx_BSRR)用来对GPIOx_ODR进行位操作

3、输入配置

  1. 输出缓冲禁止
  2. 施密特触发输入激活
  3. 上拉下拉电阻状态取决于GPIOx_PUPDR寄存器的值
  4. IO口当前状态每个AHB1时钟周期都会被送入输入数据寄存器
  5. 对输入数据寄存器的读操作获得IO口的状态

4、输出配置

  1. 输出缓冲使能:
    • 开漏模式: 输出寄存器赋值为0激活 N-MOS 而1则是处于高阻状态 (P-MOS 不会被激活)
    • 推挽模式: 输出寄存器赋值为0激活 N-MOS 输出寄存器赋值为1激活 P-MOS
  2. 施密特触发输入激活
  3. 弱上拉下拉电阻被激活
  4. IO口当前状态每个AHB1时钟周期都会被送入输入数据寄存器
  5. 对输入数据寄存器的读操作获得IO口的状态
  6. 对输出数据寄存器的读操作获得最后一次写入的状态

5、特殊功能配置

  1. 输出配置为开漏或者推挽
  2. 输出缓冲区被来自外设的信号支配
  3. 施密特触发输入激活
  4. 弱上拉下拉电阻被激活
  5. IO口当前状态每个AHB1时钟周期都会被送入输入数据寄存器
  6. 对输入数据寄存器的读操作获得IO口的状态

6、GPIO操作实例之LED灯的操作(PF9 PF10)

//外设的基地址#define PERIPH_BASE           ((uint32_t)0x40000000) /*!< Peripheral base address in the alias region//各个总线的基地址#define APB1PERIPH_BASE       PERIPH_BASE#define APB2PERIPH_BASE       (PERIPH_BASE + 0x00010000)#define AHB1PERIPH_BASE       (PERIPH_BASE + 0x00020000)#define AHB2PERIPH_BASE       (PERIPH_BASE + 0x10000000)//AHB1外设节选/*!< AHB1 peripherals */#define GPIOA_BASE            (AHB1PERIPH_BASE + 0x0000)#define GPIOB_BASE            (AHB1PERIPH_BASE + 0x0400)#define GPIOC_BASE            (AHB1PERIPH_BASE + 0x0800)#define GPIOD_BASE            (AHB1PERIPH_BASE + 0x0C00)#define GPIOE_BASE            (AHB1PERIPH_BASE + 0x1000)#define GPIOF_BASE            (AHB1PERIPH_BASE + 0x1400)#define GPIOG_BASE            (AHB1PERIPH_BASE + 0x1800)#define GPIOH_BASE            (AHB1PERIPH_BASE + 0x1C00)#define GPIOI_BASE            (AHB1PERIPH_BASE + 0x2000)#define GPIOJ_BASE            (AHB1PERIPH_BASE + 0x2400)#define GPIOK_BASE            (AHB1PERIPH_BASE + 0x2800)

实例之:一个简单的gpio初始化

void gpio_init(GPIOx_SELECT gpiox, GPIOx_pn_SELECT gpiox_pn, \               GPIO_PULL_TYPE pull, GPIO_IO_TYPE io, GPIO_STATUS_TYPE stat, GPIO_OUTPUT_TYPE otype){    GPIO_TypeDef *GPIOx;    /* Get the GPIOx's GPIO_TypeDef struct */    GPIOx = BYM_GET_GPIO_struct(gpiox);    RCC->AHB1ENR  |= (1 << gpiox);  //Enable the clock of GPIOx    /* Set the io type of GPIOx's pn */    GPIOx->MODER  &= ~(3 << (gpiox_pn * 2));       //Clear the old register data    GPIOx->MODER  |= (io << (gpiox_pn * 2));        //Set the mode of GPIOx's pn    /* Set the io ouput type of GPIOx's pn */    GPIOx->OTYPER &= ~(1 << gpiox_pn);             //Clear the old register data    GPIOx->OTYPER |= (otype << gpiox_pn);           //Set the output type of GPIOx's pn    /* Pull down or pull up or nothing for GPIOx's pn */    GPIOx->PUPDR  &= ~(3 << (gpiox_pn * 2));       //Clear the old register data    GPIOx->PUPDR  |= (pull << (gpiox_pn * 2));    /* Only set the pin status when the 'io' value is 'BYM_GPO' */    if(io == BYM_GPO)    {        GPIOx->ODR  &= ~(1 << gpiox_pn);        GPIOx->ODR  |= (stat << gpiox_pn);    }   }

实例之:获取IO口状态

/*  * Get GPIO pin status */uint32_t gpio_get(GPIOx_SELECT gpiox, GPIOx_pn_SELECT gpiox_pn){    GPIO_TypeDef *GPIOx;    /* Get the GPIOx's GPIO_TypeDef struct */    GPIOx = BYM_GET_GPIO_struct(gpiox);    return ((GPIOx->IDR) & (1 << gpiox_pn));}
//枚举变量的定义/* GPIO 段的选择枚举 */typedef enum{    BYM_GPIOA, BYM_GPIOB, BYM_GPIOC, BYM_GPIOD,    BYM_GPIOE, BYM_GPIOF, BYM_GPIOG, BYM_GPIOH,    BYM_GPIOI, BYM_GPIOJ, BYM_GPIOK,}GPIOx_SELECT;/* GPIO管脚号的选择枚举 */typedef enum{    BYM_Px0,    BYM_Px1,    BYM_Px2,    BYM_Px3,    BYM_Px4,    BYM_Px5,    BYM_Px6,    BYM_Px7,    BYM_Px8,    BYM_Px9,    BYM_Px10,   BYM_Px11,   BYM_Px12,   BYM_Px13,   BYM_Px14,   BYM_Px15,}GPIOx_pn_SELECT;/* 上拉下拉的枚举 */typedef enum{    BYM_NO_PULL,    BYM_PULL_UP,    BYM_PULL_DOWN,}GPIO_PULL_TYPE;/* 输出模式枚举 */typedef enum{    BYM_PUSH_PULL,    BYM_OPEN_DRAIN,}GPIO_OUTPUT_TYPE;/* IO管脚复用模式枚举 */typedef enum{    BYM_GPI,    BYM_GPO,    BYM_GPALT,  BYM_GPANA,}GPIO_IO_TYPE;/* 当管脚设置为输出的时候管脚状态的枚举 */typedef enum{    BYM_LOW_LEVEL,    BYM_HIGH_LEVEL,}GPIO_STATUS_TYPE;/* Get the GPIO's GPIO_TypeDef struct */#define BYM_GET_GPIO_struct(gpiox) \    ((GPIO_TypeDef *)(AHB1PERIPH_BASE + (gpiox * 0x400)))

7、GPIO口的不同附加外设功能

AF0     systemAF1     TIM1/TIM2AF2     TIM3~TIM5AF3     TIM8~TIM11AF4     I2C1~I2C3AF5     SPI1~SPI2AF6     SPI3AF7     USART1~USART3AF8     USART4~USART6AF9     CAN1/CAN2,TIM12~TIM14AF10    OTG_FS,OTG_HSAF11    ETHAF12    FSMC,SDIO,OTG_HS(1)AF13    DCMIAF14    AF15    EVENTOUT

8、管脚锁存

  • 管脚锁存通过寄存器的一系列操作之后达到gpio管脚状态锁定,直到下一次CPU复位或者gpio管脚模块复位时才允许改变状态

  • 操作步骤,通过向GPIOx_LCKR寄存器进行写操作来完成

WR LCKR[16] = ‘1’ + LCKR[15:0]WR LCKR[16] = ‘0’ + LCKR[15:0]WR LCKR[16] = ‘1’ + LCKR[15:0]/* 上面三步是要求的操作步骤 */RD LCKRRD LCKR[16] = ‘1/* 上面两步是为了保证gpio管脚状态被成功的设置了 */

9、一个GPIO口初始化过程

  • 设置该GPIO段时钟开启(所有的芯片片内外设均需要先开启时钟),AHB1ENR(GPIO属于AHB1总线)
  • 选择该段需要设置的GPIO管脚号
  • 对其寄存器进行模式设置,包括输入输出方式,速度,引脚复用,上拉下拉等等

10、与51系列8位单片机IO口的主要区别

  • 不同点:

    • 可选的上拉下拉电阻
    • 可设置的IO频率
    • 可锁存
    • 明确的输入输出状态
  • 相同点:

    • 都可设置外设功能
    • 都有推挽、开漏、普通IO口三种模式
1 0