《嵌入式-STM32开发指南》第二部分 基础篇 - 第1章 GPIO(HAL库)

1.1 GPIO流水灯硬件电路分析

发光二极管是属于二极管的一种,具有二级管单向导电特性,即只有在正向电压(二极管的正极接正,负极接负)下才能导通发光。PB0引脚接发光二极管(LED1)的正极,所以PB0引脚输出高电平LED1亮,PB0引脚输出低电平LED1熄灭,,LED2,LED3同理。

图1 LED电路图

在上一章,我们知道STM32的引脚有8中模式,我们要点亮LED,显然是输出模式,那么则要将PB0、PG6、PG7设置为普通输出模式,那么是是开漏输出,还是推挽输出呢?或者都可以。为了使得LED点亮,我们只需要将PB0、PG6、PG7输出为高电平,斌企鹅需要输出电流,则需要将其设置为推挽输出,因为如果是开漏输出,则不会有电流,LED就不会点亮。好了,就到这里吧,我们使用STM32Cube新建工程。

1.2 STM32Cube新建工程

关于如何使用使用STM32Cube新建工程在前文已经讲解过了,这里直说配置GPIO部分内容。本文要实现流水灯,其实输出为初始化设置为高电平还是低电平都可以,因为流水灯需要不断反转。

1.首先进行系统配置

Debug模式选择可以选择其他模式,默认选择No debug,Timebase Source选择SysTick,关于Timebase Source在后文会详细讲解。

图2系统配置

2.时钟配置,外部高速时钟

图3

配置系统时钟配置72MHz,APB1总线配置36MHz。默认高速时钟是使用内部(HSI),而且CPU时钟配置的比较低。以我选择的STM32F103,外部8M晶振为例(如下图)。

图4

3.GPIO初始化配置

我们将PB0、PG6、PG7配置输出模式(高电平、低电平均可)、输出速率、上/下拉等,默认即可。

图5 GPIO初始化

4.工程生成设置

图6

其他默认即可。最后点击“生成代码”即可生成代码。

图7生成代码

1.3 GPIO流水灯实现与代码分析

1.3.1 流水灯实现

我们要实现流水灯,需要在主函数添加一下代码。

HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_0);

HAL_Delay(500);

HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_0);

HAL_GPIO_TogglePin(GPIOG, GPIO_PIN_6);

HAL_Delay(500);

HAL_GPIO_TogglePin(GPIOG, GPIO_PIN_6);

HAL_GPIO_TogglePin(GPIOG, GPIO_PIN_7);

HAL_Delay(500);

HAL_GPIO_TogglePin(GPIOG, GPIO_PIN_7);
图8

1.3.2流水灯代码分析

在分析代码前,先看看流水灯编程流程:

1>使能GPIO端口时钟;

2>初始化GPIO引脚,即为GPIO初始化结构体赋值,并调用相应初始化函数完成初始化配置;

3>根据实际需求控制流水灯。

STM32采用固件库开发,代码比较多,因此,我们在看一个实际工程时,只需从主函数开始,好了,接下来,笔者就带领大家一步一步看看流水灯是怎么实现的。笔者先贴出主函数代码。

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 */

 HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_0);

 HAL_Delay(500);

 HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_0);

 HAL_GPIO_TogglePin(GPIOG, GPIO_PIN_6);

 HAL_Delay(500);

 HAL_GPIO_TogglePin(GPIOG, GPIO_PIN_6);

 HAL_GPIO_TogglePin(GPIOG, GPIO_PIN_7);

 HAL_Delay(500);

 HAL_GPIO_TogglePin(GPIOG, GPIO_PIN_7);

 /* USER CODE BEGIN 3 */

 }

 /* USER CODE END 3 */

}

注释部分不用管,我们只看代码。

1.复位所有硬件

HAL_Init()函数为复位所有硬件,这个就不细说了。

HAL_StatusTypeDef HAL_Init(void)

{

 /* Configure Flash prefetch */

#if (PREFETCH_ENABLE != 0)

#if defined(STM32F101x6) || defined(STM32F101xB) || defined(STM32F101xE) || defined(STM32F101xG) || \

 defined(STM32F102x6) || defined(STM32F102xB) || \

 defined(STM32F103x6) || defined(STM32F103xB) || defined(STM32F103xE) || defined(STM32F103xG) || \

 defined(STM32F105xC) || defined(STM32F107xC)

 /* Prefetch buffer is not available on value line devices */

 __HAL_FLASH_PREFETCH_BUFFER_ENABLE();

#endif

#endif /* PREFETCH_ENABLE */

 /* Set Interrupt Group Priority */

 HAL_NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_4);

 /* Use systick as time base source and configure 1ms tick (default clock after Reset is HSI) */

 HAL_InitTick(TICK_INT_PRIORITY);

 /* Init the low level hardware */

 HAL_MspInit();

 /* Return function status */

 return HAL_OK;

}

