一  初始化GPIO

使用HAL库的优点在于不用手动添加初始化的代码了,CubeMX会根据软件设置自动生成。

自动生成的HAL库GPIO初始化代码:

static void MX_GPIO_Init(void)
{ GPIO_InitTypeDef GPIO_InitStruct; /* GPIO Ports Clock Enable */
__HAL_RCC_GPIOH_CLK_ENABLE();
__HAL_RCC_GPIOD_CLK_ENABLE(); /*Configure GPIO pin Output Level */
HAL_GPIO_WritePin(GPIOD, GPIO_PIN_12|GPIO_PIN_13|GPIO_PIN_14|GPIO_PIN_15, GPIO_PIN_SET); /*Configure GPIO pin : PD11 */
GPIO_InitStruct.Pin = GPIO_PIN_11;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_PULLUP;
HAL_GPIO_Init(GPIOD, &GPIO_InitStruct); /*Configure GPIO pins : PD12 PD13 PD14 PD15 */
GPIO_InitStruct.Pin = GPIO_PIN_12|GPIO_PIN_13|GPIO_PIN_14|GPIO_PIN_15;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
HAL_GPIO_Init(GPIOD, &GPIO_InitStruct); }

顺序:(1)定义结构体变量。(2)使能时钟。(3)配置初始化电平。(4)通过结构体变量初始化GPIO。

1.首先定义一个结构体变量GPIO_InitStruct,该变量类型是GPIO_InitTypeDef。

GPIO_InitTypeDef 定义如下:

/**
* @brief GPIO Init structure definition
*/
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;

作用是:设置要用的是哪个引脚、引脚工作模式、上拉还是下拉、速度、XX这个还不知道是干嘛的XX。

2.使能时钟。

  /* GPIO Ports Clock Enable */
__HAL_RCC_GPIOH_CLK_ENABLE();
__HAL_RCC_GPIOD_CLK_ENABLE();

这里使能时钟的方法与标准库不一样,HAL库其实是宏定义,标准库则是函数。

宏定义(使能H口的宏定义):

#define __HAL_RCC_GPIOH_CLK_ENABLE()  do { \
__IO uint32_t tmpreg = 0x00U; \
SET_BIT(RCC->AHB1ENR, RCC_AHB1ENR_GPIOHEN);\
/* Delay after an RCC peripheral clock enabling */ \
tmpreg = READ_BIT(RCC->AHB1ENR, RCC_AHB1ENR_GPIOHEN);\
UNUSED(tmpreg); \
} while(0U)

这里使能H口是因为H口接的外部晶振。

3.配置引脚的初始化电平。

  /*Configure GPIO pin Output Level */
HAL_GPIO_WritePin(GPIOD, GPIO_PIN_12|GPIO_PIN_13|GPIO_PIN_14|GPIO_PIN_15, GPIO_PIN_SET);

这里设置D口的pin12、pin13、pin14、pin15为高电平。如果最后一个参数是GPIO_PIN_RESET则为低电平。

4.通过结构体变量配置具体的引脚。

  /*Configure GPIO pin : PD11 */
GPIO_InitStruct.Pin = GPIO_PIN_11;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_PULLUP;
HAL_GPIO_Init(GPIOD, &GPIO_InitStruct); /*Configure GPIO pins : PD12 PD13 PD14 PD15 */
GPIO_InitStruct.Pin = GPIO_PIN_12|GPIO_PIN_13|GPIO_PIN_14|GPIO_PIN_15;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);

PD11为输入,上拉。PD12-15为推挽输出。所以分开配置。

总结一下:(1)定义结构体变量。(2)使能时钟。(3)配置初始化电平。(4)通过结构体变量初始化GPIO。

其中,(3)和(4)可调换顺序

二  功能解释

1.系统分析。

STM32F4Discovery的PD12-15的四个引脚是LED。

我们要做的功能是按键一次点亮一个LED(顺时针PIN12-15,从PIN12开始)并关闭上一个LED。

首先我们需要一个标志变量来代表当前正在亮的LED:

int LEDNUM_Flag = ;

流程:按键扫描  ->  读到Pin11按下  ->  关闭当前LEDNUM_Flag代表的LED(正在亮的)  ->  LEDNUM_Flag+1  ->  点亮当前LEDNUM_Flag代表的LED;

2.按键输入。

_Bool GetPress(void)
{
if(HAL_GPIO_ReadPin(GPIOD,GPIO_PIN_11)==)
{
HAL_Delay();//防抖
if(HAL_GPIO_ReadPin(GPIOD,GPIO_PIN_11)==)
{
while(HAL_GPIO_ReadPin(GPIOD,GPIO_PIN_11)==)//等待按键抬起。
{;}
return ;
}
else return ;
}
else return ;
}

