STM32HAL-GPIO基础理论以及函数应用

目录

IO端口的硬件结构

8种输出模式:

​编辑

HAL库中常见的GPIO函数以及用法:

1.GPIO的初始化

Mode:

Pull:

Speed:

2.HAL_GPIO_DeInit

3.HAL_GPIO_ReadPin

4.HAL_GPIO_WritePin

5.HAL_GPIO_TogglePin

7.HAL_GPIO_EXTI_Callback

8. __HAL_RCC_GPIOX_CLK_ENABLE();  

实战特训:

1.点亮LED

(a)LED灯的初始化

    (b)延时函数控制灯的亮变

2.按键输入实验:

(a)按键key.h

(b)key.c

(c)beep.c蜂鸣器

(d)beep.c

(e)main.c

原理图:STM32 GPIO 详解-CSDN博客



IO端口的硬件结构

保护二极管,保护接入电路的电压不会超过可承受的范围

上下拉电阻,通常阻值在 30-50KΩ ,是一种弱上下拉(电流很小,不具备驱动能力)

施密特触发器,可以使得非方波信号转为方波信号

   施密特触发器就是一种整形电路,可以将非标准方波整形成方波,特点如下当输入电压高于正向阈值电压,输出为高;当输入电压低于负向阈值电压,输出为低;当输入在正负向阈值电压之间,输出不改变

P-MOS & N-MOS 管

G是栅极,S是源极,D是漏极
对于 P-MOS:Vgs<0,导通
对于 N-MOS:Vgs>0,导通

8种输出模式:

HAL库中常见的GPIO函数以及用法:

1.GPIO的初始化
/** @defgroup GPIO_mode_define GPIO mode define
  * @brief GPIO Configuration Mode 
  *        Elements values convention: 0xX0yz00YZ
  *           - X  : GPIO mode or EXTI Mode
  *           - y  : External IT or Event trigger detection 
  *           - z  : IO configuration on External IT or Event
  *           - Y  : Output type (Push Pull or Open Drain)
  *           - Z  : IO Direction mode (Input, Output, Alternate or Analog)
  * @{
  */
#define  GPIO_MODE_INPUT                        MODE_INPUT                                               /*!< Input Floating Mode                   */
#define  GPIO_MODE_OUTPUT_PP                    (MODE_PP | MODE_OUTPUT)                                  /*!< Output Push Pull Mode                 */
#define  GPIO_MODE_OUTPUT_OD                    (MODE_OD | MODE_OUTPUT)                                  /*!< Output Open Drain Mode                */
#define  GPIO_MODE_AF_PP                        (MODE_PP | MODE_AF)                                      /*!< Alternate Function Push Pull Mode     */
#define  GPIO_MODE_AF_OD                        (MODE_OD | MODE_AF)                                      /*!< Alternate Function Open Drain Mode    */

#define  GPIO_MODE_ANALOG                       MODE_ANALOG                                              /*!< Analog Mode  */

#define  GPIO_MODE_IT_RISING                    (EXTI_MODE | GPIO_MODE_IT | RISING_EDGE)                 /*!< External Interrupt Mode with Rising edge trigger detection          */
#define  GPIO_MODE_IT_FALLING                   (EXTI_MODE | GPIO_MODE_IT               | FALLING_EDGE)  /*!< External Interrupt Mode with Falling edge trigger detection         */
#define  GPIO_MODE_IT_RISING_FALLING            (EXTI_MODE | GPIO_MODE_IT | RISING_EDGE | FALLING_EDGE)  /*!< External Interrupt Mode with Rising/Falling edge trigger detection  */

#define  GPIO_MODE_EVT_RISING                   (EXTI_MODE | GPIO_MODE_EVT | RISING_EDGE)                /*!< External Event Mode with Rising edge trigger detection               */
#define  GPIO_MODE_EVT_FALLING                  (EXTI_MODE | GPIO_MODE_EVT               | FALLING_EDGE) /*!< External Event Mode with Falling edge trigger detection              */
#define  GPIO_MODE_EVT_RISING_FALLING           (EXTI_MODE | GPIO_MODE_EVT | RISING_EDGE | FALLING_EDGE) /*!< External Event Mode with Rising/Falling edge trigger detection       */

