今天介HAL库操作普通IO口,就是输入/输出。

  如果用CubeMX配置io工程,打开以后可以看到如下代码:

    GPIO_InitTypeDef GPIO_Initure;
__HAL_RCC_GPIOB_CLK_ENABLE(); // 根据名字,这是使能B端口 GPIO_Initure.Pin=GPIO_PIN_0;       // 0口
GPIO_Initure.Mode=GPIO_MODE_OUTPUT_PP; // 推挽输出
GPIO_Initure.Pull=GPIO_PULLUP; // 上拉
GPIO_Initure.Speed=GPIO_SPEED_HIGH; // 高速
HAL_GPIO_Init(GPIOB,&GPIO_Initure); // 调用初始化函数 HAL_GPIO_WritePin(GPIOB,GPIO_PIN_0,GPIO_PIN_SET); // 初始化电平

看到代码的时候,如果想深入了解一定要深入的仔细分析,看看到底是怎么调用的,操作了那些寄存器(不需要自己操作,但是要了解),用一个词来概括,抽丝剥茧。首先定义了一个 GPIO_InitTypeDef 类型的结构体,从名字可以看出是IO口初始化的类型配置,然后使能B端口,再然后配置刚才定义的结构体,把各种功能赋给各个成员变量。我们可以看一下这个结构体怎么定义的,,代码如下:

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;

这个结构体里面每一个元素都要仔细的看一下,Pin:指定配置那个脚,那参数怎么看呢?看英文注释,他说:这个参数是GPIO_pins_define的任何一个,这个又是什么呢?进去看看?会发现这不是变量,找不到他,那没办法,既注释中有他,那么我们肯定是可以找到的,那就整个工程搜索一下,还真的搜到了,如下:

/** @defgroup GPIO_pins_define GPIO pins define
* @{
*/
#define GPIO_PIN_0 ((uint16_t)0x0001) /* Pin 0 selected */
#define GPIO_PIN_1 ((uint16_t)0x0002) /* Pin 1 selected */
#define GPIO_PIN_2 ((uint16_t)0x0004) /* Pin 2 selected */
#define GPIO_PIN_3 ((uint16_t)0x0008) /* Pin 3 selected */
#define GPIO_PIN_4 ((uint16_t)0x0010) /* Pin 4 selected */
#define GPIO_PIN_5 ((uint16_t)0x0020) /* Pin 5 selected */
#define GPIO_PIN_6 ((uint16_t)0x0040) /* Pin 6 selected */
#define GPIO_PIN_7 ((uint16_t)0x0080) /* Pin 7 selected */
#define GPIO_PIN_8 ((uint16_t)0x0100) /* Pin 8 selected */
#define GPIO_PIN_9 ((uint16_t)0x0200) /* Pin 9 selected */
#define GPIO_PIN_10 ((uint16_t)0x0400) /* Pin 10 selected */
#define GPIO_PIN_11 ((uint16_t)0x0800) /* Pin 11 selected */
#define GPIO_PIN_12 ((uint16_t)0x1000) /* Pin 12 selected */
#define GPIO_PIN_13 ((uint16_t)0x2000) /* Pin 13 selected */
#define GPIO_PIN_14 ((uint16_t)0x4000) /* Pin 14 selected */
#define GPIO_PIN_15 ((uint16_t)0x8000) /* Pin 15 selected */
#define GPIO_PIN_All ((uint16_t)0xFFFF) /* All pins selected */ #define GPIO_PIN_MASK ((uint32_t)0x0000FFFF) /* PIN mask for assert test */

其实意思就是,结构体中的Pin变量可以是这些宏定义中的任何一个,从命名来说也就是0-15哪些脚。继续看,Mode:指定那个脚的模式,这个参数可以是 GPIO_mode_define 中的任何一个,找到他看看,如下:

