1、固件库和HAL库
固件库(Standard Peripheral Library,通常被称为SPL)和HAL库(Hardware Abstraction Layer,硬件抽象层)都是STMicroelectronics(ST)为STM32系列微控制器提供的软件开发库,
| 固件库(SPL) | HAL库 |
|-----------|----------------|------------------|
| 定义与特点 | 底层函数库,直接访问寄存器 | 高级别抽象层,简化开发 |
| 学习难度 | 较高,需要深入理解硬件 | 较低,易于上手 |
| 控制精度 | 精细控制,允许直接操作寄存器 | 较少直接操作寄存器,控制较为抽象 |
| 代码效率 | 通常生成更小、更快的代码 | 可能生成较大和/或较慢的代码 |
| 可移植性 | 较差,不同型号间差异大 | 较好,支持跨型号移植 |
| 社区支持 | 相对较少 | 较多,ST主要推广和支持 |
| 更新与支持 | 已停止更新 | 持续更新和支持 |
2、外设和内核:
外设是内核以外的设备;
3、keil5的一些报错原因:
1、未加入宏定义(建议选中c99标准)
2、要求函数无参数时需要void;
3、最后一个花括号期待一个换行
在STM32中配置GPIO端口模式的一般步骤如下:
选择GPIO端口和引脚:确定要配置的GPIO端口(如GPIOA、GPIOB等)和具体的引脚号。
配置MODER寄存器:通过写入MODER寄存器来设置GPIO引脚的模式。每个引脚的模式由MODER寄存器中的两位决定,这些位可以设置为输入模式、输出模式、复用功能模式或模拟模式等。
配置其他相关寄存器(如果需要):根据所选模式,可能需要配置其他寄存器,如输出速度寄存器(OSPEEDR)、上拉/下拉寄存器(PUPDR)、复用功能选择寄存器(AFRx)等。
启用GPIO时钟:在配置GPIO之前,需要确保该GPIO端口的时钟已经使能。
编写代码:根据所选的STM32系列和使用的开发环境(如HAL库、LL库或寄存器直接操作),编写相应的代码来配置GPIO端口。
4、使用固件库
1、keil5导入stm32头文件:
2、可以一个RCC使能函数开两个引脚;
5、中断机制
MCU执行A,中断B出现,NVIC捕获到,通知MCU去处理事件C,c结束后,返回继续执行A;
1、NVIC(嵌套向量中断控制器
):
NVIC(Nested Vectored Interrupt Controller,嵌套向量中断控制器)是ARM Cortex-M系列微控制器中的一个关键组件,它负责管理中断和异常。NVIC提供了中断的优先级管理、中断的嵌套、中断的使能和禁用等功能,使得开发者能够高效地控制中断的响应和处理。
NVIC的主要功能
- 中断优先级管理 :
- NVIC支持多个中断优先级,通常包括抢占优先级和子优先级。抢占优先级用于决定哪个中断可以打断当前正在执行的中断服务例程(ISR),而子优先级则用于在抢占优先级相同的情况下决定中断的响应顺序。
- 开发者可以通过编程设置每个中断的优先级,以优化系统的响应时间和中断处理效率。
- 中断嵌套 :
- NVIC支持中断嵌套,即一个中断可以在另一个中断的服务例程执行过程中被触发并抢占执行。这允许系统根据中断的紧急程度动态地调整中断的响应顺序。
- 中断使能和禁用 :
- NVIC允许开发者通过编程使能或禁用特定的中断。这有助于在不需要中断响应时节省系统资源,或在特定条件下避免中断的干扰。
- 中断挂起和清除 :
- NVIC维护了一个中断挂起寄存器,用于记录哪些中断已经发生但尚未被处理。当中断被触发时,相应的中断挂起位会被置位。中断服务例程执行完毕后,需要清除该位以允许后续的中断响应。
- 系统控制和状态寄存器 :
- NVIC还包含了一系列系统控制和状态寄存器,用于控制中断的使能、优先级分组、系统复位等。
使能中断,中断屏蔽;
捕获中断,通知MCU;
2、中断的优先级
设置中断优先级,比较中断优先级;
数字越小(非负整数),优先级越高;最高0;
多个中断同时产生:
单核在一个时刻上只能执行一条指令;
1、优先级:
优先级分为抢占式优先级和响应式优先级;//先比较抢占再比较响应;
抢占优先级相同时再比较响应优先级;
2、优先级分组:
优先级分组时可以更改的,默认是第0组;
一、中断优先级分组的概念
STM32的中断优先级分组是通过NVIC(Nested Vectored Interrupt Controller,嵌套向量中断控制器)来实现的。NVIC将中断优先级分为抢占优先级和子优先级两部分,而中断优先级分组则决定了这两部分在优先级寄存器中的位数分配。
二、中断优先级分组的配置
中断优先级分组是通过配置NVIC的
AIRCR
(Application Interrupt and Reset Control Register)寄存器中的PRIGROUP
字段来实现的。这个字段决定了中断优先级寄存器(IPR,Interrupt Priority Register)中哪些位用于表示抢占优先级,哪些位用于表示子优先级。STM32的中断优先级分组通常有五种不同的级别(注意:并非所有STM32系列都支持所有分组级别,具体取决于微控制器型号):
分组级别 抢占优先级位数 子优先级位数 组0 0 4 组1 1 3 组2 2 2 组3 3 1 组4 4 0 三、抢占优先级与子优先级的关系
- 抢占优先级:决定了中断的响应顺序。如果一个中断的抢占优先级比当前正在执行的中断服务例程(ISR)的抢占优先级高,那么当前的中断服务例程将被挂起,新的中断将被响应。
- 子优先级:在抢占优先级相同的情况下,用于决定哪个中断先被执行。子优先级只在抢占优先级相同的中断之间进行比较。
四、中断优先级分组的配置步骤
- 选择中断优先级分组:根据应用需求,选择合适的分组级别。这通常涉及到对系统响应时间和中断处理效率的综合考虑。
- 配置
AIRCR
寄存器 :通过设置AIRCR
寄存器中的PRIGROUP
字段来配置中断优先级分组。这通常涉及到对寄存器的直接操作或使用库函数。- 设置中断优先级:在确定了中断优先级分组后,为各个中断设置具体的抢占优先级和子优先级。这通常通过配置NVIC的IPR寄存器或使用库函数来实现。
常见的三大中断;
外部中断;串口中断;定时器中断;
时钟的初始化:
6、使用固件库代码案例:
1、使用固件库代码操作寄存器赋值:
2、使用固件库引入头文件,使用函数操作:
1、写使能
void RCC_APB2PeriphClockCmd(uint32_t RCC_APB2Periph, FunctionalState NewState)
uint32_t RCC_APB2Periph:
FunctionalState NewState
2、通过结构体赋值初始化并设置引脚工作模式:
设置工作模式:
GPIO_InitStruct.GPIO_Mode =GPIO_Mode_IN_FLOATING;
浮空输入模式(Floating Input Mode)
GPIO_Mode_IN_FLOATING
在浮空输入模式下,GPIO引脚既不连接到内部上拉电阻,也不连接到内部下拉电阻。这意味着引脚的电平状态完全由外部电路决定,如果外部没有明确的电平信号连接到该引脚,那么它的电平状态是不确定的,可能会受到周围环境的噪声影响,导致电平在高低之间随机变化,即所谓的"浮动"。
确认对应的引脚pin_0:
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_0;
配置GPIO引脚时指定引脚的速度(输出速率):
GPIO_InitStruct.GPIO_Speed =GPIO_Speed_10MHz;
调用GPIO_Init函数完成配置:
GPIO_Init(GPIOA,&GPIO_InitStruct);
3、设置输出:
GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_0)
用于读取指定GPIO引脚的输入数据位的状态。这个函数允许你检查一个GPIO引脚当前是处于高电平(通常为1)还是低电平(通常为0)。
GPIO_ResetBits(GPIOA,GPIO_Pin_1);
GPIO_ResetBits
是STM32标准外设库(SPL)中的一个函数,用于将指定的GPIO端口上的一个或多个引脚输出低电平(0)。这个函数是控制GPIO引脚状态的一种直接方式,通常用于将引脚设置为低电平或清除引脚上的高电平信号。
GPIO_SetBits(GPIOA,GPIO_Pin_1);
GPIO_SetBits
是STM32标准外设库(SPL)中的一个函数,用于将指定的GPIO端口上的一个或多个引脚输出高电平(1)。这个函数是控制GPIO引脚状态的一种直接方式,通常用于将引脚设置为高电平或激活引脚上的高电平信号。
cpp
void pushPullIutputPA0(){
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
GPIO_InitStruct.GPIO_Mode =GPIO_Mode_IN_FLOATING;
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_0;
GPIO_InitStruct.GPIO_Speed =GPIO_Speed_10MHz;
GPIO_Init(GPIOA,&GPIO_InitStruct);
}
void pushPullOutputPA1(){
RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOA,ENABLE);
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_1;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_10MHz;
GPIO_Init(GPIOA,&GPIO_InitStruct);
}
cpp
int main(){
pushPullOutputPA1();
while(1){
// if(1==GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_6))
// {
// GPIO_ResetBits(GPIOB,GPIO_Pin_2);//输出低电平
// }else{
// GPIO_SetBits(GPIOB,GPIO_Pin_2);//输出高电平
// }
if(1 == GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_0)){
GPIO_ResetBits(GPIOA,GPIO_Pin_1);
}else{
GPIO_SetBits(GPIOA,GPIO_Pin_1);
}
}