Three modes of TIM output comparison in STM32

Publisher:asa1670Latest update time:2017-11-03 Source: eefocusKeywords:STM32 Reading articles on mobile phones Scan QR code
Read articles on your mobile phone anytime, anywhere

This function is used to control an output waveform, or to indicate that a given period of time has expired.

When the contents of the counter and capture/compare registers are identical, the output compare function does the following:

● Set the output compare mode (OCxM bit in the TIMx_CCMRx register) and output polarity (OCxM bit in the TIMx_CCER register) to

The value defined by the CCxP bit) is output to the corresponding pin. When the compare match occurs, the output pin can maintain its level.

(OCxM=000), set to a valid level (OCxM=001), set to an invalid level (OCxM=010), or toggled

Transfer (OCxM=011).

● Set the flag bit in the interrupt status register (CCxIF bit in the TIMx_SR register).

● If the corresponding interrupt mask is set (CCxIE bit in the TIMx_DIER register), an interrupt is generated.

● If the corresponding enable bits are set (CCxDE bit in the TIMx_DIER register, CCDS bit in the TIMx_CR2 register

Select DMA request function), a DMA request is generated.

The OCxPE bit in TIMx_CCMRx selects whether the TIMx_CCRx register needs to use the preload register.

Three modes of TIM output comparison in STM32

● Set the flag bit in the interrupt status register (CCxIF bit in the TIMx_SR register).

● If the corresponding interrupt mask is set (CCXIE bit in the TIMx_DIER register), an interrupt is generated.

● If the corresponding enable bit is set (CCxDE bit in TIMx_DIER register, CCDS bit in TIMx_CR2 register selects DMA request function), a DMA request is generated.

The OCxPE bit in TIMx_CCMRx selects whether the TIMx_CCRx register needs to use the preload register.

In output compare mode, the update event UEV has no effect on OCxREF and OCx output.

The synchronization accuracy can reach one counting period of the counter. The output compare mode (in single pulse mode) can also be used to output a single pulse.

Configuration steps for output compare mode:

1. Select the counter clock (internal, external, prescaler)

2. Write the corresponding data into the TIMx_ARR and TIMx_CCRx registers

3. If you want to generate an interrupt request and/or a DMA request, set the CCxIE bit and/or CCxDE bit.

4. Select the output mode, for example: OCxM='011', OCxPE='0', CCxP='0' and CCxE='1' must be set. When the counter CNT matches CCRx, the output pin of OCx is flipped. CCRx is preloaded and unused. OCx output is turned on and the high level is valid.

5. Set the CEN bit of the TIMx_CR1 register to start the counter

The TIMx_CCRx register can be updated by software at any time to control the output waveform, provided that the preload register OCxPE='0' is not used, otherwise the TIMx_CCRx shadow register can only be updated when the next update event occurs)

The procedure is as follows:

  TIM_TimeBaseStructure.TIM_Period = 65535;         

  TIM_TimeBaseStructure.TIM_Prescaler = 0;      

  TIM_TimeBaseStructure.TIM_ClockDivision = 0;   

  TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;

  TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure); 

  TIM_PrescalerConfig(TIM2, 35999, TIM_PSCReloadMode_Immediate); 

  TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_Timing; //This is where the comparison mode is changed

   However, since the effect of generating interrupts is the same regardless of which comparison mode is selected, TIMING can be selected.       

  TIM_OCInitStructure.TIM_Channel = TIM_Channel_1;         

  TIM_OCInitStructure.TIM_Pulse = CCR1_Val; 

  TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;   

  TIM_OCInit(TIM2, &TIM_OCInitStructure);

  TIM_OC1PreloadConfig(TIM2, TIM_OCPreload_Disable);//