void led_init(void)
{
    GPIO_InitTypeDef gpio_init_struct; //结构体
    
    __HAL_RCC_GPIOF_CLK_ENABLE();   //GPIOF时钟使能                    

    gpio_init_struct.Pin = GPIO_PIN_9;                 
    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(GPIOF, &gpio_init_struct);           

    gpio_init_struct.Pin = GPIO_PIN_10;               
    HAL_GPIO_Init(GPIOF, &gpio_init_struct);            

    HAL_GPIO_WritePin(GPIOF, GPIO_PIN_9, GPIO_PIN_SET); 
    HAL_GPIO_WritePin(GPIOF, GPIO_PIN_10, GPIO_PIN_SET); 
}

其结构体(F1没有最后一个)

/** * @brief GPIO Init结构定义 */
typedef struct 
{ 
    uint32_t Pin; //指定要配置的GPIO引脚,该参数可以是GPIO_pins的任意值 */ 
 
    uint32_t Mode; //指定所选引脚的工作模式。该参数可以是GPIO_mode的值 */ 
 
    uint32_t Pull; //指定所选引脚的上拉或下拉激活。该参数可以是GPIO_pull的值 */ 
 
    uint32_t Speed; //指定所选引脚的速度。该参数可以是GPIO_speed_define的值 */ 
 
    uint32_t Alternate;//外设要连接到所选引脚。参数可以是GPIO_Alternate_function_selection的值
}GPIO_InitTypeDef;
Mode:

GPIO_MODE_INPUT:输入模式

GPIO_MODE_OUTPUT_PP:输出推挽

GPIO_MODE_OUTPUT_OD:输出开漏

GPIO_MODE_AF_PP:推挽复用
GPIO_MODE_AF_OD:开漏复用

GPIO_MODE_ANALOG:模拟

Pull:

GPIO_NOPULL:没有上拉或则下拉激活

GPIO_PULLUP:上拉

GPIO_PULLDOWN:下拉

Speed:

GPIO_SPEED_FREQ_LOW:                             2MHz

GPIO_SPEED_FREQ_MEDIUM                        12.5MHz~50MHz

GPIO_SPEED_FREQ_HIGH                              25MHz~100MHz

GPIO_SPEED_FREQ_VERY_HIGH                  50MHz~200MHz

2.HAL_GPIO_DeInit


HAL_GPIO_Init能够实现对GPIO的初始化,那么HAL_GPIO_DeInit就是与其相反的操作,能够将GPIO口恢复至默认状态,即各个寄存器复位时的值

void HAL_GPIO_DeInit(GPIO_TypeDef *GPIOx, uint32_t GPIO_Pin)
例:HAL_GPIO_DeInit(GPIO, GPIO_PIN_10);
3.HAL_GPIO_ReadPin

读取我们想要知道的引脚的电平状态、函数返回值类型为GPIO_PinState  =  0或1

GPIO_PinState HAL_GPIO_ReadPin(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin)
例:pin_State = HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_9);
4.HAL_GPIO_WritePin

给某个引脚写0或1,GPIO_PIN_RESET 也可写成0;GPIO_PIN_RSET 也可写成1

void HAL_GPIO_WritePin(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin, GPIO_PinState PinState)
例:HAL_GPIO_WritePin(GPIOF, GPIO_PIN_9,GPIO_PIN_RESET)
5.HAL_GPIO_TogglePin

反转电平

void HAL_GPIO_TogglePin(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin)
例:HAL_GPIO_TogglePin(GPIOF, GPIO_PIN_9);

6.HAL_GPIO_EXTI_IRQHandler

      这个函数是外部中断服务函数,用来响应外部中断的触发,函数实体里面有两个功能,1是清除中断标记位,2是调用下面要介绍的回调函数。如果使用CUbeMX生产,无需自己手写,直需要在main.c中重新定义相应的回调函数即可

void HAL_GPIO_EXTI_IRQHandler(uint16_t GPIO_Pin)
例:HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_3);//配置好CubeMX后,自动生产

7.HAL_GPIO_EXTI_Callback

中断回调函数,可以理解为中断函数具体要响应的动作。简而言之就是发生中断就会调用这个函数,需要我们重写

__weak void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)

8. __HAL_RCC_GPIOX_CLK_ENABLE();  

