历史上的今天
返回首页

历史上的今天

今天是:2024年12月03日(星期二)

正在发生

2018年12月03日 | STM32基本定时器TIM6和TIM7

2018-12-03 来源:eefocus

1. STM32上定时器的分类


前面学习了STM32系统定时器SysTick,它的主要作用是为OS提供系统滴答,当然我们也可以利用它实现了精准延时。在STM32单片机中,除了属于CM3内核中的一个外设的系统定时器外,还有几个属于片上外设的定时器:基本定时器(TIM6和TIM7)、通用定时器(TIM2/3/4/5)和高级定时器(TIM1和TIM8)。强调,这里指的是除互联型的STM32F1系列单片机。 


这里写图片描述


它们各自具有的功能特点可以详见《STM32中文参考手册_V10.pdf》-P298,这里简单描述: 


(1)基本定时器(TIM6和TIM7):16位的只能向上计数的定时器,只能实现定时,没有外部IO通道与它关联。 


(2)通用定时器(TIM2/3/4/5):16位的可向上或者向下、向上/向下的定时器,除了能实现定时功能,还可以实现输入捕获、输出比较功能(PWM),每个定时器有4个外部IO通道与它关联。 


(3)高级定时器(TIM1和TIM8):16位的可向上或者向下、向上/向下的定时器,除了能实现定时功能,还可以实现输入捕获、输出比较功能(PWM)、输出互补等专用功能,每个定时器有4个外部IO通道与它关联。 


这里写图片描述


今天先学习基本定时器。 


个人在学习定时器时的想法:定时超时能产生中断信号,本能反应,它涉及到中断编程就有可能涉及到设置NVIC(中断源优先级相关)和EXTI(外部中断/事件线EXTI0/1…/15相关),在前面实现SysTick定时编程中,由于SysTick并非片上外设所以并不需要设置NVIC,而STM32中非SysTick的定时器都属于片上外设,所以自然是要设置NVIC;EXTI是设置外部中断/事件线的,它必须关联于某个对应的IO引脚,在SysTick定时编程中不需要设置,在这里同样不需要设置。


2. 基本定时器的时基


定时器的基本功能是定时,定时的核心则是时基,看基本定时器的框图, 


这里写图片描述


2.1 时钟源CK_INT


定时器的学习,从时钟源说起,也就是图中的TIMxCLK。在时钟树中, 

 

这里写图片描述 


定时器2~7的时钟源是这样确定的:如果PCLK1的预分频系数为1,则它们的时钟源为PCLK1,否则它们的时钟源为PCLK1的2倍。PCLK1在前面的配置中,已经将APB1的预分频系数设置为2,即PCLK1为36MHz,所以定时器2~7的时钟源 = TIMxCLK = 72MHz。


2.2 计数器时钟CK_CNT


TIMxCLK经过PSC预分频器之后为CK_INT,作为CNT计数器的计数时钟。PSC可以对定时器时钟TIMxCLK进行1~65535之间任何一个数进行分频,CK_CNT = TIMxCLK / (PSC + 1)。PSC的值设置于TIMx_PSC寄存器。


2.3 计数器CNT


CNT是一个16位的计数器,只能往上递增计数,不能超过65535,当计数达到自动重装载寄存器里的数值时产生更新事件,CNT清零并从头开始计数,如果使能了中断的话,定时器还会产生溢出中断。使能的中断项有TIM_IT_Update等,详细见下面TIM_ITConfig()函数的讲解。CNT的值设置于TIMx_CNT寄存器。


2.4 自动重装寄存器ARR


ARR是一个16位的寄存器,里面装着计数器能计数的最大数值。ARR值设置于TIMx_ARR寄存器。


2.5 定时时间的计算


了解了定时器的运行时基,定时时间计算就很容易了。定时器的定时时间等于计时器的中断产生周期乘以中断的次数。定时器计一个数的时间是1 / CK_CNT,产生一次中断需要的时间是ARR / CK_CNT,利用产生多次中断即可延时多个中断产生所需要的时间。


定时器还有TIMx_CR1和TIMx_CR2控制寄存器、TIMx_DIER中断使能寄存器、TIMx_SR状态寄存器,TIMx_EGR事件产生寄存器,具体意义详见参考手册,因为是使用标准库编程,所以不再赘述。


编程常用的库函数有: 


(1)使能/失能定时器中断


TIM_ITConfig(TIM_TypeDef* TIMx, uint16_t TIM_IT, FunctionalState NewState)

1

参数1:TIMx的取值为TIM[1…8] 

参数2:表示超时后产生的中断类型,有更新事件中断TIM_IT_Update、TIM_IT_CCx[x=1..4]、TIM_IT_COM、TIM_IT_Trigger、TIM_IT_Break 

基本定时器定时取TIM_IT_Update即可。 

参数3:NewState即为DISABLE / ENABLE 


(2)清除中断标志位


void TIM_ClearITPendingBit(TIM_TypeDef* TIMx, uint16_t TIM_IT)

1

参数1:TIMx的取值为TIM[1…8] 

参数2:表示超时后产生的中断类型,有更新事件中断TIM_IT_Update、TIM_IT_CCx[x=1..4]、TIM_IT_COM、TIM_IT_Trigger、TIM_IT_Break 


(3)使能/失能计数器


void TIM_Cmd(TIM_TypeDef* TIMx, FunctionalState NewState)

1

参数1:TIMx的取值为TIM[1…8] 

参数2:NewState即为DISABLE / ENABLE 


(4)开启/关闭定时器的时钟


void RCC_APB1PeriphClockCmd(uint32_t RCC_APB1Periph, FunctionalState NewState)

1

定时器6是挂接在APB1总线上的,所以要开启该定时器的时钟需要调用RCC_APB1PeriphClockCmd函数 

参数1:


RCC_APB1Periph_TIM2, RCC_APB1Periph_TIM3, RCC_APB1Periph_TIM4,

RCC_APB1Periph_TIM5, RCC_APB1Periph_TIM6, RCC_APB1Periph_TIM7,

RCC_APB1Periph_WWDG, RCC_APB1Periph_SPI2, RCC_APB1Periph_SPI3,

RCC_APB1Periph_USART2, RCC_APB1Periph_USART3, RCC_APB1Periph_USART4, 

RCC_APB1Periph_USART5, RCC_APB1Periph_I2C1, RCC_APB1Periph_I2C2,

RCC_APB1Periph_USB, RCC_APB1Periph_CAN1, RCC_APB1Periph_BKP,

RCC_APB1Periph_PWR, RCC_APB1Periph_DAC, RCC_APB1Periph_CEC,

RCC_APB1Periph_TIM12, RCC_APB1Periph_TIM13, RCC_APB1Periph_TIM14可选


参数2:NewState即为DISABLE / ENABLE


3. 基本定时器描述结构体


在标准外设库中的stm32f10x_tim.h中有对定时器描述的4个结构体: 


(1)时基初始化结构体TIM_TimeBaseInitTypeDef 


(2)输出比较功能初始化结构体TIM_OCInitTypeDef 


(3)输入捕获功能初始化结构体TIM_ICInitTypeDef 


(4)刹车和死区功能初始化结构体TIM_BDTRInitTypeDef 


基本定时器需要用到的描述结构体只是第(1)个TIM_TimeBaseInitTypeDef:


typedef struct

{

  uint16_t TIM_Prescaler;        //预分频器

  uint16_t TIM_CounterMode;      //计数模式,向上/向下

  uint16_t TIM_Period;           //定时器周期

  uint16_t TIM_ClockDivision;    //时钟分频

  uint8_t TIM_RepetitionCounter; //重复计数器,利用它可以控制pwm个数,高级定时器用

} TIM_TimeBaseInitTypeDef;   


(1)TIM_Prescaler:定时器预分频设置,定时器的时钟是经过预分频后时钟源CK_INT,它操作的是TIMx_PSC寄存器的值,可设置的范围为0~65535,注意TIMx_PSC会自动对设置值加1,所以实现的是1~65536分频 

(2)TIM_CounterMode:定时器计数方式,取值可为:


#define TIM_CounterMode_Up                 ((uint16_t)0x0000)   //向上

#define TIM_CounterMode_Down               ((uint16_t)0x0010)   //向下    

#define TIM_CounterMode_CenterAligned1     ((uint16_t)0x0020)   //中间对齐1

#define TIM_CounterMode_CenterAligned2     ((uint16_t)0x0040)   //中间对齐2

#define TIM_CounterMode_CenterAligned3     ((uint16_t)0x0060)   //中间对齐3


基本定时器只能向上计数,即TIMx_CNT只能从0开始递增,所以不需要对此值进行初始化 

(3)TIM_Period:定时器周期,即设定自动重装载寄存器TIMx_ARR的值。设置值的范围是0~65536 

(4)TIM_ClockDivision:时钟分频设置,设置定时器时钟CK_INT频率与数字滤波器采样时钟频率分拼比,基本定时器没有这功能,不管 

(5)TIM_RepetitionCounter:重复计数器,高级定时器TIM1和TIM8才具有的功能,控制输出PWM波的输出个数 

TIM_TimeBaseInitTypeDef结构体虽然有5个成员,但是对于基本定时器只需要设置TIM_Prescaler和TIM_Period。


4. 编程实践


实现功能:利用基本定时器TIM6定时1S,超时则反转两个板载LED灯的状态。 


(1)开启TIM6定时器的时钟 


(2)初始化定时器时基描述结构 


(3)使能TIM6的更新中断 


(4)开启定时器 


(5)中断服务函数 


硬件平台是正点原子的miniSTM32开发板。


BaseTIM.h:


#ifndef __BASETIM_H__

#define __BASETIM_H__


#include "stm32f10x_conf.h"


void Led_CfgInit(void);

void BaseTIM_CfgInit(void);

void NVIC_CfgInit(void);


#endif /* __BASETIM_H__ */


main.c中,初始化外接LED灯的GPIO:


//PA8-->LED0,PD2-->LED1

void Led_CfgInit(void)

{

    GPIO_InitTypeDef GPIO_InitTypeStu;


    //开启PA和PD的时钟

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOD, ENABLE);


    //PA8为推挽输出

    GPIO_InitTypeStu.GPIO_Mode = GPIO_Mode_Out_PP;

    GPIO_InitTypeStu.GPIO_Pin = GPIO_Pin_8;

    GPIO_InitTypeStu.GPIO_Speed = GPIO_Speed_50MHz;

    GPIO_Init(GPIOA, &GPIO_InitTypeStu);

    GPIO_SetBits(GPIOA,GPIO_Pin_8);             //初始化灭灯


    //PD2为推挽输出

    GPIO_InitTypeStu.GPIO_Pin = GPIO_Pin_2;

    GPIO_Init(GPIOD, &GPIO_InitTypeStu);

    GPIO_ResetBits(GPIOD,GPIO_Pin_2);           //初始化亮灯

}


初始化定时器的时基描述结构体:


//设置中断产生间隔为1ms,CLK_INT=72,预分频系数 = 1000

void BaseTIM_CfgInit(void)

{

    TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStu;


    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM6, ENABLE); 


    TIM_TimeBaseInitStu.TIM_Prescaler = 1000;           //预分频系数

    TIM_TimeBaseInitStu.TIM_Period = 72 - 1;            //重装载值  

    TIM_TimeBaseInit(TIM6, &TIM_TimeBaseInitStu);


    //注意要开启定时器中断,这里使用更新事件中断

    TIM_ITConfig(TIM6, TIM_IT_Update, ENABLE);


    //开启计数器

    TIM_Cmd(TIM6, ENABLE);

}


初始化NVIC结构体:


void NVIC_CfgInit(void)

{

    NVIC_InitTypeDef NVIC_InitStu;

    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);     //设置中断分组寄存器

    NVIC_InitStu.NVIC_IRQChannel = TIM6_IRQn;           //外部中断线,定时器6

    NVIC_InitStu.NVIC_IRQChannelCmd = ENABLE;

    NVIC_InitStu.NVIC_IRQChannelPreemptionPriority = 1; //抢占优先级

    NVIC_InitStu.NVIC_IRQChannelSubPriority = 1;        //子优先级

    NVIC_Init(&NVIC_InitStu);

}


主函数实现模块函数的调用及阻塞:


int main(void)

{

    Led_CfgInit();  


    BaseTIM_CfgInit();

    NVIC_CfgInit();


    while(1)

    {

        while (nTime < 1000);       //1000次中断需要经历1s,超时反转led灯

        GPIO_WriteBit(GPIOD, GPIO_Pin_2, ((BitAction)!GPIO_ReadInputDataBit(GPIOD, GPIO_Pin_2)));

        GPIO_WriteBit(GPIOA, GPIO_Pin_8, ((BitAction)!GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_8)));

        nTime = 0;

    }

    return 0;

}


在stm32f10x_it.c中实现定时器超时的中断处理函数:


void TIM6_IRQHandler(void)

{

    //判断是否为定时器6的更新中断

    if (TIM_GetITStatus(TIM6, TIM_IT_Update) != RESET)

    {

        nTime++;


        //注意要清除中断标志

        TIM_ClearITPendingBit(TIM6, TIM_IT_Update);

    }   

}


注意如果没有在中断服务函数中清除中断标志,那么中断服务函数会被cpu反复执行,也就是说接下来的其他操作将永远得不到cpu资源。


推荐阅读

史海拾趣

台湾固锝(GD)公司的发展小趣事
对于需要低噪声的应用场景,应选择低噪声的放大器芯片,并合理设计电路以减少噪声。
芯联(CHIPLINK)公司的发展小趣事

在芯片短缺的大背景下,一家名为芯联集成的公司凭借其敏锐的市场洞察力和快速响应能力,迅速调整战略,专注于车规级IGBT芯片和模组的代工生产。公司凭借高效的生产能力和严格的质量控制,迅速获得了多家头部新能源车企的认可,成为他们的合作伙伴。这一举措不仅帮助芯联集成度过了行业低谷,还使其在短时间内实现了跨越式发展。

晨晶电子(Chenjing Electronics)公司的发展小趣事

晨晶电子自成立以来,始终坚持以技术创新为核心竞争力。公司拥有一支高素质的研发团队,致力于石英晶体元器件的研发与生产。通过不断的技术创新和产品升级,晨晶电子在行业内逐渐树立了技术领先的地位。其产品广泛应用于通信、计算机、消费电子等领域,赢得了众多客户的信赖和好评。

国芯佳品公司的发展小趣事

晨晶电子自成立以来,始终坚持以技术创新为核心竞争力。公司拥有一支高素质的研发团队,致力于石英晶体元器件的研发与生产。通过不断的技术创新和产品升级,晨晶电子在行业内逐渐树立了技术领先的地位。其产品广泛应用于通信、计算机、消费电子等领域,赢得了众多客户的信赖和好评。

台湾义隆电子(ELAN)公司的发展小趣事

作为一家有社会责任感的企业,义隆电子一直关注可持续发展问题。公司积极推广绿色生产理念,采取环保措施减少生产过程中的污染排放。同时,义隆电子还关注社会公益事业,积极参与各种慈善活动,回馈社会。这些举措不仅提升了公司的品牌形象,也为公司的长期发展奠定了坚实基础。

请注意,以上故事框架仅供参考,具体的故事内容需要根据义隆电子的实际情况进行撰写。

B+B SmartWorx公司的发展小趣事

B+B SmartWorx始终坚持以客户为中心,通过提供优质的产品和服务来满足客户需求。公司相信,客户满意度和产品创新是驱动其增长的关键因素。因此,B+B SmartWorx在设计和制造网络连接设备时,始终注重设备的易用性、可管理性和可靠性。这种对客户的深度理解和持续创新,使得B+B SmartWorx在电子行业中赢得了良好的声誉,并实现了持续稳健的发展。

这些故事基于B+B SmartWorx的发展历程和现有信息,虚构了一些具体情节,旨在展现该公司在电子行业中的成长与变迁。请注意,这些故事可能并不完全准确反映B+B SmartWorx的实际发展情况,如需了解更多关于该公司的具体信息,建议查阅相关官方资料或新闻报道。

问答坊 | AI 解惑

关于S3C2410裸机驱动LCD的问题

/************************************************************** 320×240 16Bpp TFT LCD功能模块初始化 **************************************************************/ void Lcd_Init(void) {         rLCDCON1=( ...…

查看全部问答>

别人的导航软件的手写输入在我定制的CE平台上识别不了,为什么?跟平台定制有关没?CE组件没加?

别人的导航软件的手写输入在我定制的CE平台上识别不了,为什么?跟平台定制有关没?CE组件没加?…

查看全部问答>

nand drive 问题

nand cach write/read 命令是自动连续读写nand 如果用这个命令后遇到坏blcok 怎么办?nand 自己会跳过吗? 谢谢…

查看全部问答>

请教KEIL中如何输入“%”,我输入就会出现错误

如题,这问题该怎么解决啊?哪位高手知道指点指点啊!谢谢了!…

查看全部问答>

wince5.0下直接读写内存

想在wince5.0下直接读写内存,往指定的空间读写数据,该怎么实现,忘达人们给点建议!!谢谢!!…

查看全部问答>

分析一个程序错误!

module delay_line(start,stop,up_out,upQ,down_out,downQ,clk,reset);input clk,start,stop,reset;reg [60:0]up_out,down_out,upQ,downQ;integer i,j,m,n;delay_unit du0(start,reset,up_out[0]);delay_unit du2(stop,reset,down_out[0]);always @ ...…

查看全部问答>

LM3S8962学习(四) -- 温度传感器

上次使用学习了一下Timer,每隔1秒钟中断一次,现在准备实现每隔1S钟读取一下内部的温度值,并在LCD上显示出来。   从手册288页上可以看出,LM3S8962的内部温度传感器有两个目的: 1.  防止温度过高或过低,影响系统芯片正常运行 ...…

查看全部问答>

大家来说说用DSP的时候你都遇到过什么样无法解决的问题

大家来说说用DSP的时候你都遇到过什么样无法解决的问题?…

查看全部问答>

超级给力DIY钢铁侠MK3方舟反应堆

从《钢铁侠1》到《复仇者联盟》再到《钢铁侠3》,托尼胸前的反应堆,也更新了好几代。高中刚毕业,放假在家,就有了想自己做一个反应堆的想法,然后就开始实践了。 ◆ 第一步:采购原材料(具体如下)      ● 网上定制的亚 ...…

查看全部问答>

∑ -μ01 HELP2416 入门分享

本帖最后由 DavidZH 于 2014-7-9 00:05 编辑 已经收到的HELP2416开发板,很精致。准备开始学习,按照以往学习其他MCU的经验,先是了解开发板的硬件,然后开始收集相关资料,如下图所示: 一、HELP2416的主芯片是S3C2416 芯片,其内核属于ARMv5 ...…

查看全部问答>