The TIMx_CCRx register can be updated by software at any time to control the output waveform, provided that the preload register OCxPE='0' is not used, otherwise the TIMx_CCRx shadow register can only be updated when the next update event occurs). The setting here is to disable so that the TIMx_CCR can be modified in the interrupt service subroutine to take effect in real time. 

  TIM_OCInitStructure.TIM_Channel = TIM_Channel_2;         

  TIM_OCInitStructure.TIM_Pulse = CCR2_Val; 

  TIM_OCInit(TIM2, &TIM_OCInitStructure);

  TIM_OC2PreloadConfig(TIM2, TIM_OCPreload_Disable); 

  TIM_OCInitStructure.TIM_Channel = TIM_Channel_3;         

  TIM_OCInitStructure.TIM_Pulse = CCR3_Val;  

  TIM_OCInit(TIM2, &TIM_OCInitStructure);

  TIM_OC3PreloadConfig(TIM2, TIM_OCPreload_Disable); 

  TIM_OCInitStructure.TIM_Channel = TIM_Channel_4;         

  TIM_OCInitStructure.TIM_Pulse = CCR4_Val;  

  TIM_OCInit(TIM2, &TIM_OCInitStructure); 

  TIM_OC4PreloadConfig(TIM2, TIM_OCPreload_Disable); 

  TIM_ARRPreloadConfig(TIM2, ENABLE);//TIM_OCPreload_Enable 

  TIM_ITConfig(TIM2, TIM_IT_CC1 | TIM_IT_CC2 | TIM_IT_CC3 | TIM_IT_CC4, ENABLE);

    // STM3210B-LK1, set PC.04 - PC.07

  GPIO_SetBits(GPIOC, GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7); 

  TIM_Cmd(TIM2, ENABLE);

  while (1)

  {

  } 

}

Interrupt service subroutine:

void TIM2_IRQHandler(void)

  { u16 capture;

     u16 CCR1_Val = 1000;

     u16 CCR2_Val = 500;

     u16 CCR3_Val = 250;

     u16 CCR4_Val = 125;

  if (TIM_GetITStatus(TIM2, TIM_IT_CC1) != RESET)

  {   

    TIM_ClearITPendingBit(TIM2, TIM_IT_CC1);   

    capture = TIM_GetCapture1(TIM2);

    TIM_SetCompare1(TIM2, capture + CCR1_Val);

   ////Set the TIMx capture compare 1 register value and then dynamically modify its CCR value to keep the whole program going    

    // PC.04

    GPIO_WriteBit(GPIOC, GPIO_Pin_4, (BitAction)(1 - GPIO_ReadOutputDataBit(GPIOC, GPIO_Pin_4)));

 

  }

  else if (TIM_GetITStatus(TIM2, TIM_IT_CC2) != RESET)

  {

   

    TIM_ClearITPendingBit(TIM2, TIM_IT_CC2);

    capture = TIM_GetCapture2(TIM2);

    TIM_SetCompare2(TIM2, capture + CCR2_Val);

 

    // PC.05

    GPIO_WriteBit(GPIOC, GPIO_Pin_5, (BitAction)(1 - GPIO_ReadOutputDataBit(GPIOC, GPIO_Pin_5)));   

  }

  else if (TIM_GetITStatus(TIM2, TIM_IT_CC3) != RESET)

  {   

    TIM_ClearITPendingBit(TIM2, TIM_IT_CC3);

    capture = TIM_GetCapture3(TIM2);

    TIM_SetCompare3(TIM2, capture + CCR3_Val);

  

    // PC.06

    //GPIO_ResetBits(GPIOC, GPIO_Pin_6);

     GPIO_WriteBit(GPIOC, GPIO_Pin_6, (BitAction)(1 - GPIO_ReadOutputDataBit(GPIOC, GPIO_Pin_6))); }

  else

  {   

    TIM_ClearITPendingBit(TIM2, TIM_IT_CC4);

    capture = TIM_GetCapture4(TIM2);

    TIM_SetCompare4(TIM2, capture + CCR4_Val);

     

    // PC.07

   // GPIO_ResetBits(GPIOC, GPIO_Pin_7);

     GPIO_WriteBit(GPIOC, GPIO_Pin_7, (BitAction)(1 - GPIO_ReadOutputDataBit(GPIOC, GPIO_Pin_7)));

  }

}

