我们过去了解了用循环实现延时,或用系统滴答计时器实现延时,但这两种方法都有一种问题:会阻塞处理器的运行。下面我们学习一种不阻塞处理器运行其他事件的功能:时钟中断。

所谓中断,就是让处理器放下手头的事情,立刻去做一件事情,做完了再做原来的事情。比如说你在写作业,但是突然来了一个人找你说话,你就停下来跟他说话,这就是中断。

要实现时钟中断,我们必须了解两种特性:通用定时器和中断控制器。

通用定时器也是通过晶体产生脉冲信号用于定时的定时器,和滴答计时器(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=;
TIME2_INIT.TIM_Period=;
TIME2_INIT.TIM_CounterMode=TIM_CounterMode_Down;
TIME2_INIT.TIM_ClockDivision=TIM_CKD_DIV1;
TIME2_INIT.TIM_RepetitionCounter=;
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=;
NVIC_INIT.NVIC_IRQChannelSubPriority=;
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);
}

完整代码如下:

#include <time2.h>
#include <stm32f10x.h>
void time2_configer(){
TIM_TimeBaseInitTypeDef TIME2_INIT; RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);
TIME2_INIT.TIM_Prescaler=;
TIME2_INIT.TIM_Period=;
TIME2_INIT.TIM_CounterMode=TIM_CounterMode_Down;
TIME2_INIT.TIM_ClockDivision=TIM_CKD_DIV1;
TIME2_INIT.TIM_RepetitionCounter=;
TIM_TimeBaseInit(TIM2,&TIME2_INIT);
TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE); NVIC_InitTypeDef NVIC_INIT; NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
NVIC_INIT.NVIC_IRQChannel=TIM2_IRQn;
NVIC_INIT.NVIC_IRQChannelPreemptionPriority=;
NVIC_INIT.NVIC_IRQChannelSubPriority=;
NVIC_INIT.NVIC_IRQChannelCmd=ENABLE;
NVIC_Init(&NVIC_INIT); TIM_Cmd(TIM2,ENABLE);
}
void TIM2_IRQHandler(){
if(TIM_GetITStatus(TIM2,TIM_IT_Update)==SET){ }
TIM_ClearITPendingBit(TIM2,TIM_IT_Update);
}
//time2.c
#ifndef _TIME2_H
#define _TIME2_H
void time2_configer();
void TIM2_IRQHandler();
#endif
//time2.h

STM32嵌入式开发学习笔记(五):中断的更多相关文章

  1. STM32嵌入式开发学习笔记(一)

    本文中,笔者将介绍使用嵌入式开发工具Keil uVision5,使用C语言,对微处理器STM32F103C8进行嵌入式开发. 开发使用C语言,首先需要新建一个C语言文件,将其设为主函数的入口,因此,将 ...

  2. STM32嵌入式开发学习笔记(六):串口通信(上)

    本文我们将了解STM32与外部设备通过串口通信的方式. 所谓串口通信,其实是一个类似于计算机网络的概念,它有物理层,比如规定用什么线通信,几伏特算高电平,几伏特算低电平.传输层,通信前要发RTS,CT ...

  3. STM32嵌入式开发学习笔记(七):串口通信(下)

    下面我们进行几个串口通信的实际应用. 实验一:发信实验,让开发板通过串口向电脑发送信息: #include <stdio.h> #include <stm32f10x.h> # ...

  4. STM32嵌入式开发学习笔记(四):使用滴答计时器实现精准计时

    前面我们讲过,因为在STM32上没有系统时间的接口,因此无法调用sleep函数,在本文中,笔者将利用滴答计时器实现精准延时. 查阅技术手册,滴答计时器依赖于一个SysTick_Type类型寄存器,定义 ...

  5. STM32嵌入式开发学习笔记(三):使用按键控制小灯

    按键和小灯一样,也是通过GPIO外设与主板连接,也是通过GPIO_InitStruct类型结构体控制其工作. 查阅技术手册,按钮连接GPIOA控制下的管脚0. 但与之不同的是,按键是一种输入设备,输入 ...

  6. STM32嵌入式开发学习笔记(二):将功能封装为库文件

    将所有的函数都堆在main.c文件里不是好的选择,庞大的代码文件会是你维护的障碍,明智的做法是,一种功能封装到一个库文件里. 库文件就是你代码开始部分写的#include<xxxx.h>里 ...

  7. stm32学习笔记——外部中断的使用

    stm32学习笔记——外部中断的使用 基本概念 stm32中,每一个GPIO都可以触发一个外部中断,但是,GPIO的中断是以组为一个单位的,同组间的外部中断同一时间只能使用一个.比如说,PA0,PB0 ...

  8. python3.4学习笔记(五) IDLE显示行号问题,插件安装和其他开发工具介绍

    python3.4学习笔记(五) IDLE显示行号问题,插件安装和其他开发工具介绍 IDLE默认不能显示行号,使用ALT+G 跳到对应行号,在右下角有显示光标所在行.列.pycharm免费社区版.Su ...

  9. stm32寄存器版学习笔记03 外部中断

    stm32的每个I/O口都可以作为中断输入,要把I/O口设置为外部中断输入,必须将I/O口设置为上拉/下拉输入 或 浮空输入(但浮空的时候外部一定要带上拉或下拉电阻,否则可能导致 中断不停的触发),干 ...

