企业在线设计网站,做游戏钓鱼网站,软件开发一般要多少钱,wordpress淘宝客主题免费下载一#xff0c;中断系统的介绍
中断#xff1a;在主程序运行过程中#xff0c;出现了特定的中断触发条件#xff08;中断源#xff09;#xff0c;使得CPU暂停当前正在运行的程序#xff0c;转而去处理中断程序#xff0c;处理完成后又返回原来被暂停的位置继续运行
中…一中断系统的介绍
中断在主程序运行过程中出现了特定的中断触发条件中断源使得CPU暂停当前正在运行的程序转而去处理中断程序处理完成后又返回原来被暂停的位置继续运行
中断优先级当有多个中断源同时申请中断时CPU会根据中断源的轻重缓急进行裁决优先响应更加紧急的中断源
中断嵌套当一个中断程序正在运行时又有新的更高优先级的中断源申请中断CPU再次暂停当前中断程序转而去处理新的中断程序处理完成后依次进行返回 中断通道包含EXTI、TIM、ADC、USART、SPI、I2C、RTC等多个外设
使用NVIC统一管理中断每个中断通道都拥有16个可编程的优先等级可对优先级进行分组进一步设置抢占优先级和响应优先级
具体串口通道需要查看手册
二NVIC嵌套中断向量控制器
1框架介绍
在stm32中用来统一分配中断优先级和管理中断的 2NVIC优先级分组
NVIC的中断优先级由优先级寄存器的4位0~15决定这4位可以进行切分分为高n位的抢占优先级和低4-n位的响应优先级
抢占优先级高的可以中断嵌套响应优先级高的可以优先排队抢占优先级和响应优先级均相同的按中断号排队 三EXTI外部中断介绍
1介绍
EXTI可以监测指定GPIO口的电平信号当其指定的GPIO口产生电平变化时EXTI将立即向NVIC发出中断申请经过NVIC裁决后即可中断CPU主程序使CPU执行EXTI对应的中断程序支持的触发方式上升沿/下降沿/双边沿/软件触发支持的GPIO口所有GPIO口但相同的Pin不能同时触发中断即不能PA1和PB1组合通道数16个GPIO_Pin外加PVD输出、RTC闹钟、USB唤醒、以太网唤醒触发响应方式中断响应/事件响应
2EXTI基本结构 3EXTI框图 4AFIO复用IO口
AFIO主要用于引脚复用功能的选择和重定义
在STM32中AFIO主要完成两个任务复用功能引脚重映射、中断引脚选择 5库函数介绍
1配置外部中断的流程
1配置RCC把涉及的外设时钟都打开2配置GPIO选择端口的输入模式3配置AFIO4配置EXTI选择边沿的触发方式比如上升沿下降沿或者双边沿还有选择中断响应和事件响应5配置NVIC给中断选择一个合适的优先级通过NVIC外部中断信号就能进入CPU
2中断初始化的配置示例
/*开启时钟*/RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); //开启GPIOB的时钟RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE); //开启AFIO的时钟外部中断必须开启AFIO的时钟/*GPIO初始化*/GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Mode GPIO_Mode_IPU;GPIO_InitStructure.GPIO_Pin GPIO_Pin_14;GPIO_InitStructure.GPIO_Speed GPIO_Speed_50MHz;GPIO_Init(GPIOB, GPIO_InitStructure); //将PB14引脚初始化为上拉输入/*AFIO选择中断引脚*/GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource14);//将外部中断的14号线映射到GPIOB即选择PB14为外部中断引脚/*EXTI初始化*/EXTI_InitTypeDef EXTI_InitStructure; //定义结构体变量EXTI_InitStructure.EXTI_Line EXTI_Line14; //选择配置外部中断的14号线EXTI_InitStructure.EXTI_LineCmd ENABLE; //指定外部中断线使能EXTI_InitStructure.EXTI_Mode EXTI_Mode_Interrupt; //指定外部中断线为中断模式EXTI_InitStructure.EXTI_Trigger EXTI_Trigger_Falling; //指定外部中断线为下降沿触发EXTI_Init(EXTI_InitStructure); //将结构体变量交给EXTI_Init配置EXTI外设/*NVIC中断分组*/NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //配置NVIC为分组2//即抢占优先级范围0~3响应优先级范围0~3//此分组配置在整个工程中仅需调用一次//若有多个中断可以把此代码放在main函数内while循环之前//若调用多次配置分组的代码则后执行的配置会覆盖先执行的配置/*NVIC配置*/NVIC_InitTypeDef NVIC_InitStructure; //定义结构体变量NVIC_InitStructure.NVIC_IRQChannel EXTI15_10_IRQn; //选择配置NVIC的EXTI15_10线NVIC_InitStructure.NVIC_IRQChannelCmd ENABLE; //指定NVIC线路使能NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority 1; //指定NVIC线路的抢占优先级为1NVIC_InitStructure.NVIC_IRQChannelSubPriority 1; //指定NVIC线路的响应优先级为1NVIC_Init(NVIC_InitStructure); //将结构体变量交给NVIC_Init配置NVIC外设 以下是外部中断的中断函数相当于C51的外部中断服务号
void EXTI15_10_IRQHandler(void)
{if (EXTI_GetITStatus(EXTI_Line14) SET) //判断是否是外部中断14号线触发的中断{/*如果出现数据乱跳的现象可再次判断引脚电平以避免抖动*/if (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_14) 0){CountSensor_Count ; //计数值自增一次}EXTI_ClearITPendingBit(EXTI_Line14); //清除外部中断14号线的中断标志位//中断标志位必须清除//否则中断将连续不断地触发导致主程序卡死}
}四TIM定时器介绍
1定时器类型介绍
定时器可以对输入的时钟进行计数并在计数值达到设定值时触发中断16位计数器、预分频器、自动重装寄存器的时基单元在72MHz计数时钟下可以实现最大59.65s的定时不仅具备基本的定时中断功能而且还包含内外时钟源选择、输入捕获、输出比较、编码器接口、主从触发模式等多种功能根据复杂度和应用场景分为了高级定时器、通用定时器、基本定时器三种类型 注意每个不同单片机的型号是不同的在使用某个外设之前一定要查看一下是不是有这个外设
2基本定时器 解释首先预分频器计数器自动重装载寄存器它们三个构成了最基本的计数计时电路这一块也成为时基单元 基本定时器只能选择内部时钟其中内部时钟的来源是RCC的TIMxCLK这里的频率值一般都是系统的主频72MHz所有通向时基单元的计数基准主频就是72MHz实际分频系数预分频系数的值1其中这个预分频器是16位的所有最大值可以写65535也就是65536就是对输入的基准频率提前进行一个分频的操作计数器可以对预分频后的计数时钟进行计数比如计数时钟每来一个上升沿计数器的值1计数器运行时会自增运行当自增运行到目标值产生中断就完成了定时的任务自动重装载寄存器就是写入一个计数目标当计数器自增到该目标就会产生中断信号并且清零计数器计数器自动开始下一次的计数计时。基本定时器仅支持向上计数
3通用定时器框图 通用定时器和高级定时器支持向上计数向下计数和中央对齐这三种模式
通用定时器可以使用外部时钟TIMx_ETR
五代码展示
1定时器中断的基本结构 下面来看几个时序图这对于代码的编写也十分重要 2定时器定时中断代码
2.1 定时器初始化配置流程
1打开RCC开启时钟定时器的基准时钟和整个外设的工作时钟都会被同时打开2选择时基单元的时钟源对于定时中断我们选择内部时钟源3配置时基单元包括预分频器自动重装器计数模式等等可以直接使用一个结构体来配置4配置输出中断控制允许更新中断输出到NVIC5配置NVIC在NVIC中打开定时器中断的通道并分配一个优先级6运行控制整个模块配置完成后需要驱动使能定时计数器当定时器使能之后计数器开始计数当计数器更新时触发中断7最后我们再写一个定时器的中断函数这样这个中断函数每隔一段时间就会自动执行一次了
2.2 定时器的相关库函数
2.2.1 定时器初始化相关函数
void TIM_DeInit(TIM_TypeDef* TIMx);//恢复缺省配置
void TIM_TimeBaseInit(TIM_TypeDef* TIMx, TIM_TimeBaseInitTypeDef* TIM_TimeBaseInitStruct);//时基单元初始化
void TIM_OC1Init(TIM_TypeDef* TIMx, TIM_OCInitTypeDef* TIM_OCInitStruct);
void TIM_OC2Init(TIM_TypeDef* TIMx, TIM_OCInitTypeDef* TIM_OCInitStruct);
void TIM_OC3Init(TIM_TypeDef* TIMx, TIM_OCInitTypeDef* TIM_OCInitStruct);
void TIM_OC4Init(TIM_TypeDef* TIMx, TIM_OCInitTypeDef* TIM_OCInitStruct);
void TIM_ICInit(TIM_TypeDef* TIMx, TIM_ICInitTypeDef* TIM_ICInitStruct);
void TIM_PWMIConfig(TIM_TypeDef* TIMx, TIM_ICInitTypeDef* TIM_ICInitStruct);
void TIM_BDTRConfig(TIM_TypeDef* TIMx, TIM_BDTRInitTypeDef *TIM_BDTRInitStruct);
void TIM_TimeBaseStructInit(TIM_TimeBaseInitTypeDef* TIM_TimeBaseInitStruct);
void TIM_OCStructInit(TIM_OCInitTypeDef* TIM_OCInitStruct);
void TIM_ICStructInit(TIM_ICInitTypeDef* TIM_ICInitStruct);
void TIM_BDTRStructInit(TIM_BDTRInitTypeDef* TIM_BDTRInitStruct);
void TIM_Cmd(TIM_TypeDef* TIMx, FunctionalState NewState);
void TIM_CtrlPWMOutputs(TIM_TypeDef* TIMx, FunctionalState NewState);
void TIM_ITConfig(TIM_TypeDef* TIMx, uint16_t TIM_IT, FunctionalState NewState);
void TIM_GenerateEvent(TIM_TypeDef* TIMx, uint16_t TIM_EventSource);
void TIM_DMAConfig(TIM_TypeDef* TIMx, uint16_t TIM_DMABase, uint16_t TIM_DMABurstLength);
void TIM_DMACmd(TIM_TypeDef* TIMx, uint16_t TIM_DMASource, FunctionalState NewState);
void TIM_InternalClockConfig(TIM_TypeDef* TIMx);
void TIM_ITRxExternalClockConfig(TIM_TypeDef* TIMx, uint16_t TIM_InputTriggerSource);
void TIM_TIxExternalClockConfig(TIM_TypeDef* TIMx, uint16_t TIM_TIxExternalCLKSource,uint16_t TIM_ICPolarity, uint16_t ICFilter); 2.2.2 定时器其他重要的相关函数
void TIM_PrescalerConfig(TIM_TypeDef* TIMx, uint16_t Prescaler, uint16_t TIM_PSCReloadMode);//单独写预分频值的
void TIM_ARRPreloadConfig(TIM_TypeDef* TIMx, FunctionalState NewState);//自动重装器预装功能配置
void TIM_SetCounter(TIM_TypeDef* TIMx, uint16_t Counter);//给计数值写值
void TIM_SetAutoreload(TIM_TypeDef* TIMx, uint16_t Autoreload);//给自动重装器写入一个值
uint16_t TIM_GetCounter(TIM_TypeDef* TIMx);//返回当时计数器的值
uint16_t TIM_GetPrescaler(TIM_TypeDef* TIMx);//返回当时预分频器的值
FlagStatus TIM_GetFlagStatus(TIM_TypeDef* TIMx, uint16_t TIM_FLAG);//检查指定定时器TIMx的特定标志TIM_FLAG的状态。
void TIM_ClearFlag(TIM_TypeDef* TIMx, uint16_t TIM_FLAG);//作用清除指定定时器TIMx的特定标志TIM_FLAG。
ITStatus TIM_GetITStatus(TIM_TypeDef* TIMx, uint16_t TIM_IT);//检查指定定时器TIMx的特定中断TIM_IT的挂起状态。
void TIM_ClearITPendingBit(TIM_TypeDef* TIMx, uint16_t TIM_IT);//清除指定定时器TIMx的特定中断TIM_IT的挂起位。
2.3 定时器代码示例
timer.c
#include stm32f10x.h // Device header/*** 函 数定时中断初始化* 参 数无* 返 回 值无*/
void Timer_Init(void)
{/*开启时钟*/RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); //开启TIM2的时钟/*配置时钟源*/TIM_InternalClockConfig(TIM2); //选择TIM2为内部时钟若不调用此函数TIM默认也为内部时钟/*时基单元初始化*/TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure; //定义结构体变量TIM_TimeBaseInitStructure.TIM_ClockDivision TIM_CKD_DIV1; //时钟分频选择不分频此参数用于配置滤波器时钟不影响时基单元功能TIM_TimeBaseInitStructure.TIM_CounterMode TIM_CounterMode_Up; //计数器模式选择向上计数TIM_TimeBaseInitStructure.TIM_Period 10000 - 1; //计数周期即ARR的值TIM_TimeBaseInitStructure.TIM_Prescaler 7200 - 1; //预分频器即PSC的值TIM_TimeBaseInitStructure.TIM_RepetitionCounter 0; //重复计数器高级定时器才会用到TIM_TimeBaseInit(TIM2, TIM_TimeBaseInitStructure); //将结构体变量交给TIM_TimeBaseInit配置TIM2的时基单元 /*中断输出配置*/TIM_ClearFlag(TIM2, TIM_FLAG_Update); //清除定时器更新标志位//TIM_TimeBaseInit函数末尾手动产生了更新事件//若不清除此标志位则开启中断后会立刻进入一次中断//如果不介意此问题则不清除此标志位也可TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE); //开启TIM2的更新中断/*NVIC中断分组*/NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //配置NVIC为分组2//即抢占优先级范围0~3响应优先级范围0~3//此分组配置在整个工程中仅需调用一次//若有多个中断可以把此代码放在main函数内while循环之前//若调用多次配置分组的代码则后执行的配置会覆盖先执行的配置/*NVIC配置*/NVIC_InitTypeDef NVIC_InitStructure; //定义结构体变量NVIC_InitStructure.NVIC_IRQChannel TIM2_IRQn; //选择配置NVIC的TIM2线NVIC_InitStructure.NVIC_IRQChannelCmd ENABLE; //指定NVIC线路使能NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority 2; //指定NVIC线路的抢占优先级为2NVIC_InitStructure.NVIC_IRQChannelSubPriority 1; //指定NVIC线路的响应优先级为1NVIC_Init(NVIC_InitStructure); //将结构体变量交给NVIC_Init配置NVIC外设/*TIM使能*/TIM_Cmd(TIM2, ENABLE); //使能TIM2定时器开始运行
}/* 定时器中断函数可以复制到使用它的地方
void TIM2_IRQHandler(void)
{if (TIM_GetITStatus(TIM2, TIM_IT_Update) SET){TIM_ClearITPendingBit(TIM2, TIM_IT_Update);}
}
*/main.c
#include stm32f10x.h // Device header
#include Delay.h
#include OLED.h
#include Timer.huint16_t Num; //定义在定时器中断里自增的变量int main(void)
{/*模块初始化*/OLED_Init(); //OLED初始化Timer_Init(); //定时中断初始化/*显示静态字符串*/OLED_ShowString(1, 1, Num:); //1行1列显示字符串Num:while (1){OLED_ShowNum(1, 5, Num, 5); //不断刷新显示Num变量}
}/*** 函 数TIM2中断函数* 参 数无* 返 回 值无* 注意事项此函数为中断函数无需调用中断触发后自动执行* 函数名为预留的指定名称可以从启动文件复制* 请确保函数名正确不能有任何差异否则中断函数将不能进入*/
void TIM2_IRQHandler(void)
{if (TIM_GetITStatus(TIM2, TIM_IT_Update) SET) //判断是否是TIM2的更新事件触发的中断{Num ; //Num变量自增用于测试定时中断TIM_ClearITPendingBit(TIM2, TIM_IT_Update); //清除TIM2更新事件的中断标志位//中断标志位必须清除//否则中断将连续不断地触发导致主程序卡死}
}3定时器外部时钟
timer.c
#include stm32f10x.h // Device header/*** 函 数定时中断初始化* 参 数无* 返 回 值无* 注意事项此函数配置为外部时钟定时器相当于计数器*/
void Timer_Init(void)
{/*开启时钟*/RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); //开启TIM2的时钟RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //开启GPIOA的时钟/*GPIO初始化*/GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Mode GPIO_Mode_IPU;GPIO_InitStructure.GPIO_Pin GPIO_Pin_0;GPIO_InitStructure.GPIO_Speed GPIO_Speed_50MHz;GPIO_Init(GPIOA, GPIO_InitStructure); //将PA0引脚初始化为上拉输入/*外部时钟配置*/TIM_ETRClockMode2Config(TIM2, TIM_ExtTRGPSC_OFF, TIM_ExtTRGPolarity_NonInverted, 0x0F);//选择外部时钟模式2时钟从TIM_ETR引脚输入//注意TIM2的ETR引脚固定为PA0无法随意更改//最后一个滤波器参数加到最大0x0F可滤除时钟信号抖动/*时基单元初始化*/TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure; //定义结构体变量TIM_TimeBaseInitStructure.TIM_ClockDivision TIM_CKD_DIV1; //时钟分频选择不分频此参数用于配置滤波器时钟不影响时基单元功能TIM_TimeBaseInitStructure.TIM_CounterMode TIM_CounterMode_Up; //计数器模式选择向上计数TIM_TimeBaseInitStructure.TIM_Period 10 - 1; //计数周期即ARR的值TIM_TimeBaseInitStructure.TIM_Prescaler 1 - 1; //预分频器即PSC的值TIM_TimeBaseInitStructure.TIM_RepetitionCounter 0; //重复计数器高级定时器才会用到TIM_TimeBaseInit(TIM2, TIM_TimeBaseInitStructure); //将结构体变量交给TIM_TimeBaseInit配置TIM2的时基单元 /*中断输出配置*/TIM_ClearFlag(TIM2, TIM_FLAG_Update); //清除定时器更新标志位//TIM_TimeBaseInit函数末尾手动产生了更新事件//若不清除此标志位则开启中断后会立刻进入一次中断//如果不介意此问题则不清除此标志位也可TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE); //开启TIM2的更新中断/*NVIC中断分组*/NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //配置NVIC为分组2//即抢占优先级范围0~3响应优先级范围0~3//此分组配置在整个工程中仅需调用一次//若有多个中断可以把此代码放在main函数内while循环之前//若调用多次配置分组的代码则后执行的配置会覆盖先执行的配置/*NVIC配置*/NVIC_InitTypeDef NVIC_InitStructure; //定义结构体变量NVIC_InitStructure.NVIC_IRQChannel TIM2_IRQn; //选择配置NVIC的TIM2线NVIC_InitStructure.NVIC_IRQChannelCmd ENABLE; //指定NVIC线路使能NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority 2; //指定NVIC线路的抢占优先级为2NVIC_InitStructure.NVIC_IRQChannelSubPriority 1; //指定NVIC线路的响应优先级为1NVIC_Init(NVIC_InitStructure); //将结构体变量交给NVIC_Init配置NVIC外设/*TIM使能*/TIM_Cmd(TIM2, ENABLE); //使能TIM2定时器开始运行
}/*** 函 数返回定时器CNT的值* 参 数无* 返 回 值定时器CNT的值范围0~65535*/
uint16_t Timer_GetCounter(void)
{return TIM_GetCounter(TIM2); //返回定时器TIM2的CNT
}/* 定时器中断函数可以复制到使用它的地方
void TIM2_IRQHandler(void)
{if (TIM_GetITStatus(TIM2, TIM_IT_Update) SET){TIM_ClearITPendingBit(TIM2, TIM_IT_Update);}
}
*/main.c
#include stm32f10x.h // Device header
#include Delay.h
#include OLED.h
#include Timer.huint16_t Num; //定义在定时器中断里自增的变量int main(void)
{/*模块初始化*/OLED_Init(); //OLED初始化Timer_Init(); //定时中断初始化/*显示静态字符串*/OLED_ShowString(1, 1, Num:); //1行1列显示字符串Num:OLED_ShowString(2, 1, CNT:); //2行1列显示字符串CNT:while (1){OLED_ShowNum(1, 5, Num, 5); //不断刷新显示Num变量OLED_ShowNum(2, 5, Timer_GetCounter(), 5); //不断刷新显示CNT的值}
}/*** 函 数TIM2中断函数* 参 数无* 返 回 值无* 注意事项此函数为中断函数无需调用中断触发后自动执行* 函数名为预留的指定名称可以从启动文件复制* 请确保函数名正确不能有任何差异否则中断函数将不能进入*/
void TIM2_IRQHandler(void)
{if (TIM_GetITStatus(TIM2, TIM_IT_Update) SET) //判断是否是TIM2的更新事件触发的中断{Num ; //Num变量自增用于测试定时中断TIM_ClearITPendingBit(TIM2, TIM_IT_Update); //清除TIM2更新事件的中断标志位//中断标志位必须清除//否则中断将连续不断地触发导致主程序卡死}
}四总结
1定时器定时中断 触发来源定时器定时中断是由STM32内部的定时器产生的。当定时器的计数值达到预设的重装载值时定时器溢出并触发中断。 应用场景定时器定时中断常用于需要周期性执行的任务如定时测量、延时控制、PWM输出等。它允许微控制器在固定的时间间隔执行特定的操作。 功能特点 可编程性定时器的计数值和重装载值可以通过软件编程进行灵活设置从而实现不同的定时周期。高精度STM32的定时器通常具有较高的精度能够满足对定时要求较高的应用场景。自动重装载许多STM32定时器支持自动重装载功能即在触发中断后自动将计数值重置为预设的重装载值从而实现连续定时。
2定时器外部中断 触发来源定时器外部中断通常指的是由外部事件如外部输入引脚状态的变化触发的中断而不是由定时器本身产生的中断。这里的“定时器外部中断”可能是一个误导性的表述因为标准的STM32外部中断是由外部中断/事件控制器EXTI管理的而不是由定时器直接管理的。然而为了回答这个问题我们可以将其理解为一种通过定时器与外部事件结合来触发的中断机制尽管这不是标准的STM32术语。 应用场景定时器外部中断如果理解为通过定时器与外部事件结合触发的中断可能用于在特定时间窗口内检测外部事件或者在外部事件发生时启动定时器以测量事件持续时间等。 功能特点 外部事件触发与定时器定时中断不同定时器外部中断的触发依赖于外部事件。时间窗口控制通过结合定时器和外部中断可以实现仅在特定时间窗口内响应外部事件的功能。灵活性定时器和外部中断的结合使用提供了更高的灵活性可以满足更复杂的定时和外部事件检测需求。
3总结
触发来源定时器定时中断由定时器内部溢出触发而定时器外部中断如果理解为一种结合机制则由外部事件触发。应用场景定时器定时中断适用于周期性任务而定时器外部中断结合机制适用于需要在特定时间窗口内检测外部事件的应用场景。功能特点两者在可编程性、精度和灵活性方面各有优势具体选择取决于应用需求。