3.点亮LED。

void TurnOnLED(int flag)
{
switch(flag)
{
case :
HAL_GPIO_WritePin(GPIOD, GPIO_PIN_12, GPIO_PIN_SET);
break;
case :
HAL_GPIO_WritePin(GPIOD, GPIO_PIN_13, GPIO_PIN_SET);
break;
case :
HAL_GPIO_WritePin(GPIOD, GPIO_PIN_14, GPIO_PIN_SET);
break;
case :
HAL_GPIO_WritePin(GPIOD, GPIO_PIN_15, GPIO_PIN_SET);
break;
}
}

4.关闭LED。

void TurnOffLED(int flag)
{
switch(flag)
{
case :
HAL_GPIO_WritePin(GPIOD, GPIO_PIN_12, GPIO_PIN_RESET);
break;
case :
HAL_GPIO_WritePin(GPIOD, GPIO_PIN_13, GPIO_PIN_RESET);
break;
case :
HAL_GPIO_WritePin(GPIOD, GPIO_PIN_14, GPIO_PIN_RESET);
break;
case :
HAL_GPIO_WritePin(GPIOD, GPIO_PIN_15, GPIO_PIN_RESET);
break;
}
}

5.标志变量自加。

void FlagPlus(int *flag)
{
(*flag)++;
if((*flag)==)
{
(*flag)=;
}
}

这里一定要用指针,因为函数参数是值传递所以只能用指针来改变LEDNUM_Flag。

6.整合代码。

#include "main.h"
#include "stm32f4xx_hal.h" void SystemClock_Config(void);
static void MX_GPIO_Init(void); int LEDNUM_Flag = ; _Bool GetPress(void); void TurnOnLED(int flag); void TurnOffLED(int flag); void FlagPlus(int *flag); int main(void)
{ HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
//最开始先点亮PD12的LED
HAL_GPIO_WritePin(GPIOD, GPIO_PIN_12, GPIO_PIN_SET);
while ()
{
//有按键按下
if(GetPress()==)
{
TurnOffLED(LEDNUM_Flag);
FlagPlus(&LEDNUM_Flag);
TurnOnLED(LEDNUM_Flag);
}
}
} /** System Clock Configuration
*/
void SystemClock_Config(void)
{ RCC_OscInitTypeDef RCC_OscInitStruct;
RCC_ClkInitTypeDef RCC_ClkInitStruct; /**Configure the main internal regulator output voltage
*/
__HAL_RCC_PWR_CLK_ENABLE(); __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1); /**Initializes the CPU, AHB and APB busses clocks
*/
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
RCC_OscInitStruct.HSIState = RCC_HSI_ON;
RCC_OscInitStruct.HSICalibrationValue = ;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI;
RCC_OscInitStruct.PLL.PLLM = ;
RCC_OscInitStruct.PLL.PLLN = ;
RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
RCC_OscInitStruct.PLL.PLLQ = ;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
} /**Initializes the CPU, AHB and APB busses clocks
*/
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2; if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_5) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
} /**Configure the Systick interrupt time
*/
HAL_SYSTICK_Config(HAL_RCC_GetHCLKFreq()/); /**Configure the Systick
*/
HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK); /* SysTick_IRQn interrupt configuration */
HAL_NVIC_SetPriority(SysTick_IRQn, , );
} /** Configure pins as
* Analog
* Input
* Output
* EVENT_OUT
* EXTI
*/
static void MX_GPIO_Init(void)
{ GPIO_InitTypeDef GPIO_InitStruct; /* GPIO Ports Clock Enable */
__HAL_RCC_GPIOH_CLK_ENABLE();
__HAL_RCC_GPIOD_CLK_ENABLE(); /*Configure GPIO pin Output Level */
HAL_GPIO_WritePin(GPIOD, GPIO_PIN_12|GPIO_PIN_13|GPIO_PIN_14|GPIO_PIN_15, GPIO_PIN_RESET); /*Configure GPIO pin : PD11 */
GPIO_InitStruct.Pin = GPIO_PIN_11;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_PULLUP;
HAL_GPIO_Init(GPIOD, &GPIO_InitStruct); /*Configure GPIO pins : PD12 PD13 PD14 PD15 */
GPIO_InitStruct.Pin = GPIO_PIN_12|GPIO_PIN_13|GPIO_PIN_14|GPIO_PIN_15;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
HAL_GPIO_Init(GPIOD, &GPIO_InitStruct); } /////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////
_Bool GetPress(void)
{
if(HAL_GPIO_ReadPin(GPIOD,GPIO_PIN_11)==)
{
HAL_Delay();
if(HAL_GPIO_ReadPin(GPIOD,GPIO_PIN_11)==)
{
while(HAL_GPIO_ReadPin(GPIOD,GPIO_PIN_11)==)
{;}
return ;
}
else return ;
}
else return ;
} void TurnOnLED(int flag)
{
switch(flag)
{
case :
HAL_GPIO_WritePin(GPIOD, GPIO_PIN_12, GPIO_PIN_SET);
break;
case :
HAL_GPIO_WritePin(GPIOD, GPIO_PIN_13, GPIO_PIN_SET);
break;
case :
HAL_GPIO_WritePin(GPIOD, GPIO_PIN_14, GPIO_PIN_SET);
break;
case :
HAL_GPIO_WritePin(GPIOD, GPIO_PIN_15, GPIO_PIN_SET);
break;
}
} void TurnOffLED(int flag)
{
switch(flag)
{
case :
HAL_GPIO_WritePin(GPIOD, GPIO_PIN_12, GPIO_PIN_RESET);
break;
case :
HAL_GPIO_WritePin(GPIOD, GPIO_PIN_13, GPIO_PIN_RESET);
break;
case :
HAL_GPIO_WritePin(GPIOD, GPIO_PIN_14, GPIO_PIN_RESET);
break;
case :
HAL_GPIO_WritePin(GPIOD, GPIO_PIN_15, GPIO_PIN_RESET);
break;
}
} void FlagPlus(int *flag)
{
(*flag)++;
if((*flag)==)
{
(*flag)=;
}
}
/////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////
/**
* @brief This function is executed in case of error occurrence.
* @param None
* @retval None
*/
void _Error_Handler(char * file, int line)
{
/* USER CODE BEGIN Error_Handler_Debug */
/* User can add his own implementation to report the HAL error return state */
while()
{
}
/* USER CODE END Error_Handler_Debug */
} #ifdef USE_FULL_ASSERT /**
* @brief Reports the name of the source file and the source line number
* where the assert_param error has occurred.
* @param file: pointer to the source file name
* @param line: assert_param error line source number
* @retval None
*/
void assert_failed(uint8_t* file, uint32_t line)
{
/* USER CODE BEGIN 6 */
/* User can add his own implementation to report the file name and line number,
ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
/* USER CODE END 6 */ } #endif