/** @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 ((uint32_t)0x00000000) /*!< Input Floating Mode */
#define GPIO_MODE_OUTPUT_PP ((uint32_t)0x00000001) /*!< Output Push Pull Mode */
#define GPIO_MODE_OUTPUT_OD ((uint32_t)0x00000011) /*!< Output Open Drain Mode */
#define GPIO_MODE_AF_PP ((uint32_t)0x00000002) /*!< Alternate Function Push Pull Mode */
#define GPIO_MODE_AF_OD ((uint32_t)0x00000012) /*!< Alternate Function Open Drain Mode */ #define GPIO_MODE_ANALOG ((uint32_t)0x00000003) /*!< Analog Mode */ #define GPIO_MODE_IT_RISING ((uint32_t)0x10110000) /*!< External Interrupt Mode with Rising edge trigger detection */
#define GPIO_MODE_IT_FALLING ((uint32_t)0x10210000) /*!< External Interrupt Mode with Falling edge trigger detection */
#define GPIO_MODE_IT_RISING_FALLING ((uint32_t)0x10310000) /*!< External Interrupt Mode with Rising/Falling edge trigger detection */ #define GPIO_MODE_EVT_RISING ((uint32_t)0x10120000) /*!< External Event Mode with Rising edge trigger detection */
#define GPIO_MODE_EVT_FALLING ((uint32_t)0x10220000) /*!< External Event Mode with Falling edge trigger detection */
#define GPIO_MODE_EVT_RISING_FALLING ((uint32_t)0x10320000) /*!< External Event Mode with Rising/Falling edge trigger detection */

上面就是IO口的各种功能配置,依次是:输入、推挽输出、开漏输出等等。同理,可以可以找到Pull、Speed等可以赋什么值。到此这个结构体就“充满”了,配置好了,我们的告诉系统啊,好接下来调用 HAL_GPIO_Init(GPIOB,&GPIO_Initure); 就是把刚才配制好的结构体扔到这个叫做IO口初始化的函数中。这个函数有两个参数,第一个是B就是那个端口,第二个是我们配置的结构体,其实就是:B端口的0号脚,这样的功能。这个函数太长了,说关键的部分,该函数会把我们的引脚的功能逐个抽离出来,然后配置相应的寄存器,就实现了这个脚的配置,代码如下:

void HAL_GPIO_Init(GPIO_TypeDef  *GPIOx, GPIO_InitTypeDef *GPIO_Init)
{
uint32_t position;
uint32_t ioposition = 0x00;
uint32_t iocurrent = 0x00;
uint32_t temp = 0x00; /* Check the parameters 这里是检查我们的配置的参数是否正确 */
assert_param(IS_GPIO_ALL_INSTANCE(GPIOx));
assert_param(IS_GPIO_PIN(GPIO_Init->Pin));
assert_param(IS_GPIO_MODE(GPIO_Init->Mode));
assert_param(IS_GPIO_PULL(GPIO_Init->Pull)); /* Configure the port pins */
for(position = ; position < GPIO_NUMBER; position++)
{
/* Get the IO position */
ioposition = ((uint32_t)0x01) << position;
/* Get the current IO position */
iocurrent = (uint32_t)(GPIO_Init->Pin) & ioposition; if(iocurrent == ioposition)
{
/*--------------------- GPIO Mode Configuration ------------------------*/
/* In case of Alternate function mode selection */
if((GPIO_Init->Mode == GPIO_MODE_AF_PP) || (GPIO_Init->Mode == GPIO_MODE_AF_OD))
{
/* Check the Alternate function parameter */
assert_param(IS_GPIO_AF(GPIO_Init->Alternate));
/* Configure Alternate function mapped with the current IO */
temp = GPIOx->AFR[position >> ];
temp &= ~((uint32_t)0xF << ((uint32_t)(position & (uint32_t)0x07) * )) ;
temp |= ((uint32_t)(GPIO_Init->Alternate) << (((uint32_t)position & (uint32_t)0x07) * ));
GPIOx->AFR[position >> ] = temp;
} /* Configure IO Direction mode (Input, Output, Alternate or Analog) */
temp = GPIOx->MODER;
temp &= ~(GPIO_MODER_MODER0 << (position * ));
temp |= ((GPIO_Init->Mode & GPIO_MODE) << (position * ));
GPIOx->MODER = temp; /* In case of Output or Alternate function mode selection */
if((GPIO_Init->Mode == GPIO_MODE_OUTPUT_PP) || (GPIO_Init->Mode == GPIO_MODE_AF_PP) ||
(GPIO_Init->Mode == GPIO_MODE_OUTPUT_OD) || (GPIO_Init->Mode == GPIO_MODE_AF_OD))
{
/* Check the Speed parameter */
assert_param(IS_GPIO_SPEED(GPIO_Init->Speed));
/* Configure the IO Speed */
temp = GPIOx->OSPEEDR;
temp &= ~(GPIO_OSPEEDER_OSPEEDR0 << (position * ));
temp |= (GPIO_Init->Speed << (position * ));
GPIOx->OSPEEDR = temp; /* Configure the IO Output Type */
temp = GPIOx->OTYPER;
temp &= ~(GPIO_OTYPER_OT_0 << position) ;
temp |= (((GPIO_Init->Mode & GPIO_OUTPUT_TYPE) >> ) << position);
GPIOx->OTYPER = temp;
} /* Activate the Pull-up or Pull down resistor for the current IO */
temp = GPIOx->PUPDR;
temp &= ~(GPIO_PUPDR_PUPDR0 << (position * ));
temp |= ((GPIO_Init->Pull) << (position * ));
GPIOx->PUPDR = temp; /*--------------------- EXTI Mode Configuration ------------------------*/
/* Configure the External Interrupt or event for the current IO */
if((GPIO_Init->Mode & EXTI_MODE) == EXTI_MODE)
{
/* Enable SYSCFG Clock */
__HAL_RCC_SYSCFG_CLK_ENABLE(); temp = SYSCFG->EXTICR[position >> ];
temp &= ~(((uint32_t)0x0F) << ( * (position & 0x03)));
temp |= ((uint32_t)(GPIO_GET_INDEX(GPIOx)) << ( * (position & 0x03)));
SYSCFG->EXTICR[position >> ] = temp; /* Clear EXTI line configuration */
temp = EXTI->IMR;
temp &= ~((uint32_t)iocurrent);
if((GPIO_Init->Mode & GPIO_MODE_IT) == GPIO_MODE_IT)
{
temp |= iocurrent;
}
EXTI->IMR = temp; temp = EXTI->EMR;
temp &= ~((uint32_t)iocurrent);
if((GPIO_Init->Mode & GPIO_MODE_EVT) == GPIO_MODE_EVT)
{
temp |= iocurrent;
}
EXTI->EMR = temp; /* Clear Rising Falling edge configuration */
temp = EXTI->RTSR;
temp &= ~((uint32_t)iocurrent);
if((GPIO_Init->Mode & RISING_EDGE) == RISING_EDGE)
{
temp |= iocurrent;
}
EXTI->RTSR = temp; temp = EXTI->FTSR;
temp &= ~((uint32_t)iocurrent);
if((GPIO_Init->Mode & FALLING_EDGE) == FALLING_EDGE)
{
temp |= iocurrent;
}
EXTI->FTSR = temp;
}
}
}
}

