STM32L0XX---HAL库---GPIO笔记

STM32L0XX_HAL_GPIO.C
// @file stm32l0xx_hal_gpio.c
// 文件 stm32l0xx_hal_gpio.c
// @author MCD Application Team
// 作者 MCD应用团队
// @brief GPIO HAL module driver.
// 简明的 GPIO HAL 模块驱动

// This fiel provides firmware functions to manage the following functionalities 
// of the General Purpose Input/Output(GPIO) peripheral:
// 这个文件提供了管理通用输入/输出GPIO外设的固件函数
// 初始化和反初始化函数
// +IO operation functions
// IO操作函数

// Copyright (c) 2016 STMicroelectronics.
// 版权所有
// All rights reserved.
// 保留所有权利
// This software is licensed under terms that can be found in the LICENSE file in 
// the root directory of this software component.
// 本软件是根据本软件组件根目录的LICENSE文件中的条款获得许可的。
// If no LICENSE file comes with this software,it is provided AS-IS.
// 如果此软件未附带许可证文件,则按原样提供。

// GPIO Peripheral features 
// GPIO外设功能 (特征 特色 特点 ; 以...为特色)
// Each port bit of the general-purpose IO (GPIO) ports can be individually configured 
// by software in several modes:
// 通用IO(GPIO)端口的每个端口位可以通过软件以下面的模式单独配置:

// Input mode
// 输入模式
// Analog mode
// 模式模式
// Output mode
// 输出模式
// Alternate function mode
// 复用功能模式
// External interrupt/event lines
// 外部中断/事件线

// During and just after reset,the alternate functions and external interrupt lines are not 
// active and the IO ports are configured in input floating mode.
// 在重置期间或重置后,备用功能和外设中断线不起作用并且IO端口被配置为输入浮空模式。

// All GPIO pins have weak internal pull-up and pull-down resistors,which can be activated or not.
// 所有GPIO引脚都有弱的内部上拉和下拉电阻器,可以选择激活或者不激活。

// In Output or Alternate mode ,each IO can be configured on open-drain or push-pull type and the IO
// speed can be selected depending on the VDD value.
// 在输出或者复用模式下,每个IO可以配置为开漏或者推完模式,IO速度可以根据VDD值进行选择。

// The microcontroller IO pins are connected to onboard peripherals/modules through a multiplexer that
// allows only one peripheral alternate function (AF) connected to an IO pin at a time.In this way,there
// can be no conflict betewwn peripherals sharing the same IO pin.
// 微控制器IO引脚通过多路复用器链接到板载外设,一次只允许一个外设复用功能启用,通过这种共享同一IO引脚的两个外设
// 之间不会发生冲突。

// All ports have external interrupt/event capability.To use external interrupt lines,the port must be 
// configured in input mode.All available GPIO pins are connected to the 16 external interrupt/event lines
// from EXTI0 to EXTI15.
// 所有的端口都具有外部中断/事件能力。要使用外部中断线,端口必须配置为输入模式。所有可用的GPIO引脚都链接到16条外部中断/
// 时间线,从EXTI0到EXTI15。

// The external interrupt/event controller consists of up to 28 edge detectors (16 lines are connected to GPIO)
// for generating event/interrupt requests each input line can be independently configured to select the type)
// (interrupt or event) and the corresponding trigger event (rising or falling or both).Each lines can also
// be masked independently.
// 外部中断/事件控制器由多大28个边缘检测器组成,(16条线路连接到GPIO),用于生成中断/事件请求(每条输入线可以独立配置以选择
// 类型(中断或事件)以及相应的触发事件(上升或下降或两者)。每条线都可以被独立的屏蔽。

// How to use this driver

// Enable the GPIO IOPORT clock using the following function :__HAL_RCC_GPIOx_CLK_ENABLE().
// 使用以下函数启用GPIO IOPORT时钟

// Configure the GPIO pin(s) using HAL_GPIO_Init().
// 使用HAL_GPIO_Init()配置GPIO引脚