串口时钟使能

 __HAL_RCC_GPIOF_CLK_ENABLE();  

Cubemx配置:

CubeMX使用教程(3)——如何配置GPIO_cubemx gpio 输入输出-CSDN博客

实战特训:

1.点亮LED

此为共阳极,因此可以为推挽也可以为开漏

(a)LED灯的初始化
void led_init(void)
{
    GPIO_InitTypeDef gpio_init_struct;
    
    __HAL_RCC_GPIOF_CLK_ENABLE();                       

    gpio_init_struct.Pin = GPIO_PIN_9;                 
    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(GPIOF, &gpio_init_struct);           

    gpio_init_struct.Pin = GPIO_PIN_10;               
    HAL_GPIO_Init(GPIOF, &gpio_init_struct);            

    HAL_GPIO_WritePin(GPIOF, GPIO_PIN_9, GPIO_PIN_SET); 
    HAL_GPIO_WritePin(GPIOF, GPIO_PIN_10, GPIO_PIN_SET); 
}
    (b)延时函数控制灯的亮变
#include "./SYSTEM/sys/sys.h"
#include "./SYSTEM/usart/usart.h"
#include "./SYSTEM/delay/delay.h"


void led_init(void);                    /* LED初始化函数声明 */

int main(void)
{
    HAL_Init();                         /* 初始化HAL库 */
    sys_stm32_clock_init(336, 8, 2, 7); /* 设置时钟,168Mhz */
    delay_init(168);                    /* 延时初始化 */
    led_init();                         /* 初始化LED */
    
    while(1)
    {
        HAL_GPIO_WritePin(GPIOF,GPIO_PIN_9,GPIO_PIN_RESET);     /* LED0 亮 */
        HAL_GPIO_WritePin(GPIOF,GPIO_PIN_10,GPIO_PIN_SET);      /* LED1 灭 */
        delay_ms(500);
        HAL_GPIO_WritePin(GPIOF,GPIO_PIN_9,GPIO_PIN_SET);       /* LED0 灭 */
        HAL_GPIO_WritePin(GPIOF,GPIO_PIN_10,GPIO_PIN_RESET);    /* LED1 亮 */
        delay_ms(500);
    }
}
2.按键输入实验:

(a)按键key.h
#ifndef __KEY_H
#define __KEY_H

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


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

#define KEY0_GPIO_PORT                  GPIOE
#define KEY0_GPIO_PIN                   GPIO_PIN_4
#define KEY0_GPIO_CLK_ENABLE()          do{ __HAL_RCC_GPIOE_CLK_ENABLE(); }while(0)   /* PE口时钟使能 */

#define KEY1_GPIO_PORT                  GPIOE
#define KEY1_GPIO_PIN                   GPIO_PIN_3
#define KEY1_GPIO_CLK_ENABLE()          do{ __HAL_RCC_GPIOE_CLK_ENABLE(); }while(0)   /* PE口时钟使能 */

#define KEY2_GPIO_PORT                  GPIOE
#define KEY2_GPIO_PIN                   GPIO_PIN_2
#define KEY2_GPIO_CLK_ENABLE()          do{ __HAL_RCC_GPIOE_CLK_ENABLE(); }while(0)   /* PE口时钟使能 */

#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 KEY2        HAL_GPIO_ReadPin(KEY2_GPIO_PORT, KEY2_GPIO_PIN)     /* 读取KEY2引脚 */
#define WK_UP       HAL_GPIO_ReadPin(WKUP_GPIO_PORT, WKUP_GPIO_PIN)     /* 读取WKUP引脚 */


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

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

#endif
(b)key.c
#include "./BSP/KEY/key.h"
#include "./SYSTEM/delay/delay.h"


/**
 * @brief       按键初始化函数
 * @param       无
 * @retval      无
 */
