STM32F1与STM32CubeIDE快速入门-按键与LED控制

GPIO数字输入与数字输出

GPIO(General Purpose Input Output)即通用输入输出。输入和输出是GPIO的基本特征。在前面的实例中,对GPIO做了整体概述,请参考STM32F1与STM32CubeIDE快速入门-GPIO概述与点亮LED。在本次实例中,将着重介绍如何通过HAL库对GPIO进行基本操作。

在这里插入图片描述

1、HAL库中GPIO的驱动介绍

1)GPIO初始化定义:GPIO_InitTypeDef

GPIO_InitTypeDef在stm32f1xx_hal_gpio.h中定义:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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 \*/
} GPIO_InitTypeDef;


2)GPIO外设特性

GPIO 端口,可以在多种模式下由软件单独配置:

  • 输入模式
  • 模拟模式
  • 输出模式
  • 交替功能模式
  • 外部中断/事件线

在复位期间和刚复位后, 替代功能和外部中断线不活动,I/O 端口配置为输入浮动模式。所有 GPIO 引脚都有内部弱上拉和下拉电阻,可以激活或不激活。

在输出或交替功能模式下,每个 IO 都可以配置为开漏或推挽类型,并且可以根据 VDD 值选择 IO 速度。

所有端口都具有外部中断/事件功能。 要使用外部中断线,端口必须配置为输入模式。 所有可用的 GPIO 引脚都连接到从 EXTI0 到 EXTI15 的 16 条外部中断/事件线。

外部中断/事件控制器由连接线设备中的多达 20 个边缘检测器或其他设备中的 19 个边缘检测器组成,用于生成事件/中断请求。 每条输入线都可以独立配置选择类型(事件或中断)和相应的触发事件(上升或下降或两者兼有)。每条线也可以独立屏蔽。 挂起寄存器维护中断请求的状态线。

2、HAL的GPIO驱动使用步骤

  • 1)启用 GPIO APB2 时钟:__HAL_RCC_GPIOx_CLK_ENABLE()
  • 2)使用 HAL_GPIO_Init() 配置 GPIO 引脚:
    • 使用GPIO_InitTypeDef 结构中的Mode字段配置 IO 模式
    • 使用 GPIO_InitTypeDef 结构中的Pull字段激活上拉、下拉电阻
    • 在输出或交替功能模式选择的情况下:通过GPIO_InitTypeDef结构中的Speed成员配置速度
    • 当引脚用作 ADC 通道或 DAC 输出时,需要配置模拟模式
    • 在外部中断/事件选择的情况下,GPIO_InitTypeDef 结构中的Mode成员选择类型(中断或事件)和相应的触发事件(上升或下降或两者)
  • 3)在外部中断/事件模式选择的情况下,使用HAL_NVIC_SetPriority()配置映射到 EXTI 线的 NVIC IRQ 优先级并使用HAL_NVIC_EnableIRQ()启用它
  • 4)使用HAL_GPIO_ReadPin()获取在输入模式下配置的引脚电平
  • 5)使用HAL_GPIO_WritePin()HAL_GPIO_TogglePin()设置/重置在输出模式下配置的引脚电平
  • 6)使用HAL_GPIO_LockPin()锁定引脚配置直到下一次复位
  • 7)在复位期间和刚复位后,交替功能未激活且GPIO引脚配置为输入浮动模式(JTAG 引脚除外)
  • 8)当 LSE 振荡器关闭时,LSE振荡器引脚OSC32_INOSC32_OUT可用作通用(分别为 PC14 和 PC15)。LSE优先于GPIO功能。
  • 9)当 HSE 振荡器关闭时,HSE 振荡器引脚OSC_IN/OSC_OUT可分别用作通用PD0和PD1。 HSE优先于GPIO 功能。

HAL库中常用的GPIO函数如下:

  • **HAL_GPIO_Init **:GPIO初始化
  • **HAL_GPIO_DeInit **:GPIO逆初始化,将GPIO的寄存设置为默认值
  • **HAL_GPIO_ReadPin **:读取指定引脚电平
  • HAL_GPIO_WritePin:设置指定引脚电平
  • **HAL_GPIO_TogglePin **:切换指定的 GPIO 引脚,即高低电平之间切换
  • **HAL_GPIO_LockPin ** **:锁定 GPIO 引脚配置寄存器
  • **HAL_GPIO_EXTI_IRQHandler **:处理 EXTI 中断请求
  • **HAL_GPIO_EXTI_Callback **:EXTI 线路检测回调