回过头来,再看一下开启GPIOB时钟,__HAL_RCC_GPIOB_CLK_ENABLE(); 他是一个很大的宏,把和这个宏有关的都贴上一起分析:

#define __HAL_RCC_GPIOB_CLK_ENABLE()    do { \
__IO uint32_t tmpreg = 0x00; \
SET_BIT(RCC->AHB1ENR, RCC_AHB1ENR_GPIOBEN);\
/* Delay after an RCC peripheral clock enabling */ \
tmpreg = READ_BIT(RCC->AHB1ENR, RCC_AHB1ENR_GPIOBEN);\
UNUSED(tmpreg); \
} while() #define SET_BIT(REG, BIT) ((REG) |= (BIT)) #define RCC_AHB1ENR_GPIOBEN ((uint32_t)0x00000002) #define READ_BIT(REG, BIT) ((REG) & (BIT)) #define UNUSED(x) ((void)(x)) // 避免警告——百度

这个宏,简单一点看,把当作一个函数看一下,执行一次do里面的,把寄存器 AHB1ENR 1位置1,就是使能GPIOB。

  总结一下IO是使用,想配置一个脚作为普通口用,就要定义一个配置结构体,初始化这个脚所在的口的时钟,然后“填满”它,在把他扔到初始化函数中,到此,就配置好了一个普通的IO口作为输入输出。

  