三  重要的API。

//IO口使能,  注意这里是D口
__HAL_RCC_GPIOD_CLK_ENABLE(); //设置推挽输出的IO口输出电平为低
HAL_GPIO_WritePin(GPIOD, GPIO_PIN_12, GPIO_PIN_RESET); //设置推挽输出的IO口输出电平为高
HAL_GPIO_WritePin(GPIOD, GPIO_PIN_12, GPIO_PIN_SET); //初始化一个IO口为输入
GPIO_InitStruct.Pin = GPIO_PIN_11;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_PULLUP;
HAL_GPIO_Init(GPIOD, &GPIO_InitStruct); //初始化IO为推挽输出
GPIO_InitStruct.Pin = GPIO_PIN_12|GPIO_PIN_13|GPIO_PIN_14|GPIO_PIN_15;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
HAL_GPIO_Init(GPIOD, &GPIO_InitStruct); //读取一个输入IO口的电平
HAL_GPIO_ReadPin(GPIOD,GPIO_PIN_11);

(1)STM32使用HAL库操作GPIO的更多相关文章

  1. (2)STM32使用HAL库操作外部中断——理论讲解

    1.中断触发过程 对主程序压栈--把中断服务函数的地址写入到程序计数器(PC)--执行中断服务函数 2.中断向量表 中断服务函数的地址在STM32的手册上的中断向量表中(如下是一部分): 如上表所示, ...

  2. (3)STM32使用HAL库操作外部中断——实战操作

    有了上一篇的基础入门知识,使用Cube创建一个简单的外部中断就容易多了. 一.Cube配置 需求:使用PD10作为外部中断(下降沿触发)控制LED(PD12-PD14) 1.选型 STM32-F4-D ...

  3. STM32 之 HAL库(固件库) _

    1 STM32的三种开发方式 通常新手在入门STM32的时候,首先都要先选择一种要用的开发方式,不同的开发方式会导致你编程的架构是完全不一样的.一般大多数都会选用标准库和HAL库,而极少部分人会通过直 ...

  4. STM32 之 HAL库(固件库)

    1 STM32的三种开发方式 通常新手在入门STM32的时候,首先都要先选择一种要用的开发方式,不同的开发方式会导致你编程的架构是完全不一样的.一般大多数都会选用标准库和HAL库,而极少部分人会通过直 ...

  5. (4)STM32使用HAL库实现串口通讯——理论讲解

    一.查询模式 1. 二.中断模式 1.中断接收. 1.1先看中断接收的流程(以 USART2 为例) 在启动文件中找到中断向量 USART2_IRQHandler 找到USART2_IRQHandle ...

  6. STM32之HAL库、标准外设库、LL库(STM32 Embedded Software)-(转载)

    STM32 Embedded Software  工作以来一直使用ST的STM32系列芯片,ST为开发者提供了非常方便的开发库.到目前为止,有标准外设库(STD库).HAL库.LL库 三种.前两者都是 ...

  7. 如何使用keil5将stm32的hal库编译成lib文件——F1版本

    hal库中keil5中编译的速度是比较慢的,相同情况下,每次都要编译的时候,比标准库是要慢很多的,因此就hal库编译成lib文件是一种加快编译速度的方法,当然也有其自身的缺点.一.步骤1.使用cube ...

  8. STM32基于HAL库通过DMA读写SDIO

    通过STM32CUBEMX生成DMA读写sdio的工程,再读写过程中总会卡死在DMA中断等待读写完成的while中,最终发现while等待的标志在SDIO的中断里置位的,而SDIO中断优先级如果小于或 ...

  9. STM32 关于HAL库硬件SPI要注意的问题总结

    利用STM32CUbeMx编写程序,大大方便了开发,最近做的项目利用到了 STM32CUbeMx的硬件SP,这里对SPI的使用做一个总结. HAL库里的硬件SPI主要有以下几个库函数: /* hspi ...

随机推荐

  1. Day3_函数

    为啥要用到函数: 复杂度增大 组织结构不清晰 可读性差 工具就是具备某一种功能的物件,就是程序中函数的概念. 事先准备工具的过程称为函数的定义 遇到特定的场景拿来用就称为函数的调用 函数的分类: 内置 ...

  2. (五)SpringBoot2.0基础篇- Mybatis与插件生成代码

    SpringBoot与Mybatis合并 一.创建SpringBoot项目,引入相关依赖包: <?xml version="1.0" encoding="UTF-8 ...

  3. Lua读取CSV文件到table中

    创建Lua函数载入CSV文件并保存到表中的函数: function GetLines(fileName) indx = 0 myLines ={} for line in io.line(string ...

  4. webpack4 splitChunksPlugin && runtimeChunkPlugin 配置杂记

    webpack2 还没研究好,就发现升级到4了,你咋这么快~ 最近要做项目脚手架,项目构建准备重新做,因为之前写的太烂了...然后发现webpack大版本已经升到4了(又去看了一眼,4.5了),这么快 ...

  5. swagger上传文件并支持jwt认证

    背景 由于swagger不仅提供了自动实现接口文档的说明而且支持页面调试,告别postman等工具,无需开发人员手动写api文档,缩减开发成本得到大家广泛认可 但是由于swagger没有提供上传文件的 ...

  6. 花生日记_花生日记APP下载_花生日记邀请码

    花生日记 国内领先的社交电商导购分享平台. 独创社交电商3+模式,社交+电商+社群,上线1个月注册用户超百万.合作商家涵括各个类目以及平台.为数万宝妈提供月收入3000以上兼职收入. 微信扫描下方二维 ...

  7. 第三次 orm自动建表及遇到的问题

    Hibernate支持自动建表,在开发阶段很方便,可以保证hbm与数据库表结构的自动同步. 方法很简单,在hibernate.cfg.xml内加入 <property name="hi ...

  8. git merge与 git rebase区别及实例

    接Git分支创建与合并,在分支合并时,有两种方式:git merge 和git rebase. git merge:将两个分支,合并提交为一个新提交,并且新提交有2个parent. git rebas ...

  9. [CVPR 2016] Weakly Supervised Deep Detection Networks论文笔记

    p.p1 { margin: 0.0px 0.0px 0.0px 0.0px; font: 13.0px "Helvetica Neue"; color: #323333 } p. ...

  10. SSM-MyBatis-11:Mybatis中查询全部用resultmap

    ------------吾亦无他,唯手熟尔,谦卑若愚,好学若饥------------- 实体类很普通,四个字段,编号,名字,作者名,价格 在接口中的方法声明如下 //查全部 public List& ...