3、STM32Cube IDE工程配置

1)第一步:创建工程,请参考:STM32F1与STM32CubeIDE快速入门-GPIO概述与点亮LED

2)第二步:配置系统时钟,请参考:STM32F1与STM32CubeIDE快速入门-GPIO概述与点亮LED

3)第三步:配置引脚:

在这里插入图片描述

  • 将PE2、PE3、PE4、PE5作为按键输入引脚
  • 将PC6、PC7、PD6、PD13作为LED输出引脚

按键电路原理图如下:

在这里插入图片描述

LED电路原理图如下:

在这里插入图片描述

4)第四步,保存配置,生成代码

4、代码实现

STM32Cube IDE根据配置生成了相应的文件。在本次实例中,只需要在main.c中添加如下代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
/\* USER CODE BEGIN Header \*/
/\*\*
\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
\* @file : main.c
\* @brief : Main program body
\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
\* @attention
\*
\* <h2><center>&copy; Copyright (c) 2021 STMicroelectronics.
\* All rights reserved.</center></h2>
\*
\* This software component is licensed by ST under BSD 3-Clause license,
\* the "License"; You may not use this file except in compliance with the
\* License. You may obtain a copy of the License at:
\* opensource.org/licenses/BSD-3-Clause
\*
\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
\*/
/\* USER CODE END Header \*/
/\* Includes ------------------------------------------------------------------\*/
#include "main.h"

/\* Private includes ----------------------------------------------------------\*/
/\* USER CODE BEGIN Includes \*/

/\* USER CODE END Includes \*/

/\* Private typedef -----------------------------------------------------------\*/
/\* USER CODE BEGIN PTD \*/

/\* USER CODE END PTD \*/

/\* Private define ------------------------------------------------------------\*/
/\* USER CODE BEGIN PD \*/
/\* USER CODE END PD \*/

/\* Private macro -------------------------------------------------------------\*/
/\* USER CODE BEGIN PM \*/

/\* USER CODE END PM \*/

/\* Private variables ---------------------------------------------------------\*/

/\* USER CODE BEGIN PV \*/

/\* USER CODE END PV \*/

/\* Private function prototypes -----------------------------------------------\*/
void SystemClock\_Config(void);
static void MX\_GPIO\_Init(void);
/\* USER CODE BEGIN PFP \*/

/\* USER CODE END PFP \*/

/\* Private user code ---------------------------------------------------------\*/
/\* USER CODE BEGIN 0 \*/

/\* USER CODE END 0 \*/

/\*\*
\* @brief The application entry point.
\* @retval int
\*/
int main(void) {
/\* USER CODE BEGIN 1 \*/

/\* USER CODE END 1 \*/

/\* MCU Configuration--------------------------------------------------------\*/

/\* Reset of all peripherals, Initializes the Flash interface and the Systick. \*/
HAL\_Init();

/\* USER CODE BEGIN Init \*/

/\* USER CODE END Init \*/

/\* Configure the system clock \*/
SystemClock\_Config();

/\* USER CODE BEGIN SysInit \*/

/\* USER CODE END SysInit \*/

/\* Initialize all configured peripherals \*/
MX\_GPIO\_Init();
/\* USER CODE BEGIN 2 \*/

/\* USER CODE END 2 \*/

/\* Infinite loop \*/
/\* USER CODE BEGIN WHILE \*/
while (1) {
/\* USER CODE END WHILE \*/

/\* USER CODE BEGIN 3 \*/
if (HAL\_GPIO\_ReadPin(GPIOE, GPIO_PIN_5) == GPIO_PIN_RESET) { // 读取引脚电平
HAL\_GPIO\_WritePin(GPIOC, GPIO_PIN_6, GPIO_PIN_SET); // 设置引脚为高电平
HAL\_Delay(100); // 延时100ms
HAL\_GPIO\_WritePin(GPIOC, GPIO_PIN_6, GPIO_PIN_RESET); // 将引脚设置为低电平
}
if (HAL\_GPIO\_ReadPin(GPIOE, GPIO_PIN_4) == GPIO_PIN_RESET) {
// HAL\_GPIO\_TogglePin(GPIOC, GPIO\_PIN\_7);
HAL\_GPIO\_WritePin(GPIOC, GPIO_PIN_7, GPIO_PIN_SET);
HAL\_Delay(100);
HAL\_GPIO\_WritePin(GPIOC, GPIO_PIN_7, GPIO_PIN_RESET);
}
if (HAL\_GPIO\_ReadPin(GPIOE, GPIO_PIN_3) == GPIO_PIN_RESET) {
// HAL\_GPIO\_TogglePin(GPIOD, GPIO\_PIN\_6);
HAL\_GPIO\_WritePin(GPIOD, GPIO_PIN_6, GPIO_PIN_SET);
HAL\_Delay(100);
HAL\_GPIO\_WritePin(GPIOD, GPIO_PIN_6, GPIO_PIN_RESET);
}
if (HAL\_GPIO\_ReadPin(GPIOE, GPIO_PIN_2) == GPIO_PIN_RESET) {
// HAL\_GPIO\_TogglePin(GPIOD, GPIO\_PIN\_13);
HAL\_GPIO\_WritePin(GPIOD, GPIO_PIN_13, GPIO_PIN_SET);
HAL\_Delay(100);
HAL\_GPIO\_WritePin(GPIOD, GPIO_PIN_13, GPIO_PIN_RESET);
}
HAL\_Delay(10);
}
/\* USER CODE END 3 \*/
}

