初学STM32之定时器中断
STM32F10x系列总共最多有8个定时器分为高级定时器,通用定时器和基本定时器。三种定时器的主要区别如下图所示:

本文章仅介绍通用定时器的一些知识。
通用定时器的功能包括:
通用定时器经常被用于测量输入信号的脉冲长度(输入捕获)或者产生输出波形(输出比较和PWM)等。
注:使用定时器预分频器和RCC时钟预分频器,脉冲长度和波形周期可以在几微秒和几毫秒间调整。STM32的每个通用定时器是完全独立的,没有相互共享的任何资源。
通用定时器的工作过程如图所示:

如图所示,通用定时器的工作过程大致可以分为时钟发生器、时基单元、输入捕获和输出比较四个部分。
在时钟发生器中,由内部时钟或外部TIMx_ETR等经过一系列处理产生时钟源,送入时基单元;在时基单元中经过预分频产生一个时钟,再由CNT进行计数(向上或向下),计数到自动重装载值时可以触发相应的中断;在输入捕获部分中,对TIMx_CHx中的信号进行捕获,再进行滤波等操作,再通过捕获比较寄存器中捕获到两次信号后的计数器的值,就可以得到脉冲宽度等;在输出比较的部分中,可以在捕获比较寄存器中设置一个数值,用计数器中的值与其比较,当高于该数值时,输出高/低电平,低于该数值时,输出低/高电平。
定时器中断主要应用到通用定时器的时钟发生器和时基单元两个部分。
计数器的时钟可以由以下时钟源提供:
时钟计算方法如图所示:

通用计数器模式分为三种:向上计数、向下计数、向上向下双向计数。
向上计数模式:计数器从0计数到自动加载值,然后从0重新开始计数并产生一个计数器溢出事件;
向下计数模式:计数器从自动装入值开始向下计数到0,然后从自动装入的值重新开始并产生一个计数器向下溢出事件;
向上/向下计数(中央对齐模式):计数器从0开始计数到自动装入的值-1,产生一个计数器溢出事件,然后向下计数到1并且产生一个计数器溢出事件;然后再从0开始重新计数。
代码如下:
void Tim3_Int_Init(u16 arr,u16 psc)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
NVIC_InitTypeDef NVIC_InitStruct;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);//使能定时器时钟
TIM_TimeBaseInitStruct.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseInitStruct.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInitStruct.TIM_Period = arr;
TIM_TimeBaseInitStruct.TIM_Prescaler = psc;
TIM_TimeBaseInit(TIM3,&TIM_TimeBaseInitStruct);//初始化定时器
TIM_ITConfig(TIM3,TIM_IT_Update,ENABLE);//开启定时器中断
NVIC_InitStruct.NVIC_IRQChannel = TIM3_IRQn;
NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStruct.NVIC_IRQChannelSubPriority = 3;
NVIC_Init(&NVIC_InitStruct);//配置NVIC
TIM_Cmd(TIM3,ENABLE);//使能定时器
}
void TIM3_IRQHandler(void)
{
if(TIM_GetITStatus(TIM3,TIM_IT_Update) == 1)//检查是否更新中断
{
TIM_ClearITPendingBit(TIM3,TIM_IT_Update);//清除更新中断标志
LED1 = !LED1;
}
}
PWM输出主要依靠通用定时器的输出比较部分。
在输出比较的部分中,可以在捕获比较寄存器中设置一个数值,用计数器中的值与其比较,当高于该数值时,输出高/低电平,低于该数值时,输出低/高电平。
工作过程如图所示:

