STM32嵌入式开发笔记(五):中断
我们过去了解了用循环实现延时,或用系统滴答计时器实现延时,但这两种方法都有一种问题:会阻塞处理器的运行。下面我们学习一种不阻塞处理器运行其他事件的功能:时钟中断。
所谓中断,就是让处理器放下手头的事情,立刻去做一件事情,做完了再做原来的事情。比如说你在写作业,但是突然来了一个人找你说话,你就停下来跟他说话,这就是中断。
要实现时钟中断,我们必须了解两种特性:通用定时器和中断控制器。
通用定时器也是通过晶体产生脉冲信号用于定时的定时器,和滴答计时器(systick)的区别是通用定时器在外设上,滴答定时器在内核里。通用定时器一共有8个,分别为TIM1~TIM8,其中TIM2~5是高级定时器,剩下的是普通定时器。
所以说,中断之所以能不阻塞处理器的运行,是因为通用定时器独立于系统内核,不占用处理器的运行时间。
中断控制器,顾名思义是用来控制各种各样种类繁多的中断的,这些中断有先有后,优先级有高有低,因此需要一个专门的控制器来控制它们。
我们尝试实现一个中断控制,选用TIM2作为控制中断的定时器,首先需要配置TIM2,我们查阅技术手册,通用定时器由TIM_TimeBaseInitTypeDef结构体来初始化,此结构体有如下成员。
typedef struct { u16 TIM_Period; //重装载值 u16 TIM_Prescaler; //预分频值 u8 TIM_ClockDivision; //时钟分割 u16 TIM_CounterMode; //计数模式 } TIM_TimeBaseInitTypeDef;
通用定时器的时钟频率还是72MHz,因此我们设定分频值为72方便计算。
TIM_TimeBaseInitTypeDef TIME2_INIT; RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE); TIME2_INIT.TIM_Prescaler=72; TIME2_INIT.TIM_Period=2000; TIME2_INIT.TIM_CounterMode=TIM_CounterMode_Down; TIME2_INIT.TIM_ClockDivision=TIM_CKD_DIV1; TIME2_INIT.TIM_RepetitionCounter=1; TIM_TimeBaseInit(TIM2,&TIME2_INIT); TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE);
如此,便将通用计时器初始化。
然后我们设置中断控制器,中断控制器由NVIC_InitTypeDef结构体来初始化,成员如下
typedef struct { u8 NVIC_IRQChannel; //中断通道,接受什么信号才中断 u8 NVIC_IRQChannelPreemptionPriority; //主优先级 u8 NVIC_IRQChannelSubPriority; //从优先级 FunctionalState NVIC_IRQChannelCmd; //使能 } NVIC_InitTypeDef;
另外,中断控制器还十分有意思,主优先级和从优先级的值,共同占用4位寄存器,因此还得用NVIC_PriorityGroupConfig函数分配一下,这四位寄存器哪几位代表主优先级,哪几位代表从优先级。
NVIC_InitTypeDef NVIC_INIT; NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); NVIC_INIT.NVIC_IRQChannel=TIM2_IRQn; NVIC_INIT.NVIC_IRQChannelPreemptionPriority=2; NVIC_INIT.NVIC_IRQChannelSubPriority=2; NVIC_INIT.NVIC_IRQChannelCmd=ENABLE; NVIC_Init(&NVIC_INIT);
接下来,使能一下TIM2即可
TIM_Cmd(TIM2,ENABLE);
然后,中断控制器当中断条件达成时,会自动调用一下TIM2_IRQHandler函数,注意这个函数名是在库里写死的。我们需要定义一下中断时的行为。
但是,有一点需要注意,在TIM2_IRQHandler函数里面,我们要确认一下这个函数是因为中断请求而调用的,如果是意外调用的则拒绝执行,直接退出,这种编程思想叫做防御式编程,即不信任传入的参数,要在执行前检查参数的合法性。
void TIM2_IRQHandler(){ if(TIM_GetITStatus(TIM2,TIM_IT_Update)==SET){ //中断时执行的事件 } TIM_ClearITPendingBit(TIM2,TIM_IT_Update); }
原文地址:https://www.cnblogs.com/isakovsky/p/11437202.html
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- php根据命令行参数生成配置文件详解
- PHP使用SOAP调用API操作示例
- 使用Zookeeper分布式部署PHP应用程序
- pytorch判断是否cuda 判断变量类型方式
- Keras搭建自编码器操作
- python程序如何进行保存
- Android Q之气泡弹窗的实现示例
- Python with语句用法原理详解
- pytorch 计算ConvTranspose1d输出特征大小方式
- Keras中 ImageDataGenerator函数的参数用法
- CI框架网页缓存简单用法分析
- 掌握PHP垃圾回收机制详解
- PHP基于面向对象封装的分页类示例
- PHP获取对象属性的三种方法实例分析
- PHP7内核之Reference详解