STM32系列第11篇--定时器

发布者:dst2015最新更新时间:2017-09-22 来源: eefocus关键字:STM32系列  定时器 手机看文章 扫描二维码
随时随地手机看文章

STM32共有8个定时器:

定时器种类位数模式特殊应用场景
高级定时器TIME1、TIME816位向上、向下、向上/下PWM点击控制
通用定时器TIME2~TIME516位向上、向下、向上/下定时计数,PWM输出,输入捕获,输出比较
基本定时器TIME6、TIME716位向上、向下、向上/下驱动DAC

通用定时器功能:

  1. 位于低速的APB1总线上(APB1)

  2. 16 位向上、向下、向上/向下(中心对齐)计数模式,自动装载计数器(TIMx_CNT)。

  3. 16 位可编程(可以实时修改)预分频器(TIMx_PSC),计数器时钟分频。

  4. 4 个独立通道(TIMx_CH1~4),这些通道可以用来作为:输入捕获、输出比较、PWM 生成(边缘或中间对齐模式)、单脉冲模式输出 。

  5. 可使用外部信号(TIMx_ETR)控制定时器和定时器互连(可以用 1 个定时器控制另外一个定时器)的同步电路。

  6. 如下事件发生时产生中断/DMA(6个独立的IRQ/DMA请求生成器): 更新:计数器向上溢出/向下溢出,计数器初始化(通过软件或者内部/外部触发) 、触发事件(计数器启动、停止、初始化或者由内部/外部触发计数) 、输入捕获 、输出比较 等。

通用定时器时钟CK_INT=2*36M=72M 
向上计数模式:计数器从0计数到自动加载值(TIMx_ARR),然后重新从0开始计数并且产生一个计数器溢出事件。

程序要求: 
通过定时器中断配置,每500ms中断一次,然后中断服务函数中控制LED实现LED1状态取反(闪烁)。

Tout(溢出时间)=(ARR+1)(PSC+1)/Tclk

timer.c

#include "timer.h"#include "led.h"//通用定时器3中断初始化//这里时钟选择为APB1的2倍,而APB1为36M//arr:自动重装值。//psc:时钟预分频数//这里使用的是定时器3!void TIM3_Int_Init(u16 arr,u16 psc)
{
    TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
    NVIC_InitTypeDef NVIC_InitStructure;
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); //时钟使能
    //定时器TIM3初始化
    TIM_TimeBaseStructure.TIM_Period = arr; //设置在下一个更新事件装入活动的自动重装载寄存器周期的值
    TIM_TimeBaseStructure.TIM_Prescaler =psc; //设置用来作为TIMx时钟频率除数的预分频值
    TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; //设置时钟分割:TDTS = Tck_tim
    TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  //TIM向上计数模式
    TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); //根据指定的参数初始化TIMx的时间基数单位
    TIM_ITConfig(TIM3,TIM_IT_Update,ENABLE ); //使能指定的TIM3中断,允许更新中断
    //中断优先级NVIC设置
    NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn;  //TIM3中断    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;  //先占优先级0级
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;  //从优先级3级
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道被使能
    NVIC_Init(&NVIC_InitStructure);  //初始化NVIC寄存器 
    TIM_Cmd(TIM3, ENABLE);  //使能TIMx}//定时器3中断服务程序void TIM3_IRQHandler(void)   //TIM3中断{    if (TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET)  //检查TIM3更新中断发生与否
    {
        TIM_ClearITPendingBit(TIM3, TIM_IT_Update  );  //清除TIMx更新中断标志 
        LED1=!LED1;
    }
}12345678910111213141516171819202122232425262728293031323334353637

PWM输出

工作过程: 
这里写图片描述

CCR1:捕获比较(值)寄存器(x=1,2,3,4):设置比较值。 
CCMR1: OC1M[2:0]位: 
对于PWM方式下,用于设置PWM模式1【110】或者PWM模式2【111】 
模式1:计数值小于CCR1值为有效电平 
模式2:计数值大于CCR1值为有效电平 
CCER:CC1P位:输入/捕获1输出极性。0:高电平有效,1:低电平有效。 
CCER:CC1E位:输入/捕获1输出使能。0:关闭,1:打开。

PWM输出配置步骤:

1、使能定时器3和相关IO口时钟。

