你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

STM32之定时器配置

[复制链接]
STMCU小助手 发布时间:2022-12-24 17:40
定时器的配置部分可以分为两个部分:初始化NVIC(中断优先级设置)和初始化定时器,下面我们来分别说明。

中断系统NVIC
这一部分要明确中断优先级的概念:stm32将优先级分为抢占优先级和响应优先级,相应的在初始化每个中断源时,都需要设定这两个优先级!!!

抢占优先级:决定中断是否可嵌套,高抢占优先级可嵌套低抢占优先级,如果抢占优先级相同,则中断没有嵌套关系。
响应优先级:抢占优先级相同且两个中断同时到达的条件下,响应优先级的高低可决定先处理哪一个中断(高者在前);抢占优先级相同但是两个中断不同时到达,则不管响应优先级的高低,都要等先发生的中断处理完才可以接着处理后到来的中断。
在优先级分组的表格中,序号越小,优先级越高。
stm32的优先级分组: 共分为5组 (NVIC_PriorityGroup_0到NVIC_PriorityGroup_4),抢占优先级数从小到大,响应优先级数从大到小,其中:NVIC_PriorityGroup_0无抢占优先级,NVIC_PriorityGroup_4无响应优先级。
响应优先级无要求的情况下:初始化时将优先级分组设置为NVIC_PriorityGroup_4的方式(只设置抢占优先级),或者不设置优先级分组(系统默认优先级),一般情况下把响应优先级也设置为0。
初始化NVIC主要是初始化四个部分:中断通道、抢占优先级、响应优先级、通道使能,这四个部分我们也能在相关的库函数(misc.h)中找到定义:

20190418171732130.png

代码部分:
  1. void NVIC_TIM4Enable(void)
  2. {
  3.         NVIC_InitTypeDef NVIC_InitStructure;
  4.        
  5.         NVIC_InitStructure.NVIC_IRQChannel = TIM4_IRQn;//选择中断通道TIM4
  6.     NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;//设定抢占优先级为0
  7.     NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;//设定响应优先级为0
  8.     NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;//使能中断通道
  9.     NVIC_Init(&NVIC_InitStructure);//调用NVIC初始化函数
  10. }
复制代码


做几点说明:
我们没有用到中断的嵌套,所以把抢占优先级也设置为0;
关于中断通道:stm32使用了Cortex-M3中的84个中断通道,(16个异常,68个中断)具体的相关信息可以在中文手册中查找到。

初始化定时器
stm32(STM32F103ZET6功能较为全面的一种)内部含有11个定时器:2个高级控制定时器(TIM1和TIM8)、4个通用定时器(TIMX:TIM2、TIM3、TIM4、TIM5)、2个基本定时器(TIM6和TIM7),他们的功能性是依次减少的,具体信息也可查手册获得(一定要利用好手册!!!),下面贴出:

高级控制定时器:

2019041816483539.png

通用定时器(TIMX):

20190418165334904.png

基本定时器:


20190418165552861.png

NIOTICE!!!注意:当计数模式为向上计数时:是从0开始向上计数,一直到计数值和重装载寄存器的数值相等时,计数器会自动归零,并产生一个溢出事件(也就是触发一次中断),这点是和51不同的。

关于预分频系数: 51单片机的学**,我们知道定时器的数值是每经过一个时钟周期自动加一的,但在32中我们可以通过设定预分频系数(N),使得定时器每经过(N+1)个时钟周期自动加一,这里为什么是N+1个时钟周期加一呢?因为我们的分频系数是从0开始的,假设设定预分频系数是3,那么实际上(0-3)总共是4个数,也就是4分频。
在开始定时器的配置之前,我们首先要使能时钟:先看一下定时器是挂接在哪条总线上的,可在手册中系统构架部分找到总的构架图:

2019041817240992.png

可以看到除TIM1外的定时器都是挂接在APB1总线上的,所以我们要使能定时器时钟就要使能APB1外设时钟寄存器,看一下函数定义:

20190418172645953.png

定时器的配置主要配置4个部分:自动重装载寄存器数值、预分频系数、时钟分割(一般的定时功能用不到,可设为0)、计数模式, 同样的,我们可以在库函数(stm32f10x_tim.h)中找到相关的结构体定义:



配置完定时器之后,我们还需要清除中断标志位(emmm,一般情况下好像没什么影响):用到的函数:

20190418173210368.png

TIMX:是写明用到哪个中断;TIM_IT:表示中断源类型
关于中断源类型: stm32有6种中断源类型,在相应的库函数(stm32f10x_tim.h)里也可以找到定义:

20190418173932662.png

