【4】STM32·HAL库·GPIO

目录

一、什么是GPIO

二、STM32 GPIO简介

2.1、GPIO特点

2.2、GPIO电气特性

2.3、GPIO引脚分布

三、IO端口基本结构介绍

3.1、F4/F7/H7 的 IO 结构图

3.2、施密特触发器简介

3.3、P-MOS & N-MOS管简介

四、GPIO的八种模式分析

4.1、输入浮空

4.2、输入上拉

4.3、输入下拉

4.4、模拟功能

4.5、开漏输出

4.6、推挽输出

4.7、开漏式复用功能

4.8、推挽式复用功能

4.9、八种模式的特点及应用

五、GPIO寄存器介绍

5.1、(F4/F7/H7)通用寄存器

5.2、模式寄存器(MODER)

5.3、输出类型寄存器(OTYPER)

5.4、输出速度寄存器(OSPEEDR)

5.5、上拉/下拉寄存器(PUPDR)

5.6、8 种工作模式对应的配置

5.7、输入数据寄存器(IDR)

5.8、输出数据寄存器(ODR)

5.9、置位/复位寄存器(BSRR)

5.10、ODR和BSRR寄存器的区别

六、GPIO配置步骤

6.1、使能时钟

6.2、设置工作模式

6.3、设置输出状态(可选)

6.4、读取输入状态(可选)

七、编程实战

7.1、点亮一个LED灯

7.2、通过一个按键控制一个LED灯亮灭


一、什么是GPIO

GPIO(General Purpose Input Output),即通用输入输出端口,简称 GPIO

作用:负责采集外部器件的信息或者控制外部器件工作,即输入输出

二、STM32 GPIO简介

2.1、GPIO特点

1、不同型号,IO 口数量可能不一样,可通过选型手册快速查询

2、快速翻转,每次翻转最快只需要两个时钟周期(F1 最高速度可以到 50MHz)

3、每个 IO 口都可以做中断

4、支持 8 种工作模式

2.2、GPIO电气特性

1、STM 工作电压范围

2V\leq VDD\leq 3.6V

2、GPIO 识别电压范围

COMS 端口:

 -0.3V\leq V_{IL}\leq1.164V

1.833V\leq V_{IH}\leq 3.6V

TTL 端口:

-0.3V\leq V_{IL}\leq1.164V

1.833V\leq V_{IH}\leq 5.5V

3、GPIO 输出电流:单个 IO,最大 25mA

2.3、GPIO引脚分布

电源引脚:原理图中以 V 开头的引脚

晶振引脚:原理图中带有 OSC 的引脚,其中 OSC32 代表低速外部晶振 32.768KHz

复位引脚:原理图中名为 NRST 的引脚

下载引脚:包括 JTAG、SW、串口

BOOT 引脚:原理图中名为 BOOT 的引脚

GPIO 引脚:原理图中以 P 开头的引脚

不同芯片引脚分布情况

IO 引脚分布特点:按组存在、组数视芯片而定、每组最多 16 个 IO 引脚

三、IO端口基本结构介绍

3.1、F4/F7/H7 的 IO 结构图

3.2、施密特触发器简介

施密特触发器就是一种整形电路,可以将非标准方波,整形成方波

特点

当输入电压高于正向阈值电压,输出为高

当输入电压低于负向阈值电压,输出为低

当输入在正负向阈值电压之间,输出不改变

作用:整形!如正弦波转方波

3.3、P-MOS & N-MOS管简介

MOS管是压控型元件,通过控制栅源电压( Vgs )来实现导通或关闭

G:栅极、S:源极、D:漏极

P:Vgs<0,导通

N:Vgs>0,导通

四、GPIO的八种模式分析

4.1、输入浮空

原理图

上拉电阻关闭,下拉电阻关闭,施密特触发器打开,双 MOS 管不导通

特点:空闲时,IO 状态不确定,由外部环境决定

4.2、输入上拉

原理图

上拉电阻打开,下拉电阻关闭,施密特触发器打开,双 MOS 管不导通

特点:空闲时,IO 呈现高电平

4.3、输入下拉

原理图

上拉电阻关闭,下拉电阻打开,施密特触发器打开,双 MOS 管不导通

特点:空闲时,IO 呈现低电平

4.4、模拟功能

原理图

上拉电阻关闭,下拉电阻关闭,施密特触发器关闭,双 MOS 管不导通

特点:专门用于模拟信号输入或输出,如 ADC 和 DAC

