STM32 学习9 中断、外部中断及定时器中断

STM32 学习9 中断、外部中断及定时器中断

  • 一、STM32中断介绍
    • 一、STM32中断介绍
      • 1. 什么是中断?
      • 2. 中断在嵌入式系统中的作用和重要性
      • 3. STM32中断的概述
    • 4. 中断的优先级
      • 4.1 中断优先级级别
      • 4.2 中断优先级分类
        • (1)硬件优先级
        • (2)响应速度优先级
        • (3)重要性优先级
        • (4)任务优先级
      • 4.3 中断优先级设置
      • 4.4 中断优先级规则
  • 二、STM32中断编程
    • 1. 使用能外设某个中断
      • (1)使能中断
      • (2)配置中断触发条件
    • 2. 设置中断优先级分组
    • 3. 编写中断服务函数
  • 三、外部中断
    • 1. 概念
    • 2. EXTI
    • 3. EXTI 框图
    • 4. EXTI中断/事件线路
    • 5. 外部中断使用步骤
    • 6. 示例
      • (1)exti_utils.h
      • (2)exti_utils.c
  • 六、定时器中断
    • 1. 简介
    • 2. 通用定时器简介
      • (1)时基单元
      • (2)计数器模式
      • (3)时钟选择
      • (4)输入通道
      • (5)捕获通道
      • (6)定时器级联
      • (7)定时器中断
    • 3. 定时时间计算公式
    • 4. 配置步骤
      • (1)选择定时器模块
      • (2) 初始化时钟
      • (3)初始化定时器参数
      • (4)设置定时器中断类型,并使能
      • (5)使能
      • (6)配置中断优先级
      • (7)中断服务函数
    • 5. 示例
      • (1)timx_utils.h
      • (2)timx_utils.c
      • (3)main.c
  • 七、中断嵌套
    • 1. 概念
    • 2. 中断的实现方式

一、STM32中断介绍

一、STM32中断介绍

1. 什么是中断?

中断是一种计算机编程中的技术,用于在程序执行期间暂停当前任务,转而执行预定义的中断服务程序(ISR),处理特定的事件或信号。

中断机制允许系统对实时事件做出及时响应,而不必用循环去等待特定事件的发生。

2. 中断在嵌入式系统中的作用和重要性

在嵌入式系统中,特别是在实时系统中,对一些事件的即时响应至关重要。例如:传感器数据的读取、定时器溢出、外部输入信号等都是需要及时处理的事件。

使用中断可以确保系统能够在这些事件发生时立即作出响应,而不会因为等待而造成延迟或丢失数据。

3. STM32中断的概述

STM32系列微控制器提供了丰富的中断支持,包括但不限于外部中断、定时器中断、串口中断和DMA中断等。
STM32F10x芯片有84个中断通道,包括16个内核中断和68个可屏蔽中断,在《STM32F10x中文参考手册》第65页有向量表进行了详细介绍,摘录如下:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

4. 中断的优先级

在STM32系列微控制器中,中断优先级决定了当多个中断同时发生时,哪一个中断将被优先处理。

4.1 中断优先级级别

中断优先级通常是一个整数,STM32F103使用中断优先级控制字节的高4位,0为最高优先级,15为最低优先级。
STM32系列微控制器通常将中断分为多个组,每个组有自己的优先级范围。例如,对于外部中断,可以有4个组,每个组可以有16个优先级。

4.2 中断优先级分类

以下是几种常见的中断优先级分类方式:

(1)硬件优先级

硬件优先级是指微控制器硬件提供的中断优先级机制。在STM32系列微控制器中,中断的硬件优先级通常是一个数字,数字越小,优先级越高。例如,优先级0是最高优先级,15是最低优先级。开发者可以根据需要为每个中断设置不同的硬件优先级。

(2)响应速度优先级

响应速度优先级是根据中断需要被多快地响应来确定的。一些紧急事件可能需要立即得到处理,因此这些中断会被分配更高的优先级,以确保系统能够及时响应。例如,定时器溢出中断可能比普通外部中断更加紧急,因此可以为定时器中断分配更高的优先级。

(3)重要性优先级

重要性优先级是根据中断对系统功能的重要性来确定的。一些关键的系统功能可能需要被优先处理,以确保系统的正常运行。例如,系统故障中断可能比其他一般中断更加重要,因此可以为系统故障中断分配更高的优先级。

(4)任务优先级

