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.
● 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);
}
}
Previous article:STM32 PWM Summary
Next article:Introduction to 8 working modes of GPIO in STM32
- Popular Resources
- Popular amplifiers
- Learn ARM development(16)
- Learn ARM development(17)
- Learn ARM development(18)
- Embedded system debugging simulation tool
- A small question that has been bothering me recently has finally been solved~~
- Learn ARM development (1)
- Learn ARM development (2)
- Learn ARM development (4)
- Learn ARM development (6)
Professor at Beihang University, dedicated to promoting microcontrollers and embedded systems for over 20 years.
- LED chemical incompatibility test to see which chemicals LEDs can be used with
- Application of ARM9 hardware coprocessor on WinCE embedded motherboard
- What are the key points for selecting rotor flowmeter?
- LM317 high power charger circuit
- A brief analysis of Embest's application and development of embedded medical devices
- Single-phase RC protection circuit
- stm32 PVD programmable voltage monitor
- Introduction and measurement of edge trigger and level trigger of 51 single chip microcomputer
- Improved design of Linux system software shell protection technology
- What to do if the ABB robot protection device stops
- Why software-defined vehicles transform cars from tools into living spaces
- How Lucid is overtaking Tesla with smaller motors
- Wi-Fi 8 specification is on the way: 2.4/5/6GHz triple-band operation
- Wi-Fi 8 specification is on the way: 2.4/5/6GHz triple-band operation
- Vietnam's chip packaging and testing business is growing, and supply-side fragmentation is splitting the market
- Vietnam's chip packaging and testing business is growing, and supply-side fragmentation is splitting the market
- Three steps to govern hybrid multicloud environments
- Three steps to govern hybrid multicloud environments
- Microchip Accelerates Real-Time Edge AI Deployment with NVIDIA Holoscan Platform
- Microchip Accelerates Real-Time Edge AI Deployment with NVIDIA Holoscan Platform
- SD card creative stickers
- The difference and relationship between embedded Linux and embedded development of 51/430/STM32
- 【DM642】Porting of H.264 source code on DM642
- [2022 Digi-Key Innovation Design Competition] Material Unboxing
- Prize-giving live broadcast: Book a session on "Meeting the test challenges in 5G signal generation" and win Keysight gifts
- Simple stopwatch based on MSP430f149 microcontroller
- A power backup solution for NVR/DVR systems
- Is there any solution to adjust the voltage accurately to 0.1V and start continuously and stably? ??? ? Help! ! ! !
- Learn about the internal structure of ST waterproof pressure sensor in this 32-second video
- 【Qinheng CH582】Evaluation Summary