4.5、开漏输出

原理图

上下拉电阻一般设为关闭,施密特触发器打开,P-MOS 管始终不导通,往 ODR 对应位写 0,N-MOS 管导通,写 1 则 N-MOS 管不导通

特点:不能输出高电平,输出高电平只能靠上拉电阻,高电平下驱动能力弱

4.6、推挽输出

原理图

上拉电阻关闭,下拉电阻关闭,施密特触发器打开,往 ODR 对应位写 0,N-MOS 管导通,写 1 则 P-MOS 管导通

特点:可输出高低电平,驱动能力强

4.7、开漏式复用功能

原理图

上下拉电阻一般设为关闭,施密特触发器打开,P-MOS 管始终不导通

特点:由其他外设控制输出,不能输出高电平,输出高电平只能靠上拉电阻,高电平下驱动能力弱

4.8、推挽式复用功能

原理图

上拉电阻关闭,下拉电阻关闭,施密特触发器打开

特点:由其他外设控制输出,可输出高低电平,驱动能力强

4.9、八种模式的特点及应用

五、GPIO寄存器介绍

5.1、(F4/F7/H7)通用寄存器

5.2、模式寄存器(MODER)

用于设置模式

5.3、输出类型寄存器(OTYPER)

用于设置输出类型 

5.4、输出速度寄存器(OSPEEDR)

用于设置 IO 的输出速度 

5.5、上拉/下拉寄存器(PUPDR)

用于设置上拉/下拉电阻

5.6、8 种工作模式对应的配置

5.7、输入数据寄存器(IDR)

用于读取 IO 引脚的电平

5.8、输出数据寄存器(ODR)

用于设置 IO 引脚输出的电平

5.9、置位/复位寄存器(BSRR)

用于设置 ODR 寄存器

5.10、ODR和BSRR寄存器的区别

ST官方给的答案:

使用ODR,在读和修改访问之间产生中断时,可能会发生风险;BSRR则无风险

风险解释:

正常来说,在修改 ODR 寄存器时会涉及到三步 读 —> 改 —> 写,但在修改 BSRR 寄存器时只有一步 

/* 配置PB3输出高电平 */
GPIOB->ODR |= 1 << 3;
GPIOB->BSRR = 0x00000008;

假设,我们在修改 ODR 寄存器经过了读和改,也就是计算出了 0x00000008(二进制 0000 0000 0000 0000 0000 0000 0000 1000),但还没有赋值给 ODR 寄存器

此时产生中断,中断程序中也修改 ODR 寄存器的其他位(例如 0x00000006 二进制 0000 0000 0000 0000 0000 0000 0000 0100),中断结束后返回原程序继续执行赋值 ODR 寄存器操作

这时就会发现,本应该为 0x0000000c(二进制 0000 0000 0000 0000 0000 0000 0000 1100),最后结果依然是 0x00000008(二进制 0000 0000 0000 0000 0000 0000 0000 1000),在中断程序中修改 ODR 寄存器的其他位被覆盖了

总的来说,建议使用BSRR寄存器控制输出!

六、GPIO配置步骤

6.1、使能时钟

HAL库驱动函数:__HAL_RCC_GPIOx_CLK_ENABLE()

#define __HAL_RCC_GPIOA_CLK_ENABLE()   do { \
                                        __IO uint32_t tmpreg = 0x00U; \
                                        SET_BIT(RCC->AHB1ENR, RCC_AHB1ENR_GPIOAEN);\
                                        /* Delay after an RCC peripheral clock enabling */ \
                                        tmpreg = READ_BIT(RCC->AHB1ENR, RCC_AHB1ENR_GPIOAEN);\
                                        UNUSED(tmpreg); \
                                          } while(0U)

其中核心代码为第三行,SET_BIT 也是一个宏

#define SET_BIT(REG, BIT)     ((REG) |= (BIT))

第一个参数 RCC->AHB1ENR

第二个参数 RCC_AHB1ENR_GPIOAEN

#define RCC_AHB1ENR_GPIOAEN_Pos            (0U)                                
#define RCC_AHB1ENR_GPIOAEN_Msk            (0x1UL << RCC_AHB1ENR_GPIOAEN_Pos)   /*!< 0x00000001 */
#define RCC_AHB1ENR_GPIOAEN                RCC_AHB1ENR_GPIOAEN_Msk             

等于 1 << 0,也就是 RCC->AHB1ENR |= 1 << 0,将 RCC_AHB1ENR 寄存器的位 0 赋值为 1,再根据参考手册的介绍可知 