任务优先级是根据中断所执行的任务的重要性来确定的。系统中可能存在多个任务,这些任务有不同的优先级。中断的优先级可以根据所执行的任务的重要性来确定,以确保系统能够优先处理重要任务。

4.3 中断优先级设置

在STM32中,中断优先级的设置是通过NVIC(Nested Vectored Interrupt Controller,嵌套向量中断控制器)进行的。

NVIC属于M3内核的一个外设,控制着芯片的中断功能。ARM给NVIC预留的功能比较多,而M3内核进行了裁剪。

中断控制器相关的寄存器在固件库的core_cm3.h 文件NVIC结构体里定义,常见的寄存器有:

  • NVIC_ISERx 使用中断寄存器
  • NVIC_ICERx 禁用中断
  • NVIC_ISPRx 设置中断挂起
  • NVIC_ICPRx 清除中断的挂起状态
  • NVIC_IPRx 设置中断优先级
  • NVIC_STIR 用于软件触发中断
  • NVIC_ICSR 提供了一些中断相关的状态和控制位

我们可以通过NVIC接口函数来配置中断的优先级,常用的函数包括NVIC_SetPriority()NVIC_SetPriorityGrouping()等。通过这些函数,可以将不同中断设置为不同的优先级,并根据实际需求进行灵活配置。

4.4 中断优先级规则

在设置中断优先级时,需要遵循一定的规则,以确保系统的正确性和稳定性:

  • 优先级较低的中断可以被较高优先级的中断抢占。换句话说,当一个中断正在执行时,如果发生了优先级更高的中断,系统会立即转去执行更高优先级的中断服务程序。
  • 优先级相同的中断,先被触发的中断会先被处理。即如果多个中断同时发生,并且优先级相同,则先触发的中断会先得到处理。

二、STM32中断编程

1. 使用能外设某个中断

(1)使能中断

(2)配置中断触发条件

2. 设置中断优先级分组

初始化 NVIC_InitTypeDef 结构体:

typedef struct
{uint8_t NVIC_IRQChannel;						// 中断源设置uint8_t NVIC_IRQChannelPreemptionPriority;   // 抢占优先级uint8_t NVIC_IRQChannelSubPriority;          // 响应优先级FunctionalState NVIC_IRQChannelCmd;          // 中断使能或失能
}

NVIC_IRQChannel中断源可以在 stm32f10x.h 头文件中查到:
在这里插入图片描述

3. 编写中断服务函数

void EXTI0_IRQHandler(void)
{// 处理外部中断0发生时的事件// 例如,读取外部输入引脚状态、清除中断标志等// 清除中断挂起标志位EXTI_ClearITPendingBit(EXTI_Line0);
}

中断服务的函数名称在启动文件中定义,建议不要修改:
在这里插入图片描述

三、外部中断

1. 概念

外部中断是STM32系列微控制器中的一种中断类型,它允许外部事件(如外部输入引脚状态的变化)触发中断,从而使系统能够实时响应外部的输入信号。外部中断常用于处理外部设备的输入,如按钮、传感器等。

2. EXTI

外部中断线路管理器(External Interrupt/Event Controller,EXTI)是STM32系列微控制器中的一个重要外设,用于管理外部中断和事件的触发和处理。

STM32F10x EXTI包含多达19个用于产生事件/中断请求的边沿检测器。

EXTI允许外部事件(例如GPIO引脚状态的变化)触发中断,可以选择类型(中断或事件)和相应的触发事件(上升沿触发、下降沿触发或边沿触发),从而实现对外部输入信号的实时响应。还可以独立地屏蔽EXTI中断。

下面是部分EXTI中断向量表:

在这里插入图片描述
除了EXTI, 另外 RTCAlarm、USB唤醒、PVD电源检测中断、ETH_WKUP 等外部中断。

3. EXTI 框图

在这里插入图片描述

4. EXTI中断/事件线路

EXTI线路说明
EXTI 线 0~15对应外部IO 口的输入中断
EXTI 线 16连接PVD输出
EXTI 线17连接到RTC闹钟事件
EXTI 线 18连接到USB唤醒事件
EXTI 线19连接到以太网唤醒事件,联网型芯片