由图可知,ARR控制PWM输出的周期,CCRx控制PWM输出的占空比。
代码如下:
void Tim3_PWM_Init(u16 arr,u16 psc)
{
GPIO_InitTypeDef GPIO_InitStruxture;
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
TIM_OCInitTypeDef TIM_OCInitStruct;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);//使能定时器时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_AFIO,ENABLE);//使能相应的GPIO口并且开启AFIO时钟
GPIO_InitStruxture.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStruxture.GPIO_Pin = GPIO_Pin_5;
GPIO_InitStruxture.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB,&GPIO_InitStruxture);//配置GPIO口
GPIO_PinRemapConfig(GPIO_PartialRemap_TIM3,ENABLE);//重映射
TIM_TimeBaseInitStruct.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseInitStruct.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInitStruct.TIM_Period = arr;
TIM_TimeBaseInitStruct.TIM_Prescaler = psc;
TIM_TimeBaseInit(TIM3,&TIM_TimeBaseInitStruct);//初始化定时器
TIM_OCInitStruct.TIM_OCMode = TIM_OCMode_PWM2;
TIM_OCInitStruct.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitStruct.TIM_OCPolarity = TIM_OCPolarity_High;
TIM_OC2Init(TIM3,&TIM_OCInitStruct);//初始化比较参数
TIM_OC2PreloadConfig(TIM3,TIM_OCPreload_Enable);//使能预装载寄存器
TIM_Cmd(TIM3,ENABLE);//使能定时器
}
输入捕获主要依靠通用定时器中的输入捕获部分
通过检测TIMx_CHx的边沿信号,在边沿信号发生跳变(上升沿/下降沿)时,将当前定时器的值(TIMx_CNT)存放到相应的捕获比较寄存器(TIMx_CCRx)里面,完成一次捕获。
注:完成一次捕获后,如果要记录高/低电平时长,不能忘记可能高/低电平持续时间过长导致中断再次刷新。
代码如下:
TIM_ICInitTypeDef TIM_ICInitStruct;
void TIM5_Cap_Init(u16 arr,u16 psc)
{
GPIO_InitTypeDef GPIO_InitStruxture;
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
NVIC_InitTypeDef NVIC_InitStruct;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM5,ENABLE);//使能定时器对应时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);//使能GPIO对应时钟
GPIO_InitStruxture.GPIO_Mode = GPIO_Mode_IPD;
GPIO_InitStruxture.GPIO_Pin = GPIO_Pin_0;
GPIO_Init(GPIOA,&GPIO_InitStruxture);//配置GPIO
//GPIO_ResetBits(GPIOA,GPIO_Pin_0);
TIM_TimeBaseInitStruct.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseInitStruct.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInitStruct.TIM_Period = arr;
TIM_TimeBaseInitStruct.TIM_Prescaler = psc;
TIM_TimeBaseInit(TIM5,&TIM_TimeBaseInitStruct);//初始化定时器
TIM_ICInitStruct.TIM_Channel = TIM_Channel_1;
TIM_ICInitStruct.TIM_ICFilter = 0x00;
TIM_ICInitStruct.TIM_ICPolarity = TIM_ICPolarity_Rising;
TIM_ICInitStruct.TIM_ICPrescaler = TIM_ICPSC_DIV1;
TIM_ICInitStruct.TIM_ICSelection = TIM_ICSelection_DirectTI;
TIM_ICInit(TIM5,&TIM_ICInitStruct);//初始化输入捕获通道
NVIC_InitStruct.NVIC_IRQChannel = TIM5_IRQn;
NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 2;
NVIC_InitStruct.NVIC_IRQChannelSubPriority = 0;
NVIC_Init(&NVIC_InitStruct);//配置NVIC
TIM_ITConfig(TIM5,TIM_IT_Update | TIM_IT_CC1,ENABLE);//开启捕获中断
TIM_Cmd(TIM5,ENABLE);//使能定时器
}
以上是STM32定时器的一些工作过程与应用,在实验过程中我用PWM控制输出实现了一个呼吸灯,紧接着再进行对按键的进行输入捕获,获取按键按下时长在编写代码时我发现,在while循环中如果不加一个delay的延迟函数,则呼吸灯无法正常工作,只能处于一个常亮的状态,而输入捕获却可以正常运行。加上延时函数则可以正常工作。目前原因还没有找到
文章目录1.开发板选择*用到的资源2.串口通信(个人理解)3.代码分析(注释比较详细)1.主函数2.串口1配置3.串口2配置以及中断函数4.注意问题5.源码链接1.开发板选择我用的是STM32F103RCT6的板子,不过代码大概在F103系列的板子上都可以运行,我试过在野火103的霸道板上也可以,主要看一下串口对应的引脚一不一样就行了,不一样的就更改一下。*用到的资源keil5软件这里用到了两个串口资源,采集数据一个,串口通信一个,板子对应引脚如下:串口1,TX:PA9,RX:PA10串口2,TX:PA2,RX:PA32.串口通信(个人理解)我就从串口采集传感器数据这个过程说一下我自己的理解,
在添加一些空格以使代码更具可读性时(与上面的代码对齐),我遇到了这个:classCdefx42endendm=C.new现在这将给出“错误数量的参数”:m.x*m.x这将给出“语法错误,意外的tSTAR,期待$end”:2/m.x*m.x这里的解析器到底发生了什么?我使用Ruby1.9.2和2.1.5进行了测试。 最佳答案 *用于运算符(42*42)和参数解包(myfun*[42,42])。当你这样做时:m.x*m.x2/m.x*m.xRuby将此解释为参数解包,而不是*运算符(即乘法)。如果您不熟悉它,参数解包(有时也称为“spl
关闭。这个问题不符合StackOverflowguidelines.它目前不接受答案。我们不允许提问寻求书籍、工具、软件库等的推荐。您可以编辑问题,以便用事实和引用来回答。关闭3年前。Improvethisquestion我正处于学习Ruby的阶段,我想查看一些小型库的源代码以了解它们是如何构建的。我不知道什么是小型图书馆,但希望SO能推荐一些易于理解的图书馆来学习。因此,如果有人知道一两个非常小的库,这是新手Rubyists学习的好例子,请推荐!我想使用Manveru'sInnatelib,因为它试图保持在2000LOC以下,但我还不熟悉其中经常使用的Ruby速记。也许大约100-5
require'mechanize'agent=Mechanize.newlogin=agent.get('http://www.schoolnet.ch/DE/HomeDE.htm')agent.clicklogin.link_withtext:/Login/然后我得到Mechanize::UnsupportedSchemeError。 最佳答案 Mechanize不支持javascript但您可以将搜索字段添加到表单并为其分配搜索词并使用mechanize提交表单form=page.forms.firstform.add_fie
在几个项目中,我希望有一个类似rakeserver的rake任务,它将通过任何需要的方式开始为该应用程序提供服务。这是一个示例:task:serverdo%x{bundleexecrackup-p1234}end这行得通,但是当我准备停止它时,按Ctrl+c并没有正常关闭;它中断了Rake任务本身,它说rakeaborted!并给出堆栈跟踪。在某些情况下,我必须执行Ctrl+c两次。我可能可以用Signal.trap写一些东西来更优雅地中断它。有没有更简单的方法? 最佳答案 trap('SIGINT'){puts"Yourmessa
我有可变数量的表格和可变数量的行,我想让它们一个接一个地显示,但如果表格不适合当前页面,请将其放在下一页,然后继续。我已将表格放入事务中,以便我可以回滚然后打印它(如果高度适合当前页面),但我如何获得表格高度?我现在有这段代码pdf.transactiondopdf.table@data,:font_size=>12,:border_style=>:grid,:horizontal_padding=>10,:vertical_padding=>3,:border_width=>2,:position=>:left,:row_colors=>["FFFFFF","DDDDDD"]pdf.
我正在寻找一个用ruby演示计时器的在线示例,并发现了下面的代码。它按预期工作,但这个简单的程序使用30Mo内存(如Windows任务管理器中所示)和太多CPU有意义吗?非常感谢deftime_blockstart_time=Time.nowThread.new{yield}Time.now-start_timeenddefrepeat_every(seconds)whiletruedotime_spent=time_block{yield}#Tohandle-vesleepinteravalsleep(seconds-time_spent)iftime_spent
LL库和HAL库简介LL:Low-Layer,底层库HAL:HardwareAbstractionLayer,硬件抽象层库LL库和hal库对比,很精简,这实际上是一个精简的库。LL库的配置选择如下:在STM32CUBEMX中,点击菜单的“ProjectManager”–>“AdvancedSettings”,在下面的界面中选择“AdvancedSettings”,然后在每个模块后面选择使用的库总结:1、如果使用的MCU是小容量的,那么STM32CubeLL将是最佳选择;2、如果结合可移植性和优化,使用STM32CubeHAL并使用特定的优化实现替换一些调用,可保持最大的可移植性。另外HAL和L
目录一、ESP32简单介绍二、ESP32Wi-Fi模块介绍三、ESP32Wi-Fi编程模型四、ESP32Wi-Fi事件处理流程 五、ESP32Wi-Fi开发环境六、ESP32Wi-Fi具体代码七、ESP32Wi-Fi代码解读6.1主程序app_main7.2自定义代码wifi_init_sta()八、ESP32Wi-Fi连接验证8.1测试方法8.2服务器模拟工具sscom58.3测试代码8.4测试结果前言为了开发一款亚马逊物联网产品,开始入手ESP32模块。为了能够记录自己的学习过程,特记录如下操作过程。一、ESP32简单介绍ESP32是一套Wi-Fi(2.4GHz)和蓝牙(4.2)双模解决方
如果您希望在Spring中启用定时任务功能,则需要在主类上添加 @EnableScheduling 注解。这样Spring才会扫描 @Scheduled 注解并执行定时任务。在大多数情况下,只需要在主类上添加 @EnableScheduling 注解即可,不需要在Service层或其他类中再次添加。以下是一个示例,演示如何在SpringBoot中启用定时任务功能:@SpringBootApplication@EnableSchedulingpublicclassApplication{publicstaticvoidmain(String[]args){SpringApplication.ru