6.2、设置工作模式

HAL库驱动函数:HAL_GPIO_Init()

/**
  * @brief  Initializes the GPIOx peripheral according to the specified parameters in the GPIO_Init.
  * @param  GPIOx where x can be (A..K) to select the GPIO peripheral for STM32F429X device or
  *                      x can be (A..I) to select the GPIO peripheral for STM32F40XX and STM32F427X devices.
  * @param  GPIO_Init pointer to a GPIO_InitTypeDef structure that contains
  *         the configuration information for the specified GPIO peripheral.
  * @retval None
  */
void HAL_GPIO_Init(GPIO_TypeDef  *GPIOx, GPIO_InitTypeDef *GPIO_Init);

第一个参数 GPIO_TypeDef  *GPIOx,先看类型

/** 
  * @brief General Purpose I/O
  */

typedef struct
{
  __IO uint32_t MODER;    /*!< GPIO port mode register,               Address offset: 0x00      */
  __IO uint32_t OTYPER;   /*!< GPIO port output type register,        Address offset: 0x04      */
  __IO uint32_t OSPEEDR;  /*!< GPIO port output speed register,       Address offset: 0x08      */
  __IO uint32_t PUPDR;    /*!< GPIO port pull-up/pull-down register,  Address offset: 0x0C      */
  __IO uint32_t IDR;      /*!< GPIO port input data register,         Address offset: 0x10      */
  __IO uint32_t ODR;      /*!< GPIO port output data register,        Address offset: 0x14      */
  __IO uint32_t BSRR;     /*!< GPIO port bit set/reset register,      Address offset: 0x18      */
  __IO uint32_t LCKR;     /*!< GPIO port configuration lock register, Address offset: 0x1C      */
  __IO uint32_t AFR[2];   /*!< GPIO alternate function registers,     Address offset: 0x20-0x24 */
} GPIO_TypeDef;

可以看出,这其实是 GPIO 寄存器映射,对应的可选参数有

#define GPIOA               ((GPIO_TypeDef *) GPIOA_BASE)
#define GPIOB               ((GPIO_TypeDef *) GPIOB_BASE)
#define GPIOC               ((GPIO_TypeDef *) GPIOC_BASE)
#define GPIOD               ((GPIO_TypeDef *) GPIOD_BASE)
#define GPIOE               ((GPIO_TypeDef *) GPIOE_BASE)
#define GPIOF               ((GPIO_TypeDef *) GPIOF_BASE)
#define GPIOG               ((GPIO_TypeDef *) GPIOG_BASE)
#define GPIOH               ((GPIO_TypeDef *) GPIOH_BASE)
#define GPIOI               ((GPIO_TypeDef *) GPIOI_BASE)

第二个参数 GPIO_InitTypeDef *GPIO_Init,先看类型

/** 
  * @brief GPIO Init structure definition  
  */ 
typedef struct
{
  uint32_t Pin;       /*!< Specifies the GPIO pins to be configured.
                           This parameter can be any value of @ref GPIO_pins_define */

  uint32_t Mode;      /*!< Specifies the operating mode for the selected pins.
                           This parameter can be a value of @ref GPIO_mode_define */

  uint32_t Pull;      /*!< Specifies the Pull-up or Pull-Down activation for the selected pins.
                           This parameter can be a value of @ref GPIO_pull_define */

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

  uint32_t Alternate;  /*!< Peripheral to be connected to the selected pins. 
                            This parameter can be a value of @ref GPIO_Alternate_function_selection */
}GPIO_InitTypeDef;

可以看出,这其实是 GPIO 初始化工作模式,通过注释中 @ref 后面跟的参考内容进行全局搜索,就能查看可选择的参数列表,选择好我们需要的工作模式

6.3、设置输出状态(可选)

HAL库驱动函数:设置输出状态 HAL_GPIO_WritePin() 和翻转输出状态 HAL_GPIO_TogglePin() 

先看设置输出状态 HAL_GPIO_WritePin()

