目录
- 基本知识框架
- 课堂笔记
- CMSIS
-
- 标准库开发
- 标准库开发 LED-GPIO
- 标准库开发 KEY-GPIO
- 标准库开发 位带操作
-
- 基本知识框架Xmind文件下载
基本知识框架
课堂笔记
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"
#define digitalHi(Port, Pin) ((Port)->BSRR = Pin)
#define digitalLi(Port, Pin) ((Port)->BRR = Pin)
#define digitalRev(Port,Pin) ((Port)->ODR ^= Pin)
#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)
#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"
void LED_GPIO_Config(void)
{
__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;
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代码主体部分实现
#include "main.h"
#include "bsp_led.h"
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
int main(void)
{
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
LED_GPIO_Config();
while (1)
{
LED1_ON;
}
}
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
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();
}
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();
}
}
static void MX_GPIO_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
__HAL_RCC_GPIOC_CLK_ENABLE();
__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE();
HAL_GPIO_WritePin(GPIOB, LED2_Pin|LED3_Pin|LED1_Pin, GPIO_PIN_SET);
GPIO_InitStruct.Pin = KEY2_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(KEY2_GPIO_Port, &GPIO_InitStruct);
GPIO_InitStruct.Pin = KEY1_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(KEY1_GPIO_Port, &GPIO_InitStruct);
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);
}
void Error_Handler(void)
{
__disable_irq();
while (1)
{
}
}
#ifdef USE_FULL_ASSERT
void assert_failed(uint8_t *file, uint32_t line)
{
}
#endif
标准库开发 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;
}
void KEY_GPIO_Config(void)
{
__HAL_RCC_GPIOC_CLK_ENABLE();
GPIO_InitTypeDef* GPIO_LED_Structure;
GPIO_LED_Structure->Pin = KEY_Pin;
GPIO_LED_Structure->Mode = GPIO_Mode_IN_FLOATING;
HAL_GPIO_Init(LED1_GPIO_Port, GPIO_LED_Structure);
}
#endif
main.c代码主体部分实现
#include "main.h"
#include "bsp_led.h"
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
int main(void)
{
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
KEY_GPIO_Config();
LED_GPIO_Config();
while (1)
{
if (GPIO_PIN_SET == KEYScan())
LED1_ON;
}
}
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
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();
}
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();
}
}
static void MX_GPIO_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
__HAL_RCC_GPIOC_CLK_ENABLE();
__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE();
HAL_GPIO_WritePin(GPIOB, LED2_Pin|LED3_Pin|LED1_Pin, GPIO_PIN_SET);
GPIO_InitStruct.Pin = KEY2_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(KEY2_GPIO_Port, &GPIO_InitStruct);
GPIO_InitStruct.Pin = KEY1_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(KEY1_GPIO_Port, &GPIO_InitStruct);
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);
}
void Error_Handler(void)
{
__disable_irq();
while (1)
{
}
}
#ifdef USE_FULL_ASSERT
void assert_failed(uint8_t *file, uint32_t line)
{
}
#endif
标准库开发 位带操作
位带
位带
位操作指的是可以对单独某个位进行读写操作,当需要对某些位进行频繁读写操作时,通过位操作可以轻松便捷的实现。但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代码主体部分实现
#ifndef BSP_BITBAND_H_
#define BSP_BITBAND_H_
#include "stm32f1xx_hal.h"
#define BITBAND(addr,bit) ((addr & 0xF0000000)+0x02000000+((addr & 0x000FFFFF)<<5)+(bit<<2))
#define MEM_ADDR(addr) (*(volatile unsigned long*)(addr))
#define BIT_ADDR(addr,bit) MEM_ADDR(BITBAND(addr,bit))
#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
#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
main.c代码主体部分实现
#include "main.h"
#include "bsp_led.h"
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
int main(void)
{
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
LED_GPIO_Config();
while (1)
{
GPIOB_OUT(5) = GPIO_PIN_RESET;
}
}
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
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();
}
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();
}
}
static void MX_GPIO_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
__HAL_RCC_GPIOC_CLK_ENABLE();
__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE();
HAL_GPIO_WritePin(GPIOB, LED2_Pin|LED3_Pin|LED1_Pin, GPIO_PIN_SET);
GPIO_InitStruct.Pin = KEY2_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(KEY2_GPIO_Port, &GPIO_InitStruct);
GPIO_InitStruct.Pin = KEY1_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(KEY1_GPIO_Port, &GPIO_InitStruct);
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);
}
void Error_Handler(void)
{
__disable_irq();
while (1)
{
}
}
#ifdef USE_FULL_ASSERT
void assert_failed(uint8_t *file, uint32_t line)
{
}
#endif
基本知识框架Xmind文件下载
链接:资源下载
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)