STM32 Series Part 11 - Timer

Publisher:dst2015Latest update time:2017-09-22 Source: eefocus Reading articles on mobile phones Scan QR code
Read articles on your mobile phone anytime, anywhere

STM32 has a total of 8 timers:

Timer TypeNumber of digitsmodelSpecial application scenarios
Advanced timer TIME1, TIME816-bitUp, Down, Up/DownPWM click control
General timer TIME2~TIME516-bitUp, Down, Up/DownTiming counting, PWM output, input capture, output comparison
Basic timer TIME6, TIME716-bitUp, Down, Up/DownDriving the DAC

General timer functions:

  1. Located on the low-speed APB1 bus (APB1)

  2. 16-bit up, down, up/down (center-aligned) counting modes, auto-reload counter (TIMx_CNT).

  3. 16-bit programmable (can be modified in real time) prescaler (TIMx_PSC) to divide the counter clock.

  4. 4 independent channels (TIMx_CH1~4), these channels can be used as: input capture, output comparison, PWM generation (edge ​​or center alignment mode), single pulse mode output.

  5. You can use external signals (TIMx_ETR) to control the synchronization circuits of timers and timer interconnections (one timer can be used to control another timer).

  6. Generate interrupts/DMA on the following events (6 independent IRQ/DMA request generators): Update: counter overflow/underflow, counter initialization (by software or internal/external trigger), trigger event (counter start, stop, initialize or count by internal/external trigger), input capture, output compare, etc.

General timer clock CK_INT = 2 * 36M = 72M 
up counting mode: the counter counts from 0 to the automatic reload value (TIMx_ARR), then restarts counting from 0 and generates a counter overflow event.

Program requirements: 
Through the timer interrupt configuration, interrupt once every 500ms, and then control the LED in the interrupt service function to achieve LED1 state inversion (flashing).

Tout (overflow time) = (ARR+1)(PSC+1)/Tclk

timer.c

#include "timer.h" #include "led.h" //General timer 3 interrupt initialization //Here the clock is selected to be twice that of APB1, and APB1 is 36M //arr: automatic reload value. //psc: clock pre-division number //Here timer 3 is used! void TIM3_Int_Init(u16 arr,u16 psc)
{
    TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
    NVIC_InitTypeDef NVIC_InitStructure;
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); //Clock enable
    //Timer TIM3 initialization
    TIM_TimeBaseStructure.TIM_Period = arr; //Set the value of the auto-reload register period to load the activity at the next update event
    TIM_TimeBaseStructure.TIM_Prescaler =psc; //Set the prescaler value used as the TIMx clock frequency divisor
    TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; //Set clock division: TDTS = Tck_tim
    TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //TIM up counting mode
    TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); //Initialize the time base unit of TIMx according to the specified parameters
    TIM_ITConfig(TIM3,TIM_IT_Update,ENABLE); //Enable the specified TIM3 interrupt and allow update interrupt
    //Interrupt priority NVIC setting
    NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn; //TIM3 interrupt NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; //Preemption priority level 0
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; //From priority level 3
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ channel is enabled
    NVIC_Init(&NVIC_InitStructure); //Initialize NVIC registers 
    TIM_Cmd(TIM3, ENABLE); //Enable TIMx} //Timer 3 interrupt service routine void TIM3_IRQHandler(void) //TIM3 interrupt { if (TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET) //Check whether TIM3 update interrupt occurs
    {
        TIM_ClearITPendingBit(TIM3, TIM_IT_Update ); //Clear TIMx update interrupt flag 
        LED1=!LED1;
    }
}12345678910111213141516171819202122232425262728293031323334353637

PWM Output

work process: 
Write the picture description here

CCR1: Capture compare (value) register (x=1,2,3,4): Set the compare value. 
CCMR1: OC1M[2:0] bit: 
For PWM mode, used to set PWM mode 1 [110] or PWM mode 2 [111] 
Mode 1: The count value is less than the CCR1 value, which is the valid level 
Mode 2: The count value is greater than the CCR1 value, which is the valid level 
CCER: CC1P bit: Input/capture 1 output polarity. 0: High level is valid, 1: Low level is valid. 
CCER: CC1E bit: Input/capture 1 output enable. 0: Off, 1: On.

PWM output configuration steps:

1. Enable timer 3 and related IO port clocks.