/**
  * @brief  Sets or clears the selected data port bit.
  *
  * @note   This function uses GPIOx_BSRR register to allow atomic read/modify
  *         accesses. In this way, there is no risk of an IRQ occurring between
  *         the read and the modify access.
  *
  * @param  GPIOx where x can be (A..K) to select the GPIO peripheral for STM32F429X device or
  *                      x can be (A..I) to select the GPIO peripheral for STM32F40XX and STM32F427X devices.
  * @param  GPIO_Pin specifies the port bit to be written.
  *          This parameter can be one of GPIO_PIN_x where x can be (0..15).
  * @param  PinState specifies the value to be written to the selected bit.
  *          This parameter can be one of the GPIO_PinState enum values:
  *            @arg GPIO_PIN_RESET: to clear the port pin
  *            @arg GPIO_PIN_SET: to set the port pin
  * @retval None
  */
void HAL_GPIO_WritePin(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin, GPIO_PinState PinState);

第一个参数 GPIO_TypeDef  *GPIOx,上面已经介绍过,第二个参数 uint16_t GPIO_Pin,和初始化工作模式中的 Pin 选择的参数是一样的,第三个参数 GPIO_PinState PinState

/** 
  * @brief  GPIO Bit SET and Bit RESET enumeration 
  */
typedef enum
{
  GPIO_PIN_RESET = 0,
  GPIO_PIN_SET
}GPIO_PinState;

这是一个枚举类型,可选参数有 GPIO_PIN_SET(高电平)和 GPIO_PIN_RESET(低电平)

然后是翻转输出状态 HAL_GPIO_TogglePin()

/**
  * @brief  Toggles the specified GPIO pins.
  * @param  GPIOx Where x can be (A..K) to select the GPIO peripheral for STM32F429X device or
  *                      x can be (A..I) to select the GPIO peripheral for STM32F40XX and STM32F427X devices.
  * @param  GPIO_Pin Specifies the pins to be toggled.
  * @retval None
  */
void HAL_GPIO_TogglePin(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);

 第一个参数和第二个参数与 HAL_GPIO_WritePin() 完全一样,只是少了输出状态设置

6.4、读取输入状态(可选)

HAL库驱动函数:HAL_GPIO_ReadPin()

/**
  * @brief  Reads the specified input port pin.
  * @param  GPIOx where x can be (A..K) to select the GPIO peripheral for STM32F429X device or
  *                      x can be (A..I) to select the GPIO peripheral for STM32F40XX and STM32F427X devices.
  * @param  GPIO_Pin specifies the port bit to read.
  *         This parameter can be GPIO_PIN_x where x can be (0..15).
  * @retval The input port pin value.
  */
GPIO_PinState HAL_GPIO_ReadPin(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);

参数和上面一样,返回是一个枚举类型,有 GPIO_PIN_SET(高电平)和 GPIO_PIN_RESET(低电平),上面也介绍过

七、编程实战

7.1、点亮一个LED灯

main.c

#include "./SYSTEM/sys/sys.h"
#include "./SYSTEM/usart/usart.h"
#include "./SYSTEM/delay/delay.h"
#include "./BSP/LED/led.h"

int main(void)
{
    HAL_Init();                         // 初始化HAL库
    sys_stm32_clock_init(336, 8, 2, 7); // 设置时钟,168Mhz
    delay_init(168);                    // 延时初始化
    led_init();                         // 初始化LED

    while (1)
    {
        LED0(0); /* LED0 亮 */
        LED1(1); /* LED1 灭 */
        delay_ms(500);
        LED0(1); /* LED0 灭 */
        LED1(0); /* LED1 亮 */
        delay_ms(500);
    }
}

led.c

#include "./BSP/LED/led.h"

void led_init(void)
{
    GPIO_InitTypeDef gpio_init_struct;

    LED0_GPIO_CLK_ENABLE(); /* LED0时钟使能 */
    LED1_GPIO_CLK_ENABLE(); /* LED1时钟使能 */

    gpio_init_struct.Pin = LED0_GPIO_PIN;             /* LED0引脚 */
    gpio_init_struct.Mode = GPIO_MODE_OUTPUT_PP;      /* 推挽输出 */
    gpio_init_struct.Pull = GPIO_PULLUP;              /* 上拉 */
    gpio_init_struct.Speed = GPIO_SPEED_FREQ_HIGH;    /* 高速 */
    HAL_GPIO_Init(LED0_GPIO_PORT, &gpio_init_struct); /* 初始化LED0引脚 */

    gpio_init_struct.Pin = LED1_GPIO_PIN;             /* LED1引脚 */
    HAL_GPIO_Init(LED1_GPIO_PORT, &gpio_init_struct); /* 初始化LED1引脚 */

    LED0(1); /* 关闭 LED0 */
    LED1(1); /* 关闭 LED1 */
}