stm32 HAL库笔记(一)——普通IO口的更多相关文章

  1. stm32 HAL库笔记(零)

    最近在设计四旋翼飞行器,用stm32f407,有三种开发方式可以选择:一.寄存器开发.二:库函数开发.三:HAL库开发,考虑了一下,选择了HAL库,原因如下: 1. 寄存器开发相对较慢,寄存器很多,配 ...

  2. stm32 HAL库笔记(一)——串口的操作

    昨天分析了普通io口的使用,和初始化代码流程,回顾一下,首先定义一个配置io口功能的结构体,然后开启时钟,再去配置这个结构体里面的各个成员变量,每个成员变量都有很多种选择,可以看各个成员变量 后面的注 ...

  3. 【有趣的全彩LED | 编程】用STM32 HAL库让WS2812B为你所动

    一.效果展示 观看演示效果:https://www.bilibili.com/video/BV1dv411Y7x3 使用STM32 HAL库编程 PWM+DMA控制输出,CubeMX生成初始工程 实现 ...

  4. 【情人节选帽子】TCS34725颜色传感器和Python图形界面编程(STM32 HAL库)

    截图 描述: l  STM32 HAL库编程 l  使用模拟IIC通信,方便程序移植 l  Python界面编写,蘑菇头的帽子是什么颜色 l  STM32 HAL库串口通信 l  Python界面使用 ...

  5. STM32 HAL库详解 及 手动移植

    源: STM32 HAL库详解 及 手动移植

  6. 【书籍连载】《STM32 HAL 库开发实战指南—基于F7》-第一章

    从今天起,每天开始连载一章<STM32 HAL 库开发实战指南—基于F7>.欢迎各位阅读.点评.学习. 第1章  如何使用本书 1.1  本书的参考资料 本书参考资料为:<STM32 ...

  7. 【春节歌曲回味 | STM32小音乐盒 】PWM+定时器驱动无源蜂鸣器(STM32 HAL库)

    l  STM32通过PWM与定时器方式控制无源蜂鸣器鸣响 l  STM32小音乐盒,歌曲进度条图形显示与百分比显示,歌曲切换 l  编程使用STM32 HAL库 l  IIC OLED界面编程,动画实 ...

  8. STM32 HAL库 UART 串口读写功能笔记

    https://www.cnblogs.com/Mysterious/p/4804188.html STM32L0 HAL库 UART 串口读写功能 串口发送功能: uint8_t TxData[10 ...

  9. STM32 HAL库与标准库的区别_浅谈句柄、MSP函数、Callback函数

    最近笔者开始学习STM32的HAL库,由于以前一直用标准库进行开发,于是发现了HAL库几点好玩的地方,在此分享. 1.句柄在STM32的标准库中,假设我们要初始化一个外设(这里以USART为例)我们首 ...

随机推荐

  1. js对json字符串和json对象的转换

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  2. Unable to load DLL 'api-ms-win-core-localization-l1-2-0.dll': 找不到指定的模块

    asp.net mvc 4.6 发布到WinServer2008R2 SP1 提示 错误 Unable to load DLL 'api-ms-win-core-localization-l1-2-0 ...

  3. Fragment跳转至Activity片段随笔

    首先需要了解Fragment的生命周期 @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, ...

  4. nginx下运行php的程序时返回200访问却是空白页问题的解决方法

    由于nginx与php-fpm之间的一个小bug,会导致这样的现象: 网站中的静态页面 *.html 都能正常访问,而 *.php 文件虽然会返回200状态码, 但实际输出给浏览器的页面内容却是空白. ...

  5. php字符串统计次数的各种方法(转)

    <?php $str = 'AbCdEfGaBcDeFgH0234;,!-AaBbCcDdEeFfGg'; $str = strtoupper($str); // 不区分大小写时,全部转换成大写 ...

  6. 关于multi-index

    [转载请注明出处]http://www.cnblogs.com/mashiqi 2017/02/22 将$D^{\alpha}$和$\partial^{\alpha}$区别对待.$D^{\alpha} ...

  7. 2java判断素数

    package com.test; import java.math.*;import java.util.Scanner; public class test222 { /** * @param a ...

  8. 面向对象的编程思想和Java中类的概念与设计

    面向对象的编程思想学习,面向对象内容的三条主线;1.java类及类的对象2.面向对象的三大特征3.其他关键字学习内容:3.1面向对象与面向过程面向对象与面向过程在应用上的区别 Java中类的概念与设计 ...

  9. java Scanner中next和nextLine()区别

    next(): 1.一定要读取到有效字符后才可以结束输入. 2.对输入有效字符之前遇到的空白,next() 方法会自动将其去掉. 3.只有输入有效字符后才将其后面输入的空白作为分隔符或者结束符. ne ...

  10. COMBIN14简单应用

    目录 案例1 说明 APDL代码 结果 案例2 说明 APDL代码 结果 案例3 说明 APDL代码 结果 参考网址:http://blog.sina.com.cn/s/blog_65936c2301 ...