/\*\*
\* @brief System Clock Configuration
\* @retval None
\*/
void SystemClock\_Config(void) {
RCC_OscInitTypeDef RCC_OscInitStruct = { 0 };
RCC_ClkInitTypeDef RCC_ClkInitStruct = { 0 };

/\*\* Initializes the RCC Oscillators according to the specified parameters
\* in the RCC\_OscInitTypeDef structure.
\*/
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;
RCC_OscInitStruct.HSIState = RCC_HSI_ON;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9;
if (HAL\_RCC\_OscConfig(&RCC_OscInitStruct) != HAL_OK) {
Error\_Handler();
}
/\*\* Initializes the CPU, AHB and APB buses 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_DIV2;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;

if (HAL\_RCC\_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK) {
Error\_Handler();
}
}

/\*\*
\* @brief GPIO Initialization Function
\* @param None
\* @retval None
\*/
static void MX\_GPIO\_Init(void) {
GPIO_InitTypeDef GPIO_InitStruct = { 0 };

/\* GPIO Ports Clock Enable \*/
\_\_HAL\_RCC\_GPIOE\_CLK\_ENABLE();
\_\_HAL\_RCC\_GPIOD\_CLK\_ENABLE();
\_\_HAL\_RCC\_GPIOC\_CLK\_ENABLE();

/\*Configure GPIO pin Output Level \*/
HAL\_GPIO\_WritePin(GPIOD, GPIO_PIN_13 | GPIO_PIN_6, GPIO_PIN_RESET);

/\*Configure GPIO pin Output Level \*/
HAL\_GPIO\_WritePin(GPIOC, GPIO_PIN_7, GPIO_PIN_RESET);

/\*Configure GPIO pins : PE2 PE3 PE4 PE5 \*/
GPIO_InitStruct.Pin = GPIO_PIN_2 | GPIO_PIN_3 | GPIO_PIN_4 | GPIO_PIN_5;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL\_GPIO\_Init(GPIOE, &GPIO_InitStruct);

/\*Configure GPIO pins : PD13 PD6 \*/
GPIO_InitStruct.Pin = GPIO_PIN_13 | GPIO_PIN_6;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL\_GPIO\_Init(GPIOD, &GPIO_InitStruct);

/\*Configure GPIO pin : PC6 \*/
GPIO_InitStruct.Pin = GPIO_PIN_6;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL\_GPIO\_Init(GPIOC, &GPIO_InitStruct);

/\*Configure GPIO pin : PC7 \*/
GPIO_InitStruct.Pin = GPIO_PIN_7;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL\_GPIO\_Init(GPIOC, &GPIO_InitStruct);

}

/\* USER CODE BEGIN 4 \*/

/\* USER CODE END 4 \*/

/\*\*
\* @brief This function is executed in case of error occurrence.
\* @retval None
\*/
void Error\_Handler(void) {
/\* USER CODE BEGIN Error\_Handler\_Debug \*/
/\* User can add his own implementation to report the HAL error return state \*/
\_\_disable\_irq();
while (1) {
}
/\* 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 /\* USE\_FULL\_ASSERT \*/

/\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* (C) COPYRIGHT STMicroelectronics \*\*\*\*\*END OF FILE\*\*\*\*/


文章来源: https://iotsmart.blog.csdn.net/article/details/123176631