Bootstrap

第2课【CMSIS和标准库开发】标准库 CMSIS 分层

基本知识框架

在这里插入图片描述

课堂笔记

CMSIS

由于有众多外设厂商为Cortex内核提供外设,不同的外设带来的差异,导致软件在编写或移植时会出现很大困难,所以Arm公司同芯片厂商共同协作推出了CMSIS标准。全称是Cortex MicroController Software Interface Standard【Cortex微控制器软件接口标准】

CMSIS的分层关系和作用

CMSIS标准规定了APPLICATION层CMSIS层MCU层,层与层之间的关系如下图
在这里插入图片描述
CMSIS标准最重要的作用就是在用户层和硬件层之间建立硬件抽象层,从而屏蔽硬件层差异,并向用户层提供处理器软件接口

CMSIS层文件结构

根据CMSIS标准,ST官方提供了内核寄存器相关文件(CMSIS相关)外设寄存器相关文件(CMSIS以外的,外设标准库),它们的关系如下
在这里插入图片描述
从文件结构可以看出,CMSIS层的核心主要分为内核函数层外设函数访问层

  • 内核函数层:其中文件主要由Arm公司提供,文件内容包括内核寄存器的的名称,地址定义
  • 外设函数访问层:其中文件主要由芯片生产商提供,文件内容包括外设寄存器和中断的名称,地址定义
内核函数层文件

内核函数层的文件主要的作用是时钟配置与操作内核寄存器,一般来说很少会使用

  • system_stm32f10x.h / .c:操作RCC时钟,实现系统时钟的配置。系统上电时,会首先执行startup文件,startup文件会调用SystemInit函数,这个函数就是在本文件中定义的,默认状态下调用完成后会将系统时钟初始化为72MHz
  • core_cm3.h / .c:实现内核寄存器的名称地址定义,操作寄存器的函数
外设函数访问层文件

外设函数访问层的文件主要作用是实现外设地址映射,操作外设寄存器,这里的文件会经常用到

  • stm32f10x_xxxx.h / .c:xxxx指的是gpio,adc等等,每个外设都有对应src驱动源文件和inc定义相关头文件。是外设标准库的主要部分
  • stm32f10x.h:实现了片上外设的所有寄存器映射

标准库开发

在之前的第1课中,已经实现了基础的库函数,并通过它点亮了LED灯。在学习了标准库后,可以尝试通过标准库来实现点亮LED的功能,并加上其他进阶的其他功能

标准库开发 LED-GPIO

LED功能 头文件bsp_led.h代码主体部分实现

#ifndef __BSP_LED_H__
#define __BSP_LED_H__

#include "stm32f1xx_hal.h"
// GPIO输出高、低以及反转电平
#define digitalHi(Port, Pin) ((Port)->BSRR = Pin)
#define digitalLi(Port, Pin) ((Port)->BRR  = Pin)
#define digitalRev(Port,Pin) ((Port)->ODR ^= Pin)
// RGB灯的开、关以及反转
#define LED1_ON  digitalLi(LED1_GPIO_Port, LED1_Pin)
#define LED1_OFF digitalHi(LED1_GPIO_Port, LED1_Pin)
#define LED1_REV digitalRev(LED1_GPIO_Port, LED1_Pin)

#define LED2_ON  digitalLi(LED2_GPIO_Port, LED2_Pin)
#define LED2_OFF digitalHi(LED2_GPIO_Port, LED2_Pin)
#define LED2_REV digitalRev(LED2_GPIO_Port, LED2_Pin)

#define LED3_ON  digitalLi(LED3_GPIO_Port, LED3_Pin)
#define LED3_OFF digitalHi(LED3_GPIO_Port, LED3_Pin)
#define LED3_REV digitalRev(LED3_GPIO_Port, LED3_Pin)
// RGB灯以及其它衍生颜色的灯
#define LED_RED \
				LED1_ON;\
				LED2_OFF;\
				LED3_OFF;

#define LED_GREEN \
				LED1_OFF;\
				LED2_ON;\
				LED3_OFF;

#define LED_BLUE \
				LED1_OFF;\
				LED2_OFF;\
				LED3_ON;

#define LED_YELLOW \
				LED1_ON;\
				LED2_ON;\
				LED3_OFF;

#define LED_PURPLE \
				LED1_ON;\
				LED2_OFF;\
				LED3_ON;

#define LED_CYAN \
				LED1_OFF;\
				LED2_ON;\
				LED3_ON;

#define LED_WHITE \
				LED1_ON;\
				LED2_ON;\
				LED3_ON;