Enable timer 3 clock: RCC_APB1PeriphClockCmd(); 
Enable GPIOB clock: RCC_APB2PeriphClockCmd();

2. Initialize the IO port as multiplexed function output. Function: GPIO_Init();

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;

3. Here we want to use PB5 as the PWM output pin of the timer, so we need to remap the configuration.

So you need to turn on the AFIO clock. Also set the remapping. 
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE); 
GPIO_PinRemapConfig(GPIO_PartialRemap_TIM3, ENABLE);

4. Initialize timer: ARR, PSC, etc.: TIM_TimeBaseInit(); 
5. Initialize output comparison parameters: TIM_OC2Init(); 
6. Enable preload register:

TIM_OC2PreloadConfig(TIM3, TIM_OCPreload_Enable);

7. Enable the timer. TIM_Cmd(); 
8. Continuously change the comparison value CCRx to achieve different duty cycle effects: TIM_SetCompare2();

Program Requirements:

Use the PWM function of timer 3 to output a PWM wave with a variable duty cycle to drive the LED light, so that the brightness of LED [PB5] changes from dark to bright, and then from bright to dark, and so on.

timer.c

void TIM3_PWM_Init(u16 arr,u16 psc)
{  
    //Define structure variables
    GPIO_InitTypeDef GPIO_InitStructure;
    TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
    TIM_OCInitTypeDef TIM_OCInitStructure;  
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); //Enable timer 3 clock
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_AFIO, ENABLE); //Enable GPIO clock and AFIO multiplexing function module clock
    GPIO_PinRemapConfig(GPIO_PartialRemap_TIM3, ENABLE); //Timer3 partial remap TIM3_CH2->PB5   
    //GPIO initialization, set the pin to multiplex output function, output TIM3 CH2 PWM pulse waveform 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); //Initialize TIM3
    TIM_TimeBaseStructure.TIM_Period = arr; //Set the value of the auto-reload register period to load the activity at the next update event
    TIM_TimeBaseStructure.TIM_Prescaler =psc; //Set the prescaler value used as the TIMx clock frequency divisor 
    TIM_TimeBaseStructure.TIM_ClockDivision = 0; //Set clock division: TDTS = Tck_tim
    TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //TIM up counting mode
    TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); //Initialize the time base unit of TIMx according to the parameters specified in TIM_TimeBaseInitStruct    

    //Initialize TIM3 Channel2 PWM mode 
    TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2; //Set PWM mode 2
    TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //Comparison output enable
    TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; //High level is valid
    TIM_OC2Init(TIM3, &TIM_OCInitStructure); //Initialize peripheral TIM3 OC2 according to the parameters specified by T    
    TIM_OC2PreloadConfig(TIM3, TIM_OCPreload_Enable); //Enable TIM3 preload register on CCR2    
    TIM_Cmd(TIM3, ENABLE); //Enable TIM3}123456789101112131415161718192021222324252627282930

main.c

int main(void)
{ u16 led0pwmval=0; u8 dir=1;
   delay_init(); //delay function initialization  
   NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //Set NVIC interrupt group 2: 2-bit preemption priority, 2-bit response priority
   uart_init(115200); //Serial port initialized to 115200
   LED_Init(); //LED port initialization
   TIM3_PWM_Init(899,0); //No frequency division. PWM frequency = 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); //Set duty cycle
   } 
}12345678910111213141516171819

Input capture:

General configuration steps for input capture: 
① Initialize the timer and the clock of the channel corresponding to the IO. 
② Initialize the IO port, the mode is input: GPIO_Init();

GPIO_InitStructure.GPIO_Mode= GPIO_Mode_IPD; //PA0 input

③ Initialize timer ARR, PSC

TIM_TimeBaseInit();

④Initialize input capture channel

TIM_ICInit();

⑤If you want to enable capture interrupt,

TIM_ITConfig(); 
NVIC_Init();

⑥ Enable timer: TIM_Cmd();

⑦Write interrupt service function: TIMx_IRQHandler();

Experimental purpose: measure the pulse width of the signal

