STM32中断
中断的作用
(1)速度匹配,提高机器系统效率。 系统中处理机的工作速度远高于外围设备的工作速度。通过中断可以协调它们之间的工作。当外围设备需要与处理机交换信息时,由外围设备向处理机发出中断请求,处理机及时响应并作相应处理。不交换信息时,处理机和外围设备处于各自独立的并行工作状态。
(2)分时操作,维持系统可靠正常工作。现代计算机中,程序员不能直接干预和操纵机器,必须通过中断系统向操作系统发出请求,由操作系统来实现人为干预。主存储器中往往有多道程序和各自的存储空间。在程序运行过程中,如出现越界访问,有可能引起程序混乱或相互破坏信息。为避免这类事件的发生,由存储管理部件进行监测,一旦发生越界访问,向处理机发出中断请求,处理机立即采取保护措施。
(3)实时响应,满足实时处理要求。 在实时系统中,各种监测和控制装置随机地向处理机发出中断请求,处理机随时响应并进行处理。
(4)提供故障现场处理手段,可靠性高。 处理机中设有各种故障检测和错误诊断的部件,一旦发现故障或错误,立即发出中断请求,进行故障现场记录和隔离,为进一步处理提供必要的依据。
?
中断的分类
中断按事件来源分类,可以分为外部中断和内部中断。中断事件来自于内核外部的被称为外部中断,来自于内核内部的则为内部中断。
? ? ? ? 进一步细分,外部中断还可分为可屏蔽中断(maskable interrupt)和不可屏蔽中断(non-maskable interrupt)两种,而内部中断按事件是否正常来划分可分为软中断和异常两种。
? ? ? ? 外部中断的中断事件来源于内核外部,必然是某个硬件产生的,所以外部中断又被称为硬件中断(hardware interrupt)。计算机的外部设备,如网卡、声卡、显卡等都能产生中断。外部设备的中断信号是通过两根信号线通知CPU的,一根是IRQ,另一根是NMI。CPU从IRQ收到的中断信号都是不影响系统运行的,CPU可以选择屏蔽(通过设置中断屏蔽寄存器中的IF位),而从NMI中收到的中断信号则是影响系统运行的严重错误,不可屏蔽,因为屏蔽的意义不大,系统已经无法运行。
? ? ? ? 内部中断来自于内核内部,其中软中断是由软件主动发起的中断,常被用于系统调用(system call),任务切换(PendSV)等;而异常则是指令执行期间CPU内部产生的错误引起的。异常也和不可屏蔽中断区别在于不可屏蔽中断发生的事件会导致处理器无法运行(如断电、电源故障等),而异常则是影响系统正常运行的中断(如除0、越界访问等)。
?
NVIC中断控制器
内核有一个专门管理中断的外设NVIC(嵌套向量中断控制器),可以实现低延迟的中断处理和晚到中断的高效处理,通过优先级控制中断的嵌套和调度来管理;NVIC是一个总的中断控制器,无论是来在内核的异常还是外设的外部中断, 都由NVIC统一进行管理。NVIC收到外设的中断请求,会将其中断请求发送给内核,内核收到NVIC的中断通知之后,就会去判断此时哪个中断发生,然后查找FLASH中断向量表去获取相应的中断处理函数。
? ? ? ? 它具有以下特征:
(1)支持嵌套和向量中断;
(2)自动保存和恢复处理器状态;
(3)动态改变优先级;
(4)简化的和确定的中断时间。
? ? ? ? 带来的优势:
(1)响应速度提高;
(2)标准化,统一管理。
中断优先级
中断优先级寄存器有4位抢占如果占1位(0和1),响应占3位(0-7)
抢占如果占3位(0-7),响应占1位(0和1)
中断优先级有两种,一种是抢占优先级,一种是响应优先级。响应优先级通常又被称为“亚优先级”或者“副优先级”。当两个中断的抢占优先级相同时,用相应优先级来决定中断的处理顺序。如果两个中断的抢占优先级和相应优先级相同,则根据芯片手册中的中断向量号来决定中断的处理顺序。比如同时来了两个中断请求,在抢占优先级和响应优先级均相同时,中断向量号为41的中断会比中断向量号为42的中断先被处理。
STM32提供了16个可编程的优先等级(使用了4位中断优先级),优先级分组可以使用库函数提供的NVIC_PriorityGroupConfig()设置。
?
中断实验
按下第一个按键,三个小灯亮
按下第二个按键,蜂鸣器响
按下第三个按键,灯和蜂鸣器都关闭
inte.h
#ifndef __INTE_H
#define __INTE_H
#include "stm32f10x_conf.h"
typedef void(*inte_handler)(void);//函数指针
extern void inte_init(void);//初始化中断
extern void set_inte_handler(inte_handler h0,inte_handler h1,inte_handler h2);//回调函数
#endif
inte.c
#include"inte.h"
inte_handler h_0,h_1,h_2;//定义全局变量
void inte_init(void)
{
GPIO_InitTypeDef GPIO_Value;
EXTI_InitTypeDef Exti_Value;
NVIC_InitTypeDef Nvic_Value;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC|RCC_APB2Periph_GPIOA|RCC_APB2Periph_AFIO,ENABLE);
GPIO_Value.GPIO_Mode=GPIO_Mode_IPU;
GPIO_Value.GPIO_Pin=GPIO_Pin_9|GPIO_Pin_8;
GPIO_Init(GPIOC,&GPIO_Value);
GPIO_Value.GPIO_Mode=GPIO_Mode_IPD;
GPIO_Value.GPIO_Pin=GPIO_Pin_0;
GPIO_Init(GPIOC,&GPIO_Value);
//选择引脚作为外部中断触发源
GPIO_EXTILineConfig(GPIO_PortSourceGPIOC,GPIO_PinSource9);
GPIO_EXTILineConfig(GPIO_PortSourceGPIOC,GPIO_PinSource8);
GPIO_EXTILineConfig(GPIO_PortSourceGPIOC,GPIO_PinSource0);
//初始化EXTI
Exti_Value.EXTI_Line=EXTI_Line9|EXTI_Line8;//选择外部中断线8,9
Exti_Value.EXTI_LineCmd=ENABLE;//EXTI使能
Exti_Value.EXTI_Mode=EXTI_Mode_Interrupt;//选择中读模式
Exti_Value.EXTI_Trigger=EXTI_Trigger_Falling;//下降沿
EXTI_Init(&Exti_Value);//按照上述配置初始化
Exti_Value.EXTI_Line=EXTI_Line0;//选择外部中断线0
Exti_Value.EXTI_Trigger=EXTI_Trigger_Rising;//上升沿
EXTI_Init(&Exti_Value);//按照上述配置初始化
//初始化NVIC
Nvic_Value.NVIC_IRQChannel=EXTI9_5_IRQn;
Nvic_Value.NVIC_IRQChannelCmd=ENABLE;//NVIC初始化
Nvic_Value.NVIC_IRQChannelPreemptionPriority=2; //先占优先级
Nvic_Value.NVIC_IRQChannelSubPriority=2;//从优先级
NVIC_Init(&Nvic_Value);
Nvic_Value.NVIC_IRQChannel=EXTI0_IRQn;
NVIC_Init(&Nvic_Value);
}
void EXTI9_5_IRQHandler(void)
{
if(EXTI_GetFlagStatus(EXTI_Line9)==SET)
{
h_0();
EXTI_GetFlagStatus(EXTI_Line9);
}
if(EXTI_GetFlagStatus(EXTI_Line8)==SET)
{
h_1();
EXTI_GetFlagStatus(EXTI_Line8);
}
}
void EXTI0_IRQHandler(void)
{
if(EXTI_GetFlagStatus(EXTI_Line0)==SET)
{
h_2();
EXTI_ClearITPendingBit(EXTI_Line0);
}
}
void set_inte_handler(inte_handler h0,inte_handler h1,inte_handler h2)
{
h_0=h0;
h_1=h1;
h_2=h2;
}
main.c
/*看门狗*/
#include"iwdg.h"
#include"led.h"
#include"fmq.h"
#include"key.h"
#include"delay.h"
#include"inte.h"
void h0(void)
{
Led_On(0);
Led_On(1);
Led_On(2);
}
void h1(void)
{
Fmq_On();
}
void h2(void)
{
Led_Off(1);
Fmq_Off();
}
int main(void)
{
int i=0,j=0;
inte_init();
Led_Init();
Key_Init();
Fmq_Init();
delay_init();
iwdg_init(5);
set_inte_handler(h0,h1,h2);
for(i=0;i<3;i=(i+1)%3)
{
iwdg_fee_dog();
Led_On(i);
delay_ms(1);
Led_Off(i);
delay_ms(1);
}
return 0;
}
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!