完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
|
|
相关推荐
1个回答
|
|
17.1 初学者重要提示
1、 如何阅读HAL库源码的问题 HAL库实现的函数有复杂的,也有简单的,简单的可以直接阅读代码。复杂的代码阅读起来比较耗时间,如果再配合参考手册抠每个寄存器的配置,那就更消耗时间了。所以对于这种函数,用户仅需了解每个部分实行的功能即可,而且HAL库都做了关键注释,以说明这部分实现的功能。所以用户没有必要去抠每个配置是如何实现的,仅需知道实现了什么功能。以后工程项目有需要了解具体配置时,再看即可。 2、 学习本章节前,务必保证已经学习了第15章。 17.2 GPIO涉及到的寄存器 GPIO外设涉及到的寄存器比较少,也容易理解,推荐大家阅读GPIO源码的时候将参考手册中对应的寄存器功能做一个了解。 很多时候,我们会直接调用GPIO的寄存器进行配置,而不使用HAL进行调用,以提高执行效率,特别是中断里面执行时。 17.3 源文件stm32f4xx_hal_gpio.c 这个文件主要是实现GPIO的引脚配置,学习这个文件注意事项:
函数原型: void HAL_GPIO_Init(GPIO_TypeDef *GPIOx, GPIO_InitTypeDef *GPIO_Init){/* 部分省略未写 */ /* 配置GPIO引脚,这些采用16个引脚的循环检测模式 */ for(position = 0; position < GPIO_NUMBER; position++) { /* 部分省略未写 */ if(iocurrent == ioposition) { /*--------------------- GPIO模式配置 ------------------------*/ /*--------------------- EXTI模式配置 ------------------------*/ } }} 函数描述: 此函数用于初始化GPIO,此函数主要实现如下功能:
#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) #define GPIOJ ((GPIO_TypeDef *) GPIOJ_BASE) #define GPIOK ((GPIO_TypeDef *) GPIOK_BASE)
{ uint32_t Pin; uint32_t Mode; uint32_t Pull; uint32_t Speed; uint32_t Alternate; }GPIO_InitTypeDef; 下面将结构体每个成员做个说明:
GPIO_MODE_INPUT /* 输入模式 */GPIO_MODE_OUTPUT_PP /* 推挽输出 */GPIO_MODE_OUTPUT_OD /* 开漏输出 */GPIO_MODE_AF_PP /* 复用推挽 */GPIO_MODE_AF_OD /* 复用开漏 */GPIO_MODE_ANALOG /* 模拟模式 */GPIO_MODE_IT_RISING /* 外部中断,上升沿触发检测 */GPIO_MODE_IT_FALLING /* 外部中断,下降沿触发检测 */GPIO_MODE_IT_RISING_FALLING /* 外部中断,双沿触发检测 */GPIO_MODE_EVT_RISING /* 外部事件模式,上升沿触发检测 */GPIO_MODE_EVT_FALLING /* 外部事件模式,下降沿触发检测 */GPIO_MODE_EVT_RISING_FALLING /* 外部事件模式,双沿触发检测 */
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; GPIO_InitStruct.Pin = GPIO_PIN_0;HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); //这里会执行16次for查询GPIO_InitStruct.Pin = GPIO_PIN_1;HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); //这里会执行16次for查询 GPIO_InitStruct.Pin = GPIO_PIN_2;HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); //这里会执行16次for查询 如果是程序运行期间的引脚状态切换,最好采用下面的方式或者直接寄存器操作: GPIO_InitStruct.Pin = GPIO_PIN_0 |GPIO_PIN_1 | GPIO_PIN_2 ;GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); //这里会执行16次for查询 使用举例: GPIO_InitTypeDef GPIO_InitStruct;GPIO_InitStruct.Pin = GPIO_PIN_0;GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; /* 推挽输出 */ GPIO_InitStruct.Pull = GPIO_NOPULL; /* 无上拉和下拉电阻 */ GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; /* GPIO速度等级最高 */HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); 17.3.2 函数HAL_GPIO_DeInit 函数原型: void HAL_GPIO_DeInit(GPIO_TypeDef *GPIOx, uint32_t GPIO_Pin){ for(position = 0; position < GPIO_NUMBER; position++) { /* 部分省略未写 */ if(iocurrent == ioposition) { /*------------------------- GPIO Mode Configuration --------------------*/ /* 配置为模拟模式 */ GPIOx->MODER |= (GPIO_MODER_MODER0 << (position * 2)); /* 配置复用模式为AF0,即作为通用IO */ GPIOx->AFR[position >> 3] &= ~((uint32_t)0xF << ((uint32_t)(position & (uint32_t)0x07) * 4)) ; /* 配置到最低速度 */ GPIOx->OSPEEDR &= ~(GPIO_OSPEEDER_OSPEEDR0 << (position * 2)); /* 输出类型是推挽,如果IO模式被设置为模拟,此选项对其没有影响 */ GPIOx->OTYPER &= ~(GPIO_OTYPER_OT_0 << position) ; /* 无上拉和下拉电阻 */ GPIOx->PUPDR &= ~(GPIO_PUPDR_PUPDR0 << (position * 2)); /*------------------------- EXTI模式配置 --------------------*/ } }} 函数描述: 此函数用于复位IO到初始化状态,具体状态看函数原型中的注释即可。 函数参数:
#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)#define GPIOJ ((GPIO_TypeDef *) GPIOJ_BASE)#define GPIOK ((GPIO_TypeDef *) GPIOK_BASE)
此函数的使用比较简单,需要调用的时候直接调用即可。 17.3.3 函数HAL_GPIO_ReadPin 函数原型: GPIO_PinState HAL_GPIO_ReadPin(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin){ GPIO_PinState bitstatus; /* Check the parameters */ assert_param(IS_GPIO_PIN(GPIO_Pin)); if((GPIOx->IDR & GPIO_Pin) != (uint32_t)GPIO_PIN_RESET) { bitstatus = GPIO_PIN_SET; } else { bitstatus = GPIO_PIN_RESET; } return bitstatus;} 函数描述: 此函数用于读取引脚状态,通过GPIO的IDR寄存器读取。 函数参数:
此函数的使用比较简单,需要调用的时候直接调用即可。 17.3.4 函数HAL_GPIO_WritePin 函数原型: void HAL_GPIO_WritePin(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin, GPIO_PinState PinState){ /* Check the parameters */ assert_param(IS_GPIO_PIN(GPIO_Pin)); assert_param(IS_GPIO_PIN_ACTION(PinState)); if(PinState != GPIO_PIN_RESET) { GPIOx->BSRRL = GPIO_Pin; } else { GPIOx->BSRRH = GPIO_Pin ; }} 函数描述: 此函数用于设置引脚输出高电平或者低电平。使用GPIO的BSRR寄存器进行设置,使用这个寄存器的好处是支持原子操作,由硬件支持的。原子操作的含义是操作过程不会被中断打断,而我们使用GPIO中另一个设置输出的寄存ODR是会被中断打断的。大家看下寄存器赋值操作对应的反汇编,是由多条汇编指令组成的。 函数参数:
此函数的使用比较简单,需要调用的时候直接调用即可。 17.3.5 函数HAL_GPIO_TogglePin 函数原型: void HAL_GPIO_TogglePin(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin){ /* Check the parameters */ assert_param(IS_GPIO_PIN(GPIO_Pin)); GPIOx->ODR ^= GPIO_Pin;} 函数描述: 此函数用于设置引脚的电平翻转,使用GPIO的ODR寄存器进行设置。 函数参数:
此函数的使用比较简单,需要调用的时候直接调用即可。 17.3.6 函数HAL_GPIO_LockPin 函数原型:HAL_StatusTypeDef HAL_GPIO_LockPin(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin) { __IO uint32_t tmp = GPIO_LCKR_LCKK; assert_param(IS_GPIO_LOCK_INSTANCE(GPIOx)); assert_param(IS_GPIO_PIN(GPIO_Pin)); /* 应用IO锁的写入顺序 */ tmp |= GPIO_Pin; /* 设置 LCKx bit(s): LCKK='1' + LCK[15-0] */ GPIOx->LCKR = tmp; /* 复位 LCKx bit(s): LCKK='0' + LCK[15-0] */ GPIOx->LCKR = GPIO_Pin; /* 设置 LCKx bit(s): LCKK='1' + LCK[15-0] */ GPIOx->LCKR = tmp; /* 复位 LCKK bit*/ tmp = GPIOx->LCKR; if((GPIOx->LCKR & GPIO_LCKR_LCKK) != RESET) { return HAL_OK; } else { return HAL_ERROR; }} 函数描述: 此函数用于锁住GPIO引脚所涉及到的寄存器,这些寄存器包括GPIOx_MODER,GPIOx_OTYPER,GPIOx_OSPEEDR,GPIOx_PUPDR,GPIOx_AFRL 和 GPIOx_AFRH。 函数参数:
此函数的使用比较简单,需要调用的时候直接调用即可。 17.4 如何使用HAL库的GPIO驱动 使用方法由HAL库提供(本章17.3.1小节提供的例子就是这种方式):
(2) 通过结构体GPIO_InitTypeDef的成员Pull配置上拉、下拉电阻。 (3) 通过结构体GPIO_InitTypeDef的成员Speed配置GPIO速度等级。 (4) 如果选择了复用模式,那么就需要配置结构体GPIO_InitTypeDef的成员Alternate。 (5) 如果引脚功能用于ADC、DAC的话,需要配置引脚为模拟模式。 (6) 如果是用于外部中断/事件,结构体GPIO_InitTypeDef的成员Mode可以配置相应模式,相应的上升沿、下降沿或者双沿触发也可以选择。
另外注意下面三个问题:
本章节就为大家讲解这么多,建议大家将GPIO的驱动源码结合参考手册中的寄存器通读一遍,对于我们后面章节的学习大有裨益。 |
|
|
|
只有小组成员才能发言,加入小组>>
调试STM32H750的FMC总线读写PSRAM遇到的问题求解?
1298 浏览 1 评论
X-NUCLEO-IHM08M1板文档中输出电流为15Arms,15Arms是怎么得出来的呢?
1310 浏览 1 评论
721 浏览 2 评论
STM32F030F4 HSI时钟温度测试过不去是怎么回事?
531 浏览 2 评论
ST25R3916能否对ISO15693的标签芯片进行分区域写密码?
1327 浏览 2 评论
1727浏览 9评论
STM32仿真器是选择ST-LINK还是选择J-LINK?各有什么优势啊?
435浏览 4评论
STM32F0_TIM2输出pwm2后OLED变暗或者系统重启是怎么回事?
390浏览 3评论
378浏览 3评论
stm32cubemx生成mdk-arm v4项目文件无法打开是什么原因导致的?
357浏览 3评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-9-20 13:53 , Processed in 0.756415 second(s), Total 43, Slave 38 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号