GPIO引脚复用和映射:IO口通过一个复用器连接到内置外设和模块;复用器一次只允许一个外设的复用功能(AF)连接到对应的IO口。这样可以确保共用同一个IO引脚的外设之间不会发生冲突;每个IO引脚都有一个复用器
端口复用为复用功能配置过程:
①GPIO端口时钟使能。
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA,ENABLE);
②复用外设时钟使能。
比如你要将端口PA9,PA10复用为串口,所以要使能串口时钟。
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);
③端口模式配置为复用功能。 GPIO_Init()函数。
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;//复用功能
④配置GPIOx_AFRL或者GPIOx_AFRH寄存器,将IO连接到所需的AFx。
IO口作为复用功能时查表寻找对应功能
NVIC中断优先级分组
中断管理方法:首先分组,设置抢占优先级,响应优先级
抢占优先级 & 响应优先级区别:
1.高优先级的抢占优先级是可以打断正在进行的低抢占优先级中断的。
2.抢占优先级相同的中断,高响应优先级不可以打断低响应优先级的中断。
3.抢占优先级相同的中断,当两个中断同时发生的情况下,哪个响应优先级高,哪个先执行。
4.如果两个中断的抢占优先级和响应优先级都是一样的话,则看哪个中断先发生就先执行;
中断分组在程序中只设置一次!!!
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
中断优先级设置步骤
系统运行后先设置中断优先级分组。调用函数:
void NVIC_PriorityGroupConfig(uint32_t NVIC_PriorityGroup);
整个系统执行过程中,只设置一次中断分组。
②针对每个中断,设置对应的抢占优先级和响应优先级:
void NVIC_Init(NVIC_InitTypeDef* NVIC_InitStruct);
③ 如果需要挂起/解挂,查看中断当前激活状态,分别调用相关函数即可。
外部中断
STM32F4的每个IO都可以作为外部中断输入。
每个外部中断线可以独立的配置触发方式(上升沿,下降沿或者双边沿触发),触发/屏蔽,专用的状态位。
中断服务函数列表:
EXTI0_IRQHandler
EXTI1_IRQHandler
EXTI2_IRQHandler
EXTI3_IRQHandler
EXTI4_IRQHandler
EXTI9_5_IRQHandler
EXTI15_10_IRQHandler
外部中断常用库函数
①void SYSCFG_EXTILineConfig(uint8_t EXTI_PortSourceGPIOx, uint8_t EXTI_PinSourcex);
//设置IO口与中断线的映射关系
②void EXTI_Init(EXTI_InitTypeDef* EXTI_InitStruct);
//初始化中断线:触发方式等
③ITStatus EXTI_GetITStatus(uint32_t EXTI_Line);
//判断中断线中断状态,是否发生
④void EXTI_ClearITPendingBit(uint32_t EXTI_Line);
//清除中断线上的中断标志位
⑤RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE);//使能SYSCFG时钟
//这个函数非常重要,在使用外部中断的时候一定要先使能SYSCFG时钟
外部中断的一般配置步骤:
1使能SYSCFG时钟: RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE);
2初始化IO口为输入 GPIO_Init();
3设置IO口与中断线的映射关系 void SYSCFG_EXTILineConfig();
4初始化线上中断,设置触发条件等 EXTI_Init();
5配置中断分组(NVIC),并使能中断 NVIC_Init();
6编写中断服务函数。EXTIx_IRQHandler();
7清除中断标志位EXTI_ClearITPendingBit();
利用外部中断,我写了一个按键控制流水灯速度的程序:
#include"delay.h"
#include"led.h"
#include"key.h"
#include"exit.h"
#include"sys.h"
#include"fmq.h"
void EXITX_Init(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
EXTI_InitTypeDef EXTI_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG ,ENABLE);
KEY_Init();
SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOE,EXTI_PinSource2);
SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOE,EXTI_PinSource3);
EXTI_InitStructure.EXTI_Line=EXTI_Line2|EXTI_Line3;
EXTI_InitStructure.EXTI_LineCmd=ENABLE;
EXTI_InitStructure.EXTI_Mode=EXTI_Mode_Interrupt;
EXTI_InitStructure.EXTI_Trigger=EXTI_Trigger_Falling;
EXTI_Init(&EXTI_InitStructure);
NVIC_InitStructure.NVIC_IRQChannel=EXTI2_IRQn;
NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority=1;
NVIC_Init(&NVIC_InitStructure);
NVIC_InitStructure.NVIC_IRQChannel=EXTI3_IRQn;
NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=2;
NVIC_InitStructure.NVIC_IRQChannelSubPriority=1;
NVIC_Init(&NVIC_InitStructure);
}
void EXTI2_IRQHandler(void)
{
delay_ms(10);
if(KEY0==0)
{
while(1)
{
GPIO_SetBits(GPIOF,GPIO_Pin_9);
delay_ms(500);
GPIO_ResetBits(GPIOF,GPIO_Pin_9);
delay_ms(500);
GPIO_SetBits(GPIOF,GPIO_Pin_10);
delay_ms(500);
GPIO_ResetBits(GPIOF,GPIO_Pin_10);
delay_ms(500);
}
}
EXTI_ClearITPendingBit(EXTI_Line2);
}
void EXTI3_IRQHandler(void)
{
delay_ms(10);
if(KEY1==0)
{
while(1)
{
GPIO_SetBits(GPIOF,GPIO_Pin_9);
delay_ms(20);
GPIO_ResetBits(GPIOF,GPIO_Pin_9);
delay_ms(20);
GPIO_SetBits(GPIOF,GPIO_Pin_10);
delay_ms(20);
GPIO_ResetBits(GPIOF,GPIO_Pin_10);
delay_ms(20);
}
}
EXTI_ClearITPendingBit(EXTI_Line2);
}