1、什么是中断?
1.1、查询机制
系统的查询机制有两种,第一种是软件轮询,利用CPU软件查询,浪费CPU时间,实时性不高。第二种就是中断,CPU内部中断控制器带软件查询,实时性高但是不够灵活。
中断是一种硬件查询机制,当某一件事情一旦发生必须执行,且我们不知道何时发生的时候,我们可以把这个事件配置为中断模式。
1.2、常用名词定义
CPU在正常情况下运行的程序称为现行程序;向CPU提出申请中断的设备称为中断源;由中断源向CPU发出的请求中断的信号称为中断请求;CPU在满足条件的情况下接受中断申请,终止现行程序转而为申请中断的对象服务称为中断响应;为申请中断的对象服务的程序称为中断服务程序;现行程序被中断的地址称为断点;中断服务程序结束后返回到原来程序成为中断返回。
中断响应的过程:1、检测中断,2、保护现场,3、中断服务,4、清除中断标志位,5、恢复现场,6、中断返回。
可嵌套:在stm32提供了可嵌套的中断方式,即中断中可以再次发生中断。
2、M4内核中断管理
2.1、嵌套向量中断控制器NVIC(Nested Vectored Interrupt Controller )
管理的通道数量有256个,M4内部中断16个,M4外部中断240个。向量:可用来形成相应的中断服务程序的入口地址或存放中断服务程序的首地址称为中断向量。在AVR或ARM微处理器中,中断向量的大小也是4个字节,但其中存放的不是中断程服务程序的入口地址,而是可执行的代码。当响应中断时,硬件自动执行相应中断向量处的跳转代码,然后跳转到具体的中断服务程序的入口地址。
2.2、中断的优先级
抢占优先级:决定中断是否嵌套(高位),
次级优先级:在抢占优先级相同的情况下同时到来谁先执行(低位),
优先级分组:设置抢占优先级和次级优先级各占几位(M4支持256个(8位)优先级)。
2.3、操作方法
有寄存器操作方式或者调用M4内核函数。
3、STM32的中断框架
3.1、STM32中断框架对M4内核做出的改动
STM32使用了M4的82个中断通道,4位优先级(M4优先级的高四位)
3.2、中断向量
一个中断向量就是一个中断通道,一个通道可以有多条中断源
3.3、外部中断(EXTI)
一共有23条中断线(中断源)
EXTI0~15 -- 中断信号通过GPIO传输进来
EXTI线16 连接到 PVD 输出
EXTI线17 连接到 RTC 闹钟事件
EXTI线18 连接到 USB OTG FS 唤醒事件
EXTI线19 连接到以太网唤醒事件
EXTI线20 连接到 USB OTG HS(在FS中配置)唤醒事件EXTI线21连接到RTC入侵和时间戳事件
EXTI线22 连接到RTC唤醒事件
13条中断通道(中断向量)
EXTI0-4各占一个通道
EXTI5-9(5 6 7 8 9)
EXTI10-15(10 11 12 13 14 15)
其他各占一个
4、如何配置一个外部中断
1、初始化一个输入的GPIO
2、将IO引脚映射到EXTI线上:配置SYSCFG
3、配置EXTI的触发方式和使能中短线
4、配置NVIC:先设置分组,在设置优先级,然后使能中断
5、修改中断服务函数
5、利用连接在PA0上的按键的上升沿去控制中断的开启,中断函数执行蜂鸣器反转
gpio.c
#include "gpio.h"
void Gpio_Init(GPIO_TypeDef * GPIOx, uint8_t Pin, uint8_t Mode)
{
switch(Mode)
{
case 1:
GPIOx->MODER &=~ (3<<(Pin+Pin));
GPIOx->PUPDR &=~ (3<<(Pin+Pin));
break;
case 0:
//输出 推挽 高速 上拉
GPIOx->MODER &=~ (3<<(Pin+Pin));
GPIOx->MODER |= (1<<(Pin+Pin));
GPIOx->OTYPER &=~ (1<<Pin);
GPIOx->OSPEEDR |= (3<<(Pin+Pin));
GPIOx->PUPDR &=~ (3<<(Pin+Pin));
break;
default:
break;
}
}
void Beep_Init(void)
{
RCC->AHB1ENR |= (1<<5);//开启GPIOF的时钟
Gpio_Init(GPIOF,8,0);
}
void Key_Init(void)
{
RCC->AHB1ENR |= (1<<0);//开启GPIOA的时钟
RCC->AHB1ENR |= (1<<4);//开启GPIOE的时钟
Gpio_Init(GPIOA,0,1);
RCC->APB2ENR |= (1<<14);//开启SYSCFG的时钟
SYSCFG->EXTICR[0] &=~ (0xf<<0);//EXTI0映射GPIOA
EXTI->IMR |= (1<<0);//开放来自EXTI0的中断请求
EXTI->RTSR |= (1<<0);//允许上升沿触发
NVIC_EnableIRQ(EXTI0_IRQn);//M4内核使能
}
default:
break;
}
}
void Beep_Init(void)
{
RCC->AHB1ENR |= (1<<5);//开启GPIOF的时钟
Gpio_Init(GPIOF,8,0);
}
void Key_Init(void)
{
RCC->AHB1ENR |= (1<<0);//开启GPIOA的时钟
RCC->AHB1ENR |= (1<<4);//开启GPIOE的时钟
Gpio_Init(GPIOA,0,1);
RCC->APB2ENR |= (1<<14);//开启SYSCFG的时钟
SYSCFG->EXTICR[0] &=~ (0xf<<0);//EXTI0映射GPIOA
EXTI->IMR |= (1<<0);//开放来自EXTI0的中断请求
EXTI->RTSR |= (1<<0);//允许上升沿触发
NVIC_EnableIRQ(EXTI0_IRQn);//M4内核使能
}
gpio.h
#ifndef GPIO_H
#define GPIO_H
#include "stm32f4xx.h"
#define BEEP_TOGGLE() GPIOF->ODR ^= (1<<8)
#define BEEP(x) x?(GPIOF->ODR &=~ (1<<8)):(GPIOF->ODR |= (1<<8))
#define KEY1() (GPIOA->IDR & (1<<0))
#define KEY2() !(GPIOE->IDR & (1<<2))
#define KEY3() !(GPIOE->IDR & (1<<3))
#define KEY4() !(GPIOE->IDR & (1<<4))
void Beep_Init(void);
void Key_Init(void);
#endif
main.c
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "gpio.h"
void delay_us(uint32_t us)
{
uint64_t Time = us * 16.8f;
while(Time--);
}
void delay_ms(uint32_t ms)
{
uint64_t Time = ms * 16800;
while(Time--);
}
void EXTI0_IRQHandler(void)
{
EXTI->PR |= (1<<0);//清中段
BEEP_TOGGLE();
}
/**
* @brief Main program
* @param None
* @retval None
*/
int main(void)
{
NVIC_SetPriorityGrouping(7);
Beep_Init();
Key_Init();
/* Infinite loop */
while (1)
{
}
}
#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 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) */
/* Infinite loop */
while (1)
{
}
}
#endif
/**
* @}
*/
/**
* @}
*/
/************************ (C) COPYRIGHT Holmes *****END OF FILE****/