zoukankan      html  css  js  c++  java
  • STM32F4 TIM(外设定时器)

    TIM概述

      外设定时器除了和系统定时器一样具有基本定时功能外,还具有PWM(Pulse width modulation)输出的功能,stm32f4的外设定时器非常多,一 共有14个,分为2个高级控制定时器、10 个通用定时器 和 2 个基本定时器:
        1.高级控制定时器(TIM1和TIM8),挂载到APB2:具有16位定时器功能,具有4通道、输入捕获、PWM输出高级控制功能;
        2.通用定时器(TIM2到TIM5),挂载到APB1:具有16或32位定时功能,具有4通道、输入捕获、PWM输出控制功能;
          通用定时器(TIM9到TIM14),挂载到AP1或APB2:具有16位定时功能,具有2通道、输入捕获、PWM输出控制功能;
        3.基本定时器(TIM6和TIM7),挂载到APB1:具有16位定时功能。

    定时计算

      对于TIM的外设定时器的时钟频率,需要注意参考手册RCC章节中如下两句话

    STM32F405xx/07xx 和 STM32F415xx/17xx 的定时器时钟频率由硬件自动设置。分为两种
    情况:
    1. 如果APB预分频器为1,定时器时钟频率等于APB域的频率。
    2. 否则,等于APB域的频率的两倍 (×2)。
    

      而在函数SetSysClock中可以看到,APB1=1/4 x AHB,APB2=1/2 x AHB,也就是挂载在APB下的TIM,其时钟频率为对应的APB时钟频率的两倍,而外设TIM也不会对所得到时钟频率进行再次分频才使用,而是直接使用。但是在使用PWM输出/比较或定时功能时需要使用预分频器对其分频,从TIM的框图中可以看出:

    实验程序1

      通过原理图发现LED4的引脚连接了TIM14的通道1,便可以通过TIM14通道1实现呼吸灯。
    led.c

    #include "stm32f4xx.h"
    #include "common.h"
    #include "led.h"
    
    void breathinglight_init()
    {
            GPIO_InitTypeDef 	GPIO_InitStructure ;
            TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
            TIM_OCInitTypeDef  TIM_OCInitStructure;        
    	//初始化对应端口的引脚 
    	GPIO_InitStructure.GPIO_Pin  = LED_PIN_4;//指定第9根引脚 
    	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF ;//配置为复用模式
    	GPIO_InitStructure.GPIO_Speed =GPIO_Speed_50MHz ;//配置引脚的响应时间=1/50MHz 
    	GPIO_InitStructure.GPIO_OType = GPIO_OType_PP ;//推挽的输出模式,增加输出电流和灌电流的能力
    	GPIO_InitStructure.GPIO_PuPd  = GPIO_PuPd_NOPULL ;//不使能内部上下拉电阻
    	GPIO_Init(LED_PORT2,&GPIO_InitStructure);
    	
    	//将LED4的引脚连接到TIM14
    	GPIO_PinAFConfig(LED_PORT2, LED4_PinSource, GPIO_AF_TIM14);
    
    	//配置TIM14的相关参数:计数值(决定定时时间)、分频值
    	//TIM14的硬件时钟频率=AHBCLK/4*2=APB1CLK*2=84000000Hz
            //设置预分频器为8400:84000000/8400
    	//只要进行10000次计数,就是1秒时间的到达,也就是1Hz的频率输出
    	TIM_TimeBaseStructure.TIM_Period = 10000/200-1;//如:计数值10000/100-1,决定了输出频率为100Hz,计数值为10000/50-1,频率为50Hz
    	TIM_TimeBaseStructure.TIM_Prescaler = 8400-1;//预分频,也就是第一次分频,当前8400分频,就是84MHz/8400
    	TIM_TimeBaseStructure.TIM_ClockDivision = 0;//时钟分频,也称之二次分频这个F407是不支持的,因此该参数是不会生效的
    	TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;//就是从0开始计数,然后计数到TIM_Period
    	TIM_TimeBaseInit(TIM14, &TIM_TimeBaseStructure);
    	
    	//占空比的配置
    	TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;//工作在PWM1模式,当计时器值小于比较器设定值时则输出脚此时输出有效电位。
    	TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;	//脉冲的输出开关,当前是输出脉冲
    	TIM_OCInitStructure.TIM_Pulse = 25;//这个值是决定了占空比,配置比较值,现在的输出占空比为50%
    	TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;//有效电平为高电平
    
    	//TIM14的通道1配置
    	TIM_OC1Init(TIM14, &TIM_OCInitStructure);
    	//使能定时器14工作
    	TIM_Cmd(TIM14, ENABLE);
    }
    

    led_test.c

    #include "led_test.h"
    #include "sys_tick.h"
    
    void breathinglight_test()
    {
    	uint32_t pwm = 50;
    	uint32_t flag = 0;
            while(1)
    	{
    		//设置TIM14的通道1比较值为20,亮度高
    		if (0 == flag)
    		{
    			TIM_SetCompare1(TIM14, pwm);//设置TIM14通道1的比较值
    			pwm  = pwm  - 1;
    			if (pwm <= 0)
    			{
    				flag = 1;
    			}
    		}
    		delay_ms(50);
    		if (1 == flag)
    		{
    			TIM_SetCompare1(TIM14,l);
    			pwm = pwm  + 1;
    			if (pwm >= 50)
    			{	
    				flag = 0;
    			}
    		}
    	}
    }
    

    main.c

    #include "hwconf.h"
    #include "led.h"
    #include "led_test.h"
    
    int main()
    {
        init_board(); //初始化相关时钟
        breathinglight_init();
        breathinglight_test();
    }
    

    实验程序2

      使用TIM3的定时器中断功能实现LED4闪烁。
    tim.c

    #include "stm32f4xx.h"
    #include "tim.h"
    
    void tim3_init()
    {
    	TIM_TimeBaseInitTypeDef  TIM_TimeBaseStruct;
    	NVIC_InitTypeDef 	NVIC_InitStruct;
    
    	TIM_TimeBaseStruct.TIM_Period = 10000/2-1;//计数值5000-1,决定了定时时间500ms,即频率为2Hz
    	TIM_TimeBaseStruct.TIM_Prescaler = 8400-1;//预分频,也就是第一次分频,当前8400分频,就是84MHz/8400
    	TIM_TimeBaseStruct.TIM_ClockDivision = 0;
    	TIM_TimeBaseStruct.TIM_CounterMode = TIM_CounterMode_Up;
    	TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStruct);
    	
    	//配置TIM3的中断触发方式:时间更新中断
    	TIM_ITConfig(TIM3,TIM_IT_Update , ENABLE);
    
    	//配置TIM3的优先级
    	NVIC_InitStruct.NVIC_IRQChannel = TIM3_IRQn;
    	NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 0;
    	NVIC_InitStruct.NVIC_IRQChannelSubPriority = 1;
    	NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
    	NVIC_Init(&NVIC_InitStruct);
    	
    	//使能定时器3工作
    	TIM_Cmd(TIM3, ENABLE);
    }
    

    main.c

    #include "hwconf.h"
    #include "common.h"
    #include "led.h"
    #include "tim.h"
    
    void main()
    {
        init_board();//初始化相关时钟
        led4_init();//初始化LED4
        tim3_init();
    }
    
    void TIM3_IRQHandler(void)
    {
    	//检测是否超时时间到达
    	if(TIM_GetITStatus(TIM3,TIM_IT_Update)==SET)
    	{
    		FLASH_LED4;
    		//清空标志位,告诉CPU当前数据接收完毕,可以响应新的中断请求
    		TIM_ClearITPendingBit(TIM3,TIM_IT_Update);
    	}
    }
    

      以上的程序都是基于作者本人之前工程模板,和文件进行编写的,有需要可以参考我之前的stm32相关随笔。

    总结

      1.注意区分不同类型的TIM;
      2.TIM的输出频率计数有些复杂,需要谨慎计算;
      3.注意PWM占空比的计算:假设高电平有效,比较器值/(计数器值+1)。

  • 相关阅读:
    进程间通信、线程同步 概要
    【Stackoverflow好问题】将InputStream转换为String
    cocos2dx --- Widget 载入中 CCNode
    ZeroMQ注意事项
    2015第25周日
    2015第25周六
    2015第25周五
    2015第24周四
    2015第25周三iframe小结
    2015第25周二
  • 原文地址:https://www.cnblogs.com/ding-ding-light/p/14427389.html
Copyright © 2011-2022 走看看