5. 外部中断使用步骤

  1. 使能外部中断:通过配置外部中断线路管理器(EXTI)和GPIO外设,使能外部中断功能;
 // 使能外部中断线0NVIC_InitTypeDef NVIC_InitStruct;NVIC_InitStruct.NVIC_IRQChannel = EXTI0_IRQn; // 外部中断0NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 0x01; // 抢占优先级为1NVIC_InitStruct.NVIC_IRQChannelSubPriority = 0x01; // 响应优先级为1NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;NVIC_Init(&NVIC_InitStruct);
  1. 开启AFIO 时钟,设置IO口与中断线映射关系;
  2. 配置中断分组,使能中断;
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); // 选择优先级分组方式,这里选择分组2
  1. 初始化EXTi,选择触发方式;
    初始化使用 EXTI_InitStruct 函数;
    // 初始化外部中断线路管理器(EXTI)EXTI_InitTypeDef EXTI_InitStruct;EXTI_InitStruct.EXTI_Line = EXTI_Line0; // 使用外部中断线0EXTI_InitStruct.EXTI_Mode = EXTI_Mode_Interrupt; // 设置为中断模式EXTI_InitStruct.EXTI_Trigger = EXTI_Trigger_Rising; // 上升沿触发EXTI_InitStruct.EXTI_LineCmd = ENABLE; // 使能外部中断线0EXTI_Init(&EXTI_InitStruct);
  1. 编写EXTI中断服务函数
  • EXTI0_IRQHandler
  • EXTI1_IRQHandler
  • EXTI2_IRQHandler
  • EXTI3_IRQHandler
  • EXTI4_IRQHandler
  • EXTI9_5_IRQHandler
  • EXTI5_10_IRQHandler

6. 示例

本实例使用的开发板 GPIO 按键电路:
在这里插入图片描述
对于开发板的K1、K2、K3 使用下降沿触发,
KEY_UP 使用上升沿触发。对应的引脚:

  • KEY_UP:GPIOA GPIO_Pin0 引脚
  • KEY_LEFT:GPIOE GPIO_Pin2 引脚
  • KEY_RIGHT:GPIOE_GPIO_Pin4 引脚
  • KEY_DOWN:GPIOE_GPIO_Pin3 引脚

(1)exti_utils.h

#ifndef __exti_utils_h__
#define __exti_utils_h__#include "stm32f10x.h"
void custom_exti_init(void);
#endif

(2)exti_utils.c