使能定时器3时钟:RCC_APB1PeriphClockCmd(); 
使能GPIOB时钟:RCC_APB2PeriphClockCmd();

2、初始化IO口为复用功能输出。函数:GPIO_Init();

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;

3、这里我们是要把PB5用作定时器的PWM输出引脚,所以要重映射配置,

所以需要开启AFIO时钟。同时设置重映射。 
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE); 
GPIO_PinRemapConfig(GPIO_PartialRemap_TIM3, ENABLE);

4、初始化定时器:ARR,PSC等:TIM_TimeBaseInit(); 
5、初始化输出比较参数:TIM_OC2Init(); 
6、使能预装载寄存器:

TIM_OC2PreloadConfig(TIM3, TIM_OCPreload_Enable);

7、使能定时器。TIM_Cmd(); 
8、不断改变比较值CCRx,达到不同的占空比效果:TIM_SetCompare2();

程序要求:

使用定时器3的PWM功能,输出占空比可变的PWM波,用来驱动LED灯,从而达到LED【PB5]亮度由暗变亮,又从亮变暗,如此循环。

timer.c

void TIM3_PWM_Init(u16 arr,u16 psc)
{  
    //定义结构体变量
    GPIO_InitTypeDef GPIO_InitStructure;
    TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
    TIM_OCInitTypeDef  TIM_OCInitStructure;  
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);//使能定时器3时钟
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB  | RCC_APB2Periph_AFIO, ENABLE);  //使能GPIO时钟和AFIO复用功能模块时钟
    GPIO_PinRemapConfig(GPIO_PartialRemap_TIM3, ENABLE); //Timer3部分重映射TIM3_CH2->PB5   
    //GPIO初始化,设置该引脚为复用输出功能,输出TIM3 CH2的PWM脉冲波形GPIOB.5
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5; //TIM_CH2
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOB, &GPIO_InitStructure);    //初始化TIM3
    TIM_TimeBaseStructure.TIM_Period = arr; //设置在下一个更新事件装入活动的自动重装载寄存器周期的值
    TIM_TimeBaseStructure.TIM_Prescaler =psc; //设置用来作为TIMx时钟频率除数的预分频值 
    TIM_TimeBaseStructure.TIM_ClockDivision = 0; //设置时钟分割:TDTS = Tck_tim
    TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  //TIM向上计数模式
    TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); //根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位    

    //初始化TIM3 Channel2 PWM模式 
    TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2; //设置PWM模式2
    TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //比较输出使能
    TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; //高电平有效
    TIM_OC2Init(TIM3, &TIM_OCInitStructure);  //根据T指定的参数初始化外设TIM3 OC2    
    TIM_OC2PreloadConfig(TIM3, TIM_OCPreload_Enable);  //使能TIM3在CCR2上的预装载寄存器    
    TIM_Cmd(TIM3, ENABLE);  //使能TIM3}123456789101112131415161718192021222324252627282930

main.c

int main(void)
{   u16 led0pwmval=0;   u8 dir=1;
   delay_init();     //延时函数初始化  
   NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);  //设置NVIC中断分组2:2位抢占优先级,2位响应优先级
   uart_init(115200); //串口初始化为115200
   LED_Init();     //LED端口初始化
   TIM3_PWM_Init(899,0); //不分频。PWM频率=72000000/900=80Khz
   while(1)
   {
       delay_ms(10); 
       if(dir)led0pwmval++;       else led0pwmval--;   
       if(led0pwmval>300)dir=0;       if(led0pwmval==0)dir=1; 
       TIM_SetCompare2(TIM3,led0pwmval);  //设置占空比
   } 
}12345678910111213141516171819

输入捕获:

输入捕获的一般配置步骤: 
① 初始化定时器和通道对应IO的时钟。 
② 初始化IO口,模式为输入:GPIO_Init();

GPIO_InitStructure.GPIO_Mode= GPIO_Mode_IPD; //PA0 输入

③初始化定时器ARR,PSC

TIM_TimeBaseInit();

④初始化输入捕获通道

TIM_ICInit();

⑤如果要开启捕获中断,

TIM_ITConfig(); 
NVIC_Init();

⑥使能定时器:TIM_Cmd();

⑦编写中断服务函数:TIMx_IRQHandler();