下面 LED0 和 LED1 接的 IO 口需要根据自己的硬件电路来修改

led.h

#ifndef __LED_H
#define __LED_H

#include "./SYSTEM/sys/sys.h"

/******************************************************************************************/
/* 引脚 定义 */

#define LED0_GPIO_PORT                  GPIOF
#define LED0_GPIO_PIN                   GPIO_PIN_9
#define LED0_GPIO_CLK_ENABLE()          do{ __HAL_RCC_GPIOF_CLK_ENABLE(); }while(0)             /* PF口时钟使能 */

#define LED1_GPIO_PORT                  GPIOF
#define LED1_GPIO_PIN                   GPIO_PIN_10
#define LED1_GPIO_CLK_ENABLE()          do{ __HAL_RCC_GPIOF_CLK_ENABLE(); }while(0)             /* PF口时钟使能 */

/******************************************************************************************/

/* LED端口定义 */
#define LED0(x)   do{ x ? \
                      HAL_GPIO_WritePin(LED0_GPIO_PORT, LED0_GPIO_PIN, GPIO_PIN_SET) : \
                      HAL_GPIO_WritePin(LED0_GPIO_PORT, LED0_GPIO_PIN, GPIO_PIN_RESET); \
                  }while(0)       /* LED0 = RED */

#define LED1(x)   do{ x ? \
                      HAL_GPIO_WritePin(LED1_GPIO_PORT, LED1_GPIO_PIN, GPIO_PIN_SET) : \
                      HAL_GPIO_WritePin(LED1_GPIO_PORT, LED1_GPIO_PIN, GPIO_PIN_RESET); \
                  }while(0)       /* LED1 = GREEN */

/* LED取反定义 */
#define LED0_TOGGLE()    do{ HAL_GPIO_TogglePin(LED0_GPIO_PORT, LED0_GPIO_PIN); }while(0)       /* LED0 = !LED0 */
#define LED1_TOGGLE()    do{ HAL_GPIO_TogglePin(LED1_GPIO_PORT, LED1_GPIO_PIN); }while(0)       /* LED1 = !LED1 */

/******************************************************************************************/
/* 外部接口函数*/
void led_init(void);                                                                            /* 初始化 */

#endif

7.2、通过一个按键控制一个LED灯亮灭

由于按键按下和松开时会发生抖动

需要加入软件消抖:通过延时跳过抖动的时间段,再判断IO输入电平 

 main.c

#include "./SYSTEM/sys/sys.h"
#include "./SYSTEM/usart/usart.h"
#include "./SYSTEM/delay/delay.h"
#include "./BSP/LED/led.h"
#include "./BSP/KEY/key.h"

int main(void)
{
    uint8_t key;

    HAL_Init();                         // 初始化HAL库
    sys_stm32_clock_init(336, 8, 2, 7); // 设置时钟,168Mhz
    delay_init(168);                    // 延时初始化
    led_init();                         // 初始化LED
    key_init();                         /* 初始化按键 */
    LED0(0);                            /* 先点亮红灯 */

    while (1)
    {
        key = key_scan(0); /* 得到键值 */

        if (key)
        {
            switch (key)
            {
            case KEY0_PRES:    /* 控制LED0(RED)翻转 */
                LED0_TOGGLE(); /* LED0状态取反 */
                break;

            case KEY1_PRES:    /* 控制LED1(GREEN)翻转 */
                LED1_TOGGLE(); /* LED1状态取反 */
                break;

            case WKUP_PRES:    /* 同时控制LED0, LED1翻转 */
                LED0_TOGGLE(); /* LED0状态取反 */
                LED1_TOGGLE(); /* LED1状态取反 */
                break;

            default:
                break;
            }
        }
        else
        {
            delay_ms(10);
        }
    }
}

 key.c

#include "./BSP/KEY/key.h"
#include "./SYSTEM/delay/delay.h"

void key_init(void)
{
    GPIO_InitTypeDef gpio_init_struct; /* GPIO配置参数存储变量 */
    KEY0_GPIO_CLK_ENABLE();            /* KEY0时钟使能 */
    KEY1_GPIO_CLK_ENABLE();            /* KEY1时钟使能 */
    WKUP_GPIO_CLK_ENABLE();            /* WKUP时钟使能 */

    gpio_init_struct.Pin = KEY0_GPIO_PIN;             /* KEY0引脚 */
    gpio_init_struct.Mode = GPIO_MODE_INPUT;          /* 输入 */
    gpio_init_struct.Pull = GPIO_PULLUP;              /* 上拉 */
    gpio_init_struct.Speed = GPIO_SPEED_FREQ_HIGH;    /* 高速 */
    HAL_GPIO_Init(KEY0_GPIO_PORT, &gpio_init_struct); /* KEY0引脚模式设置,上拉输入 */

    gpio_init_struct.Pin = KEY1_GPIO_PIN;             /* KEY1引脚 */
    gpio_init_struct.Mode = GPIO_MODE_INPUT;          /* 输入 */
    gpio_init_struct.Pull = GPIO_PULLUP;              /* 上拉 */
    gpio_init_struct.Speed = GPIO_SPEED_FREQ_HIGH;    /* 高速 */
    HAL_GPIO_Init(KEY1_GPIO_PORT, &gpio_init_struct); /* KEY1引脚模式设置,上拉输入 */

    gpio_init_struct.Pin = WKUP_GPIO_PIN;             /* WKUP引脚 */
    gpio_init_struct.Mode = GPIO_MODE_INPUT;          /* 输入 */
    gpio_init_struct.Pull = GPIO_PULLDOWN;            /* 下拉 */
    gpio_init_struct.Speed = GPIO_SPEED_FREQ_HIGH;    /* 高速 */
    HAL_GPIO_Init(WKUP_GPIO_PORT, &gpio_init_struct); /* WKUP引脚模式设置,下拉输入 */
}

uint8_t key_scan(uint8_t mode)
{
    static uint8_t key_up = 1; /* 按键按松开标志 */
    uint8_t keyval = 0;

    if (mode)
        key_up = 1; /* 支持连按 */

    if (key_up && (KEY0 == 0 || KEY1 == 0 || WK_UP == 1)) /* 按键松开标志为1, 且有任意一个按键按下了 */
    {
        delay_ms(10); /* 去抖动 */
        key_up = 0;

        if (KEY0 == 0)
            keyval = KEY0_PRES;

        if (KEY1 == 0)
            keyval = KEY1_PRES;

        if (WK_UP == 1)
            keyval = WKUP_PRES;
    }
    else if (KEY0 == 1 && KEY1 == 1 && WK_UP == 0) /* 没有任何按键按下, 标记按键松开 */
    {
        key_up = 1;
    }

    return keyval; /* 返回键值 */
}

下面 KEY0、KEY1 和 WKUP 接的 IO 口需要根据自己的硬件电路来修改 

 key.h

#ifndef __KEY_H
#define __KEY_H

#include "./SYSTEM/sys/sys.h"

/******************************************************************************************/
/* 引脚 定义 */

#define KEY0_GPIO_PORT                  GPIOB
#define KEY0_GPIO_PIN                   GPIO_PIN_9
#define KEY0_GPIO_CLK_ENABLE()          do{ __HAL_RCC_GPIOB_CLK_ENABLE(); }while(0)   /* PB口时钟使能 */

#define KEY1_GPIO_PORT                  GPIOB
#define KEY1_GPIO_PIN                   GPIO_PIN_8
#define KEY1_GPIO_CLK_ENABLE()          do{ __HAL_RCC_GPIOB_CLK_ENABLE(); }while(0)   /* PB口时钟使能 */

#define WKUP_GPIO_PORT                  GPIOA
#define WKUP_GPIO_PIN                   GPIO_PIN_0
#define WKUP_GPIO_CLK_ENABLE()          do{ __HAL_RCC_GPIOA_CLK_ENABLE(); }while(0)   /* PA口时钟使能 */

/******************************************************************************************/

#define KEY0        HAL_GPIO_ReadPin(KEY0_GPIO_PORT, KEY0_GPIO_PIN)     /* 读取KEY0引脚 */
#define KEY1        HAL_GPIO_ReadPin(KEY1_GPIO_PORT, KEY1_GPIO_PIN)     /* 读取KEY1引脚 */
#define WK_UP       HAL_GPIO_ReadPin(WKUP_GPIO_PORT, WKUP_GPIO_PIN)     /* 读取WKUP引脚 */

#define KEY0_PRES    1              /* KEY0按下 */
#define KEY1_PRES    2              /* KEY1按下 */
#define WKUP_PRES    4              /* KEY_UP按下(即WK_UP) */

void key_init(void);                /* 按键初始化函数 */
uint8_t key_scan(uint8_t mode);     /* 按键扫描函数 */

#endif
  • 22
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

HZU_Puzzle

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值