//Timer 5 channel 1 input capture configuration 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); //Enable TIM5 clock
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //Enable GPIOA clock
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; //PA0 clears the previous settings  
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD; //PA0 input  
    GPIO_Init(GPIOA, &GPIO_InitStructure);
    GPIO_ResetBits(GPIOA,GPIO_Pin_0); //PA0 pull down
    //Initialize timer 5 TIM5
    TIM_TimeBaseStructure.TIM_Period = arr; //Set the counter to automatically reload value 
    TIM_TimeBaseStructure.TIM_Prescaler =psc; //Prescaler   
    TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; //Set clock division: TDTS = Tck_tim
    TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //TIM up counting mode
    TIM_TimeBaseInit(TIM5, &TIM_TimeBaseStructure); //Initialize the time base unit of TIMx according to the parameters specified in TIM_TimeBaseInitStruct

    //Initialize TIM5 input capture parameters
    TIM5_ICInitStructure.TIM_Channel = TIM_Channel_1; //CC1S=01 Select input IC1 to map to TI1
    TIM5_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising; //Rising edge capture
    TIM5_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI; //Map to TI1
    TIM5_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1; //Configure input frequency division, no frequency division 
    TIM5_ICInitStructure.TIM_ICFilter = 0x00; //IC1F=0000 Configure input filter No filtering
    TIM_ICInit(TIM5, &TIM5_ICInitStructure); //Interrupt group initialization
    NVIC_InitStructure.NVIC_IRQChannel = TIM5_IRQn; //TIM3 interrupt
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2; //Preemption priority level 2
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; //From priority level 0
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ channel is enabled
    NVIC_Init(&NVIC_InitStructure); //Initialize peripheral NVIC registers according to the parameters specified in NVIC_InitStruct 
    TIM_ITConfig(TIM5,TIM_IT_Update|TIM_IT_CC1,ENABLE); //Enable update interrupt, allow CC1IE to capture interrupt
    TIM_Cmd(TIM5,ENABLE ); //Enable timer 5}u8 TIM5CH1_CAPTURE_STA=0; //Input capture status u16TIM5CH1_CAPTURE_VAL; //Input capture value //Timer 5 interrupt service routine void TIM5_IRQHandler(void)
{ 
    if((TIM5CH1_CAPTURE_STA&0X80)==0)//Not captured successfully
    {  
        if (TIM_GetITStatus(TIM5, TIM_IT_Update) != RESET)
        {    
            if(TIM5CH1_CAPTURE_STA&0X40)//High level has been captured
            { if((TIM5CH1_CAPTURE_STA&0X3F)==0X3F)//The high level is too long
                {
                    TIM5CH1_CAPTURE_STA|=0X80; //Marks a successful capture
                    TIM5CH1_CAPTURE_VAL=0XFFFF;
                } else TIM5CH1_CAPTURE_STA++;
            } 
        } if (TIM_GetITStatus(TIM5, TIM_IT_CC1) != RESET) //Capture 1 capture event occurs
        { if(TIM5CH1_CAPTURE_STA&0X40) //Capture a falling edge 
            {  
                TIM5CH1_CAPTURE_STA|=0X80; //Marks a successful capture of a high level pulse width
                TIM5CH1_CAPTURE_VAL=TIM_GetCapture1(TIM5);
                TIM_OC1PolarityConfig(TIM5,TIM_ICPolarity_Rising); //CC1P=0 set to rising edge capture
            }else //Not started yet, first capture rising edge
            {

                TIM5CH1_CAPTURE_STA=0; //Clear
                TIM5CH1_CAPTURE_VAL=0;
                TIM_SetCounter(TIM5,0);
                TIM5CH1_CAPTURE_STA|=0X40; //Marker captures the rising edge
                TIM_OC1PolarityConfig(TIM5,TIM_ICPolarity_Falling); //CC1P=1 set to falling edge capture
            }    
        }            
    }
    TIM_ClearITPendingBit(TIM5, TIM_IT_CC1|TIM_IT_Update); //Clear interrupt flag bit}

main.cextern u8 TIM5CH1_CAPTURE_STA; // Input capture status extern u16TIM5CH1_CAPTURE_VAL; // Input capture value int main(void)
{ u32 temp=0; 
    delay_init(); //delay function initialization  
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //Set NVIC interrupt group 2: 2-bit preemption priority, 2-bit response priority
    uart_init(115200); //Serial port initialized to 115200
    LED_Init(); //LED port initialization
    TIM3_PWM_Init(899,0); //No frequency division. PWM frequency = 72000/(899+1) = 80Khz
    TIM5_Cap_Init(0XFFFF,72-1); //Count at 1Mhz frequency 
    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)//Successfully captured a rising edge
        {
            temp=TIM5CH1_CAPTURE_STA&0X3F;
            temp*=65536; //Total overflow time
            temp+=TIM5CH1_CAPTURE_VAL; //get the total high level time
            printf("HIGH:%d us\r\n",temp);//Print the total high point flat time
            TIM5CH1_CAPTURE_STA=0; //Start the next capture
        }
    }
}