实验目的:测量信号的脉冲宽度

//定时器5通道1输入捕获配置TIM_ICInitTypeDef  TIM5_ICInitStructure;
void TIM5_Cap_Init(u16 arr,u16 psc)
{ 
    GPIO_InitTypeDef GPIO_InitStructure;
    TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
    NVIC_InitTypeDef NVIC_InitStructure;
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM5, ENABLE);//使能TIM5时钟
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);  //使能GPIOA时钟
    GPIO_InitStructure.GPIO_Pin  = GPIO_Pin_0;  //PA0 清除之前设置  
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD; //PA0 输入  
    GPIO_Init(GPIOA, &GPIO_InitStructure);
    GPIO_ResetBits(GPIOA,GPIO_Pin_0); //PA0 下拉
    //初始化定时器5 TIM5
    TIM_TimeBaseStructure.TIM_Period = arr; //设定计数器自动重装值 
    TIM_TimeBaseStructure.TIM_Prescaler =psc; //预分频器   
    TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; //设置时钟分割:TDTS = Tck_tim
    TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  //TIM向上计数模式
    TIM_TimeBaseInit(TIM5, &TIM_TimeBaseStructure); //根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位

    //初始化TIM5输入捕获参数
    TIM5_ICInitStructure.TIM_Channel = TIM_Channel_1; //CC1S=01 选择输入端 IC1映射到TI1上
    TIM5_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;//上升沿捕获
    TIM5_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI; //映射到TI1上
    TIM5_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1; //配置输入分频,不分频 
    TIM5_ICInitStructure.TIM_ICFilter = 0x00;//IC1F=0000 配置输入滤波器 不滤波
    TIM_ICInit(TIM5, &TIM5_ICInitStructure);    //中断分组初始化
    NVIC_InitStructure.NVIC_IRQChannel = TIM5_IRQn;  //TIM3中断
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;  //先占优先级2级
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;  //从优先级0级
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道被使能
    NVIC_Init(&NVIC_InitStructure);  //根据NVIC_InitStruct中指定的参数初始化外设NVIC寄存器 
    TIM_ITConfig(TIM5,TIM_IT_Update|TIM_IT_CC1,ENABLE);//允许更新中断 ,允许CC1IE捕获中断
    TIM_Cmd(TIM5,ENABLE ); //使能定时器5}u8  TIM5CH1_CAPTURE_STA=0;//输入捕获状态    u16TIM5CH1_CAPTURE_VAL;//输入捕获值//定时器5中断服务程序 void TIM5_IRQHandler(void)
{ 
    if((TIM5CH1_CAPTURE_STA&0X80)==0)//还未成功捕获
    {  
        if (TIM_GetITStatus(TIM5, TIM_IT_Update) != RESET)
        {    
            if(TIM5CH1_CAPTURE_STA&0X40)//已经捕获到高电平了
            {                if((TIM5CH1_CAPTURE_STA&0X3F)==0X3F)//高电平太长了
                {
                    TIM5CH1_CAPTURE_STA|=0X80;//标记成功捕获了一次
                    TIM5CH1_CAPTURE_VAL=0XFFFF;
                }                else TIM5CH1_CAPTURE_STA++;
            } 
        }        if (TIM_GetITStatus(TIM5, TIM_IT_CC1) != RESET)//捕获1发生捕获事件
        {            if(TIM5CH1_CAPTURE_STA&0X40)//捕获到一个下降沿 
            {  
                TIM5CH1_CAPTURE_STA|=0X80;//标记成功捕获到一次高电平脉宽
                TIM5CH1_CAPTURE_VAL=TIM_GetCapture1(TIM5);
                TIM_OC1PolarityConfig(TIM5,TIM_ICPolarity_Rising); //CC1P=0 设置为上升沿捕获
            }else  //还未开始,第一次捕获上升沿
            {

                TIM5CH1_CAPTURE_STA=0;//清空
                TIM5CH1_CAPTURE_VAL=0;
                TIM_SetCounter(TIM5,0);
                TIM5CH1_CAPTURE_STA|=0X40;//标记捕获到了上升沿
                TIM_OC1PolarityConfig(TIM5,TIM_ICPolarity_Falling);//CC1P=1 设置为下降沿捕获
            }    
        }            
    }
    TIM_ClearITPendingBit(TIM5, TIM_IT_CC1|TIM_IT_Update); //清除中断标志位}

main.cextern u8  TIM5CH1_CAPTURE_STA;//输入捕获状态    extern u16TIM5CH1_CAPTURE_VAL;//输入捕获值int main(void)
{    u32 temp=0; 
    delay_init();     //延时函数初始化  
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //设置NVIC中断分组2:2位抢占优先级,2位响应优先级
    uart_init(115200); //串口初始化为115200
    LED_Init();     //LED端口初始化
    TIM3_PWM_Init(899,0); //不分频。PWM频率=72000/(899+1)=80Khz
    TIM5_Cap_Init(0XFFFF,72-1);//以1Mhz的频率计数 
    while(1)
    {
        delay_ms(10);
        TIM_SetCompare2(TIM3,TIM_GetCapture2(TIM3)+1);        if(TIM_GetCapture2(TIM3)==300)   TIM_SetCompare2(TIM3,0);        if(TIM5CH1_CAPTURE_STA&0X80)//成功捕获到了一次上升沿
        {
            temp=TIM5CH1_CAPTURE_STA&0X3F;
            temp*=65536;//溢出时间总和
            temp+=TIM5CH1_CAPTURE_VAL;//得到总的高电平时间
            printf("HIGH:%d us\r\n",temp);//打印总的高点平时间
            TIM5CH1_CAPTURE_STA=0;//开启下一次捕获
        }
    }
}


关键字:STM32系列  定时器 引用地址:STM32系列第11篇--定时器

上一篇:STM32系列第12篇--电容触摸按键原理
下一篇:STM32系列第10篇--看门狗

推荐阅读最新更新时间:2024-03-16 15:38

KEIL(MDK)同时兼容STM32和51系列单片机的方法
keil4 方法一: 首先安装KEIL4,然后安装KEIL3到MDK相同目录,安装过的就跳过。然后以管理员身份打开KEIL4,用KEIL4的注册机,注册ARM和C51。 破解结果 方法二: 下面这个方法可以让keilMDK兼容51的工程,只要一个keil就都能编译51和stm32的工程了: 1、安装keilC51,并破解,安装目录 T:keilC51 2、安装keilMDK,并破解,安装目录 T:keilMDK 3、把T:keilC51 里面的 C51 文件夹复制到 T:keilMDK 里 4、把 T:keilC51 里面的 UV4 文件夹复制到 T:keilMDK 里,提示有同名文件都不要
[单片机]
8951定时器的定时中断模式
定时器的使用与我之前所说的中断使用差不多。首先也是设置初始化定时器。先上代码: #include reg52.h #define uchar unsigned char #define uint unsigned int sbit led=P1^0; sbit s1=P3^0; sbit s2=P3^1; uchar counter=0; uchar temp=0; uchar flag=0; code uchar a ={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90}; void delay(uint t) { uint i; while(t--) { f
[单片机]
STM32有哪几种定时器 STM32高级定时器有哪些功能
在数字电路中时钟是整个电路的心脏,电路的的一举一动都是根据时钟节拍下进行的,随着信息量逐渐提高,对硬件信息处理能力提出了更大的需求,时钟作为数字硬件的关键成员,其性能需要我们关注,尤其在高速电路设计中对模拟转换芯片对时钟性能有很高的需求,因此正确选择时钟是很关键的一步,前提是我们要了解时钟的关键参数咯。在数字电路中最常见的时钟元件有晶振和锁相环、时钟缓冲器等,本节对外部定时器进行重点讲解。 STM32 定时器专题讲解 SysTick定时器的功能比较单一,主要是供给系统使用的,系统默认设置为1ms触发一次中断。而用户想要使用自己的定时器,STM32提供的用户定时器不但数量多且功能更加强大。不同型号的STM32提供的定时器数量不同
[单片机]
<font color='red'>STM32</font>有哪几种<font color='red'>定时器</font> <font color='red'>STM32</font>高级<font color='red'>定时器</font>有哪些功能
利用STM32定时器实现呼吸灯
实验目标 利用STM32定时器产生PWM信号; 利用PWM信号实现呼吸灯。 什么是PWM信号呢? PWM,英文名Pulse Width Modulation。 PWM信号是一种脉宽调制信号,广范用于LED和电机控制等场合。 PWM信号其实类似于方波,只有0和1两种状态。 PWM信号可以调节占空比。 不同占空比可以使LED产生不同的亮度。 占空比就是指在一个周期内, 信号处于高电平的时间占据整个信号周期的百分比, 例如上图中所示脉冲的占空比就是25%。 PWM波可以由GPIO口产生,通过GPIO口输出高电平,延时,输出低电平,延时来产生PWM波。 还可以使用定时器,利用比较寄存器形成PWM。 本实验就是利用PWM信号这一特性
[单片机]
利用<font color='red'>STM32</font><font color='red'>定时器</font>实现呼吸灯
stm8 16位定时器TIM1
第一步:TIM1概述 STM8S提供三种类型的 TIM 定时器:高级控制型(TIM1)、通用型(TIM2/TIM3/TIM5)和基本型定时器(TIM4/TIM6)。它们虽有不同功能但都基于共同的架构。此共同的架构使得采用各个定时器来设计应用变得非常容易与方便(相同的寄存器映射,相同的基本功能)。STM8S系列的定时器TIM1,TIM5和TIM6之间没有共享任何资源,但是它们可以TIM5/TIM6定时器的同步中的描述来同步和连接。在拥有TIM1,TIM2,TIM3和TIM4定时器的STM8S系列产品中,定时器是没有连接在一起的。 可以看到TIM1是可以向上、向下、向上/向下自动装载的。分频系数为1~65535之间的任意数值。
[单片机]
51单片机(三)——定时器/计数器
一、定时器/计数器 1.1 定时器/计数器概述 51单片机有两个内置定时器/计数器。 当记数脉冲来自于外部输入时,为计算器。而来自于系统时钟时,为定时器。 定时器0有四种模式。定时器1支持三种模式,可以被用来产生波特率。 PCON寄存器里的SMOD0位表示每12时钟或者每6时钟产生一次计数脉冲。 1.2 TCON寄存器 bit B7 B6 B5 B4 B3 B2 B1 B0 name TF1 TR1 TR0 TF0 TR0 IE1 IT1 IE0 TF0和TF1为定时器溢出位、TR0和TR1为运行控制位、其他位用于外部中断。 TR0和TR1: 分别控制定时器0和1的运行,该位置1时才允许定时器计数,清0时
[单片机]
C++ MFC中定时器的使用
用处:定时重绘,形成动态波形图。如温度曲线。 思路:与单片机定时器中断一样,先打开定时器再把执行的代码写进编译器生成的CMy56Dlg::OnTimer(UINT nIDEvent)函数中。 其中 nIDEvent 中的n代表定时器的编号;通常与switch-case语句构成多个定时器的同时使用。 步骤: 一.通过类向导在对话框基类中添加 OnTimer子类。步骤:【查看】-【类向导】-【Messagemaps】-【CMy**Dlg】-【message】-【WM_timer】编译后CMyDlg类此时会自动添加一个 OnTimer(UINT nIDEvent)子类。并添加一个响应函数 void CMy56Dlg::OnTimer(U
[单片机]
可由CR设定数微秒~数十秒时间的通用定时器
电路的功能 如果定时脉冲的精度要求不要高,可使用CR充放电式定时器,只要改变CR参数,就能产生很宽的脉冲。 555定时IC是一种早期的单稳态多谐振振荡器IC,现在仍被广泛应用,主要用作单稳态多谐振振荡器和自激多谐振荡。 电路工作原理 输入触发信号电平低于电源电压的1/3时,内部比较器开始工作,触发电路被触发,放电晶体管断开,电容C1被充电电压超过VCC的2/3时,比较器再次工作,放电晶体管管把C1中积蓄的电荷放掉,然后等待下次触发,脉冲宽幅度YW由TW=1.1C1.R1确定。 虽然电阻误差为1%左右,但对CR常数偏差的影响较大,若把电阻R1的一部分必用可变电阻,便可得到准确的脉冲宽度。例如,为了产生100
[工业控制]
可由CR设定数微秒~数十秒时间的通用<font color='red'>定时器</font>
小广播
添点儿料...
无论热点新闻、行业分析、技术干货……
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved