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=;
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嵌入式开发学习笔记(五):中断的更多相关文章
- STM32嵌入式开发学习笔记(一)
本文中,笔者将介绍使用嵌入式开发工具Keil uVision5,使用C语言,对微处理器STM32F103C8进行嵌入式开发. 开发使用C语言,首先需要新建一个C语言文件,将其设为主函数的入口,因此,将 ...
- STM32嵌入式开发学习笔记(六):串口通信(上)
本文我们将了解STM32与外部设备通过串口通信的方式. 所谓串口通信,其实是一个类似于计算机网络的概念,它有物理层,比如规定用什么线通信,几伏特算高电平,几伏特算低电平.传输层,通信前要发RTS,CT ...
- STM32嵌入式开发学习笔记(七):串口通信(下)
下面我们进行几个串口通信的实际应用. 实验一:发信实验,让开发板通过串口向电脑发送信息: #include <stdio.h> #include <stm32f10x.h> # ...
- STM32嵌入式开发学习笔记(四):使用滴答计时器实现精准计时
前面我们讲过,因为在STM32上没有系统时间的接口,因此无法调用sleep函数,在本文中,笔者将利用滴答计时器实现精准延时. 查阅技术手册,滴答计时器依赖于一个SysTick_Type类型寄存器,定义 ...
- STM32嵌入式开发学习笔记(三):使用按键控制小灯
按键和小灯一样,也是通过GPIO外设与主板连接,也是通过GPIO_InitStruct类型结构体控制其工作. 查阅技术手册,按钮连接GPIOA控制下的管脚0. 但与之不同的是,按键是一种输入设备,输入 ...
- STM32嵌入式开发学习笔记(二):将功能封装为库文件
将所有的函数都堆在main.c文件里不是好的选择,庞大的代码文件会是你维护的障碍,明智的做法是,一种功能封装到一个库文件里. 库文件就是你代码开始部分写的#include<xxxx.h>里 ...
- stm32学习笔记——外部中断的使用
stm32学习笔记——外部中断的使用 基本概念 stm32中,每一个GPIO都可以触发一个外部中断,但是,GPIO的中断是以组为一个单位的,同组间的外部中断同一时间只能使用一个.比如说,PA0,PB0 ...
- python3.4学习笔记(五) IDLE显示行号问题,插件安装和其他开发工具介绍
python3.4学习笔记(五) IDLE显示行号问题,插件安装和其他开发工具介绍 IDLE默认不能显示行号,使用ALT+G 跳到对应行号,在右下角有显示光标所在行.列.pycharm免费社区版.Su ...
- stm32寄存器版学习笔记03 外部中断
stm32的每个I/O口都可以作为中断输入,要把I/O口设置为外部中断输入,必须将I/O口设置为上拉/下拉输入 或 浮空输入(但浮空的时候外部一定要带上拉或下拉电阻,否则可能导致 中断不停的触发),干 ...
随机推荐
- Service系统服务(三):查看进程信息、进程调度及终止、系统日志分析、使用systemctl工具
一.查看进程信息 目标: 本例要求掌握查看进程信息的操作,使用必要的命令工具完成下列任务: 找出进程 gdm 的 PID 编号值 列出由进程 gdm 开始的子进程树结构信息 找出进程 sshd 的父进 ...
- ZROI week5
考试 Part 简单题,从结尾倒着扫一遍就行. Pref 选一个最长的好的序列. 题目有点小简单,似乎直接哈希就行,然后还打了一遍\(kmp\). Chess 一道很不错的题目,用异或维护修改即可. ...
- 分布式系统理论基础6:Raft、Zab
本文转自:https://www.cnblogs.com/bangerlee/p/5991417.html 本文转自 https://www.cnblogs.com/bangerlee/p/52684 ...
- 【Java架构:基础技术】一篇文章搞掂:Gradle
前言 Gradle是什么: Gradle提供了一个域特定语言(DSL),用于描述构建 它使用 Groovy 语言,使其更容易来形容和构建 Gradle 中的每一个构建脚本使用UTF-8进行编码保存,并 ...
- 2019牛客第八场多校 D_Distance 三维BIT或定期重建套路
目录 题意: 分析: @(2019牛客暑期多校训练营(第八场)D_Distance) 题意: 在三维空间\((n\times m\times h\le 100000)\)内,有\(q(q\le 100 ...
- MacBook Pro常用快捷键
MacBook Pro常用快捷键 Mac fn + left / right / up / down 相当于 home/end/page up /page down delete 删除光标前一个字符 ...
- 建立一个更高级别的查询 API:正确使用Django ORM 的方式
https://www.oschina.net/translate/higher-level-query-api-django-orm
- leetcode.双指针.633平方数之和-Java
1. 具体题目 给定一个非负整数 c ,你要判断是否存在两个整数 a 和 b,使得 a^2 + b^2 = c. 示例1: 输入: 5 输出: True 解释: 1 * 1 + 2 * 2 = 5 注 ...
- redis的一些特性
Redis内存回收 Redis复制原理 Redis提供的高可用方案 Redis提供的分片算法 Redis迁移
- Oracle上课学习笔记<1>
简单的select查询语句 1.select查询语句基本语法 使用两个关键字: select 指定要查询的字段和内容 from 从哪张表中查询 语法:select 字段名 from 表名; 三种不同的 ...