我们的程序里用到的是更新事件中断(TIM_IT_Update)
使能定时器: 可以理解为51中的(TR0 = 1)这行代码,就是开启定时器,同样的,一旦使能了定时器,就会开始计数。 用到的函数:

20190418174454176.png

开启中断(中断初始化): 相当于(ET0 = 1)这行代码,用到的函数:

20190418174515446.png

加入中断优先级设置部分的代码后就是完整的定时器配置的内容了,下面给出的代码中把两者写入了一个函数,读者也可以分两个函数来写:
  1. #include "stm32f10x.h"

  2. void TIM4_Init(u32 period, u32 prescaler)//period-计数周期(实际值),prescaler-预分频值(实际值)
  3. {
  4.     TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
  5.     NVIC_InitTypeDef NVIC_InitStructure;
  6.     RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE);//使能TIM4时钟
  7.     /*没有设置优先级分组,使用系统默认优先级*/
  8.     NVIC_InitStructure.NVIC_IRQChannel = TIM4_IRQn;//选择中断通道TIM4
  9.     NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;//设定抢占优先级为0
  10.     NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;//设定响应优先级为0
  11.     NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;//使能中断通道
  12.     NVIC_Init(&NVIC_InitStructure);//调用NVIC初始化函数
  13.    
  14.     TIM_TimeBaseStructure.TIM_Period = period - 1;//设定自动重装载计数值
  15.     TIM_TimeBaseStructure.TIM_Prescaler = prescaler - 1;//设定预分频系数
  16.     TIM_TimeBaseStructure.TIM_ClockDivision = 0;//基本定时器没有预分频功能,此项会被忽略
  17.     TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;//设置计数模式为向上计数
  18.     TIM_TimeBaseInit(TIM4, &TIM_TimeBaseStructure);//初始化TIM4
  19.    
  20.     TIM_Cmd(TIM4, ENABLE);//使能TIM4定时器
  21.     TIM_ITConfig(TIM4, TIM_IT_Update, ENABLE);//使能TIM4中断
  22. }
复制代码

说明:
为什么自动重装载计数值是实际值减一呢? 这个其实和上面我们解释的预分频值是一样的,因为计数值是从0开始计数的,假设我们想要计1000个值就归0,那么我们只需要从0计到999就可以了,也就是说自动重装载寄存器的数值要是999(1000-1)。

实战:(利用定时器实现L1一秒闪烁)

stm32f10x_it.c文件

  1. void TIM4_IRQHandler(void)//每次产生一个中断溢出事件就会进入一次中断函数
  2. {
  3.     if (TIM_GetITStatus(TIM4, TIM_IT_Update) == SET)//检测是否为溢出中断
  4.     {
  5.         TIM_ClearITPendingBit(TIM4, TIM_IT_Update);//清除中断标志位,否则启动时会进入中断服务函数
  6.         
  7.         GPIOC->ODR ^= (1 << 8);
  8.         GPIOD->ODR |= (1 << 2);
  9.         GPIOD->ODR &= ~(1 << 2);
  10.     }
  11. }
  12. 、、、
复制代码


main.c文件

  1. #include "stm32f10x.h"
  2. #include "led.h"
  3. #include "timer.h"

  4. u32 TimingDelay = 0;

  5. void Delay_Ms(u32 nTime);

  6. //Main Body
  7. int main(void)
  8. {
  9.     SysTick_Config(SystemCoreClock/1000);
  10.    
  11.         LED_Init();
  12.     TIM4_Init(10000, 7200);//定时1S
  13.    
  14.         while(1)
  15.     {
  16.    
  17.     }
  18. }

  19. void Delay_Ms(u32 nTime)
  20. {
  21.         TimingDelay = nTime;
  22.         while(TimingDelay != 0);       
  23. }

复制代码

注意!!!!:

中断服务函数官方规定统一写在(stm32f10x_it.c)这个文件里,(emmm,当然也可以写在别的文件里)。
定时时间的计算公式:预装载值(period) /(72M /预分频值(prescaler )) ;
时钟频率为72M,那么一个时钟周期就是:1/72M;
计一个数需要的时间:预分频值*(1/72M);
定时时间:预装载值(period)* 预分频值*(1/72M);也可以写为:预装载值(period) /(72M /预分频值(prescaler ))
1s定时:10000(period)/72000000/7200(prescaler) = 1s。
一个快速写底层的方法:
理解之后,可以参照stm32固件库里的底层参考例程,用到哪些地方就粘贴那一部分的内容,只需要改变里面的参数即可:
底层文件查找路径:stm32固件库->STM32F10x文件->Project->STM32F10x_StdPeriph_Examples

20190418183757850.png

————————————————
版权声明:ReRrain


20190418163128855.png
收藏 评论0 发布时间:2022-12-24 17:40

举报

0个回答
关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版