工商企业网站,wordpress插件没有设置,免费360地图手机版,新网域名转出032 - STM32学习笔记 - TIM定时器#xff08;一#xff09; - 基本定时器知识 这节开始学习一下TIM定时器功能#xff0c;从字面意思上理解#xff0c;定时器的基本功能就是用来定时#xff0c;与定时器相结合#xff0c;可以实现一些周期性的数据发送、采集等功能#…032 - STM32学习笔记 - TIM定时器一 - 基本定时器知识 这节开始学习一下TIM定时器功能从字面意思上理解定时器的基本功能就是用来定时与定时器相结合可以实现一些周期性的数据发送、采集等功能比如定时发送USART数据、ADC定时采集数据、与GPIO结合测量信号输入脉宽以及产生输出波形常用的PWM波控制电机就是定时器的一种应用。
在STM32F42xxx系列控制器中有2个高级控制定时器、10个通用定时器和2个基本定时器以及2个看门狗定时器。控制器上所有定时器都是彼此独立不共享任何资源。高级控制定时器包含通用定时器的所有功能通用定时器包含基本定时器的所有功能。其特性参见下表
定时器类型Timer计数器分辨率计数器类型预分频系数DMA请求生成捕获/比较通道互补输入最大接口时钟MHz最大定时器时钟MHz高级控制TIM116位递增、递减、递增/递减1~65536有4有90APB2180通用TIM232位递增、递减、递增/递减1~65536有4无45APB190/180通用TIM316位递增、递减、递增/递减1~65536有4无45APB190/180通用TIM416位递增、递减、递增/递减1~65536有4无45APB190/180通用TIM532位递增、递减、递增/递减1~65536有4无45APB190/180基本TIM616位递增1~65536有0无45APB190/180基本TIM716位递增1~65536有0无45APB190/180高级控制TIM816位递增、递减、递增/递减1~65536有4有90APB2180通用TIM916位递增1~65536无2无90APB1180通用TIM1016位递增1~65536无1无90APB1180通用TIM1116位递增1~65536无1无90APB1180通用TIM1216位递增1~65536无2无45APB190/180通用TIM1316位递增1~65536无1无45APB190/180通用TIM1416位递增1~65536无1无45APB190/180
这里需要注意所有定时机器预分频系数都是在1~65536之间取值且都为整数。最大定时器时钟可以通过RCC_DCKCFGR寄存器进行配置可配置值为90/180MHz。
一、基本定时器功能框图
基本定时器的功能框图包含了基本定时器最核心的内容其结构如下图 在上图中绿框中是对定时器的图标解释黑框带阴影方框中方框内容一般为寄存器名称比如上面的自动重载寄存器TIMx_ARR和PSCTIMx_PSC预分频寄存器方框加阴影效果主要是为了突出表示该寄存后面还有一个寄存器只是这个寄存器我们无法进行操作这里我们称之为影子寄存器而上面我们可以操作的寄存器我们称之为源寄存器。影子寄存器是在程序运行时真正起到作用的源寄存器只是给我们提供读写功能当特定事件发生时才会把源寄存器的值拷贝给其影子寄存器。多个影子寄存器一起使用可以达到同步更新多个寄存器内容。
下面向下趋势的折线箭头表示为一个事件向上趋势的这下箭头表示中断和DMA输出以上图为例在自动重载寄存器左侧带有字母“U”的是按图标表示在更新事件生成时就把自动重载寄存器内容拷贝到影子寄存器内寄存器右边的时间图标、中断和DMA输出图标表示在自动重载寄存器与计数器寄存器值相等时生成事件、中断和DMA输出。
在了解图示图标后下来我们逐项分析下基本定时器框图
1、时钟源
既然要实现定时的功能就必须要给定时器提供时钟源实现计数基本定时器时钟只能使用内部时钟而高级和通用定时器可以选择外部时钟源或者其他定时器等待模式。可以通过RCC专用始终配置寄存器RCC_DCKCFGR的TIMPRE位设置所有定时器的时钟频率一般改为设置为默认值0。从而使得上面表中的可选最大定时器时钟为90MHz即基本定时器的内部时钟CK_INT频率为90MHz。
基本定时器只能使用内部时钟当TIM6和TIM7控制寄存器1TIMx_CR1的GEN位置1时启动基本定时器并且预分频器的始终来源位CK_INT。
2、控制器
控制器用于控制实现定时器功能控制其复位、使能、计数等其基础功能基本定时器还专门用于DAC转换触发。
3、计数器
基本定时器计数过程中主要针对三界寄存器分别位计数器寄存器TIMx_CNT、预分频器寄存器TIMx_PSC、自动重载寄存器TIMx_ARR这三个寄存器均为16位有效位可以设置的值为0~65535。
预分频寄存器PSC预分频器PSC有一个输入时钟CK_PSC和一个输出时钟CK_CNT输入时钟CK_PSC来源于控制器基本定时器只有内部时钟源所以CK_PSC实际等于CK_INT即90MHz。当需要不同的定时频率时可以通过设置预分频器PSC的值可以得到不同的时钟输出CK_CNT计算公式如下 f C K C N T f C K P S C / ( P S C [ 15 : 0 ] 1 ) fCKCNT fCKPSC/(PSC[15:0]1) fCKCNTfCKPSC/(PSC[15:0]1)
上图中明确表示了将预分频从1改为4时计数器变化过程在1分频时CK_PSC和CK_CNT频率相同。向TIMx_PSC寄存器写入新值时并不会马上更新CK_CNT的输出频率需要等到更新事件发生时把TIMx_PSC寄存器值更新到影子寄存器中才能产生效果。当更新为4分频后CK_PSC每产生4个脉冲时CK_CNT才会产生1个脉冲。
当定时器使能时CNT_EN 1计数器COUNTER根据CK_CNT的频率向上计数意思就是当CK_CNT每产生一个脉冲TIMx_CNT的值就累加1。当TIMx_CNT的值与TIMx_ARR的值一致时会自动生成事件并且TIMx_CNT自动清零然后开始下一轮计数如此往复。
因此我们只需要设置CK_PSC和TIMx_ARR这两个寄存器的值就可以控制事件生成的事件一般的应用程序就是在事件生成的会点函数中运行在TIMx_CNT递增至TIMx_ARR值相等时我们称之为定时器上溢。
自动重载寄存器TIMx_ARR用于存放与计数器值比较的数值设定值如果两个数值相等就生成事件将相关事件标志位置位生成DMA和中断输出。TIMx_ARR有影子寄存器可通过RIMx_CR1寄存器的ARPE位控制影子寄存器功能如果ARPE位置1影子寄存器有效当且只有事件更新时才会将TIMx_ARR值赋值给影子寄存器如果ARPE位为0修改TIMx_ARR值则可以马上生效。
4、定时器周期计算
通过上面的内容我们直到定时时间生成时间主要由TIMx_PSC和TIMx_ARR两个寄存器值决定这个称之为定时器的周期。假如我们需要一个1s周期的定时器该如何设置这两个寄存器的值呢
假设我们先设置TIMx_ARR寄存器的值为9999则表示当TIMx_CNT从0开始计数当累加到9999个脉冲后生成事件合计就是10000次那么如果此时时钟源周期为100us就刚好得到了1s的定时周期。
如此我们只需要关注如何设置TIMx_PSC寄存器值使得CK_CNT输出为100us1/0.0001 10000Hz周期的时钟即可。预分频的输入时钟CK_PSC为90Mhz根据上面提供的CK_CNT计算公式得到PSC 90MHz / 10000Hz - 1 9000 - 1 8999。
OK定时器的基本内容学习完了下来就是了解一下与定时器相关的结构体了。
二、定时器相关结构体
标准库中对定时器外设建立了四个初始化结构体其中基本定时只用到一个即TIM_TimeBaseInitTypeDef该结构体成员用于设置定时器基本工作参数并由定时器基本初始化配置函数TIM_TimeBaseInit调用。
TIM_TimeBaseInitTypeDef结构体定义在stm32f4xx_tim.h中TIM_TimeBaseInit函数定义在stm32f4xx_tim.c中首先我们先看一下TIM_TimeBaseInitTypeDef结构体定义
typedef struct {uint16_t TIM_Prescaler; // 预分频器uint16_t TIM_CounterMode; // 计数模式uint32_t TIM_Period; // 定时器周期uint16_t TIM_ClockDivision; // 时钟分频uint8_t TIM_RepetitionCounter; // 重复计算器
} TIM_TimeBaseInitTypeDef;定时器预分频器TIM_Prescaler时钟源经过该分频器之后输出的才是定时器时钟该值设置的为TIM_PSC寄存器的值可设置范围为065535可实现165536分频。
定时器计数模式TIM_CounterMode可视之为向上计数、向下计数以及三种中心对其模式基本定时器只能为向上计数即TIMx_CNT只能从0开始递增并且无需初始化。
定时器周期TIM_Period实际就是设置自定重载寄存器的值当事件生成时更新到影子寄存器可设置范围为0~65535。
时钟分频TIM_ClockDivision设置定时器时钟CK_INT频率与数字滤波器采样时钟频率分频比。基本定时器没有此项功能不用设置。
重复计数器TIM_RepetitionCounter该项输入高级控制寄存器的专用寄存器位利用它可以控制输出PWM的个数基本寄存器中无需设置。
综上虽然定时器初始化结构体由5个成员但是对于基本定时器来说只需要设置其中两个就可以其余的暂时不涉及。
OK 关于定时器的基本知识下来我们实践一下使用基本定时器操作LED以1s的节奏闪烁。
三、实验
这里实现使用基本定时器控制LED以1s的节拍闪烁编程思路如下
初始化RGB彩灯GPIO开启基本定时器时钟设置定时器周期和预分频器启动定时器更新中断并开启定时器定时器中断服务函数实现RGB彩灯翻转。
宏定义
#ifndef __BSP_TIM_H__
#define __BSP_TIM_H__
#include stm32f4xx.h
#define BASE_TIM TIM6
#define BASE_TIM_CLK RCC_APB1Periph_TIM6
#define BASE_TIM_IRQn TIM6_DAC_IRQn
#define BASE_TIM_IRQHandler TIM6_DAC_IRQHandler
void TIMx_Config(void);
#endif /*__BSP_TIM_H__*/NVIC配置
static void TIM_NVIC_Config(void)
{NVIC_InitTypeDef NVIC_InitStruct;NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0); //设置中断组为0NVIC_InitStruct.NVIC_IRQChannel BASE_TIM_IRQn; //设置中断来源为TIM中断NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority 0; //设置为抢占优先级NVIC_InitStruct.NVIC_IRQChannelSubPriority 3; //设置子优先级NVIC_InitStruct.NVIC_IRQChannelCmd ENABLE; //通道使能NVIC_Init(NVIC_InitStruct);
}TIM结构体初始化
static void TIM_Mode_Config(void)
{TIM_TimeBaseInitTypeDef TIM_InitStruct;RCC_APB1PeriphClockCmd(BASE_TIM_CLK,ENABLE); //开启TIM6时钟TIM_InitStruct.TIM_Period 9999; //设置定时器周期为9999次从0开始计数因此为10000-1定时1sTIM_InitStruct.TIM_Prescaler 8999; //设置预分频器值这个已经计算过了设置8999即可。TIM_TimeBaseInit(BASE_TIM,TIM_InitStruct); //初始化定时器TIM_ClearFlag(BASE_TIM,TIM_FLAG_Update); //清除定时器更新中断标志位TIM_ITConfig(BASE_TIM,TIM_IT_Update,ENABLE); //开启定时器更新中断TIM_Cmd(BASE_TIM,ENABLE); //使能定时器
}使用外设第一件事一定是开时钟千万不要忘了TIM6的时钟位于APB1总线开启即可。
这里我们以1s为周期闪烁LED灯因此设定定时器周期为应该为10000*100us因此此处设置10000-1 9999。
预分频器值就按照上面我们计算的值进行设置即可。
中断服务子程序
#include bsp_tim.h
#include bsp_led.h
void BASE_TIM_IRQHandler(void) //记得在stm32f4xx_it.h中声明
{if ( TIM_GetITStatus( BASE_TIM, TIM_IT_Update) ! RESET ) {LED_G_TOGGLE;TIM_ClearITPendingBit(BASE_TIM , TIM_IT_Update);}
}main函数
#include stm32f4xx.h
#include bsp_usart_dma.h
#include bsp_led.h
#include bsp_tim.h
#include stdio.h
int main(void)
{LED_Config();DEBUG_USART1_Config();TIMx_Config();printf(\r\n---------------TIM基本定时器实验----------------\r\n);while(1){}
}最终效果