// Configure the IO mode using "Mode" member from GPIO_InitTypeDef structure
// 使用GPIO_InitTypeDef结构中的"mode"成员配置IO模式

// Activate Pull-up,Pull-down resistor using "Pull" member from GPIO_InitTypeDef structure
// 使用GPIO_Init_TypeDef结构中的"pull"成员激活上拉、下拉电阻器

// resistor:电阻器

// In case of Output or alternate function mode selection: the speed is configured through "Speed" 
// member from GPIO_InitTypeDef structure.
// 在选择输出或复用功能模式的情况下:可以使用GPIO_InitTypeDef结构中的速度成员。

// In alternate mode is selection,the alternate function connected to the IO is configured through
// "Alternate" member from GPIO_InitTypeDef structure.
// 在选择复用功能时,通过GPIO_InitTypeDef结构体中的“复用”成员配置连接到IO的复用功能。

// Analog mode is required when a pin is to be used as ADC channel or DAC output.
// 当引脚用作ADC通道或DAC输出时,需要使用模拟模式。

// In case of external interrupt/event selection the "Mode" member from GPIO_InitTypeDef structure select
// the type (interrupt or event) and the corresponding trigger event (rising or falling or both).
// 在外部中断/事件模式的情况下,GPIO_InitTypeDef结构体中的"模式"成员选择类型(中断/事件)和相应的触发事件(上升或
// 下降或两者兼有)。

// In case of external interrupt/event mode selection, configure NVIC IRQ priority mapped to the EXTI line unsing
// HAL_NVIC_SetPriority() and enable it using HAL_NVIC_EnableIRQ.
// 在外部中断/事件模式选择下,配置映射到EXIT线路的NVIC IRQ优先级可以使用HAL_NVIC_SetPriority()并使用HAL_NVIC_EnableIRQ
// 启用它。

// HAL_GPIO_DeInit allows to set register values to their reset value.This function is also to be used when unconfiguring
// pin which was used as an external interrupt or in event mode.That is the only way to reset the corresponding bit in 
// EXIT & SYSCFG registers.
// HAL_GPIO_DeInit允许将寄存器值设置为其重置值。当取消对用作外部中断或事件模式的引脚的配置时,也可以使用此功能。这是重置EXIT和SYSCFG
// 寄存器中的响应位。

// To get the level of a pin configured in input mode use HAL_GPIO_ReadPin().
// 要获得在输入模式下配置的引脚的电平,请使用HAL_GPIO_ReadPin()函数。

// To set/reset the level of a pin configured in output mode use HAL_GPIO_WritePin()/HAL_GPIO_TogglePin().
// 要置位/复位在输出模式下配置的引脚的电平,请使用HAL_GPIO_WritePin()/HAL_GPIO_TogglePin()这两个函数。

// To lock pin configuration until next reset use HAL_GPIO_LockPin().
// 要锁定引脚配置直到下一次重置,请使用HAL_GPIO_LockPin()函数。

// During and just afer reset.the alternate functions are not activ and the GPIO pins are configured in input floating mode(except JTAG
// pins).
// 重置期间或之后,复用功能不起作用,GPIO引脚配置为输入浮空模式(JTAG引脚除外)。

// The LSE oscillator pins OSC32_IN and OSC32_OUT can be used as general purpose(PC14 and PC15,respectively) when the LSE oscillator is
// off.The LSE has priority over the GPIO function.
// 当LSE振荡器关闭时,LSE振荡器引脚OSC32_IN and OSC32_OUT可以用作通用GPIO(PC14和PC15)。LSE优先于GPIO功能。

// The HSE oscillator pins OSC_IN/OSC_OUT can be used as general purpose PH0 and PH1,respectively,when the HSE oscillator is off.
// The HSE has priority over the GPIO function.
// 当HSE 振荡器关闭时,HSE震荡器引脚OSC_IN/OSC_OUT可以分别用作通用PH0和PH1。HSE优先于GPIO功能。