In some applications of STM32, users have the requirement to execute certain programs periodically. The timer can be used to generate a fixed time period to meet such requirements.

STM32 related features:

STM32 advanced timers TIM1, TIM8, general timers TIM2, TIM3, TIM4, TIM5; the maximum clock of the timer is 72MHz, and with pre-scaling, it provides flexible clock cycles; each TIM has 4 independent capture/compare channels, DMA/interrupt functions; the channel works in output comparison timing mode, and one TIM can provide up to 4 different timing cycles. 

Principle: When a certain output/capture channel of TIM works in output comparison timing mode, an interrupt is generated when the counter counts to the comparison value, and the capture comparison register is refreshed in the interrupt, so that the next interrupt can be generated after the same time interval.

 

The TIM2 clock is set to 36MHz, the prescaler is set to 2, and the Output Compare Toggle Mode is used.

The TIM2 counter clock can be expressed as: TIM2 counter clock = TIMxCLK / (Prescaler +1) = 12 MHz

Set the TIM2_CCR1 register value to 32768, then the CC1 update frequency is the TIM2 counter clock frequency divided by the CCR1 register value, which is 366.2 Hz. Therefore, TIM2 channel 1 can generate a periodic signal with a frequency of 183.1 Hz.

Similarly, according to the values ​​of registers TIM2_CCR2, TIM2_CCR3 and TIM2_CCR4, TIM2 channel 2 can generate a periodic signal with a frequency of 366.3 Hz; TIM2 channel 3 can generate a periodic signal with a frequency of 732.4 Hz; and TIM2 channel 4 can generate a periodic signal with a frequency of 1464.8 Hz.

#include "stm32f10x_lib.h"

TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;

TIM_OCInitTypeDef TIM_OCInitStructure;

vu16 CCR1_Val = 32768;

vu16 CCR2_Val = 16384;

vu16 CCR3_Val = 8192;

vu16 CCR4_Val = 4096;

ErrorStatus HSEStartUpStatus;

void RCC_Configuration(void);

void GPIO_Configuration(void);

void NVIC_Configuration(void);   

int main(void)

{

#ifdef DEBUG

  debug();

#endif

 

  RCC_Configuration(); 

  NVIC_Configuration(); 

  GPIO_Configuration();

 

  TIM_TimeBaseStructure.TIM_Period = 65535; //This must be 65535, set the count overflow size, and generate an update event for each count     
TIM_TimeBaseStructure.TIM_Prescaler = 2;      

  TIM_TimeBaseStructure.TIM_ClockDivision = 0;   

  TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; 

  TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);

 

  TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_Toggle; //Pin output mode: flip (TIM output comparison trigger mode)   

  TIM_OCInitStructure.TIM_Channel = TIM_Channel_1;         

  TIM_OCInitStructure.TIM_Pulse = CCR1_Val; //Flip cycle

  TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low; //TIM output comparison polarity low

  TIM_OCInit(TIM2, &TIM_OCInitStructure);

  TIM_OC1PreloadConfig(TIM2, TIM_OCPreload_Disable); //Disable TIMx preload register on CCR1

 

  TIM_OCInitStructure.TIM_Channel = TIM_Channel_2;         

  TIM_OCInitStructure.TIM_Pulse = CCR2_Val;  

  TIM_OCInit(TIM2, &TIM_OCInitStructure);

  TIM_OC2PreloadConfig(TIM2, TIM_OCPreload_Disable);

 

  TIM_OCInitStructure.TIM_Channel = TIM_Channel_3;         

  TIM_OCInitStructure.TIM_Pulse = CCR3_Val;  

  TIM_OCInit(TIM2, &TIM_OCInitStructure);

  TIM_OC3PreloadConfig(TIM2, TIM_OCPreload_Disable); 

  TIM_OCInitStructure.TIM_Channel = TIM_Channel_4;         

  TIM_OCInitStructure.TIM_Pulse = CCR4_Val; 

 

  TIM_OCInit(TIM2, &TIM_OCInitStructure);

  TIM_OC4PreloadConfig(TIM2, TIM_OCPreload_Disable);

 

  TIM_Cmd(TIM2, ENABLE); 

  TIM_ITConfig(TIM2, TIM_IT_CC1 | TIM_IT_CC2 | TIM_IT_CC3 | TIM_IT_CC4, ENABLE);

  while (1)

  {

  } 

}