void key_init(void)
{
    GPIO_InitTypeDef gpio_init_struct;                          /* GPIO配置参数存储变量 */
    KEY0_GPIO_CLK_ENABLE();                                     /* KEY0时钟使能 */
    KEY1_GPIO_CLK_ENABLE();                                     /* KEY1时钟使能 */
    KEY2_GPIO_CLK_ENABLE();                                     /* KEY2时钟使能 */
    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 = KEY2_GPIO_PIN;                       /* KEY2引脚 */
    gpio_init_struct.Mode = GPIO_MODE_INPUT;                    /* 输入 */
    gpio_init_struct.Pull = GPIO_PULLUP;                        /* 上拉 */
    gpio_init_struct.Speed = GPIO_SPEED_FREQ_HIGH;              /* 高速 */
    HAL_GPIO_Init(KEY2_GPIO_PORT, &gpio_init_struct);           /* KEY2引脚模式设置,上拉输入 */

    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引脚模式设置,下拉输入 */

}

/**
 * @brief       按键扫描函数
 * @note        该函数有响应优先级(同时按下多个按键): WK_UP > KEY2 > KEY1 > KEY0!!
 * @param       mode:0 / 1, 具体含义如下:
 *   @arg       0,  不支持连续按(当按键按下不放时, 只有第一次调用会返回键值,
 *                  必须松开以后, 再次按下才会返回其他键值)
 *   @arg       1,  支持连续按(当按键按下不放时, 每次调用该函数都会返回键值)
 * @retval      键值, 定义如下:
 *              KEY0_PRES, 1, KEY0按下
 *              KEY1_PRES, 2, KEY1按下
 *              KEY2_PRES, 3, KEY2按下
 *              WKUP_PRES, 4, 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 || KEY2 == 0 || WK_UP == 1))  /* 按键松开标志为1, 且有任意一个按键按下了 */
    {
        delay_ms(10);           /* 去抖动 */
        key_up = 0;

        if (KEY0 == 0)  keyval = KEY0_PRES;

        if (KEY1 == 0)  keyval = KEY1_PRES;

        if (KEY2 == 0)  keyval = KEY2_PRES;

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

    return keyval;              /* 返回键值 */
}
(c)beep.c蜂鸣器

#ifndef __BEEP_H
#define __BEEP_H

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


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

#define BEEP_GPIO_PORT                  GPIOF
#define BEEP_GPIO_PIN                   GPIO_PIN_8
#define BEEP_GPIO_CLK_ENABLE()          do{ __HAL_RCC_GPIOF_CLK_ENABLE(); }while(0)         /* PF口时钟使能 */

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

/* 蜂鸣器控制 */
#define BEEP(x)         do{ x ? \
                            HAL_GPIO_WritePin(BEEP_GPIO_PORT, BEEP_GPIO_PIN, GPIO_PIN_SET) : \
                            HAL_GPIO_WritePin(BEEP_GPIO_PORT, BEEP_GPIO_PIN, GPIO_PIN_RESET); \
                        }while(0)

/* BEEP状态翻转 */
#define BEEP_TOGGLE()   do{ HAL_GPIO_TogglePin(BEEP_GPIO_PORT, BEEP_GPIO_PIN); }while(0)    /* BEEP = !BEEP */

void beep_init(void);   /* 初始化蜂鸣器 */

#endif
(d)beep.c

#include "./BSP/BEEP/beep.h"


/**
 * @brief       初始化BEEP相关IO口, 并使能时钟
 * @param       无
 * @retval      无
 */
void beep_init(void)
{
    GPIO_InitTypeDef gpio_init_struct;
    BEEP_GPIO_CLK_ENABLE();                             /* BEEP时钟使能 */

    gpio_init_struct.Pin = BEEP_GPIO_PIN;               /* 蜂鸣器引脚 */
    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(BEEP_GPIO_PORT, &gpio_init_struct);   /* 初始化蜂鸣器引脚 */

    BEEP(0);                                            /* 关闭蜂鸣器 */
}
(e)main.c
#include "./SYSTEM/sys/sys.h"
#include "./SYSTEM/usart/usart.h"
#include "./SYSTEM/delay/delay.h"
#include "./BSP/LED/led.h"
#include "./BSP/BEEP/beep.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 */
    beep_init();                            /* 初始化蜂鸣器 */
    key_init();                             /* 初始化按键 */
    LED0(0);                                /* 先点亮红灯 */

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

        if (key)
        {
            switch (key)
            {
                case WKUP_PRES:             /* 控制蜂鸣器 */
                    BEEP_TOGGLE();          /* BEEP状态取反 */
                    break;

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

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

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

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

原理图:STM32 GPIO 详解-CSDN博客

  • 13
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值