完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
|
|
相关推荐
1个回答
|
|
中断的概念: 中断是当单片机的CPU在执行程序时,外部或内部发生了一个随机事件,导致CPU暂时中断正在执行的程序,转去执行一段特殊的服务程序也就是中断服务子程序或中断处理程序。当处理完服务程序后,返回到被中断的程序继续执行,这样的一个过程就被称为中断,引发这个中断的事件被称为中断源。中断在stm32中还被分为相应的优先级,低优先级的中断会被高优先级中断所中断,即为中断的嵌套。在Crotex-M3内核中支持256个中断,其中包含16个内核中断以及240个外部中断。STM32F10X芯片中只用了其中的84个中断通道,包含16个内核中断和68个可屏蔽中断。
中断的优先级: STM32的每个中断通道都有一个中断优先级控制字节(8位二进制数据,可设置为0~255,数值越小,优先级越高。在STM32F103中只用其中高4位数据),其用于表达优先级的高4位又被分为抢占式优先级和响应式优先级。在抢占式优先级相同情况下,高响应优先级的中断优先被响应。优先级相同时,按照中断响应的顺序执行服务程序,越靠前的先执行。中断的相关功能需要通过NVIC(嵌套向量中断器)来配置。 中断的配置: 首先使能某个外设中断;然后设置中断优先级分组,初始化NVIC_InitTypeDef结构体,设置抢占优先级和响应优先级,使能中断请求;最后编写中断服务函数。 1、外部中断编程 1.1 EXTI的结构 在STM32F10X芯片中外部中断/事件控制器(EXTI)有20个用于产生中断/事件请求的边沿检测器,其对应的每一根输入线都可以单独进行配置,选择“中断”或“事件”类型以及触发事件(上升沿触发、边沿触发和下降沿触发),还可以对中断开启屏蔽。外部中断/事件控制器(EXTI)的结构如下图中所示: EXTI主要有两个功能,一个用来产生中断,另一个被用来产生事件。 (1)产生中断的线路由输入线开始,经边沿检测电路,到一个或门电路再到一个与门电路,最后至NVIC中断控制器结束。输入线可以通过寄存器设置为任何一个GPIO引脚,也可以是外设的时间,在这部分主要是传递一个电平变化的信号;边沿检测电路可以对触发方式进行选择,有上升沿触发、下降沿触发以及边沿触发三种方式;或门电路使得中断不仅可以由外部电路进行触发也可以通过软件来启动中断/事件;与门电路用来决定是否产生中断,只有中断屏蔽寄存器端和或门电路端的有效信号均为1时,中断才会被产生;最后将挂起寄存器内容输入到NVIC中,实现系统中断事件的控制。 (2)产生事件的前三步与(1)相同,后经过一个与门电路,再经过一个脉冲发生器电路后结束。其中与门电路是用来决定是否产生事件,只有事件屏蔽寄存器端和或门电路端的有效信号均为1时,事件才会被产生;脉冲发生器电路只有在与门电路为有效信号1时才会输出一个脉冲信号;脉冲信号可被用于其他外设电路的使用,如定时器、ADC等等。 从EXTI框图中可以看出,中断的输出是NVIC控制器,从而会导致系统运行中断服务函数,处于软件层面;时间的输出是脉冲信号流向其他外设电路,处于硬件层面。 1.2 外部中断/事件线 映射 STM32F10X的EXTI对用连接的外设如下表中所示: [tr]EXTI线路说明[/tr]
1.3 外部中断/事件线 映射 EXTI相关的库函数在stm32f10x_exti.c和stm32f10x_exti.h文件中,使用库函数对外部中断进行配置的步骤如下: 使能IO口时钟,配置IO模式为输入; 开启AFIO时钟,设置IO口与中断线的映射关系; 首先需要使能AFIO时钟,其是挂载在APB2总线上的; RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE); 然后将GPIO映射到对应的中断线上; GPIO_EXTILineConfig(GPIO_PortSourceGPIOx, GPIO_PinSourceY]);//Y是0~15号中断线 配置中断分组(NVIC),使能中断; NVIC_InitTypeDef NVIC_InitStructure; NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn; //EXTI0 中断通道 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=2; //抢占优先级 NVIC_InitStructure.NVIC_IRQChannelSubPriority =3; //子优先级 NVIC_Init(&NVIC_InitStructure); 初始化EXTI,选择触发方式; 配置好NVIC后就需要对中断线上的中断进行初始化,需要调用void EXTI_Init(EXTI_InitTypeDef* EXTI_InitStruct)函数,其中结构体EXTI_InitTypeDef的成员变量有: typedef struct { uint32_t EXTI_Line; //中断/事件线 EXTIMode_TypeDef EXTI_Mode; //EXTI模式 EXTITrigger_TypeDef EXTI_Trigger; //EXTI 触发方式 FunctionalState EXTI_LineCmd; //中断线使能或失能 } EXTI_Line: 可配置参数为EXTI0~EXTI20; EXTI_Mode: 可配置为EXTI_Mode_Interrupt(中断模式)和EXTI_Mode_Event(事件模式); EXTI_Trigger: 可配置为EXTI_Trigger_Rising(上升沿触发)、EXTI_Trigger_Falling(下降沿触发)以及EXTI_Trigger_Rising_Falling(边沿触发); EXTI_LineCmd: 配置ENABLE为使能,DISABLE为失能。 5. 编写EXTI中断服务函数 中断服务函数就是当外部中断发生后,需要执行的一段用户程序,可根据需求进行编写。 1.4 应用示例 在本小节中使用一个按键来触发外部中断,在服务函数中执行点亮LED的程序,这个功能是很简单的,但也能够解释清楚外部中断的配置过程,详细的代码如下所示(其中LED文件的代码在上一章节中已经给出): exit.h #ifndef _exti_H #define _exti_H #include "system.h" void MY_EXTI_Init(void); #endif exit.c #include "exti.h" #include "SysTick.h" #include "key.h" #include "led.h" void MY_EXTI_Init() { NVIC_InitTypeDef NVIC_InitStructure; EXTI_InitTypeDef EXTI_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE); GPIO_EXTILineConfig(GPIO_PortSourceGPIOA,GPIO_PinSource0); GPIO_EXTILineConfig(GPIO_PortSourceGPIOE,GPIO_PinSource2); GPIO_EXTILineConfig(GPIO_PortSourceGPIOE,GPIO_PinSource3); GPIO_EXTILineConfig(GPIO_PortSourceGPIOE,GPIO_PinSource4); NVIC_InitStructure.NVIC_IRQChannel=EXTI0_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=2; NVIC_InitStructure.NVIC_IRQChannelSubPriority=3; NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE; NVIC_Init(&NVIC_InitStructure); NVIC_InitStructure.NVIC_IRQChannel=EXTI2_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=2; NVIC_InitStructure.NVIC_IRQChannelSubPriority=2; NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE; NVIC_Init(&NVIC_InitStructure); NVIC_InitStructure.NVIC_IRQChannel=EXTI3_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=2; NVIC_InitStructure.NVIC_IRQChannelSubPriority=1; NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE; NVIC_Init(&NVIC_InitStructure); NVIC_InitStructure.NVIC_IRQChannel=EXTI4_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=2; NVIC_InitStructure.NVIC_IRQChannelSubPriority=0; NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE; NVIC_Init(&NVIC_InitStructure); EXTI_InitStructure.EXTI_Line=EXTI_Line0; EXTI_InitStructure.EXTI_LineCmd=ENABLE; EXTI_InitStructure.EXTI_Mode=EXTI_Mode_Interrupt; EXTI_InitStructure.EXTI_Trigger=EXTI_Trigger_Rising; EXTI_Init(&EXTI_InitStructure); EXTI_InitStructure.EXTI_Line=EXTI_Line2|EXTI_Line3|EXTI_Line4; EXTI_InitStructure.EXTI_LineCmd=ENABLE; EXTI_InitStructure.EXTI_Mode=EXTI_Mode_Interrupt; EXTI_InitStructure.EXTI_Trigger=EXTI_Trigger_Falling; EXTI_Init(&EXTI_InitStructure); } void EXTI0_IRQHandler() { if(EXTI_GetFlagStatus(EXTI_Line0)==1) { delay_ms(10); if(K_UP==1) { led2=0; } } EXTI_ClearITPendingBit(EXTI_Line0); } void EXTI2_IRQHandler() { if(EXTI_GetFlagStatus(EXTI_Line2)==1) { delay_ms(10); if(K_LEFT==0) { led3=1; } } EXTI_ClearITPendingBit(EXTI_Line2); } void EXTI3_IRQHandler() { if(EXTI_GetFlagStatus(EXTI_Line3)==1) { delay_ms(10); if(K_DOWN==0) { led2=1; } } EXTI_ClearITPendingBit(EXTI_Line3); } void EXTI4_IRQHandler() { if(EXTI_GetFlagStatus(EXTI_Line4)==1) { delay_ms(10); if(K_RIGHT==0) { led3=0; } } EXTI_ClearITPendingBit(EXTI_Line4); } key.h #ifndef _key_H #define _key_H #include "system.h" #define KEY_UP_Pin GPIO_Pin_0 #define KEY_LEFT_Pin GPIO_Pin_2 #define KEY_DOWN_Pin GPIO_Pin_3 #define KEY_RIGHT_Pin GPIO_Pin_4 #define KEY_UP_PORT GPIOA #define KEY_PORT GPIOE #define K_UP PAin(0) #define K_DOWN PEin(3) #define K_LEFT PEin(2) #define K_RIGHT PEin(4) #define KEY_UP 1 #define KEY_LEFT 3 #define KEY_DOWN 2 #define KEY_RIGHT 4 void KEY_Init(void); u8 KEY_Scan(u8 mode); #endif key.c #include "key.h" #include "SysTick.h" void KEY_Init() { GPIO_InitTypeDef GPIO_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOE,ENABLE); GPIO_InitStructure.GPIO_Pin=KEY_UP_Pin; GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IPD; GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz; GPIO_Init(KEY_UP_PORT,&GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin=KEY_LEFT_Pin|KEY_DOWN_Pin|KEY_RIGHT_Pin; GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IPU; GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz; GPIO_Init(KEY_PORT,&GPIO_InitStructure); } u8 KEY_Scan(u8 mode) { static u8 key=1; if(key==1&&(K_UP==1||K_DOWN==0||K_LEFT==0||K_RIGHT==0)) { delay_ms(10); key=0; if(K_UP==1) { return KEY_UP; } else if(K_DOWN==0) { return KEY_DOWN; } else if(K_LEFT==0) { return KEY_LEFT; } else if(K_RIGHT==0) { return KEY_RIGHT; } } else if(K_UP==0&&K_DOWN==1&&K_LEFT==1&&K_RIGHT==1) { key=1; } if(mode==1) { key=1; } return 0; } main.c #include "system.h" #include "led.h" #include "SysTick.h" #include "exti.h" #include "key.h" u8 i=0; int main() { SysTick_Init(72); NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); MY_EXTI_Init(); LED_Init(); KEY_Init(); while(1) { i++; if(i%20==0) { led1=!led1; } delay_ms(10); } } 2、 定时器中断编程 STM32F1的定时器系统由2个基本定时器(TIM6、TIM7)、4个通用定时器(TIM2~TIM5)和2个高级定时器(TIM1、TIM8)所组成。基本定时器同51单片机内的定时器类似,功能较为简单;通用定时器在其基础上增加了输入捕获与输出比较功能;高级定时器又在通用定时器基础上增加了可编程死去互补输出、重复计数、带刹车(断路)的功能主要针对于工业电机的控制。 2.1 通用定时器 STM32F1的通用定时器内有一个16位自动重载计数器(CNT)由可编程预分频器(PSC)驱动,其可用于测量输入信号的脉冲宽度(输入捕获)或者生产输出波形(输出比较和PWM)。使用定时器预分频器和RCC时钟控制器预分频器,脉冲长度和波形周期可以在几微秒到几毫秒之间调整,此外每一个定时器都是独立的,之间不互相共享任何资源。通用定时器TIM2~TIM5具备如下功能:
2.2 定时器配置步骤 定时器相关的库函数在stm32f10x_tim,c和stm32f10x_tim.h文件中,使用库函数对定时器进行配置的详细步骤如下: 使能定时器时钟; 定时器是挂载在APB1总线上的设备,因此使能定时器可以调用函数: RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIMx, ENABLE); 初始化定时器参数,包含了自动重装值,分频系数,计数方式等; 调用函数:void TIM_TimeBaseInit(TIM_TypeDef* TIMx, TIM_TimeBaseInitTypeDef* TIM_TimeBaseInitStruct); TIM_TimeBaseInitTypeDef为一个结构体类型,包含了定时器初始化的成员变量: typedef struct { uint16_t TIM_Prescaler; //定时器预分频器 unit16_t TIM_CouterMode; //计数模式 unit16_t TIM_Period; //定时器周期 unit16_t TIM_ClockDivision; //时钟分频 unit8_t TIM_RepetitionCounter; //重复计数器 } TIM_Prescaler: 时钟源经过该预分频器后输出的是定时器时钟,设置范围为0~65535; TIM_CouterMode: 可设置为TIM_CounterMode_Up(向上)、TIM_CounterMode_Down(向下)以及中心对齐计数模式; TIM_Period:设置定时器自动重载计数值,范围为0~65536; TIM_ClockDivision: 时钟分频因子,设置定时器时钟CK_INT频率与数字滤波器采样时钟频率分频比; TIM_RepetitionCounter: 重复计数器,简单的控制PWM输出个数。 设置定时器中断类型,使能定时器; 调用函数:void TIM_ITConfig(TIM_TypeDef* TIMx, uint16_t TIM_IT, FunctionalState NewState); TIM_IT 用来设置定时器中断类型,包含TIM_IT_Update(更新中断)、TIM_IT_Trigger(触发中断)以及输入捕获中断等等; FunctionalState 用来使能或使能定时器中断,ENABLE和DISABLE。 设置定时器中断优先级,使能定时器中断通道; 对NVIC初始化,如前一节中所示。 开启定时器; 调用函数:void TIM_Cmd(TIM_TypeDef* TIMx, FunctionalState NewState); 编写定时器中断服务函数 由于定时器中断类型有很多,因此在中断服务函数中需要通过状态寄存器的值来判断此次中断属于哪一种类型,然后再执行相应的用户程序。 2.3 应用示例 本次实验通过TIM4定时器的更新中断控制LED灯实现不断闪烁的功能,详细的代码如下所示; time.h #ifndef _time_H #define _time_H #include "system.h" void TIM4_Init(u16 pre,u16 psc); #endif time.c #include "time.h" #include "led.h" void TIM4_Init(u16 pre,u16 psc) { TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure; NVIC_InitTypeDef NVIC_InitStructure; RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4,ENABLE); TIM_TimeBaseInitStructure.TIM_Period=pre;//ÖÜÆÚ TIM_TimeBaseInitStructure.TIM_Prescaler=psc; TIM_TimeBaseInitStructure.TIM_ClockDivision=TIM_CKD_DIV1; TIM_TimeBaseInitStructure.TIM_CounterMode=TIM_CounterMode_Up; TIM_TimeBaseInit(TIM4,&TIM_TimeBaseInitStructure); TIM_ITConfig(TIM4,TIM_IT_Update,ENABLE); TIM_ClearITPendingBit(TIM4,TIM_CounterMode_Up); NVIC_InitStructure.NVIC_IRQChannel=TIM4_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=2; NVIC_InitStructure.NVIC_IRQChannelSubPriority=3; NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE; NVIC_Init(&NVIC_InitStructure); TIM_Cmd(TIM4,ENABLE); } void TIM4_IRQHandler(void) { if(TIM_GetITStatus(TIM4,TIM_IT_Update)==1) { led2=!led2; } TIM_ClearITPendingBit(TIM4,TIM_IT_Update); } main.c #include "system.h" #include "led.h" #include "SysTick.h" #include "time.h" u8 i=0; int main() { SysTick_Init(72); NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); LED_Init(); TIM4_Init(1000,36000-1);//500ms while(1) { i++; if(i%20==0) { led1=!led1; } delay_ms(10); } } |
|
|
|
只有小组成员才能发言,加入小组>>
调试STM32H750的FMC总线读写PSRAM遇到的问题求解?
2211 浏览 1 评论
X-NUCLEO-IHM08M1板文档中输出电流为15Arms,15Arms是怎么得出来的呢?
1848 浏览 1 评论
1346 浏览 2 评论
STM32F030F4 HSI时钟温度测试过不去是怎么回事?
880 浏览 2 评论
ST25R3916能否对ISO15693的标签芯片进行分区域写密码?
2215 浏览 2 评论
2116浏览 9评论
STM32仿真器是选择ST-LINK还是选择J-LINK?各有什么优势啊?
1035浏览 4评论
stm32f4下spi+dma读取数据不对是什么原因导致的?
409浏览 3评论
STM32F0_TIM2输出pwm2后OLED变暗或者系统重启是怎么回事?
738浏览 3评论
720浏览 3评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2025-4-18 05:41 , Processed in 0.983763 second(s), Total 76, Slave 60 queries .
Powered by 电子发烧友网
© 2015 www.ringvoyeur.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191