Reference address:STM32 Series Part 11 - Timer

Previous article:STM32 Series Chapter 12 - Principle of Capacitive Touch Button
Next article:STM32 Series Part 10 - Watchdog

Recommended ReadingLatest update time:2024-11-16 13:05

MSP430F5529 (VI) Timer Timer_A-1
MSP430F5529 has two types of timers, three Timer_A timers and one Timer_B timer. According to the number of capture/compare registers, they are named Timer0_A (with 5 capture/compare registers), Timer1_A (3), Timer2_A (3), and Timer0_B (7).                         In this chapter, we will talk about Timer0_A. (All A t
[Microcontroller]
MSP430F5529 (VI) Timer Timer_A-1
PIC Timer (TIMER2)
1. PIC TIMER2 timer The function of Timer2 is somewhat different from Timer0. Timer2 is an eight-bit counter with an eight-bit counting register TMR2. Timer2 has the following functions: There are two frequency dividers, one is the pre-divider and the other is the post-divider. The frequency division can be set by s
[Microcontroller]
PIC Timer (TIMER2)
Interrupt-timer0
Use timer0 interrupt to flash the LED Heat. c /*  * init.c: do some initialization  */    #include "s3c24xx.h"   void disable_watch_dog(void); void clock_init(void); void memsetup(void); void copy_steppingstone_to_sdram(void); void init_led(void); void timer0_init(void); void init_irq(void); void delay(int n) { int
[Microcontroller]
Timer0 of PIC16F877
    Timer0 is an 8-bit timer counter with a programmable 8-bit prescaler. The hardware structure is shown in the figure below:   There are three registers associated with it: If counting mode is required, T0CKI should be set to input mode, that is, the corresponding position in TRISA is set to 1.     TMR
[Microcontroller]
Typical application of Timer_A of MSP430 - PWM
Program 1: #include  "msp430x14x.h" void  main(  void  ) {     WDTCTL  =  WDTPW  +  WDTHOLD;                //Turn off the watchdog     TACTL=TASSEL0+TACLR+MC0;                      //ACLK is the clock source, clear TAR, increment mode     TACCR0=512-1;                                                             
[Microcontroller]
Latest Microcontroller Articles
  • Download from the Internet--ARM Getting Started Notes
    A brief introduction: From today on, the ARM notebook of the rookie is open, and it can be regarded as a place to store these notes. Why publish it? Maybe you are interested in it. In fact, the reason for these notes is ...
  • Learn ARM development(22)
    Turning off and on interrupts Interrupts are an efficient dialogue mechanism, but sometimes you don't want to interrupt the program while it is running. For example, when you are printing something, the program suddenly interrupts and another ...
  • Learn ARM development(21)
    First, declare the task pointer, because it will be used later. Task pointer volatile TASK_TCB* volatile g_pCurrentTask = NULL;volatile TASK_TCB* vol ...
  • Learn ARM development(20)
    With the previous Tick interrupt, the basic task switching conditions are ready. However, this "easterly" is also difficult to understand. Only through continuous practice can we understand it. ...
  • Learn ARM development(19)
    After many days of hard work, I finally got the interrupt working. But in order to allow RTOS to use timer interrupts, what kind of interrupts can be implemented in S3C44B0? There are two methods in S3C44B0. ...
  • Learn ARM development(14)
  • Learn ARM development(15)
  • Learn ARM development(16)
  • Learn ARM development(17)
Change More Related Popular Components

EEWorld
subscription
account

EEWorld
service
account

Automotive
development
circle

About Us Customer Service Contact Information Datasheet Sitemap LatestNews


Room 1530, 15th Floor, Building B, No.18 Zhongguancun Street, Haidian District, Beijing, Postal Code: 100190 China Telephone: 008610 8235 0740

Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved 京ICP证060456号 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号