#include "exti_utils.h"
#include "stdio.h"
#include "sys_tick_utils.h"
#include "led_utils.h"
#include "key_utils.h"/*** @brief  外部中断初始化
*/
void custom_exti_init(void) {// 开启AFIO时钟RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);// GPIO 引脚映射到 EXTI 中断线GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource0);// GPIOE 映射到 EXTI 中断线GPIO_EXTILineConfig(GPIO_PortSourceGPIOE, GPIO_PinSource2);GPIO_EXTILineConfig(GPIO_PortSourceGPIOE, GPIO_PinSource3);GPIO_EXTILineConfig(GPIO_PortSourceGPIOE, GPIO_PinSource4);// 配置外部中断0的优先级NVIC_InitTypeDef NVIC_InitStruct;NVIC_InitStruct.NVIC_IRQChannel = EXTI0_IRQn;NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 0x02;   // 抢占优先级为1NVIC_InitStruct.NVIC_IRQChannelSubPriority = 0x03;          // 响应优先级为3NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;NVIC_Init(&NVIC_InitStruct);NVIC_InitStruct.NVIC_IRQChannel = EXTI2_IRQn;NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 0x02;   // 抢占优先级为1NVIC_InitStruct.NVIC_IRQChannelSubPriority = 0x02;          // 响应优先级为2NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;NVIC_Init(&NVIC_InitStruct);NVIC_InitStruct.NVIC_IRQChannel = EXTI3_IRQn;NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 0x02;   // 抢占优先级为1NVIC_InitStruct.NVIC_IRQChannelSubPriority = 0x1;          // 响应优先级为1NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;NVIC_Init(&NVIC_InitStruct);NVIC_InitStruct.NVIC_IRQChannel = EXTI4_IRQn;NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 0x02;   // 抢占优先级为1NVIC_InitStruct.NVIC_IRQChannelSubPriority = 0x0;          // 响应优先级为0NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;NVIC_Init(&NVIC_InitStruct);// 初始化外部中断线路管理器(EXTI)EXTI_InitTypeDef EXTI_InitStruct;EXTI_InitStruct.EXTI_Line = EXTI_Line0;                 // 外部中断线0EXTI_InitStruct.EXTI_Mode = EXTI_Mode_Interrupt;        // 中断模式EXTI_InitStruct.EXTI_Trigger = EXTI_Trigger_Rising;    // 上升沿触发EXTI_InitStruct.EXTI_LineCmd = ENABLE;                  // 使能外部中断线0EXTI_Init(&EXTI_InitStruct);EXTI_InitStruct.EXTI_Line = EXTI_Line2;                 // 外部中断线2EXTI_InitStruct.EXTI_Mode = EXTI_Mode_Interrupt;        // 中断模式EXTI_InitStruct.EXTI_Trigger = EXTI_Trigger_Falling;    // 下降沿触发EXTI_InitStruct.EXTI_LineCmd = ENABLE;                  // 使能外部中断线0EXTI_Init(&EXTI_InitStruct);EXTI_InitStruct.EXTI_Line = EXTI_Line3;                 // 外部中断线2EXTI_InitStruct.EXTI_Mode = EXTI_Mode_Interrupt;        // 中断模式EXTI_InitStruct.EXTI_Trigger = EXTI_Trigger_Falling;    // 下降沿触发EXTI_InitStruct.EXTI_LineCmd = ENABLE;                  // 使能外部中断线0EXTI_Init(&EXTI_InitStruct);EXTI_InitStruct.EXTI_Line = EXTI_Line4;                 // 外部中断线2EXTI_InitStruct.EXTI_Mode = EXTI_Mode_Interrupt;        // 中断模式EXTI_InitStruct.EXTI_Trigger = EXTI_Trigger_Falling;    // 下降沿触发EXTI_InitStruct.EXTI_LineCmd = ENABLE;                  // 使能外部中断线0EXTI_Init(&EXTI_InitStruct);
}
/*** @brief  外部中断0中断服务函数
*/
void EXTI0_IRQHandler(void) {if (EXTI_GetITStatus(EXTI_Line0) != RESET) {delay_ms(10);if (key_up_value  == 1) {led_lightn(0);EXTI_ClearITPendingBit(EXTI_Line0); // 清除中断标志位return;}}
}
/*** @brief  外部中断2中断服务函数
*/
void EXTI2_IRQHandler(void) {if (EXTI_GetITStatus(EXTI_Line2) != RESET) {delay_ms(10);if (key_left_value  == 0) {led_lightn(2);EXTI_ClearITPendingBit(EXTI_Line2); // 清除中断标志位return;}}
}
/*** @brief  外部中断3中断服务函数
*/
void EXTI3_IRQHandler(void) {if (EXTI_GetITStatus(EXTI_Line3) != RESET) {delay_ms(10);if (key_down_value  == 0) {led_lightn(1);EXTI_ClearITPendingBit(EXTI_Line3); // 清除中断标志位return;}}
}
/*** @brief  外部中断4中断服务函数
*/
void EXTI4_IRQHandler(void) {if (EXTI_GetITStatus(EXTI_Line4) != RESET) {delay_ms(10);if (key_right_value  == 0) {led_lightn(3);EXTI_ClearITPendingBit(EXTI_Line4); // 清除中断标志位return;}}
}

本示例的功能,在按下按键后,分别使用LED显示 0,1,2,3。

六、定时器中断

1. 简介

STM32F1系列微控制器提供了多种定时器模块,包括:

  • 2个 基本定时器(TIM6和TIM7):用于生成简单的定时中断,适用于一些简单的定时任务。
  • 4个 通用定时器(TIM2至TIM5):具有更多的功能和配置选项,可以实现更复杂的定时任务和PWM输出等功能。
  • 2个 高级定时器(TIM1、TIM8):功能最为丰富的定时器,可以用于高级的PWM控制、编码器接口、脉冲捕获等应用。
    通用定时器通常挂接在APB1;
    高级定时器通常挂载在AHB上。

2. 通用定时器简介

STM32F1的通用定时器包含一个 16位 自动重载计数器(CNT),该计数器由可编程预分频器(PSC)驱动。
通用定时器支持多种工作模式,包括定时器模式、定时器中断模式、PWM输出模式、输入捕获模式和输出比较模式等。

使用定时器预分频器和RCC时钟控制器预分频器,脉冲长度和波形周期可以在几个微秒至几个毫秒间调整。
通用定时器框图:
在这里插入图片描述

(1)时基单元

通用定时器的时基单元是指定时器的基本计时单元,它决定了定时器计数的频率和精度。时基单元包括 :

  • 计数器寄存器(TIMx_CNT),16位;
  • 预分频器寄存器(TIMx_PSC),16位,在1~65535之间取值;
  • 自动装载寄存器(TIMx_ARR)。

预分频系数用来将定时器的时钟频率降低到一个合适的范围,以适应具体的应用需求,它的值是一个正整数,通常可以通过以下公式来计算:

[ \text{实际频率} = \frac{\text{时钟源频率}}{\text{预分频系数}} ]

(2)计数器模式

根据所选的计数器模式,定时器的计数器将以不同的方式进行计数。

  • 在向上计数模式下,计数器从0开始递增;
  • 在向下计数模式下,计数器从自动重装载值开始递减;
  • 在中央对齐模式和双边沿对齐模式下,计数器的溢出值为自动重装载值的一半。

不同的计数器模式适用于不同的应用场景,可以根据具体的需求选择合适的模式来实现相应的功能。

(3)时钟选择

通用定时器的时钟决定了定时器的计数速率和精度。在STM32微控制器中,通用定时器可以选择多种时钟源,包括内部时钟源和外部时钟源。

常见的时钟源:

  1. 内部时钟源(Internal Clock Source):内部时钟源是由微控制器内部的时钟模块提供的时钟信号,通常为主时钟(HCLK)或高速内部时钟(HSI)。内部时钟源具有稳定性好、可靠性高的优点,适用于大多数应用场景。

  2. 外部时钟源(External Clock Source):外部时钟源是由外部晶振或外部时钟信号提供的时钟信号,通常通过外部引脚输入到微控制器内部。外部时钟源具有精度高、抗干扰能力强的特点,适用于对时钟精度有较高要求的应用场景。

(4)输入通道

通用定时器包含4个独立通道(TIMx_CH1-4),每个通道对应芯片的引脚,如下图所示:
在这里插入图片描述

(5)捕获通道

捕获通道是通用定时器(TIM)中用于捕获外部事件(如输入脉冲)时间戳的通道。在捕获模式下,定时器可以监视一个外部信号的边沿触发,并记录下此时计数器的值,从而得到外部事件的时间戳信息。捕获通道通常用于测量脉冲宽度、频率、周期等应用场景,其主要特点:

  • 外部事件捕获:捕获通道允许定时器监视外部信号的变化,如上升沿或下降沿,以捕获外部事件的时间戳。
  • 多通道支持:通用定时器通常支持多个捕获通道,每个通道可以独立地捕获外部事件的时间戳。
  • 精确度高:由于定时器的高精度计数器和硬件触发机制,捕获通道可以实现很高的时间精度和稳定性。

(6)定时器级联

如果使用外部信号控制定时器,可实现多个定时器互连(使用一个定时器控制另一个定时器)。

(7)定时器中断

通用定时器(TIM)在STM32微控制器中可以产生多种类型的中断,常见的中断包括:

  1. 更新中断(Update Interrupt):当定时器的计数器溢出或者自动重装载值被加载到计数器时,会产生更新事件,从而触发更新中断。更新中断是定时器最基本的中断类型,用于处理定时器计数周期结束时的事件。

  2. 比较/捕获中断(Compare/Capture Interrupt):定时器可以配置为输出比较模式或输入捕获模式,在这些模式下,当计数器的值与比较值相等或者外部事件触发捕获时,会产生比较/捕获事件,从而触发比较/捕获中断。比较/捕获中断用于处理定时器与外部事件的相关操作。

  3. 触发中断(Trigger Interrupt):定时器可以配置为外部时钟模式或触发输入模式,在这些模式下,当外部触发事件到来时,会产生触发事件,从而触发触发中断。触发中断用于处理外部触发事件的相关操作。

  4. DMA请求中断(DMA Request Interrupt):当定时器的更新、比较或捕获事件发生时,可以产生DMA请求,从而触发DMA请求中断。DMA请求中断用于处理DMA传输相关的操作。

3. 定时时间计算公式

定时器定时时间的公式可以通过以下方式进行计算:
T o u t = ( p e r i o d ∗ ( p s c + 1 ) ) T c l k T_{out} = \frac{(period * (psc+1))}{T_{clk}} Tout=Tclk(period(psc+1))

4. 配置步骤

通用定时器的配置步骤通常包括以下几个关键步骤:

(1)选择定时器模块

首先确定要使用的通用定时器模块,通常有 TIM1、TIM2、TIM3、TIM4 等可供选择,根据具体的需求选择合适的定时器模块。

(2) 初始化时钟

// 使能TIM4时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4,ENABLE);  

(3)初始化定时器参数

需要初始化自动重装值,分频系数,计数方式等。

 	// 定时器配置TIM_TimeBaseInitTypeDef TIM_InitStruct;TIM_InitStruct.TIM_Prescaler = 36000 - 1; 			 // 预分频系数,1~65535,实际值会自动加1TIM_InitStruct.TIM_CounterMode = TIM_CounterMode_Up; // 向上计数模式TIM_InitStruct.TIM_Period = 1000; 				 // 自动重装载值,即定时器周期TIM_InitStruct.TIM_ClockDivision = TIM_CKD_DIV1;	 // 时钟分频TIM_InitStruct.TIM_RepetitionCounter = 0;			 // 重复计数器,高级计数器使用TIM_TimeBaseInit(TIM2, &TIM_InitStruct);

这里计算的定时时间为:
1000 ∗ 36000 72 M = 0.5 ( 秒 ) \frac{1000 * 36000}{72M}=0.5(秒) 72M100036000=0.5()

其中的频率是APB1总线频率*2。

(4)设置定时器中断类型,并使能

// 定时器配置TIM_TimeBaseInitTypeDef TIM_InitStruct;// 此处配置定时器的参数,如预分频系数、计数器模式、自动重装载值等// 初始化定时器TIM_TimeBaseInit(TIM2, &TIM_InitStruct);// 使能更新中断TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);

(5)使能

    // 使能定时器TIM_Cmd(TIM2, ENABLE);

(6)配置中断优先级

    // 配置定时器中断优先级NVIC_InitTypeDef NVIC_InitStruct;NVIC_InitStruct.NVIC_IRQChannel = TIM2_IRQn;NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 0;NVIC_InitStruct.NVIC_IRQChannelSubPriority = 0;NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;NVIC_Init(&NVIC_InitStruct);

(7)中断服务函数

void TIM2_IRQHandler(void) {if (TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET) {// 处理定时器更新中断事件// 清除中断标志位TIM_ClearITPendingBit(TIM2, TIM_IT_Update);}
}

5. 示例

本示例通过定时器中断控制LED闪烁。

(1)timx_utils.h

#ifndef __TIMX_UTILS_H__
#define __TIMX_UTILS_H__
#include "stm32f10x.h"
void timx_init(u16 preriod, u16 psc);
void timx_init_ms(u16 ms);
#endif

(2)timx_utils.c

#include "timx_utils.h"
#include "led_utils.h"
#include "stm32f10x.h"/*** @brief  初始化定时器* @param  preriod: 自动重装载寄存器周期值* @param  prescaler: 时钟预分频数
*/
void timx_init(u16 preriod, u16 prescaler)
{TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;NVIC_InitTypeDef NVIC_InitStructure;RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE);TIM_TimeBaseStructure.TIM_Period = preriod;TIM_TimeBaseStructure.TIM_Prescaler = prescaler;TIM_TimeBaseStructure.TIM_ClockDivision = 0;TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;// 初始化TIM_TimeBaseInit(TIM4, &TIM_TimeBaseStructure);// 中断使能TIM_ITConfig(TIM4, TIM_IT_Update, ENABLE);// 使能定时器TIM_Cmd(TIM4, ENABLE);// 中断优先级NVIC设置NVIC_InitStructure.NVIC_IRQChannel = TIM4_IRQn;NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;NVIC_Init(&NVIC_InitStructure);
}
/*** @brief  初始化定时器* @param  ms: 定时器中断时间
*/
void timx_init_ms(u16 ms)
{// 直接调用 timx_init 函数timx_init(ms*2, 36000-1);
}static u8 n=0;void TIM4_IRQHandler(void)
{if (TIM_GetITStatus(TIM4, TIM_IT_Update) != RESET){led_lightn(n);n++;if(n>9){n=0;}TIM_ClearITPendingBit(TIM4, TIM_IT_Update);}
}

(3)main.c

#include "gpio_utils.h"
#include "stm32f10x.h"
#include "sys_tick_utils.h"
#include "led_utils.h"
#include "exti_utils.h"
#include "timx_utils.h"// 主函数
int main(void)
{GPIO_Configuration(); //调用GPIO配置函数sys_tick_init(72);NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);// 定时器的时钟频率是72MHz,预分频系数是36000,// 所以定时器的时钟频率是72MHz/36000=2KHz,周期是1000,// 所以定时器的周期是1000/2KHz=0.5stimx_init_ms(1000);led_all_off();while (1) //无限循环{delay_ms(10);}
}

七、中断嵌套

1. 概念

中断嵌套是指在一个中断服务程序(ISR)中允许发生另一个中断的情况。简单来说,就是当一个中断正在处理时,如果发生了另一个中断,系统能够暂时中断当前的中断处理流程,转而处理新的中断请求,待新的中断处理完成后再返回继续处理原先的中断。

在嵌套中断系统中,通常存在多个中断优先级,每个中断都有其自己的优先级,高优先级的中断可以抢占正在执行的低优先级中断。这样可以确保高优先级的事件能够得到及时处理,提高了系统对紧急事件的响应能力。

2. 中断的实现方式

中断嵌套的实现通常需要硬件和软件的支持。

  • 硬件需要提供支持多级中断优先级的中断控制器,如STM32系列微控制器中的嵌套向量中断控制器(NVIC)。
  • 软件方面则需要编写合适的中断服务程序,并在其中实现中断优先级的管理和中断处理的逻辑。

本文代码开源地址:
https://gitee.com/xundh/stm32_arm_learn

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/726724.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

挑战杯 基于深度学习的目标检测算法

文章目录 1 简介2 目标检测概念3 目标分类、定位、检测示例4 传统目标检测5 两类目标检测算法5.1 相关研究5.1.1 选择性搜索5.1.2 OverFeat 5.2 基于区域提名的方法5.2.1 R-CNN5.2.2 SPP-net5.2.3 Fast R-CNN 5.3 端到端的方法YOLOSSD 6 人体检测结果7 最后 1 简介 &#x1f5…

Nuxt2升级Nuxt3指南(二):nuxt.config.js配置文件

一、代码移植原则 前置说明:根据项目开发的实际情况,本次升级不采用Typescript。 升级的原则是开始尽量的简单配置,将代码分阶段逐步移植到新版本框架上,遇到问题逐一排查解决。 大致阶段,可以分为: 第一…

在idea中如何开启项目的热部署

热部署&#xff1a;就是当我们IDEA的项目在运行期间&#xff0c;我们修改代码以后&#xff0c;不需要我们自己重启项目&#xff0c;IDEA就会自动的重启项目 在idea中开启项目热部署的步骤 第一步&#xff1a;引入热部署的依赖 <dependency><groupId>org.springfr…

STP---生成树协议

STP的作用 a)Stp通过阻塞端口来消除环路&#xff0c;并能够实现链路备份目的 b)消除了广播风暴 c)物理链路冗余&#xff0c;网络变成了层次化结构的网络 STP操作 选举一个根桥每个非根交换机选举一个根端口每个网段选举一个指定端口阻塞非根&#xff0c;非指定端口 STP--生成树…

基于单片机的智能空调设计

目 录 摘 要 I Abstract II 引 言 1 1 系统整体设计 3 1.1 系统方案设计 3 1.2 系统工作原理 3 2 硬件设计 5 2.1 电源模块设计 5 2.1.1 电源模块选择 5 2.1.2 电源模块电路设计 5 2.2 单片机模块设计 5 2.2.1 单片机型号选择 5 2.2.2 单片机模块电路设计 6 2.3 按键模块设计 …

vue3中el-input输入无效的原因之一

表单的model用的是&#xff1a;reactive let updateForm reactive({ id: 0, className: "" }); reactive的数据不能这么赋值&#xff0c;会破坏响应性 错误方法&#xff08;&#xff09;{ updateForm { id: 0, className: "asdasdas" }; } 解决方法&…

1.5如何缓解图像分类任务中训练数据不足带来的问题?

1.5 图像数据不足时的处理方法 场景描述 在机器学习中&#xff0c;绝大部分模型都需要大量的数据进行训练和学习(包括有监督学习和无监督学习)&#xff0c;然而在实际应用中经常会遇到训练数据不足的问题。 比如图像分类&#xff0c;作为计算机视觉最基本的任务之一&#xff0…

高效提升控制效率 | 基于ACM32 MCU的LED灯箱控制器方案

LED灯箱上各种文字、图案有序跳跃、交替辉映&#xff0c;产生强烈的视觉冲击力&#xff0c;被广泛应用于商场、美容美发、宾馆、娱乐场所等地方。 锁存器的工作原理 在LED和数码管显示方面&#xff0c;要维持一个数据的显示&#xff0c;往往要持续的快速的刷新。尤其是在四段八…

Python算法100例-3.6 自守数

1.问题描述2.问题分析3.算法设计4.求给定数的位数5.分离给定数中的最后几位6.确定程序框架7.完整的程序 1&#xff0e;问题描述 自守数是指一个数的平方的尾数等于该数自身的自然数。例如&#xff0c; 5 2 25 &#xff0c; 2 5 2 625 &#xff0c; 7 6 2 5776 &#xff0c…

java基础-锁之volatilesynchronized

文章目录 volatilevolatile内存语义volatile的可见性volatile无法保证原子性volatile禁止重排优化硬件层的内存屏障volatile内存语义的实现下面是基于保守策略的JMM内存屏障插入策略。下面是保守策略下&#xff0c;volatile写插入内存屏障后生成的指令序列示意图下图是在保守策…

Android APP性能指标(二)

文章目录 一、响应时间1.1 数据获取1.2 响应时间指标测试点1.3 启动速度测试点1.4 响应时间测试解决方法 二、流量2.1 数据获取2.2 流量测试关注点2.3 测试标准 三、电量3.1 连接手机3.2 数据获取3.3 获取APP的UID3.3 重置电池数据收集数据3.4 电量指标测试 四、温度五、性能测…

打包系统待优化点

Base.Widget.AppCompat.ActivityChooserView中相关资源重复 D:\channelPackage\ToolConfigPath\games\dcpPro\100081\mumu\tempRes\values\attrs.xml:1171: error: duplicate value for resource attr/displayOptions with config . D:\channelPackage\ToolConfigPath\games\d…

【C++精简版回顾】19.异常处理

1.throw抛出问题 int print(int a,int b) {if (b 0)throw b;return a / b; } 2.try与catch解决问题 try {print(2, 0); } catch (int b) {cout << "竟然是&#xff1a;"<<b<<endl; } 结果&#xff1a; 补充1&#xff1a;可以抛出字符串等 1.throw…

day13_微服务监控Nginx(微服务集成SBA)

文章目录 1 微服务系统监控1.1 监控系统的意义1.2 SBA监控方案1.3 SBA实战1.3.1 创建SBA服务端1.3.2 微服务集成SBA 1.4 微服务集成logback1.5 配置邮件告警 2 Nginx2.1 Nginx简介2.2 下载和安装2.2.1 方式1&#xff1a;window本地安装2.2.1.1 下载2.2.1.2 安装2.2.1.3 目录结构…

关于 typeof 与 instanceof 区别引出的原型对象问题

一、关于 typeof 与 instanceof 区别&#xff1a; typeof 和 instanceof 是 JavaScript 中用于检查变量类型的两个不同操作符&#xff0c;它们在使用上有着明显的区别和不同的适用场景。 typeof typeof 是一个一元操作符&#xff0c;用于返回一个变量或表达式的数据类型的字符…

简单认识算法

什么是算法&#xff1f; 解决某个实际问题的过程和方法。 排序算法 1.冒泡排序 打印结果&#xff1a; 2.选择排序 打印结果&#xff1a; 优化选择排序&#xff1a;因为每一轮都需要以当前位置为基准与后面元素比较&#xff0c;太过繁琐&#xff0c;所以可以找到后面元素中较小…

Long使用==

1、背景&#xff1a;测试程序的时候发生了没数据的bug,于是在sevice层的一堆代码中调试&#xff0c;最后发现问题是在stream的filter方法中对两个Long使用造成的问题。 2、测试代码&#xff1a; Long a Long.valueOf(340);Long b Long.valueOf(340);System.out.println(a b)…

指针的学习4

目录 回调函数 qsort使用样例 使用qsort函数排序整形数据 使用qsort函数排序结构体 回调函数 回调函数就是一个通过函数指针调用的函数。如果把函数的指针&#xff08;地址&#xff09;作为参数传递给另一个函数&#xff0c;当这个指针被用来调用其所指向的函数时&#xf…

想打造爆款AI应用?ai虚拟数字人制作助你一臂之力

如今&#xff0c;随着人工智能技术的飞速发展&#xff0c;AI应用已经渗透到我们生活的方方面面。而在这个充满竞争和创新的时代&#xff0c;不少企业都在努力寻找打造爆款AI应用的机会。其中&#xff0c;AI虚拟数字人制作可以为他们提供一臂之力。 AI虚拟数字人制作是指利用人…

六氟化硫SF6气体怎么监测泄漏?

在当今的电力工程领域中,六氟化硫是一种应用广泛的电负性气体,从它发明至今已有百年历史。六氟化硫耐电强度为同一压力下氮气的2.5倍,击穿电压是空气的2.5倍,灭弧能力是空气的100倍,是一种优于空气和油之间的新-代超高压绝缘介质材料。 六氟化硫以其良好的绝缘性能和灭弧性能,在…