void RCC_Configuration(void)

{  

 

  RCC_DeInit(); 

  RCC_HSEConfig(RCC_HSE_ON); 

  HSEStartUpStatus = RCC_WaitForHSEStartUp();

  if(HSESTartUpStatus == SUCCESS)

  {

   FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);   

   FLASH_SetLatency(FLASH_Latency_2);   

   RCC_HCLKConfig(RCC_SYSCLK_Div1);   

   RCC_PCLK2Config(RCC_HCLK_Div1);   

   RCC_PCLK1Config(RCC_HCLK_Div4);

   

    RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9);   

    RCC_PLLCmd(ENABLE);

   

    while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET)

    {

    }

   

    RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);   

    while(RCC_GetSYSCLKSource() != 0x08)

    {

    }

  }

  RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); 

  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);

}

void GPIO_Configuration(void)

{

  GPIO_InitTypeDef GPIO_InitStructure; 

  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3;

  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;

  GPIO_InitStructure.GPIO_Speed ​​= GPIO_Speed_50MHz;

  GPIO_Init(GPIOA, &GPIO_InitStructure);

}

void NVIC_Configuration(void)

{

  NVIC_InitTypeDef NVIC_InitStructure;

  

#ifdef VECT_TAB_RAM  

  NVIC_SetVectorTable(NVIC_VectTab_RAM, 0x0);

#else  

  NVIC_SetVectorTable(NVIC_VectTab_FLASH, 0x0);  

#endif 

 

  NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQChannel;

  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;

  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; 

  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;

  NVIC_Init(&NVIC_InitStructure);

}

#ifdef DEBUG

void assert_failed(u8* file, u32 line)

{

  while (1)

  {

  } 

}

#endif 

Interrupt service:

 

void TIM2_IRQHandler(void)

  if (TIM_GetITStatus(TIM2, TIM_IT_CC1) != RESET) // Check whether the specified TIM interrupt occurs

  {

    TIM_ClearITPendingBit(TIM2, TIM_IT_CC1); //Clear the pending interrupt bit of TIMx

 capture = TIM_GetCapture1(TIM2);

 TIM_SetCompare1(TIM2, capture + CCR1_Val ); //Set TIMx auto-reload register value

        //Increase the value of TIM2_CC1 by CCR1_Val, so that the next TIM event also requires CCR1_Val pulses,

  }

 

  if (TIM_GetITStatus(TIM2, TIM_IT_CC2) != RESET)

  {

     TIM_ClearITPendingBit(TIM2, TIM_IT_CC2);

     capture = TIM_GetCapture2(TIM2);

    TIM_SetCompare2(TIM2, capture + CCR2_Val);

  } 

 

  if (TIM_GetITStatus(TIM2, TIM_IT_CC3) != RESET)

  {

    TIM_ClearITPendingBit(TIM2, TIM_IT_CC3);

    capture = TIM_GetCapture3(TIM2);

    TIM_SetCompare3(TIM2, capture + CCR3_Val);

  }

 

  if (TIM_GetITStatus(TIM2, TIM_IT_CC4) != RESET)

  {

    TIM_ClearITPendingBit(TIM2, TIM_IT_CC4);

 capture = TIM_GetCapture4(TIM2);

    TIM_SetCompare4(TIM2, capture + CCR4_Val);

  }  

}


Keywords:STM32 Reference address:Three modes of TIM output comparison in STM32

Previous article:STM32 PWM Summary
Next article:Introduction to 8 working modes of GPIO in STM32

Latest Microcontroller Articles
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号