stm32 HAL库笔记(一)——普通IO口
今天介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口的更多相关文章
- stm32 HAL库笔记(零)
最近在设计四旋翼飞行器,用stm32f407,有三种开发方式可以选择:一.寄存器开发.二:库函数开发.三:HAL库开发,考虑了一下,选择了HAL库,原因如下: 1. 寄存器开发相对较慢,寄存器很多,配 ...
- stm32 HAL库笔记(一)——串口的操作
昨天分析了普通io口的使用,和初始化代码流程,回顾一下,首先定义一个配置io口功能的结构体,然后开启时钟,再去配置这个结构体里面的各个成员变量,每个成员变量都有很多种选择,可以看各个成员变量 后面的注 ...
- 【有趣的全彩LED | 编程】用STM32 HAL库让WS2812B为你所动
一.效果展示 观看演示效果:https://www.bilibili.com/video/BV1dv411Y7x3 使用STM32 HAL库编程 PWM+DMA控制输出,CubeMX生成初始工程 实现 ...
- 【情人节选帽子】TCS34725颜色传感器和Python图形界面编程(STM32 HAL库)
截图 描述: l STM32 HAL库编程 l 使用模拟IIC通信,方便程序移植 l Python界面编写,蘑菇头的帽子是什么颜色 l STM32 HAL库串口通信 l Python界面使用 ...
- STM32 HAL库详解 及 手动移植
源: STM32 HAL库详解 及 手动移植
- 【书籍连载】《STM32 HAL 库开发实战指南—基于F7》-第一章
从今天起,每天开始连载一章<STM32 HAL 库开发实战指南—基于F7>.欢迎各位阅读.点评.学习. 第1章 如何使用本书 1.1 本书的参考资料 本书参考资料为:<STM32 ...
- 【春节歌曲回味 | STM32小音乐盒 】PWM+定时器驱动无源蜂鸣器(STM32 HAL库)
l STM32通过PWM与定时器方式控制无源蜂鸣器鸣响 l STM32小音乐盒,歌曲进度条图形显示与百分比显示,歌曲切换 l 编程使用STM32 HAL库 l IIC OLED界面编程,动画实 ...
- STM32 HAL库 UART 串口读写功能笔记
https://www.cnblogs.com/Mysterious/p/4804188.html STM32L0 HAL库 UART 串口读写功能 串口发送功能: uint8_t TxData[10 ...
- STM32 HAL库与标准库的区别_浅谈句柄、MSP函数、Callback函数
最近笔者开始学习STM32的HAL库,由于以前一直用标准库进行开发,于是发现了HAL库几点好玩的地方,在此分享. 1.句柄在STM32的标准库中,假设我们要初始化一个外设(这里以USART为例)我们首 ...
随机推荐
- js实现上拉加载思路整理
1.整体模拟滚动 监听touchmove事件,比较 scrollTop 和 $scroller.scrollHeight() - $container.height(). 缺点:滑动不流畅, tran ...
- springcloud Zuul学习笔记
SpringCloud Zull是一个基于NetflixZuul实现的API网关组件,它实现了请求路由,负载均衡,校验过滤等功能;本文主要记录springcloud zuul的入门级demo开发过程; ...
- Python基础06_list
尽量多挤点时间用来学点知识吧. list是不同于字符串的,字符串定义后不可修改,而list是可以修改的. 以下是学习笔记: #!/usr/bin/env python # coding:utf-8 l ...
- guava-retrying 源码解析(时间限制策略)
一.时间限制策略相关接口和类 什么是时间限制策略呢?是指在一个时间限制内,包装任何一种重试(尝试)规则,如果超过该限制,那么这个尝试规则可能会被中断,并抛出UncheckedTimeoutExcept ...
- VBA消息框
MsgBox函数显示一个消息框,并等待用户点击一个按钮,然后根据用户点击该按钮的动作执行. 语法 MsgBox(prompt[,buttons][,title][,helpfile,context]) ...
- latex之注释快捷键
注释快捷键 ctrl+T:注释掉选中区域 ctrl_U:解除选中区域的注释
- 基于VM上的Ubuntu16.04如何和window界面进行复制,粘贴工作
1.卸载VMware tools: sudo apt-get autoremove open-vm-tools 2.安装界面版VMware tools. sudo apt-get install op ...
- python set 集合复习--点滴
一.set特性: set是一个无序不重复的元素集合. 集合对象是一组无序排列的可哈希的值,集合成员可以做字典中的键.集合支持用in和not in操作符检查成员,由len()内建函数得到集合的基数(大小 ...
- Linux内核分析第六次作业
分析system_call中断处理过程 一.先在实验楼的虚拟机中MenuOs增加utsname和utsname-asm指令. 具体实现如下: 1.克隆最新新版本的menu,之后进入menu 2.进入t ...
- 知识图谱实战开发案例剖析-番外篇(1)- Neo4j是否支持按照边权重加粗和大数量展示
一.前言 本文是<知识图谱实战开发案例完全剖析>系列文章和网易云视频课程的番外篇,主要记录学员在知识图谱等相关内容的学习 过程中,提出的共性问题进行展开讨论.该部分内容原始内容记录在网易云 ...