17.1 初学者重要提示
1、 如何阅读HAL库源码的问题
HAL库实现的函数有复杂的,也有简单的,简单的可以直接阅读代码。复杂的代码阅读起来比较耗时间,如果再配合参考手册抠每个寄存器的配置,那就更消耗时间了。所以对于这种函数,用户仅需了解每个部分实行的功能即可,而且HAL库都做了关键注释,以说明这部分实现的功能。所以用户没有必要去抠每个配置是如何实现的,仅需知道实现了什么功能。以后工程项目有需要了解具体配置时,再看即可。
2、 学习本章节前,务必保证已经学习了第15章。
17.2 GPIO涉及到的寄存器
GPIO外设涉及到的寄存器比较少,也容易理解,推荐大家阅读GPIO源码的时候将参考手册中对应的寄存器功能做一个了解。
很多时候,我们会直接调用GPIO的寄存器进行配置,而不使用HAL进行调用,以提高执行效率,特别是中断里面执行时。
17.3 源文件stm32h7xx_hal_gpio.c
这个文件主要是实现GPIO的引脚配置,学习这个文件注意事项:
系统上电后,引脚默认状态是模拟模式。
所有的引脚有弱上拉和弱下拉电阻,阻值范围30-50KΩ。其中配置为模拟模式时,上拉和下拉被硬件禁止,其它的输入、输出和复用都可以配置上拉和下拉。
在输出或者复用模式,每个引脚可以配置成推挽或者开漏,且有GPIO速度等级可配置。另外注意,不同的供电范围,实际速度等级是有些区别的。
每个GPIO都可以配置成外部中断/事件模式,但要特别注意,引脚要配置成输入模式,在芯片的内部有个多路选择器,选择引脚与16个外部中断/事件EXTI0 - EXTI15中的那个导通。这就决定了,每个外部中断/事件只能与一个引脚导通,如果用户配置了多个引脚PA0,PB0,PC0等,那么只有一个能够与EXTI0导通。
17.3.1 函数HAL_GPIO_Init
函数原型:
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,此函数主要实现如下功能:
GPIO功能配置。
设置EXTI功能。
函数参数:
第1个参数用于填写使用的端口号,可以是:
#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)
第2个形参是GPIO_InitTypeDef类型的结构体变量,这个变量比较重要,要熟练掌握,定义如下:
typedef struct
{
uint32_t Pin;
uint32_t Mode;
uint32_t Pull;
uint32_t Speed;
uint32_t Alternate;
}GPIO_InitTypeDef;
下面将结构体每个成员做个说明:
成员Pin用于配置选择的引脚,范围GPIO_PIN_0到GPIO_PIN_15,额外还可以选择GPIO_PIN_All和GPIO_PIN_MASK。
成员Mode可以选择:
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 /* 外部事件模式,双沿触发检测 */
成员Pull用于配置上拉下拉电阻:
GPIO_NOPULL /* 无上拉和下拉电阻 */
GPIO_PULLUP /* 带上拉电阻 */
GPIO_PULLDOWN /* 带下拉电阻 */
成员Speed用于配置GPIO速度等级,有下面四种可选:
GPIO_SPEED_FREQ_LOW /* 低速 */
GPIO_SPEED_FREQ_MEDIUM /* 中等速度 */
GPIO_SPEED_FREQ_HIGH /* 快速 */
GPIO_SPEED_FREQ_VERY_HIGH /* 高速 */
成员Alternate用于配置引脚复用,可选择的复用方式在文件stm32h7xx_hal_gpio_ex.h里面进行了定义,比如串口复用:
GPIO_AF7_USART1
GPIO_AF7_USART2
GPIO_AF7_USART3
GPIO_AF7_USART6
GPIO_AF7_UART7
注意事项:
与F1,F4系列的标准库不同,H7的HAL库已经没有单独的EXTI外部中断设置文件,是将其整合到此函数里面了。
函数HAL_GPIO_Init对引脚的初始化是把同组16个引脚for循环检测了一遍,效率稍低。所以不推荐下面这种初始化:
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到初始化状态,具体状态看函数原型中的注释即可。
函数参数:
第1个参数用于填写使用的端口号,可以是:
#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)
第2个参数是配置选择的引脚,范围GPIO_PIN_0到GPIO_PIN_15。
使用举例:
此函数的使用比较简单,需要调用的时候直接调用即可。
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寄存器读取。
函数参数:
第1个参数用于填写使用的端口号,从GPIOA到GPIAK。
第2个参数是配置选择的引脚,范围GPIO_PIN_0到GPIO_PIN_15。
使用举例:
此函数的使用比较简单,需要调用的时候直接调用即可。
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是会被中断打断的。大家看下寄存器赋值操作对应的反汇编,是由多条汇编指令组成的。
函数参数:
第1个参数用于填写使用的端口号,从GPIOA到GPIAK。
第2个参数是配置选择的引脚,范围GPIO_PIN_0到GPIO_PIN_15。
第3个参数用于设置引脚输出高电平还是低电平,GPIO_PIN_RESET表示低电平,GPIO_PIN_SET表示高电平。
使用举例:
此函数的使用比较简单,需要调用的时候直接调用即可。
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寄存器进行设置。
函数参数:
第1个参数用于填写使用的端口号,从GPIOA到GPIAK。
第2个参数是配置选择的引脚,范围GPIO_PIN_0到GPIO_PIN_15。
使用举例:
此函数的使用比较简单,需要调用的时候直接调用即可。
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;
上一篇:【STM32H7教程】第18章 STM32H7的GPIO应用之跑马灯
下一篇:【STM32H7教程】第16章 STM32H7必备的HAL库API(重要)
推荐阅读
史海拾趣
Brainboxes公司成立于1984年,总部位于英国利物浦市。创立之初,公司专注于数据和I/O连接产品的设计和制造。凭借对串行通信技术的深刻理解,Brainboxes迅速在行业内崭露头角。其早期产品,如串口服务器和适配器,因高度可配置和可靠的特性而受到市场的欢迎。随着业务的发展,公司逐渐扩大产品线,涵盖IO模块等多个领域。
尽管Elpida Memory已经不复存在,但其在DRAM领域的技术和经验仍然对全球半导体产业产生了深远的影响。Elpida Memory在技术研发、生产管理和市场营销等方面的经验,为后来的半导体企业提供了宝贵的借鉴和参考。同时,Elpida Memory的失败也提醒了半导体企业需要时刻保持警惕和创新精神,以应对日益激烈的市场竞争和技术变革。
ASSMANN WSW components公司一直致力于技术创新和产品研发。在某个关键时刻,公司研发团队成功开发出了一种具有革命性的新型连接器,这种连接器不仅性能稳定、寿命长,而且具有极高的可靠性和安全性。这一技术突破使得ASSMANN WSW在电子元件市场上脱颖而出,迅速成为行业内的佼佼者。
随着新能源汽车产业的快速发展,富芯森美敏锐地捕捉到了这一市场机遇。公司投入大量资源研发车规级功率半导体器件,产品设计遵循APQP标准,制造管理符合IATF 16949要求,质量检验则严格遵循AEC-Q101标准。这些举措使得富芯森美的车规级产品能够满足汽车行业的严苛要求,成功打入新能源汽车供应链体系,为公司带来了新的增长点。
近年来,智能制造成为电子行业的新趋势。FCT Electronics紧跟时代步伐,开始探索智能制造领域。公司引进了先进的自动化生产线和检测设备,提高了生产效率和产品质量。同时,FCT Electronics还积极开发智能测试系统,为客户提供更加便捷、高效的服务。这一转型不仅提升了公司的市场竞争力,也为未来的发展打开了新的空间。
上述五个故事,仅基于公开信息和电子行业的一般发展趋势构建,并非FCT Electronics公司的真实历史事件。如需了解FCT Electronics公司的真实发展情况,请查阅相关官方资料。
企业文化是企业的灵魂和精神支柱。创都公司自创立之初就注重企业文化的建设与发展。他们倡导“创新、协作、务实、进取”的企业精神,鼓励员工勇于创新、敢于担当。同时,公司还注重员工培训和职业发展规划的制定与实施,为员工提供了广阔的发展空间和良好的职业前景。这些措施不仅激发了员工的积极性和创造力还增强了企业的凝聚力和向心力使得创都公司在激烈的市场竞争中始终保持着旺盛的发展势头。
设计要求,设计一个电子密码锁,在开锁的状态下输入密码,密码共四位,用数据开关k1~k10分别表示0~9,输入密码用数码管显示,最后输入的密码显示在最右边的数码管上,即每输入一位数,密码在数码管上的显示左移一位,可删除输入的数字,删除的是最 ...… 查看全部问答∨ |
|
ORG 0000H AJMP START ORG 30H START: MOV R1,#01HMOV P1,#0FFH ;关所 灯 MOV TMOD,#00000001B ;定时/计数器0工作于方式1 MOV TH0,#15H MOV TL0,#0A0H ;即数5536 SETB TR0 ;定时/计数器0开始运行 LOOP:JBC TF0,NEXT ;如果TF0等于1,则清TF ...… 查看全部问答∨ |
|
通过模拟开关或者继电器导通电流信号,现有问题,请大家指教 1,如果是模拟开关,漏电流不能恒定,会随着信号的大小变化。以至于信号本来是线性的,结果就非线性了。2,如果是继电器,有声音。有无声的继电器吗? 那种光电转换的继电器也会有漏电 ...… 查看全部问答∨ |
|
圆点博士免费送ARDUINO UNO PCB拉(申请对象仅限在校学生) 圆点博士免费送ARDUINO UNO PCB拉(申请对象仅限在校学生): 这两天整理东西,找出来以前做的ARDUINO UNO兼容PCB. PCB上预留了蓝牙转COM口模块。当初的设计资料找不到了,就只有这个PCB板了,不过线路是根据UNO来的。大家用得着的话,可以跟贴报名 ...… 查看全部问答∨ |
现在lauchpad不在身边,要画PCB需要相应参数。最好有文档神马的,原来用游标卡尺测过,数据没有带来……就是J1排针和J5排针,以及J6排针和J5排针之间的距离… 查看全部问答∨ |
本帖最后由 tiankai001 于 2015-2-27 17:20 编辑 你在自己的学习工作中,能不能跟和你意见不一致的人一起工作,能不能保持一种宽容的心态。因为人与人的思维方式是不一样的,你在你的工作中肯定会遇到与你意见不一致的人,这一点是毫 ...… 查看全部问答∨ |
本人新手,想参加电赛的电源类试题,在准备开关电源这一块的时候,一直不懂单片机输出pwm波,然后pwm波控制mos管的占空比过程是怎么实现的。网上找到的都是一笔带过,找不到相关的电路图或者详细的分析过程,这个地方一直就变成了我的盲区,希望论 ...… 查看全部问答∨ |