#define LED_BLACK \
				LED1_OFF;\
				LED2_OFF;\
				LED3_OFF;

void LED_GPIO_Config(void);

#endif

LED功能 源文件bsp_key.c代码主体部分实现

#ifndef BSP_LED_C_
#define BSP_LED_C_

#include "bsp_led.h"
#include "main.h"
// LED相关GPIO口初始化
void LED_GPIO_Config(void)
{
	// 使能GPIOB的时钟
	__HAL_RCC_GPIOB_CLK_ENABLE();
	
	// 定义并补充结构体信息
	GPIO_InitTypeDef* GPIO_LED_Structure;
	
	GPIO_LED_Structure->Pin   = LED1_Pin;

	GPIO_LED_Structure->Mode  = GPIO_MODE_OUTPUT_PP;

	GPIO_LED_Structure->Speed = GPIO_SPEED_FREQ_HIGH;
	
	// 初始化GPIO口
	HAL_GPIO_Init(LED1_GPIO_Port, GPIO_LED_Structure);

	GPIO_LED_Structure->Pin   = LED2_Pin;

	HAL_GPIO_Init(LED2_GPIO_Port, GPIO_LED_Structure);

	GPIO_LED_Structure->Pin   = LED3_Pin;

	HAL_GPIO_Init(LED3_GPIO_Port, GPIO_LED_Structure);
	
	// 输出高电平
	HAL_GPIO_WritePin(LED1_GPIO_Port, LED1_Pin, GPIO_PIN_SET);

	HAL_GPIO_WritePin(LED2_GPIO_Port, LED2_Pin, GPIO_PIN_SET);

	HAL_GPIO_WritePin(LED3_GPIO_Port, LED3_Pin, GPIO_PIN_SET);
}
#endif

main.c代码主体部分实现

/* 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 */
#include "bsp_led.h"
/* 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 */
  LED_GPIO_Config();
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */
	LED1_ON;
    /* USER CODE BEGIN 3 */
  }
  /* 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_HSI;
  RCC_OscInitStruct.HSIState = RCC_HSI_ON;
  RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE;
  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_HSI;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;

  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_0) != 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_GPIOC_CLK_ENABLE();
  __HAL_RCC_GPIOA_CLK_ENABLE();
  __HAL_RCC_GPIOB_CLK_ENABLE();

  /*Configure GPIO pin Output Level */
  HAL_GPIO_WritePin(GPIOB, LED2_Pin|LED3_Pin|LED1_Pin, GPIO_PIN_SET);

  /*Configure GPIO pin : KEY2_Pin */
  GPIO_InitStruct.Pin = KEY2_Pin;
  GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  HAL_GPIO_Init(KEY2_GPIO_Port, &GPIO_InitStruct);

  /*Configure GPIO pin : KEY1_Pin */
  GPIO_InitStruct.Pin = KEY1_Pin;
  GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  HAL_GPIO_Init(KEY1_GPIO_Port, &GPIO_InitStruct);

  /*Configure GPIO pins : LED2_Pin LED3_Pin LED1_Pin */
  GPIO_InitStruct.Pin = LED2_Pin|LED3_Pin|LED1_Pin;
  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);

}

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

标准库开发 KEY-GPIO

KEY功能 头文件bsp_key.h代码主体部分实现

#ifndef __BSP_LED_H__
#define __BSP_LED_H__

#include "stm32f1xx_hal.h"

void KEYScan(void);

void LED_GPIO_Config(void);

#endif

KEY功能 源文件bsp_key.c代码主体部分实现

#ifndef BSP_LED_C_
#define BSP_LED_C_

#include "bsp_led.h"
#include "main.h"

void KEYScan(void)
{
	if (GPIO_PIN_SET == HAL_GPIO_WritePin(KEY_GPIO_Port, KEY_Pin))
		while(GPIO_PIN_SET == HAL_GPIO_WritePin(KEY_GPIO_Port, KEY_Pin));
		return GPIO_PIN_SET;
	else
		return GPIO_PIN_RESET;
}

// KEY相关GPIO口初始化
void KEY_GPIO_Config(void)
{
	// 使能GPIOC的时钟
	__HAL_RCC_GPIOC_CLK_ENABLE();
	
	// 定义并补充结构体信息
	GPIO_InitTypeDef* GPIO_LED_Structure;
	
	GPIO_LED_Structure->Pin   = KEY_Pin;

	GPIO_LED_Structure->Mode  = GPIO_Mode_IN_FLOATING;
	
	// 初始化GPIO口
	HAL_GPIO_Init(LED1_GPIO_Port, GPIO_LED_Structure);

}
#endif

