STM32F1与STM32CubeIDE快速入门-GPIO概述与点亮LED

GPIO概述与点亮LED

在本次实例中,我们将讨论 STM32 GPIO 硬件。 它是如何工作的以及有哪些功能,因此可以以最佳方式对其进行配置以满足应用程序需求。 我们将进入 GPIO 速度、替代功能、锁定机制和不同的可能配置。
在这里插入图片描述

1、STM32的GPIO端口介绍

在STM32中,每个通用 I/O 端口有两个 32 位配置寄存器、两个 32 位数据寄存器、一个 32 位设置/复位寄存器、一个 16 位复位寄存器和一个 32 位锁定寄存器。 每个 I/O 端口位均可自由编程,但是,I/O 端口寄存器必须以 32 位字的形式访问(不允许半字或字节访问)。 设置/复位寄存器的目的是允许对任何 GPIO 寄存器进行原子读/修改访问。 这样,就没有在读取和修改访问之间发生 IRQ 的风险。

一个典型的 GPIO 引脚内部结构的数字图。 它显示了二极管保护、内部上拉或下拉启用/禁用,以及推挽输出驱动器、用于在输入/输出引脚模式之间切换的输出启用/禁用、施密特触发的数字输入、模拟输入。

在这里插入图片描述

必须假设默认情况下除了特定的GPIO引脚,所有GPIO 引脚都不支持5V的,引脚大多为 3.3v。

在这里插入图片描述

所以必须小心输入引脚的电压电平。 设置GPIO输出管脚时还要注意输出电流。 根据数据表,可流入或流入任何 GPIO 引脚的最大电流为 25mA。 并且必须针对正在处理的特定目标微控制器检查它。

GPIO速度

输入模式

当 GPIO 引脚设置为输入模式时,I/O 引脚上的数据在每个 APB2 时钟周期被采样到输入数据寄存器中。 这意味着 APB2 总线速度决定了 GPIO 引脚的输入采样速度。

输出模式

当 GPIO 引脚设置为输出模式时,可以选择通过对配置寄存器中的相应位进行编程来配置引脚速度模式。STM32F103x的配置如下:

在这里插入图片描述

GPIO 位原子操作

在位级别对 GPIOx_ODR 进行编程时,软件无需禁用中断:可以在单个原子 APB2 写访问中仅修改一位或几位。 这是通过将位设置/复位寄存器(GPIOx_BSRR,或仅用于复位 GPIOx_BRR)编程为“1”以选择要修改的位来实现的。 未选择的位将不会被修改。

GPIO 外部中断

所有端口都具有外部中断功能。 要使用外部中断线,端口必须配置为输入模式。 当我们进入 EXTI(外部中断/事件控制器)主题时,我们将更详细地讨论这个问题。

外设引脚选择 (PPS)

为了优化不同器件封装的外设 I/O 功能的数量,可以将一些备用功能重新映射到一些其他引脚。 这是通过软件通过对相应寄存器进行编程来实现的。

此选项可以帮助重新映射外围设备 io 引脚,因此当更改板上的目标微控制器时,不必在 PCB 布局中进行太多更改。 这可能非常有利并简化路由过程。 并帮助您将高速信号移开,从而降低某些部分的噪音水平。

GPIO 锁定机制

锁定机制允许冻结 IO 配置。 当 LOCK 序列应用于端口位时,在下一次复位之前无法再修改端口位的值。

GPIO 配置

根据数据表中列出的每个 I/O 端口的特定硬件特性,通用 IO (GPIO) 端口的每个端口位都可以由软件在多种模式下单独配置:

输出配置

  • 输出开漏
  • 输出推挽

输入配置

  • 输入浮动 (Hi-Z)
  • 输入上拉
  • 输入下拉

备用功能配置

  • 交替功能推挽
  • 备用功能开漏

总之,在STM32中,并非所有 GPIO 引脚都能承受 5v 电压。 大多数情况下,它们是 3.3v。无论操作模式如何,都必须为要使用的 GPIO 启用时钟。置 GPIO 输出引脚时,可以选择适合您应用的速度。 IO线上是否需要高频开关。APB2 总线速度决定了所有 GPIO 输入配置引脚的采样率。

2、创建并配置STM32Cube IDE工程

第一步、创建工程

在这里插入图片描述

第二步、选择芯片

在这里插入图片描述

第三步、完成工程创建:

在这里插入图片描述

第四步、配置时钟

在这里插入图片描述

在这里插入图片描述

第五步、配置GPIO

在这里插入图片描述

在这里插入图片描述

第六步、保存配置,生成代码

在这里插入图片描述

生成的代码如下:

在这里插入图片描述

3、编写驱动代码

STM32Cube IDE生成了脚手架代码,用户自定代码必须添加在

1
2
3
/* xxx BEGIN x*/
/* xxx END x*/

之间,或者创建的文件中。如果在此范围之外定义代码,在下次更改配置,生成代码时,将被覆盖!!!

STM32Cube IDE生成的主要代码如下:

系统时钟配置代码

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
/\*\*
\* @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();
}
}

GPIO初始化代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
/\*\*
\* @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\_GPIOC\_CLK\_ENABLE();

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

/\*Configure GPIO pin : PC6 \*/
GPIO_InitStruct.Pin = 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(GPIOC, &GPIO_InitStruct);

}

应用程序入口代码

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
/\*\*
\* @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 \*/
}
/\* USER CODE END 3 \*/
}

main.c文件的main函数中添加如下代码:

在这里插入图片描述

编译并生成程序,下载到开发板即可运行。

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