-
2021-09-23 12:31:34
STM32 的通用定时器是一个通过可编程预分频器(PSC)驱动的 16 位自动装载计数器(CNT)构成。
STM32 的通用定时器可以被用于:测量输入信号的脉冲长度(输入捕获)或者产生输出波形(输出比较和 PWM)等。
高级定时器:TIME1、TIME8
通用定时器:TIME2~TIME5
基本定时器:TIME6、TIME7
定时器相关的库函数主要集中在固件库文件 stm32f10x_tim.h 和 stm32f10x_tim.c 文件中。
功能 函数 1. TIM3 时钟使能 RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); //时钟使能 2. 初始化定时器参数,设置自动重装值,分频系数,记数方式等 voidTIM_TimeBaseInit(TIM_TypeDef* TIMx, TIM_TimeBaseInitTypeDef* TIM_TimeBaseInitStruct); 3. 设置 TIM3_DIER 允许更新中断 void TIM_ITConfig(TIM_TypeDef* TIMx, uint16_t TIM_IT, FunctionalState NewState); 使能 TIM3 的更新中断 TIM_ITConfig(TIM3,TIM_IT_Update,ENABLE ); 4. TIM3 中断优先级设置 5. 允许 TIM3 工作,也就是使能 TIM3 void TIM_Cmd(TIM_TypeDef* TIMx, FunctionalState NewState) 使能定时器 3 TIM_Cmd(TIM3, ENABLE); //使能 TIMx 外设 6. 编写中断服务函数 ITStatus TIM_GetITStatus(TIM_TypeDef* TIMx, uint16_t) 比如,判断定时器 3 是否发生更新(溢出)中断 if (TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET){} void TIM_ClearITPendingBit(TIM_TypeDef* TIMx, uint16_t TIM_IT) TIM_ClearITPendingBit(TIM3, TIM_IT_Update);
控制寄存器 1(TIMx_CR1)。本实验我们只用到了 TIMx_CR1 的最低位,也就是计数器使能位,该位必须置 1,才能让定时器开始计数。
DMA/中断使能寄存器(TIMx_DIER)。这里我们同样只关心它的第 0 位,该位是更新中断允许位,本章用到的是定时器的更新中断,所以该位要设置为 1,来允许由于更新事件所产生的中断。
预分频寄存器(TIMx_PSC)。该寄存器用设置对时钟进行分频,然后提供给计数器,作为计数器的时钟。
TIMx_CNT 寄存器
自动重装载寄存器(TIMx_ARR)。
状态寄存器(TIMx_SR)。
本章将通过 TIM3 的中断来控制 DS1 的亮灭,DS0 和 DS1 的电路在之前已经介绍过。而 TIM3 属于 STM32 的内部资源,只需要软件设置即可正常工作。
main.c
#include "led.h" #include "delay.h" #include "sys.h" #include "timer.h" int main(void) { delay_init(); // 延时函数初始化 NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); // 设置中断优先级分组2 LED_Init(); // 初始化与LED连接的硬件接口 TIM3_Int_Init(4999,7199); // 10Khz的计数频率,计数到5000为500ms while(1) { LED0=!LED0; delay_ms(200); } }
timer.c
#include "timer.h" #include "led.h" //通用定时器中断初始化 //这里时钟选择为APB1的2倍,而APB1为36M //arr:自动重装值。 //psc:时钟预分频数 //这里使用的是定时器3! void TIM3_Int_Init(u16 arr,u16 psc) { TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; NVIC_InitTypeDef NVIC_InitStructure; RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); // 时钟使能 // 定时器 TIM3 初始化 TIM_TimeBaseStructure.TIM_Prescaler = psc; // 设置用来作为TIMx时钟频率除数的预分频值 10Khz的计数频率 TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; // TIM向上计数模式 TIM_TimeBaseStructure.TIM_Period = arr; // 设置在下一个更新事件装入活动的自动重装载寄存器周期的值 计数到5000为500ms TIM_TimeBaseStructure.TIM_ClockDivision = 0; // 设置时钟分割:TDTS = Tck_tim TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); // 根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位 TIM_ITConfig(TIM3, TIM_IT_Update, ENABLE); // 使能或者失能指定的TIM中断 // 中断优先级 NVIC 设置 NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn; // TIM3中断 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; // 先占优先级0级 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; // 从优先级3级 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; // IRQ通道被使能 NVIC_Init(&NVIC_InitStructure); // 根据NVIC_InitStruct中指定的参数初始化外设NVIC寄存器 TIM_Cmd(TIM3, ENABLE); // 使能TIMx外设 } // 定时器 3 中断服务程序 void TIM3_IRQHandler(void) //TIM3中断 { if (TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET) // 检查指定的TIM中断发生与否:TIM 中断源 { TIM_ClearITPendingBit(TIM3, TIM_IT_Update); // 清除TIMx的中断待处理位:TIM 中断源 LED1=!LED1; } }
timer.h
#ifndef __TIMER_H #define __TIMER_H #include "sys.h" void TIM3_Int_Init(u16 arr,u16 psc); #endif
更多相关内容 -
STM32—中断详解(配合按键中断代码,代码亲测)
2019-07-25 17:35:23(注:本文章所用代码为中断按键代码,实现了按键进入中断从而控制LED亮灭) 配置NVIC_Config()函数 NVIC 是嵌套向量中断控制器,控制着整个芯片中断相关的功能,它跟内核紧密耦合,是内核里面的一个外设。 NVIC_...在STM32中执行中断主要分三部分:
1.配置NVIC_Config()函数
2.配置EXTI_Config()函数
3.编写中断服务函数
(注:本文章所用代码为中断按键代码,实现了按键进入中断从而控制LED亮灭)配置NVIC_Config()函数
NVIC 是嵌套向量中断控制器,控制着整个芯片中断相关的功能,它跟内核紧密耦合,是内核里面的一个外设。
NVIC_Config()函数代码如下:static void NVIC_Config(void) /* 主要是配置中断源的优先级与打开使能中断通道 */ { NVIC_InitTypeDef NVIC_InitStruct ; /* 配置中断优先级分组(设置抢占优先级和子优先级的分配),在函数在misc.c */ NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1) ; /* 配置初始化结构体 在misc.h中 */ /* 配置中断源 在stm32f10x.h中 */ NVIC_InitStruct.NVIC_IRQChannel = KEY1_EXTI_IRQN ; /* 配置抢占优先级 */ NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 1 ; /* 配置子优先级 */ NVIC_InitStruct.NVIC_IRQChannelSubPriority = 0 ; /* 使能中断通道 */ NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE ; /* 调用初始化函数 */ NVIC_Init(&NVIC_InitStruct) ; /* 对key2执行相同操作 */ NVIC_InitStruct.NVIC_IRQChannel = KEY2_EXTI_IRQN ; NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 1 ; NVIC_InitStruct.NVIC_IRQChannelSubPriority = 1 ; NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE ; NVIC_Init(&NVIC_InitStruct) ; }
配置NVIC_Config()的目的是选择中断源的优先级以及打开中断通道,主要功能通过配置NVIC初始化结构体NVIC_InitStruct来完成。通俗的讲,STM32中有很多中断,而当有多个中断同时发生时就涉及到中断执行的先后问题了,所以引入了中断优先级的概念,中断优先级越高中断就越先执行。在这里我们只讨论外部中断的优先级,在 NVIC 有一个专门的寄存器:中断优先级寄存器 NVIC_IPRx,用来配置外部中断的优先级。优先级高低的比较包括抢占优先级和子优先级,先比较抢占优先级,如果抢占优先级相同就比较子优先级,从而得出中断之间的优先级高低。NVIC的主要任务就是给对应的中断源分配中断优先级。 中断优先级分配的原理繁杂,但固件库编程的好处就是化繁为简,我们只需要按照NVIC_InitStruct()中的内容进行配置就行。
接下来简单讲解一下NVIC_Config()函数的内容:
1.首先设置中断优先级分组
中断优先级分组其实是确立一个大纲,中断优先级寄存器 NVIC_IPRx中有4个位用来确定优先级,中断优先级的分组就是把这4个位分配在抢占优先级和子优先级中。比如设定一个位配置抢占优先级,其余三个位配置子优先级。通过函数NVIC_PriorityGroupConfig() ; 实现分组,详细代码如下:1 /** 2 * 配置中断优先级分组:抢占优先级和子优先级 3 * 形参如下: 4 * @arg NVIC_PriorityGroup_0: 0bit for 抢占优先级 5 * 4 bits for 子优先级 6 * @arg NVIC_PriorityGroup_1: 1 bit for 抢占优先级 7 * 3 bits for 子优先级 8 * @arg NVIC_PriorityGroup_2: 2 bit for 9 * 2 bits for 子优先级 10 * @arg NVIC_PriorityGroup_3: 3 bit for 抢占优先级 11 * 1 bits for 子优先级 12 * @arg NVIC_PriorityGroup_4: 4 bit for 抢占优先级 13 * 0 bits for 子优先级 14 * @注意 如果优先级分组为 0,则抢占优先级就不存在,优先级就全部由子优先级控制 15 */ 16 void NVIC_PriorityGroupConfig(uint32_t NVIC_PriorityGroup) 17 { 18 // 设置优先级分组 19 SCB->AIRCR = AIRCR_VECTKEY_MASK | NVIC_PriorityGroup; 20 }
2.优先级分组完毕后,是配置NVIC初始化结构体
typedef struct { 2 uint8_t NVIC_IRQChannel; // 中断源 3 uint8_t NVIC_IRQChannelPreemptionPriority; // 抢占优先级 4 uint8_t NVIC_IRQChannelSubPriority; // 子优先级 5 FunctionalState NVIC_IRQChannelCmd; // 中断使能或者失能 6 } NVIC_InitTypeDef;
初始化结构体的作用是,收集中断源的信息(包括配置的是哪一个中断源、中断源的抢占优先级是多少、中断源的子优先级是多少、中断源的使能是否开启)。
NVIC_IROChannel:用来设置中断源,不同的中断中断源不一样,且不可写错,即使写错了程序也不会报错,只会导致不响应中断。 stm32f10x.h 头文件里面的 IRQn_Type 结构体定义,这个结构体包含了所有的中断源。
NVIC_IRQChannelPreemptionPriority和NVIC_IRQChannelSubPriority 分别设置抢占优先级和子优先级,具体的值要根据中断优先级分组来确定。
NVIC_IRQChannelCmd:设置中断使能(ENABLE)或者失能(DISABLE),相当于一个电源总开关。
3.最后借助NVIC初始化函数将NVIC初始化结构体中的信息写入相应的寄存器中 (体现了固件库编程的优点,不需要我们深入到寄存器层次去,只需要掌握相应函数的配置即可)配置EXTI_Config()函数
EXTI(External interrupt/event controller):外部中断/事件控制器,管理了控制器的 20个中断/事件线。每个中断/事件线都对应有一个边沿检测器,可以实现输入信号的上升沿检测和下降沿的检测。 EXTI 可以实现对每个中断/事件线进行单独配置,可以单独配置为中断或者事件,以及触发事件的属性。
按我的理解,EXTI是一个有着多达20个接口的控制器,它可以为每一个接入接口的信号源配置中断(或事件)线、设置信号的检测方式、设置触发事件的性质,也就是说,传入EXTI的仅仅是一个信号,EXTI的功能就是根据信号传入的“线”对信号做出相应的处理,然后将处理后的信号转向NVIC。 就像一个分拣机器,传入的东西经过筛选处理被送往不同的地方,只是EXTI分拣的是信号罢了。 如果说NVIC是配置中断源,那么EXTI就是向NVIC传送中断信号。EXTI功能框图:
EXTI 可分为两大部分功能,一个是产生中断,另一个是产生事件,线路1-2-4-5是产生中断的流程,20/代表着有20条相同的线路。
接下来讲解一下EXTI_Config()函数代码:
void EXTI_Config() /* 主要是连接EXTI与GPIO */ { GPIO_InitTypeDef GPIO_InitStruct ; EXTI_InitTypeDef EXTI_InitStruct ; NVIC_Config(); /* 初始化要与EXTI连接的GPIO */ /* 开启GPIOA与GPIOC的时钟 */ RCC_APB2PeriphClockCmd(KEY1_EXTI_GPIO_CLK | KEY2_EXTI_GPIO_CLK, ENABLE) ; GPIO_InitStruct.GPIO_Pin = KEY1_EXTI_GPIO_PIN ; GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING ; GPIO_Init(KEY1_EXTI_GPIO_PORT , &GPIO_InitStruct) ; GPIO_InitStruct.GPIO_Pin = KEY2_EXTI_GPIO_PIN ; GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING ; GPIO_Init(KEY2_EXTI_GPIO_PORT , &GPIO_InitStruct) ; /* 初始化EXTI外设 */ /* EXTI的时钟要设置AFIO寄存器 */ RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE) ; /* 选择作为EXTI线的GPIO引脚 */ GPIO_EXTILineConfig( KEY1_GPIO_PORTSOURCE , KEY1_GPIO_PINSOURCE) ; /* 配置中断or事件线 */ EXTI_InitStruct.EXTI_Line = KEY1_EXTI_LINE ; /* 使能EXTI线 */ EXTI_InitStruct.EXTI_LineCmd = ENABLE ; /* 配置模式:中断or事件 */ EXTI_InitStruct.EXTI_Mode = EXTI_Mode_Interrupt ; /* 配置边沿触发 上升or下降 */ EXTI_InitStruct.EXTI_Trigger = EXTI_Trigger_Rising ; EXTI_Init(&EXTI_InitStruct) ; GPIO_EXTILineConfig( KEY2_GPIO_PORTSOURCE , KEY2_GPIO_PINSOURCE) ; EXTI_InitStruct.EXTI_Line = KEY2_EXTI_LINE ; EXTI_InitStruct.EXTI_LineCmd = ENABLE ; EXTI_InitStruct.EXTI_Mode = EXTI_Mode_Interrupt ; EXTI_InitStruct.EXTI_Trigger = EXTI_Trigger_Falling ; EXTI_Init(&EXTI_InitStruct); }
代码可大体分为三部分:
配置GPIO相应引脚、配置EXTI并连接GPIO引脚、传入NVIC_Config()
1.配置GPIO相应引脚
该代码是通过按键产生一个电平信号,然后经EXTI处理传入NVIC产生中断的,所以要配置连接按键的GPIO引脚,主要是设置相应的引脚模式为浮空输入 。老规矩,先开启相应GPIO的时钟,然后配置引脚初始化结构体,再利用初始化函数将初始化结构体写入寄存器中。
2.配置EXTI并连接GPIO引脚
要操作外设,首先要打开相关的时钟,EXTI挂载在APB2总线上,并且开启时钟时要操作AFIO寄存器 ,准备工作就绪后连接GPIO相应的引脚到EXTI中,前面说了EXTI有20个接口,所以特定的引脚有特定的接口,所以要根据GPIO_EXTILineConfig();函数选择用作EXTI线的GPIO引脚,函数说明如下/** * @brief Selects the GPIO pin used as EXTI Line. * @param GPIO_PortSource: selects the GPIO port to be used as source for EXTI lines. * This parameter can be GPIO_PortSourceGPIOx where x can be (A..G). * @param GPIO_PinSource: specifies the EXTI line to be configured. * This parameter can be GPIO_PinSourcex where x can be (0..15). * @retval None */ void GPIO_EXTILineConfig(uint8_t GPIO_PortSource, uint8_t GPIO_PinSource) { uint32_t tmp = 0x00; /* Check the parameters */ assert_param(IS_GPIO_EXTI_PORT_SOURCE(GPIO_PortSource)); assert_param(IS_GPIO_PIN_SOURCE(GPIO_PinSource)); tmp = ((uint32_t)0x0F) << (0x04 * (GPIO_PinSource & (uint8_t)0x03)); AFIO->EXTICR[GPIO_PinSource >> 0x02] &= ~tmp; AFIO->EXTICR[GPIO_PinSource >> 0x02] |= (((uint32_t)GPIO_PortSource) << (0x04 * (GPIO_PinSource & (uint8_t)0x03))); }
其实对应的EXTI线就对应GPIO引脚号,这样看起来还比较直观。
连接好GPIO引脚与EXTI后就该配置EXTI的初始化结构体了,结构体如下:typedef struct { uint32_t EXTI_Line; // 中断/事件线 EXTIMode_TypeDef EXTI_Mode; // EXTI 模式 EXTITrigger_TypeDef EXTI_Trigger; // 触发类型 FunctionalState EXTI_LineCmd; // EXTI 使能 } EXTI_InitTypeDef;
配置此结构体主要是:选择相应的EXTI线 、选择触发模式、选择产生的结果(中断还是事件)、是否使能EXTI线。
EXTI_Line:中断线选择,可选 EXTI_0 至 EXTI_19(一共20个)。既然刚才配置好了与GPIO引脚对应的EXTI线,所以初始化结构体中的EXTI线就是与GPIO连接的那个线。
EXTI_Mode: EXTI 模式选择,可选为产生中断或者产生事件。就是决定信号的发展方向,是产生中断呢?还是产生事件呢?此处是中断。
EXTI_Trigger: EXTI 边沿触发模式,可选上升沿触发、下降 沿 触 发 或 者 上 升 沿 和 下 降 沿 都 触 发。触发信号。
EXTI_LineCmd:控制是否使能 EXTI 线,可选使能 EXTI 线或禁用。
初始化结构体配置完毕后交由初始化函数写入相应的寄存器中。
3.传入NVIC_Config()
之后就自动传入NVIC中了。。。编写中断服务函数
到这里就万事俱备只欠东风了,中断的触发与处理及优先级定义都已经安排上了,最后一步就是编写中断函数的内容了,只要进入中断就会执行中断函数中的代码,所以这是收尾工作。STM32的中断服务函数不同于51单片机中的中断服务函数,STM32的所有中断函数都被偷偷安排了,每个中断都有其固定的名字,只有找到这个名字,在这个固定的函数名下编写中断服务函数才是有效的,所有中断函数的编写都要在stm32f10x_it.c 中,如示:
从所给的信息可得知外设的中断服务函数的名字都存放在startup_stm32f10x_xx.s 中,而且是由汇编语言编写,如示:
可知EXTI线0到EXTI线4线都是单独的中断函数名、EXTI线5到EXTI线9共用一个中断函数名、EXTI线10线到EXTI线15线共用一个中断函数名。
我们要做的就是以相应的EXTI线的中断函数名字在stm32f10x_it.c中编写中断函数 如下:void EXTI0_IRQHandler(void) { if( EXTI_GetITStatus(KEY1_EXTI_LINE)!=RESET) { LED1_TOGGLE; //LED1的亮灭状态反转 } EXTI_ClearITPendingBit(KEY1_EXTI_LINE); } void EXTI15_10_IRQHandler(void) { if( EXTI_GetITStatus(KEY2_EXTI_LINE)!=RESET) { LED2_TOGGLE; //LED2的亮灭状态反转 } EXTI_ClearITPendingBit(KEY2_EXTI_LINE); }
每次进入中断函数后,靠ITStatus EXTI_GetITStatus(uint32_t EXTI_Line)读取中断是否执行 ,执行完之后要利用void EXTI_ClearITPendingBit(uint32_t EXTI_Line)清除清除中断标志位,以免不断进入中断
大功告成
到此完整的中断系统就已经完成,主函数只需调用即可!!!
(附上主函数及俩个头文件)
希望可以一起交流学习
qq:2723808286#include "stm32f10x.h" #include "bsp_led.h" #include "bsp_key.h" int main(void) { LED_GPIO_Config(); EXTI_Config(); while(1) { } }
#ifndef __BSP_KEY_H #define __BSP_KEY_H #include "stm32f10x.h" #define KEY1_EXTI_GPIO_CLK RCC_APB2Periph_GPIOA #define KEY1_EXTI_GPIO_PORT GPIOA #define KEY1_EXTI_GPIO_PIN GPIO_Pin_0 #define KEY1_EXTI_IRQN EXTI0_IRQn /* 对应着引脚号 */ #define KEY1_EXTI_LINE EXTI_Line0 /* 中断、事件线对应引脚号 */ #define KEY1_GPIO_PORTSOURCE GPIO_PortSourceGPIOA #define KEY1_GPIO_PINSOURCE GPIO_PinSource0 #define KEY1_EXTI_IRQHANDLER EXTI0_IRQHandler #define KEY2_EXTI_GPIO_CLK RCC_APB2Periph_GPIOC #define KEY2_EXTI_GPIO_PORT GPIOC #define KEY2_EXTI_GPIO_PIN GPIO_Pin_13 #define KEY2_EXTI_IRQN EXTI15_10_IRQn #define KEY2_EXTI_LINE EXTI_Line13 #define KEY2_GPIO_PORTSOURCE GPIO_PortSourceGPIOC #define KEY2_GPIO_PINSOURCE GPIO_PinSource13 #define KEY2_EXTI_IRQHANDLER EXTI15_10_IRQHandler void EXTI_Config(void); #endif
#ifndef __BSP_LED_H #define __BSP_LED_H #include "stm32f10x.h" #define LED1_GPIO_CLK RCC_APB2Periph_GPIOC /*时钟*/ #define LED1_GPIO_PORT GPIOC /*端口*/ #define LED1_GPIO_PIN GPIO_Pin_2 /*引脚*/ #define LED2_GPIO_PIN GPIO_Pin_3 #define LED2_GPIO_CLK RCC_APB2Periph_GPIOC #define LED2_GPIO_PORT GPIOC #define digitalTOGGLE(p,i) {p->ODR ^=i;} #define LED1_TOGGLE digitalTOGGLE(LED1_GPIO_PORT,LED1_GPIO_PIN) #define LED2_TOGGLE digitalTOGGLE(LED2_GPIO_PORT,LED2_GPIO_PIN) /* LED状态反转 */ void LED_GPIO_Config(void); #endif
-
51单片机按键中断
2018-04-28 01:39:3251单片机按键中断代码,初始化:边沿触发方式下降沿,打开总的中断。 -
STM8L外部中断代码
2012-03-28 09:02:45下降沿低电平触发STM8外部中断,进入中断后点亮小灯。 -
STM8l串口中断代码
2012-03-28 09:08:48若有字符接收单片机会产生接收中断,在中断中读取字符再发送出去。 -
stm32 EXIT外部中断及代码应用
2022-01-24 15:28:05先来了解一些基本概念 RCC外设,即复位和时钟控制的英文缩写,负责芯片的复位和时钟控制。 复位方式: 系统复位...//电平反转 } } 参考代码: 链接:https://pan.baidu.com/s/1r3j_jL4I6KkO5-Ek4VhMmw 提取码:ox4d先来了解一些基本概念
RCC外设,即复位和时钟控制的英文缩写,负责芯片的复位和时钟控制。
复位方式:
系统复位:系统复位将复位除时钟控制寄存器CSR中的复位标志和备份区域中的寄存器以外的所有寄存器为它们的复位数值。
电源复位:电源复位将复位除了备份区域外的所有寄存器。
后备域复位:备份区域拥有两个专门的复位,它们只影响备份区域。
当以下事件中的一件发生时,产生一个系统复位:
1. NRST引脚上的低电平(外部复位)
2.窗口看门狗计数终止(WDG复位) 3.独立看门狗计数终止(IWDG复位) 4.软件复位(SW复位)
5.低功耗管理复位例,如图所示当按键按下时启动系统复位
时钟:
时钟可以简单地理解为“心跳”,通常说的72Mhz,480Mhz就是stm32芯片的主时钟频率,芯片依据这些频率来达到各种器件同步的工作
三种不同的时钟源可被用来驱动系统时钟(SYSCLK):
-HSI振荡器时钟(高速内部时钟) --HSE振荡器时钟(高速外部时钟) -PLL时钟(锁相环倍频时钟,可认为是由其他时钟发展而来)
频率越高,器件性能及工作速度也越快,相应的功耗也会增大,要根据芯片运行的工作条件来选择频率。
中断:中断是指计算机运行过程中,出现某些意外情况需主机干预时,机器能自动停止正在运行的程序并转入处理新情况的程序,处理完毕后又返回原被暂停的程序继续运行。ARM Cortex M3内核支持256个中断,包括16个内核中断和240个外设中断,拥有256个中断优先级别。
中断的优先级:中断的优先级分别两种:可编程、不可编程。
对于STM32的中断优先级,决定着内核优先相应谁的中断请求。
小值优先原则,中断优先级数值越小,中断会被优先响应。
中断优先级按照优先级分组配置。如图所示,Reset、NMI及硬件失效中断的优先级是固定的不能改变,而‘存储管理’优先级是可以改变的
中断的优先级分组
以F103为例,STM32上只使用了M3内核支持的8bit优先级中的高4位bit。也就是说STM32支持2^4个优先级。在F103上,使用这个4个bit,组织成五组优先级分组。这五组中,每组分为l个抢占组、1个子优先级组。组织形式如下。
通过优先级分组,可以管理中断的响应顺序。
只有抢占优先级才有抢占中断权限,发生中断嵌套。
那按怎样的顺序发生中断呢? 抢占优先级高的先执行,如果中断抢占优先级相同,不发生抢占行为。
如果多个挂起的中断具有相同的抢占优先级,则子优先级高的先行(数值越小优先级越高),如果子优先级相同,则IRQ编号小的先行。可编程的优先级,通过嵌套向量中断控制器(NVIC)实现。 其中,IRQ编号可在芯片对应头文件里找到。总的来说就是:抢占优先级>子优先级>IRQ编号
EXTI--扩展中断和事件控制器
STM32上有许多外设,是通过内部信号来协同工作的,这个信号可理解为事件,比如定时器定时完成的“计数完成事件”。根据寄存器中是否可以查到事件的标志将事件分为可见和不可见,一般通过中断来捕获事件
EXTI是STM32上的一个外设。它可以捕获外部输入线电平变化等等的一些事件。EXTI捕获到了事件后,还可以生成相应的EXTI中断及等等的一些中断。
所以EXTI外设可以大致概括为两个功能: -捕获外部输入等事件。
-生成EXTI中断等中断请求。
EXTI外设框图线路①,当有外部输入时唤醒MCU,如按手机开关键屏幕亮起; 线路②,当有中断请求而且没有被屏蔽的情况下产生中断。
EXTI主要特性如下:
每个中断/事件都有独立的触发和屏蔽 每个中断线都有专用的状态位
支持多达20个软件的中断/事件请求
检测脉冲宽度低于APB2时钟宽度的外部信号。外部中断/事件线路映像
112通用IO端口以下图的方式连接到16个外部中断/事件线上:基于STM32CubeMX的外部中断设计步骤:
【1】在STM32CubeMX中指定引脚,配置中断初始化参数。 【2】重写该IO引脚对应的中断回调函数。
例:简单实现按下按键3即PC2为外部中断输入,实现LED3反转电平,按下按键4即PC3为外部中断输入,实现LED4反转电平。Cube MX的配置如下
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) { if(GPIO_Pin==GPIO_PIN_2)//按键3触发中断 { LED3_TOG;//电平反转(定义的宏定义) } if(GPIO_Pin==GPIO_PIN_3)//按键4触发中断 { LED4_TOG;//电平反转 } }
参考代码:
链接:https://pan.baidu.com/s/1r3j_jL4I6KkO5-Ek4VhMmw
提取码:ox4d -
哈工大计算机组成原理简单中断的实现代码
2016-05-05 17:50:28哈工大计算机组成原理简单中断的实现代码 -
STM32 外部中断触发定时器 详细代码(编译通过)
2011-12-31 11:02:18该资源为本人自己研究出来 可能对于有些人都会使用 但改代码编写正式 注释详细 且已编译通过 运行正常 有利于初学者和有疑问者参考学习STM32的外部中断和定时器的使用 可以直接拿过来使用 采用开发板为 STM32F103C8 ... -
STM32 外部中断详解(原理+配置代码)
2020-02-27 22:24:38本文介绍了STM32基于标准外设库的外部中断配置,以及基于参考手册如何更加寄存器配置外部中断本文介绍了STM32基于标准外设库的外部中断配置,以及基于参考手册如何更加寄存器配置外部中断
1 前言
打算写一下中断,又忍不住想说一下中断的概念,去书上翻一翻,或者自己在搜索引擎上搜一下,都可以找到一大堆,包括本文写的这个外部中断也不例外。如果要写光是中断就可以单独写一篇了,所以本文直入主题,对于STM32的外部中断进行详细的剖析。
2 STM32的外部中断
下图来自《STM32参考手册》,从整个架构图可以知道,外部中断的功能可以配置六个寄存器;
- 中断屏蔽寄存器(EXTI_IMR)
- 事件屏蔽寄存器(EXTI_EMR)
- 上升沿触发选择寄存器(EXTI_RTSR)
- 下降沿触发选择寄存器(EXTI_FTSR)
- 软件中断事件寄存器(EXTI_SWIER)
- 挂起寄存器(EXTI_PR)
EXTI支持配置20个中断和事件屏蔽位; - GPIO端口以下图的方式连接到16个外部中断/事件线上;
EXTI_Line0
—EXTI_Line15
; - EXTI_Line16 连接到PVD输出 ;
- EXTI_Line17连接到RTC闹钟事件;
- EXTI_Line18连接到USB唤醒事件;
- EXTI_Line19连接到以太网唤醒事件(只适用于互联型产品);
GPIO的映射关系图如下所示;
3 中断服务函数的映射关系
GPIO IRQn IRQHandler GPIO_Pin0 EXTI0_IRQn EXTI0_IRQHandler GPIO_Pin1 EXTI1_IRQn EXTI1_IRQHandler GPIO_Pin2 EXTI2_IRQn EXTI2_IRQHandler GPIO_Pin3 EXTI3_IRQn EXTI3_IRQHandler GPIO_Pin4 EXTI4_IRQn EXTI4_IRQHandler GPIO_Pin5 — GPIO_Pin9 EXTI9_5_IRQn EXTI9_5_IRQHandler GPIO_Pin10 — GPIO_Pin15 EXTI15_10_IRQn EXTI15_10_IRQHandler 4 外部中断的配置
宏定义,抽象一下接口,方便后面修改;
#define Z_GPIO_PIN GPIO_Pin_5 #define Z_GPIO_PORT GPIOE #define Z_PortSource GPIO_PortSourceGPIOE #define Z_PinSource GPIO_PinSource5 #define Z_Line EXTI_Line5 #define Z_IRQ EXTI9_5_IRQn
GPIO的配置;这里GPIO的输入模式可以配置为浮空输入(
GPIO_Mode_IN_FLOATING
),上拉输入(GPIO_Mode_IPU
)或者下拉输入(GPIO_Mode_IPD
),具体如下图所示;
GPIO的配置代码如下;
GPIO_InitTypeDef GPIO_InitStructure; GPIO_StructInit(&GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin = Z_GPIO_PIN; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(Z_GPIO_PORT, &GPIO_InitStructure);
不要忘记外设总线时钟的配置;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOC | RCC_APB2Periph_GPIOD | RCC_APB2Periph_GPIOE | RCC_APB2Periph_GPIOF | RCC_APB2Periph_GPIOG, ENABLE);
EXTI的配置,EXTI_Trigger这里支持三种模式;
- EXTI_Trigger_Rising 上升沿触发;
- EXTI_Trigger_Falling 下降沿触发;
- EXTI_Trigger_Rising_Falling 上升沿和下降沿都可以触发;
GPIO_EXTILineConfig(Z_PortSource, Z_PinSource); EXTI_InitStructure.EXTI_Line = Z_Line; EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling; //下降沿 EXTI_InitStructure.EXTI_LineCmd = ENABLE; EXTI_Init(&EXTI_InitStructure);
NVIC的配置
NVIC_InitStructure.NVIC_IRQChannel = Z_IRQ; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure);
中断服务函数
void EXTI9_5_IRQHandler(void) { //中断服务函数 }
以上就完成了检测下降沿信号的
GPIOE5
的外部中断;
也参考官方DEMO
,
STM32F10x_StdPeriph_Lib_V3.5.0\Project\STM32F10x_StdPeriph_Examples\EXTI\EXTI_Config。5 寄存器的操作
以下摘自**《STM32参考手册》**
产生产生中断的步骤,必须先配置好并使能中断线。根据需要的边沿检测设置2个触发寄存器,同时在**中断屏蔽寄存器(EXTI_IMR)的相应位写1
允许中断请求。当外部中断线上发生了期待的边沿时,将产生一个中断请求,对应的挂起位也随之被置1
。在挂起寄存器(EXTI_PR)的对应位写1
,将清除该中断请求。
产生事件的步骤:必须先配置好并使能事件线。根据需要的边沿检测通过设置2个触发寄存器,同时在中断屏蔽寄存器(EXTI_IMR)**的相应位写1
允许事件请求。当事件线上发生了需要的边沿时,将产生一个事件请求脉冲,对应的挂起位不被置1
。通过在软件中断/事件寄存器写1
,也可以通过软件产生中断/事件请求。- 中断屏蔽寄存器(EXTI_IMR)
- 事件屏蔽寄存器(EXTI_EMR)
- 上升沿触发选择寄存器(EXTI_RTSR)
- 下降沿触发选择寄存器(EXTI_FTSR)
- 软件中断事件寄存器(EXTI_SWIER)
- 挂起寄存器(EXTI_PR)
IMR如下图所示,其他几个类似;
5.1 硬件中断选择
通过下面的过程来配置20个线路做为中断源:
- 配置20个中断线的屏蔽位(EXTI_IMR)
- 配置所选中断线的触发选择位(EXTI_RTSR和EXTI_FTSR);
- 配置对应到外部中断控制器(EXTI)的NVIC中断通道的使能和屏蔽位,使得20个中断线中的请求可以被正确地响应。
5.2 硬件事件选择
通过下面的过程,可以配置20个线路为事件源
- 配置20个事件线的屏蔽位(EXTI_EMR)
- 配置事件线的触发选择位(EXTI_RTSR和EXTI_FTSR)
5.3 软件中断/事件的选择
20个线路可以被配置成软件中断/事件线。下面是产生软件中断的过程:
- 配置20个中断/事件线屏蔽位(EXTI_IMR, EXTI_EMR)
- 设置软件中断寄存器的请求位(EXTI_SWIER)
6 总结
本文参考stm32手册对于外部中断的概念以及配置进行了介绍,本人能力有限,难免存在错误和纰漏,请大佬不吝赐教。
-
STC89C52单片机定时器及中断系统的介绍以及代码示例
2022-01-26 11:21:36九,定时器时钟代码演示 一,定时器介绍 定时器介绍: 51单片机的定时器属于单片机的内部资源,其电路的连接和运转均在单片机内部完成 定时器作用: (1)用于计时系统,可实现软件计时,或者使程序每隔一固定... -
stm32 usart空闲中断代码(hal库)
2020-03-11 11:45:43 -
中断控制器Verilog源代码
2015-10-29 10:26:05Intc的verilog源代码,用于接收中断源的中断信号,并判断优先级,依次发给CPU,CPU通过查状态寄存器IFSR确定需要服务的中断源,从而按优先级执行中断服务程序。 -
mini2440 定时器中断实验源代码
2012-08-09 17:29:25是能在友善之臂的mini2440板子上运行的定时器中断代码。定时器没0.5秒产生一次中断,控制led1的亮灭。可以结合韦东山的《嵌入式Linux应用开发完全手册》第十章来理解。 -
MSP430-GRACE 实战(二):按键中断
2021-12-23 21:03:13MSP430-GRACE 实战(二):按键中断 -
单片机中断原理——以外部中断为例,代码详写,你“一看就懂”
2020-02-01 17:09:31中断系统原理 何为中断,何为中断系统 举个例子: 生活中常见的例子,一个正在写寒假作业的孩子突然听到一阵敲门声,原来是父母下班回来了,孩子说:“等会,我来了”。于是,他记住当下页码放下作业去开门,然后... -
STM32CubeMX生成代码学习笔记(一)中断优先级配置后没有生成相关代码问题
2021-01-07 17:06:42STM32CubeMX生成代码学习笔记(一)中断优先级配置后没有生成相关代码问题 在CubeMX中配置中断优先级后查看代码会发现似乎设置的优先级并没有生成相关代码,只在初始化中有一个默认组4优先级设置。如下图 生成代码后... -
DSP2812 XINT外部中断完整工程代码
2018-10-16 16:29:53DSP2812 XINT外部中断完整工程代码 XINT外部中断 完美实现 -
串口收发数据-中断-C语言代码.rar
2012-06-30 16:07:47串口收发数据-中断方式-C语言代码,代码简单,有注释,方便理解 -
嵌入式中断:统计各中断关键信息 (中断执行/挂起/被打断次数,中断优先级异常等)
2021-08-05 10:57:35嵌入式中断:统计各中断关键信息 ,中断执行/挂起/被打断次数,中断优先级异常等 先上图 实现方法: 实现代码: 数据结构 初始化 获取中断寄存器数据:ICSR 获取中断寄存器数据:IABR 换算中断抢占数据 打印/存储... -
linux arm64 中断处理流程完整分析 (二)—— 中断处理流程c代码部分 以gic_v3 为例
2022-03-06 11:16:01本文以gic 为例,探索中断中断控制器的注册过程,以及相关中断处理流程。 GIC V3 结构 详细可以参考这个页面。这里只做简单介绍。 /*drivers/irqchip/irq-gic-v3.c*/ IRQCHIP_DECLARE(gic_v3, "arm,gic-v3", gic_of... -
单片机课设-中断程序(仿真图,代码全)
2021-06-02 09:05:54proteus单片机中断程序 利用单片机的P0口做输出接8只发光二极管,P3.2引脚接独立按键产生外部中断信号。编写程序,当程序正常运行时8个发光二极管做流水灯显示,当外部中断0有中断请求信号时,8只发光二极管全部点亮... -
韦东山:在Linux设备树(DTS)中指定中断_在代码中获得中断
2020-04-08 18:22:023.在代码中获得中断 参考: 内核Documentation\devicetree\bindings\interrupt-controller\interrupts.txt 1.设备树里中断节点的语法 1.1 设备树里的中断控制器 中断的硬件框图如下: 在硬件上,“中断控制器”只有... -
230-外部中断1(51单片机C语言实例Proteus仿真和代码)
2022-06-16 06:15:35230-外部中断1(51单片机C语言实例Proteus仿真和代码)230-外部中断1(51单片机C语言实例Proteus仿真和代码)230-外部中断1(51单片机C语言实例Proteus仿真和代码)230-外部中断1(51单片机C语言实例Proteus仿真和代码)230-... -
51单片机系列--定时器中断
2021-07-17 23:28:16//打开总中断 } /******************************************************************************* * 函 数 名 : main * 函数功能 : 主函数 * 输 入 : 无 * 输 出 : 无 ****************************************... -
319-用外中断0的中断方式进行数据采集(51单片机C语言实例Proteus仿真和代码)
2022-06-16 19:16:55319-用外中断0的中断方式进行数据采集(51单片机C语言实例Proteus仿真和代码)319-用外中断0的中断方式进行数据采集(51单片机C语言实例Proteus仿真和代码)319-用外中断0的中断方式进行数据采集(51单片机C语言实例... -
171-外部中断的使用(51单片机C语言实例Proteus仿真和代码)
2022-06-16 05:41:26171-外部中断的使用(51单片机C语言实例Proteus仿真和代码)171-外部中断的使用(51单片机C语言实例Proteus仿真和代码)171-外部中断的使用(51单片机C语言实例Proteus仿真和代码)171-外部中断的使用(51单片机C语言实例... -
ESP8266定时器篇源代码
2016-01-08 10:18:22ESP8266定时器篇源代码是一个简单的程序。是果云教内的源代码,使用说明可安信可论坛去看。 -
64-矩阵键盘中断扫描(51单片机C语言实例Proteus仿真和代码)
2022-06-15 06:47:4264-矩阵键盘中断扫描(51单片机C语言实例Proteus仿真和代码)64-矩阵键盘中断扫描(51单片机C语言实例Proteus仿真和代码)64-矩阵键盘中断扫描(51单片机C语言实例Proteus仿真和代码)64-矩阵键盘中断扫描(51单片机C语言... -
172-定时器和外部中断(51单片机C语言实例Proteus仿真和代码)
2022-06-16 05:41:56172-定时器和外部中断(51单片机C语言实例Proteus仿真和代码)172-定时器和外部中断(51单片机C语言实例Proteus仿真和代码)172-定时器和外部中断(51单片机C语言实例Proteus仿真和代码)172-定时器和外部中断(51单片机... -
114-串口通讯中断应用(51单片机C语言实例Proteus仿真和代码)
2022-06-15 07:14:19114-串口通讯中断应用(51单片机C语言实例Proteus仿真和代码)114-串口通讯中断应用(51单片机C语言实例Proteus仿真和代码)114-串口通讯中断应用(51单片机C语言实例Proteus仿真和代码)114-串口通讯中断应用(51单片机...