随机推荐

  1. kubernetes部署metrics-server metrics-server-v0.3.4 pod报错

    [root@hadoop02 ~]# kubectl logs metrics-server-v0.3.4-76db4dd54b-s4t2d -c metrics-server -n kube-sys ...

  2. vue 学习中遇到的一些问题

    Vue中data有return返回函数问题: 在简单的vue实例中会看到Vue实例中data属性展示方式如下: let app= newVue({ el:"#app", data: ...

  3. prototype、proto和constructor 关系

    记录: 1.构造函数:如下,Foo()就是一个构造函数 function Foo(){} 2.prototype:每一个构造函数都有一个属性叫prototype,相当于一个指针,指向它的原型对象 Fo ...

  4. 【Java架构:基础技术】一篇文章搞掂:MyBatis-Plus

    前言 Mybatis:一个流行的半自动ORM框架. Mybatis-Plus:一个Mybatis的增强工具,在Mybatis的基础上只做增强不做改变,为简化开发.提高效率而生. 本文使用的版本:myb ...

  5. MySQL 5.7配置文件

    原文:http://www.voidcn.com/article/p-zrikccdi-hr.html # MySql5.7配置文件my.cnf设置[client]port = 3306socket ...

  6. 性能测试基础 ---TCP通信过程的状态码与过程,以及出现错误码的分析(TIME_WAIT,CLOSE_WAIT)

    TCP通信过程 如下图所示,TCP通信过程包括三个步骤:建立TCP连接通道(三次握手).数据传输.断开TCP连接通道(四次挥手). 这里进一步探究TCP三路握手和四次挥手过程中的状态变迁以及数据传输过 ...

  7. 人物-IT-胡玮炜:百科

    ylbtech-人物-IT-胡玮炜:百科 胡玮炜,女,汉族,1982年出生于浙江东阳,毕业于浙江大学城市学院新闻系,摩拜单车创始人 . 2004年胡玮炜从浙江大学城市学院新闻系毕业后进入<每日经 ...

  8. idea 查看字节码 bytecode插件 (jclasslib Bytecode Viewer、ASM Bytecode Viewer )

    文章目录 jclasslib Bytecode Viewer ASM Bytecode Viewer jclasslib Bytecode Viewer 然后重启idea===>重新编译(构建项 ...

  9. JVM内存图

  10. .net报错大全

    1.未能加载文件或程序集“Newtonsoft.Json, Version=4.5.0.0"[已解决] 解决方案:https://blog.csdn.net/mzl87/article/de ...