#include "stm32l0xx_hal.h"
#ifdef HAL_GPIO_MODULE_ENABLE

void HAL_GPIO_Init(GPIO_TypeDef *GPIOx,GPIO_InitTypeDef *GPIO_Init)
{
    uint32_t positon = 0x00U;
    uint32_t iocurrent = 0x00U;
    uint32_t tem = 0x00U;

    assert_param(IS_GPIO_MODE(GPIO_Init->Mode));
    assert_param(IS_GPIO_PIN_AVAILABLE(GPIOx,(GPIO_Init->Pin)));
    // AVAILABLE:可获得的;可购得的;可找到的;有空的
    while(((GPIO_Init->Pin) >> position) != 0)
    // position:位置;地方;恰当位置;处境;观点;地位;角色;安装;安置
    {
        iocurrent = (GPIO_Init -> Pin) & (1U << positon);
        // current:现在的;当前的;流通的;流行的;电流;气流;潮流
        if(iocurrent)
        {
            //在选择输出或复用功能模式的情况下
            if(((GPIO_Init -> Mode & GPIO_MODE) == MODE_OUTPUT) || ((GPIO_Init -> Mode & GPIO_MODE) == MODE_AF))
            {
                // 检查速度参数
                assert_param(IS_GPIO_SPEED(GPIO_Init -> Speed));
                // 配置IO速度
                temp = GPIOx -> OSPEEDR;
                temp &= ~(GPIO_OSPEEDER_OSPEED0 << (position * 2U));
                // OSPEEDER:调速器
                temp |= (GPIO_Init -> Speed << (positon * 2U));
                GPIOx -> OSPEEDER = temp;

                // 配置IO输出类型
                temp = GPIOx -> OTYPER;
                // OTYPER:OUT PUT TYPER
                temp &= ~(GPIO_OTYPER_OT_O << position);
                temp |= (((GPIO_Init -> Mode & OUTPUT_TYPE) >> OUTPUT_TYPE_Pos) << positon);
                GPIOx -> OTYPER = temp;
            }

            if((GPIO_Init -> Mode & GPIO_MODE) != MODE_ANALOG)
            {
            //检查Pull参数
            assert_param(IS_GPIO_PULL(GPIO_Init->Pull));
            // 激活当前IO的上下拉电阻器
            temp = GPIOx -> PUPDR;
            temp &= ~(GPIO_PUPDR_PUPDO << (position * 2U));
            temp |= ((GPIO_Init -> Pull) << (position * 2U));
            GPIOx -> PUPDR = temp;
            }

            // 在选择复用功能模式的情况下
            if((GPIO_Init -> Mode & GPIO_MODE) == MODE_AF)
            {
                //检查复用功能参数
                assert_param(IS_GPIO_AF_INSTANCE(GPIOx));
                // INSTANCE:实例
                assert_param(IS_GPIO_AF(GPIO_Init -> Alternate));
                // Alternate:候补;代理人;交替

            //配置与当前IO映射的复用功能
            temp = GPIOx -> AFR[position >> 3U];
            temp &= ~(0xFUL << ((uint32_t)(position & 0x07UL) * 4U));
            temp |= ((uint32_t) (GPIO_Init -> Alternate) << (((uint32_t) position &(uint32_t)0x07U) * 4U));
            GPIOx -> AFR[position >> 3U] = temp;

            // 配置IO方向模式(输入、输出、备用或模拟)
            temp = GPIOx -> MODER;
            temp &= ~(GPIO_MODER_MODE0 << (position * 2U));
            temp |= ((GPIO_Init -> Mode & GPIO_MODE) << (position * 2U));
            GPIOx -> MODER = temp;

            // EXTI模式配置
            // 为当前IO配置外部中断或事件
            if((GPIO_Init -> Mode & EXTI_MODE) != 0x00U)
            {
                // 启用SYSCFG时钟
                __HAL_RCC_SYSCFG_CLK_ENABLE();

                temp = SYSCFG -> EXTICR[position >>2U];
                CLEAR_BIT(temp,(0x0FUL) << (4U * (position & 0x03U)));
                SET_BIT(temp,(GPIO_GET_INDEX(GPIOx)) << (4 * (position & 0x03U));
                SYSCFG->EXTICR[position >> 2U] = temp;

                // 清除上升下降边缘配置
                temp = EXTI->RTSR;
                temp &= ~((uint32_t)iocurrent);
                if((GPIO_Init->Mode & TRIGGER_RISING) != 0x00U);
                {
                    temp |= iocurrent;
                }
                EXTI->RTSR = temp;
                temp = EXTI->FTSR;
                // FTSR:下降沿触发
                // RTSR:上升沿触发
                temp &= !((uint32_t)iocurrent);
                if((GPIO_Init->Mode & trigger_falling) != 0x00U)
                {
                    temp |= iocurrent;
                }
                EXTI->FTSR = temp;

                temp  = EXTI->EMR;

                temp &= ~((uint32_t)iocurrent);
                if((GPIO_Init->Mode & EXTI_EVT) != 0x00U)
                {
                    temp |= iocurrnet;
                }
                EXTI->EMR = temp;

                // 清楚EXTI线路配置
                temp = EXTI->IMR;
                temp &= ~((uint32_t)iocurrent);
                if((GPIO_Init->Mode & EXTI_IT) != 0x00U)
                {
                    temp |= iocurrent;
                }
                EXTI->IMR = temp;
            }
        
        }
        position++;
    }  
}

void HAL_GPIO_DeInit(GPIO_TypeDef *GPIOx,uint32_t GPIO_Pin)
{
    uint32_t position = 0x00U;
    uint32_t iocurrent = 0x00U;
    uint32_t tmp = 0x00U;

    // 检查参数
    assert_param(IS_GPIO_PIN_AVAILABLE(GPIOx,GPIO_Pin));

    // 配置端口引脚
    while((GPIO_Pin >> position) != 0)
    {
        // 获取IO位置
        iocurrent = (GPIO_Pin) & (1U << position);

        if(iocurrent)
        {
            // EXTI模式配置
            // 清楚当前IO的外部中断或事件
            tmp = SYSCFG->EXTICR[position >> 2U];
            tmp &= ((0x0FUL) << (4U * (position & 0x03U)));
            if(tmp == (GPIO_GET_INDEX(GPIOx) << (4U * (position & 0x03U))))
            {
                // 清楚EXTI线路配置
                EXTI->IMR &= ~((uint32_t)iocurrent);
                EXTI->EMR &= ~((uint32_t)iocurrent);

                // 清楚上升或下降边缘配置
                EXTI->FTSR &= ~((uint32_t)iocurrent);
                EXTI->RTSR &= ~((uint32_t)iocurrent);

                tmp = (0x0FUL) << (4U * (position & 0x03U));
                SYSCFG->EXTICR[position >> 2U] &= ~tmp;
            }

            // GPIO模式配置
            // 在模拟模式下配置IO方向(重置状态)
            GPIOx->MODER |= (GPIO_MODE_ANALOG << (position *  2U));

            // 配置当前IO中的默认复用功能
            GPIOx->AFR[position >> 3U] &= ~(0xFUL << ((uint32_t) (position & 0x07UL) * 4U));
            // position:位置;角色;地方

            // 停用当前IO的上拉和下拉电阻器
            GPIOx->PUPDR &= ~(GPIO_PUPDR_PUPD0 << (position * 2U));

            // 配置默认值IO输出类型
            GPIOx->otyper &= ~(GPIO_OTYPER_OT_0 << position);

            // 配置IO速度的默认值
            GPIOx->OSPEEDR &= ~(GPIO_OSPEEDER_OSPEED0 << (position * 2U));
        }
        position++;
    }
}

// IO操作函数
// 读取指定的输入端口引脚
GPIO_PinState HAL_GPIO_ReadPin(GPIO_TypeDef *GPIOx,uint16_t GPIO_Pin)
{
    GPIO_PinState bitstatus;

    // 检查参数
    assert_param(IS_GPIO_PIN_AVAILABLE(GPIOx,GPIO_Pin));

    if((GPIOx->IDR & GPIO_Pin) != (uint32_t)(GPIO_PIN_RESET))
    {
        bitstatus = GPIO_PIN_SET;
    } else
    {
        bitstatus = GPIO_PIN_RESET;
    }
    return bitstatus;
}

// 设置或清除选定的数据端口位
// 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.
// 此函数使用GPIOx_BSRR寄存器来允许原子读取/修改访问。通过这种方式,在读取和修改访问之间不存在发生IRQ的风险。
void HAL_GPIO_WritePin(GPIO_TypeDef *GPIOx,uint16_t GPIO_Pin,GPIO_PinState PinState)
{
    // 检查参数
    assert_param(IS_GPIO_PIN_AVAILABLE(GPIOx,GPIO_Pin));
    assert_param(IS_GPIO_PIN_ACTION(PinState));

    if(PinState != GPIO_PIN_RESET)
    {
        GPIOx->BSRR = GPIO_Pin;
    }
    else
    {
        GPIOx->BRR = GPIO_Pin;
    }
}

// 切换指定的GPIO引脚
void HAL_GPIO_TogglePin(GPIO_TypeDef *GPIOx,uint16_t GPIO_Pin)
{
    uint32_t odr;

    // 检查参数
    assert_param(IS_GPIO_PIN_AVAILABLE(GPIOx,GPIO_Pin));

    // 获取当前输出数据寄存器值
    odr = GPIOx->ODR;

    // 设置低电平的选定引脚,并重置高电平的引脚
    GPIOx->BSRR = ((odr & GPIO_Pin) << GPIO_NUMBER) | (~odr & GPIO_Pin);
}

// 锁定GPIO引脚配置寄存器
HAL_StartusTypeDef HAL_GPIO_LockPin(GPIO_TypeDef * GPIOx, uint16_t GPIO_Pin)
{
    __IO uint32_t tmp = GPIO_LCKR_LCKK;
    // 检查参数
    assert_param(IS_GPIO_PIN_AVAILABLE(GPIOx,GPIO_Pin));

    // 应用锁定键写入顺序
    tmp |= GPIO_Pin;
    // 设置LCK
    GPIOx->LCKR = tmp;
    // 复位LCK
    GPIOx->LCKR = GPIO_Pin;
    // 设置LCK
    GPIOx->LCKR = tmp;
    读取LCKK寄存器,此读书是完成钥匙锁定顺序所必须的。
    tmp = GPIOx->LCKR;

    // 再次读取以确认锁定处于活动状态
    if((GPIOx->LCKR & GPIO_LCKR_LCKK) != RESET)
    {
        return HAL_OK;
    }
    else
    {
        return HAL_ERROR;
    }
}

// 此函数处理EXTI中断请求
// GPIO_Pin指定连接到EXTI线的引脚
void HAL_GPIO_EXTI_IRQHandler(uint16_t GPIO_Pin)
{
    // 检测到EXTI线路中断
    if(__HAL_GPIO_EXTI_GET_IT(GPIO_Pin) != RESET)
    {
        __HAL_GPIO_EXTI_CLEAR_IT(GPIO_Pin);
        HAL_GPIO_EXTI_Callback(GPIO_Pin);
    }
}

// EXTI线路检测回调
// GPIO_Pin指定连接到EXTI线的引脚
__weak void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
    // 阻止未使用的参数编译警告
    UNUSED(GPIO_Pin);
    // 注意:不应该修改此函数,当需要回调时,可以在用户文件中实现 HAL_GPIO_EXTI_Callback
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值