main.c代码主体部分实现

/* 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 */
#include "bsp_led.h"
/* 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 */
  KEY_GPIO_Config();
  LED_GPIO_Config();
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */
	if (GPIO_PIN_SET == KEYScan())
		LED1_ON;
    /* USER CODE BEGIN 3 */
  }
  /* 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_HSI;
  RCC_OscInitStruct.HSIState = RCC_HSI_ON;
  RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE;
  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_HSI;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;

  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_0) != 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_GPIOC_CLK_ENABLE();
  __HAL_RCC_GPIOA_CLK_ENABLE();
  __HAL_RCC_GPIOB_CLK_ENABLE();

  /*Configure GPIO pin Output Level */
  HAL_GPIO_WritePin(GPIOB, LED2_Pin|LED3_Pin|LED1_Pin, GPIO_PIN_SET);

  /*Configure GPIO pin : KEY2_Pin */
  GPIO_InitStruct.Pin = KEY2_Pin;
  GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  HAL_GPIO_Init(KEY2_GPIO_Port, &GPIO_InitStruct);

  /*Configure GPIO pin : KEY1_Pin */
  GPIO_InitStruct.Pin = KEY1_Pin;
  GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  HAL_GPIO_Init(KEY1_GPIO_Port, &GPIO_InitStruct);

  /*Configure GPIO pins : LED2_Pin LED3_Pin LED1_Pin */
  GPIO_InitStruct.Pin = LED2_Pin|LED3_Pin|LED1_Pin;
  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);

}

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

标准库开发 位带操作

位带
位带

位操作指的是可以对单独某个位进行读写操作,当需要对某些位进行频繁读写操作时,通过位操作可以轻松便捷的实现。但Cortex内核的寻址能力仅能达到字节级别,如果要进行位操作,就只能通过位带

位带指的是STM32中可以进行位操作的地址区域。但这里的位操作不是直接对位带中的地址进行位操作,而是要通过访问位带区的“替身”:位带别名区

位带别名区

位带别名区是STM32中服务于位带区的特殊地址范围。对于位带别名区的所有操作,都会体现到位带区上

STM32中可以实现位带的地址区域有两个外设位带区sRam位带区

外设位带区sRam位带区
地址范围:0X4000 0000~0X4010 0000地址范围:0X2000 0000~X2010 0000
大小:1MB大小:1MB
外设位带别名区sRam位带别名区
地址范围:0X4200 0000~0X43FF FFFF地址范围:0X2200 0000~0X23FF FFFF
大小:32MB大小:32MB

访问的原理:将位带区的每1个位【bit】一一映射到位带别名区对应的4个字节【Byte】。而位带别名区地址对应的内容是LSB,也就是最低位有效,这意味着只要读写位带别名区那四个字节的最低位,就等效于读写位带区的对应位

位带区和位带别名区大小的联系
由于将位带区的1个位映射到位带别名区的4个字节,1字节=8位,所以位带别名区的大小是位带区的32倍


为什么要将1个位映射到4个字节
由于STM32内部的数据总线是32位的,CPU进行32位数据的处理是最高效的,所以将1位映射成4字节,是一种用空间换取时间的做法,原理类似于C语言结构体中的成员大小对齐

位带区和位带别名区的地址转换

根据位带区与位带别名区的映射原理,要想得到位带区中地址A对应字节的第n位,对应位带别名区地址。

计算公式:位带别名区地址 = (0xF000 000 * A + 0x0200 0000) + ((A * 0x00FF FFFF * 8 + n) * 4)

  • 前半部分0xF000 000 * A + 0x0200 0000 :计算的是位带别名区的起始地址,并根据地址判断到底是外设位带别名区还是sRam位带别名区
  • 后半部分(A * 0x00FF FFFF * 8 + n) * 4:计算的是位对于位带别名区起始地址的偏移量,(A * 0x00FF FFFF * 8 + n)首先计算出位带区中给,A的第n位相对于起始地址的偏移量,单位为位,最后*4是将这个偏移量转换成对应位带别名区偏移量
通过位带操作点亮LED灯

位带操作LED功能 头文件bsp_bitband.h代码主体部分实现

/*
 * bsp_bitband.h
 *
 *  Created on: Sep 16, 2021
 *      Author: 67566
 */

#ifndef BSP_BITBAND_H_
#define BSP_BITBAND_H_

