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

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

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

通用定时器也是通过晶体产生脉冲信号用于定时的定时器,和滴答计时器(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. 【Flutter学习】事件处理与通知之事件处理

    一,概述 移动应用中一个必不可少的环节就是与用户的交互,在Flutter中提供的手势检测为GestureDetector. Flutter中的手势系统分为二层: 第一层是触摸原事件(指针) Point ...

  2. kubernetes批量删除pod

    监控页面出现看到有运行失败的pod 1) 查看有哪些不运行的podcustom-metrics-apiserver日志占满空间被驱逐 [root@hadoop03 ~]# kubectl get po ...

  3. paper 134:结构张量structure tensor(二)

    根据结构张量能区分图像的平坦区域.边缘区域与角点区域. 此算法也算是计算机科学最重要的32个算法之一了.链接的文章中此算法名称为Strukturtensor算法,不过我搜索了一下,Strukturte ...

  4. CDN技术之-介绍

    “第一公里”是指万维网流量向用户传送的第一个出口,是网站服务器接入互联网的链路所能提供的带宽.这个带宽决定了一个网站能为用户提供的访问速度和并发访问量.如果业务繁忙,用户的访问数越多,拥塞越严重,网站 ...

  5. 小程序 页面传值 json 被截断

    因此解决这个报错的方法是将要传输的数据用 encodeURIComponent()函数(可把字符串作为 URI 组件进行编码) 先进行编码, 传输过去后再通过decodeURIComponent()函 ...

  6. Qt获取文件路径、文件夹路径

    1.首先是选择文件 QString file_path = QFileDialog::getOpenFileName(this, "请选择文件路径...", "默认路径( ...

  7. HTML-参考手册: HTML 字符集

    ylbtech-HTML-参考手册: HTML 字符集 1.返回顶部 1. HTML 字符集 HTML 字符集 如需正确地显示 HTML 页面,浏览器必须知道使用何种字符集. 万维网早期使用的字符集是 ...

  8. 90、Tensorflow实现分布式学习,多台电脑,多个GPU 异步试学习

    ''' Created on 2017年5月28日 @author: weizhen ''' import time import tensorflow as tf from tensorflow.e ...

  9. 【计算机网络mooc】二、物理层

    1.物理层基本概念 物理层只考虑传输bit流,不包括网线等传输媒体(可认为是第0层),屏蔽传输媒体的差异,不同的传输媒体定义不同标准. 主要任务:确定与传输媒体的接口的特性. 机械特性:网线上面的水晶 ...

  10. flask-sqlalchemy报错 Object '<User at xxxx>' is already attached to session '1' (this is '2')

    报错:  Object '<User at xxxx>' is already attached to session '1' (this is '2') 结论:      两个不同的db ...