2.时钟初始化函数

SystemClock_Config()函数用于时钟初始化,也就是通过STM32Cube实现。

图9时钟配置

时钟初始化函数如下:

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();

 }

}

RCC_OscInitTypeDef结构体类型定义时钟来源和系统时钟生成配置,就是图9中的配置,本例程使用外部8MHz晶振,通过PLL锁相环9倍频后得到72M系统时钟。

RCC_ClkInitTypeDef结构体类型定义总线时钟配置,一般选择使能系统时钟、AHB、APB1和APB2总线时钟,其中只有APB1总线时钟36MHz,其他都为72MHz。

HAL_RCC_ClockConfig函数就是HAL定义的一个系统滴答定时器初始化配置函数,通过这个函数得到延时效果。

2.GPIO初始化函数

MX_GPIO_Init()函数用于LED的GPIO初始化,代码如下:

static void MX_GPIO_Init(void)

{

 GPIO_InitTypeDef GPIO_InitStruct = {0};

 /* GPIO Ports Clock Enable */

 __HAL_RCC_GPIOB_CLK_ENABLE();

 __HAL_RCC_GPIOG_CLK_ENABLE();

 /*Configure GPIO pin Output Level */

 HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_RESET);

 /*Configure GPIO pin Output Level */

 HAL_GPIO_WritePin(GPIOG, GPIO_PIN_6|GPIO_PIN_7, GPIO_PIN_RESET);

 /*Configure GPIO pin : PB0 */

 GPIO_InitStruct.Pin = GPIO_PIN_0;

 GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;

 GPIO_InitStruct.Pull = GPIO_NOPULL;

 GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;

 HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

 /*Configure GPIO pins : PG6 PG7 */

 GPIO_InitStruct.Pin = GPIO_PIN_6|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(GPIOG, &GPIO_InitStruct);

}

以上就是LED的初始化函数,初始化GPIO有个重要的结构体GPIO_InitTypeDef,先看看该结构体。

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;
  • Pin:引脚编号选择,一个GPIO有16个引脚可选,参数可选有:GPIO_PIN_0、….、GPIO_PIN_15和GPIO_PIN_ALL。很多时候我们可以使用或运算进行选择:GPIO_PIN_0| GPIO_PIN_4。

  • Mode:引脚模式选择,在前文笔者已经介绍了引脚有8中工作模式,根据外设选择相应模式。

表1GPIO引脚工作模式
  • Pull:上下拉,用于输入模式,可选:GPIO_NOPULL不上下拉;GPIO_PULLUP:使能下拉;GPIO_PULLDOWN使能下拉;

  • Speed:引脚速度,可选:GPIO_SPEED_FREQ_LOW:低速(2MHz);中速(10MHz);高速(50MHz)。

在初始化代码中,还有一个重要的函数HAL_GPIO_WritePin()。HAL_GPIO_WritePin()函数为3个LED灯时钟初始化状态,这里设置为低电平,所以初始化状态3个LED都是暗的。

4.流水灯实现

在前文已经贴出了流水灯的相应代码。

while (1)

{

 /* USER CODE END WHILE */

 HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_0);

 HAL_Delay(500);

 HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_0);

 HAL_GPIO_TogglePin(GPIOG, GPIO_PIN_6);

 HAL_Delay(500);

 HAL_GPIO_TogglePin(GPIOG, GPIO_PIN_6);

 HAL_GPIO_TogglePin(GPIOG, GPIO_PIN_7);

 HAL_Delay(500);

 HAL_GPIO_TogglePin(GPIOG, GPIO_PIN_7);

 /* USER CODE BEGIN 3 */

}

HAL_GPIO_TogglePin函数用于GPIO电平反转,HAL_Delay用于延时,单位是毫秒,以此不断将LED1、LED2、LED3关灭,这就是实现流水灯的效果。

1.4实验现象

将编译好的程序下载到板子中,可以看到三个LED灯不同地闪烁。


代码获取方式
1.关注公众号[嵌入式实验楼]
2.在公众号回复关键词[STM32F1]获取资料

欢迎访问我的网站:
BruceOu的哔哩哔哩
BruceOu的主页
BruceOu的博客
CSDN博客

你可能感兴趣的:(《嵌入式-STM32开发指南》第二部分 基础篇 - 第1章 GPIO(HAL库))