#include "stm32f1xx_hal.h"
// 计算位带区对应位带别名区地址
#define BITBAND(addr,bit)   ((addr & 0xF0000000)+0x02000000+((addr & 0x000FFFFF)<<5)+(bit<<2))
// 强转地址,其中volatile不能省略,否则编译器会进行参数优化
#define MEM_ADDR(addr)      (*(volatile unsigned long*)(addr))
#define BIT_ADDR(addr,bit)  MEM_ADDR(BITBAND(addr,bit))
// GPIO对应ODR\IDR地址
#define GPIOA_ODR_ADDR      GPIOA_BASE + 0x0c
#define GPIOB_ODR_ADDR      GPIOB_BASE + 0x0c
#define GPIOC_ODR_ADDR      GPIOC_BASE + 0x0c
#define GPIOD_ODR_ADDR      GPIOD_BASE + 0x0c
#define GPIOE_ODR_ADDR      GPIOE_BASE + 0x0c
#define GPIOF_ODR_ADDR      GPIOF_BASE + 0x0c
#define GPIOG_ODR_ADDR      GPIOG_BASE + 0x0c

#define GPIOA_IDR_ADDR      GPIOA_BASE + 0x08
#define GPIOB_IDR_ADDR      GPIOB_BASE + 0x08
#define GPIOC_IDR_ADDR      GPIOC_BASE + 0x08
#define GPIOD_IDR_ADDR      GPIOD_BASE + 0x08
#define GPIOE_IDR_ADDR      GPIOE_BASE + 0x08
#define GPIOF_IDR_ADDR      GPIOF_BASE + 0x08
#define GPIOG_IDR_ADDR      GPIOG_BASE + 0x08
// GPIO引脚输出\输入
#define GPIOA_OUT(bit)      BIT_ADDR(GPIOA_ODR_ADDR,bit)
#define GPIOA_IN(bit)       BIT_ADDR(GPIOA_IDR_ADDR,bit)

#define GPIOB_OUT(bit)      BIT_ADDR(GPIOB_ODR_ADDR,bit)
#define GPIOB_IN(bit)       BIT_ADDR(GPIOB_IDR_ADDR,bit)

#define GPIOC_OUT(bit)      BIT_ADDR(GPIOC_ODR_ADDR,bit)
#define GPIOC_IN(bit)       BIT_ADDR(GPIOC_IDR_ADDR,bit)

#define GPIOD_OUT(bit)      BIT_ADDR(GPIOD_ODR_ADDR,bit)
#define GPIOD_IN(bit)       BIT_ADDR(GPIOD_IDR_ADDR,bit)

#define GPIOE_OUT(bit)      BIT_ADDR(GPIOE_ODR_ADDR,bit)
#define GPIOE_IN(bit)       BIT_ADDR(GPIOE_IDR_ADDR,bit)

#define GPIOF_OUT(bit)      BIT_ADDR(GPIOF_ODR_ADDR,bit)
#define GPIOF_IN(bit)       BIT_ADDR(GPIOF_IDR_ADDR,bit)

#define GPIOG_OUT(bit)      BIT_ADDR(GPIOG_ODR_ADDR,bit)
#define GPIOG_IN(bit)       BIT_ADDR(GPIOG_IDR_ADDR,bit)

#endif /* BSP_BITBAND_H_ */

main.c代码主体部分实现

/* 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 */
#include "bsp_led.h"
/* 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 */
  LED_GPIO_Config();
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */
	GPIOB_OUT(5) = GPIO_PIN_RESET;
    /* USER CODE BEGIN 3 */
  }
  /* 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_HSI;
  RCC_OscInitStruct.HSIState = RCC_HSI_ON;
  RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE;
  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_HSI;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;

  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_0) != 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_GPIOC_CLK_ENABLE();
  __HAL_RCC_GPIOA_CLK_ENABLE();
  __HAL_RCC_GPIOB_CLK_ENABLE();

  /*Configure GPIO pin Output Level */
  HAL_GPIO_WritePin(GPIOB, LED2_Pin|LED3_Pin|LED1_Pin, GPIO_PIN_SET);

  /*Configure GPIO pin : KEY2_Pin */
  GPIO_InitStruct.Pin = KEY2_Pin;
  GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  HAL_GPIO_Init(KEY2_GPIO_Port, &GPIO_InitStruct);

  /*Configure GPIO pin : KEY1_Pin */
  GPIO_InitStruct.Pin = KEY1_Pin;
  GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  HAL_GPIO_Init(KEY1_GPIO_Port, &GPIO_InitStruct);

  /*Configure GPIO pins : LED2_Pin LED3_Pin LED1_Pin */
  GPIO_InitStruct.Pin = LED2_Pin|LED3_Pin|LED1_Pin;
  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);

}

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

基本知识框架Xmind文件下载

链接:资源下载

;