Use two TIM timers:
one outputs PWM with adjustable frequency and duty cycle,
and the other counts (times) the output PWM pulses.
1. The gated method can be implemented, but it requires complex configuration and calculation, and is not recommended.
2. Pulse counting is a more practical and simpler method;
There are several ways to count (time) the output PWM pulses:
1. IO interrupt count, or synchronous timing interrupt count: use another timer to interrupt count at the same frequency (similar to IO interrupt);
2. Calculate the time required for all outputs based on the PWM frequency and the number of pulses, use the timing interrupt to turn off the output PWM;
3. Use the timer external pulse trigger (external clock mode 2 function), and when the count number is the required number of pulses (10 pulses), turn off the output PWM;
The STM32 timer
uses blocking delay to control the high and low changes of IO to output PWM. This method is simple. In fact, this method has great disadvantages.
1. The output PWM may have errors;
2. It may affect the real-time performance of the entire system;
so this method is not recommended.
Several implementation methods
use two timers to cooperate to output PWM waveforms with adjustable frequency and duty cycle, and the method and principle of specifying the number of output pulses are actually not difficult.
The method of outputting PWM is to use the PWM mode that comes with the TIM timer. The main difficulty lies in controlling the number of specified output pulses.
As for how to control the number of specified output pulses, the following are roughly three methods:
1. Pulse interrupt counting method
IO interrupt, or timer synchronization (pulse) interrupt.
To put it simply, the timer synchronization (pulse) interrupt uses the timer to simultaneously generate an interrupt signal of the same frequency (or waveform), accumulates it in the interrupt, and when the accumulated number reaches the specified number of output waveforms, the output of the PWM waveform is turned off, and the interrupt count is also turned off.
For example: I output 10 waveforms, and after 10 interruptions (each time +1), I turn off the output.
Its principle is roughly as shown below:
It is recommended not to use this method when outputting high-frequency PWM, as frequent interrupts also have a certain impact on the real-time performance of the system. It is recommended to use this method for PWM below 1KHz.
2. The timed interrupt method
is based on the first method above and is not suitable for high-frequency PWM pulse interrupts. After thinking about it, can we accumulate the time of multiple interrupts and respond to only one interrupt?
The principle is to set the timing time to n times (n pulses) of a single pulse and use only one interrupt.
Its principle is roughly as shown below:
According to the tips in the picture, it is recommended to use a 32-bit timer here. This value may be very large.
3. Pulse triggering method
This method can avoid the shortcomings of the above two methods and is more practical than the above two methods. In the circuit, the waveform of the PWM output needs to be connected to the ETR pin of another timer.
There is nothing special about its principle. It is similar to the timed update interrupt we often use, except that the input signal is changed to a PWM pulse waveform (the default is the internal clock CK_INT, such as: 36M).
External clock source mode 2 implementation method
As mentioned above, using PWM as the input clock of another timer can achieve the function of PWM counting.
Please refer to the TIM timer clock selection section in the manual.
1. Output PWM configuration
void PWM_TIM_Configuration(void) { GPIO_InitTypeDef GPIO_InitStructure; TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; TIM_OCInitTypeDef TIM_OCInitStructure;
RCC_APB1PeriphClockCmd(PWM_TIM_CLK, ENABLE); RCC_AHB1PeriphClockCmd(PWM_TIM_GPIO_CLK, ENABLE); GPIO_InitStructure.GPIO_Pin = PWM_TIM_PIN; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz; GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; GPIO_Init(PWM_TIM_GPIO_PORT, &GPIO_InitStructure) ;
GPIO_PinAFConfig(PWM_TIM_GPIO_PORT, PWM_TIM_SOURCE, PWM_TIM_AF);
TIM_TimeBaseStructure.TIM_Prescaler = PWM_PRESCALER; //Prescaler value TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //Count up TIM_TimeBaseStructure.TIM_Period = 0xFFFF; //Timing period TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; //Division factor TIM_TimeBaseInit(PWM_TIMx, &TIM_TimeBaseStructure);
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; //PWM1 mode TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //Enable output TIM_OCInitStructure.TIM_Pulse = 0xFFFF; //Pulse width value TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; //Output polarity PWM_TIM_OCxInit(PWM_TIMx, &TIM_OCInitStructure); TIM_Cmd(PWM_TIMx, DISABLE); }The
initialization frequency and duty cycle are filled with the maximum value, that is, TIM_Period = 0xFFFF; TIM_Pulse = 0xFFFF; The timer is not actually enabled (see the function interface below for the output configuration)
2. Select external clock and timer interrupt configuration
void CNT_TIM_Configuration(void) { GPIO_InitTypeDef GPIO_InitStructure; TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB1PeriphClockCmd(CNT_TIM_CLK, ENABLE); RCC_AHB1PeriphClockCmd(CNT_TIM_GPIO_CLK, ENABLE); GPIO_InitStructure.GPIO_Pin = CNT_TIM_PIN; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz; GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; GPIO_Init(CNT_TIM_GPIO_PORT, &GPIO_InitStructure) ;
GPIO_PinAFConfig(CNT_TIM_GPIO_PORT, CNT_TIM_SOURCE, CNT_TIM_AF);
NVIC_InitStructure.NVIC_IRQChannel = CNT_TIM_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = CNT_TIM_Priority; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC _InitStructure);
TIM_ETRClockMode2Config(CNT_TIMx, TIM_ExtTRGPSC_OFF, TIM_ExtTRGPolarity_Inverted, 0);
TIM_TimeBaseStructure.TIM_Prescaler = 0; //Prescaler value TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //Count up TIM_TimeBaseStructure.TIM_Period = 0xFFFF; //Timing period TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; //Division factor TIM_TimeBaseInit(CNT_TIMx, &TIM_TimeBaseStructure); TIM_ClearFlag(CNT_TIMx, TIM_FLAG_Update); TIM_ITConfig(CNT_TIMx, TIM_IT_Update, ENABLE); //Enable "Update" interrupt TIM_Cmd(CNT_TIMx, DISABLE); }
The difference from the conventional one is: Use external clock source
TIM_ETRClockMode2Config(CNT_TIMx, TIM_ExtTRGPSC_OFF, TIM_ExtTRGPolarity_Inverted, 0);
Pay attention to the detection (capture) polarity TIM_ExtTRGPolarity_Inverted. Generally, PWM is a pulse waveform when it is high level, and the falling edge is counted as a waveform.
3. Output PWM function interface
void PWM_Output(uint32_t Frequency, uint32_t Dutycycle, uint32_t NumPulse) { uint32_t pwm_period; uint32_t pwm_pulse;
pwm_period = PWM_CK_CNT/Frequency - 1; //Calculate the counting period (determine the output frequency) pwm_pulse = (pwm_period + 1)*Dutycycle / 100; //Calculate the pulse width (determine the PWM duty cycle) TIM_Cmd(PWM_TIMx, DISABLE); //Disable TIM TIM_SetCounter(PWM_TIMx, 0); //Reset count TIM_SetAutoreload(PWM_TIMx, pwm_period); //Change frequency PWM_TIM_SetComparex(PWM_TIMx, pwm_pulse); //Change duty cycle TIM_Cmd(PWM_TIMx, ENABLE); //Enable TIM TIM_Cmd(CNT_TIMx, DISABLE); TIM_SetCounter(CNT_TIMx, 0); TIM_SetAutoreload(CNT_TIMx, NumPulse-1); //Set the interrupt update number TIM_ClearFlag(CNT_TIMx, TIM_FLAG_Update); TIM_Cmd(CNT_TIMx, ENABLE); }
void PWM_Output(uint32_t Frequency, uint32_t Dutycycle, uint32_t NumPulse);
We only need to call this function interface to achieve the specified number of PWM outputs. No software parameters are needed in the middle. When the output ends, it automatically responds to the timing interrupt and turns off the timer.
Interrupt interface function
void CNT_TIM_IRQHandler(void) {
if(TIM_GetITStatus(CNT_TIMx, TIM_IT_Update) != RESET) { TIM_ClearITPendingBit(CNT_TIMx, TIM_IT_Update); TIM_Cmd(PWM_TIMx, DISABLE); //Turn off PWM output TIM_Cmd(CNT_TIMx, DISABLE); //Close counting} }
Previous article:STM32F407ADC multi-channel + timer trigger + DMA mode setting
Next article:Solution to the problem that the program cannot be burned after STM32 enters low power mode
- Popular Resources
- Popular amplifiers
- Naxin Micro and Xinxian jointly launched the NS800RT series of real-time control MCUs
- How to learn embedded systems based on ARM platform
- Summary of jffs2_scan_eraseblock issues
- Application of SPCOMM Control in Serial Communication of Delphi7.0
- Using TComm component to realize serial communication in Delphi environment
- Bar chart code for embedded development practices
- Embedded Development Learning (10)
- Embedded Development Learning (8)
- Embedded Development Learning (6)
Professor at Beihang University, dedicated to promoting microcontrollers and embedded systems for over 20 years.
- Intel promotes AI with multi-dimensional efforts in technology, application, and ecology
- ChinaJoy Qualcomm Snapdragon Theme Pavilion takes you to experience the new changes in digital entertainment in the 5G era
- Infineon's latest generation IGBT technology platform enables precise control of speed and position
- Two test methods for LED lighting life
- Don't Let Lightning Induced Surges Scare You
- Application of brushless motor controller ML4425/4426
- Easy identification of LED power supply quality
- World's first integrated photovoltaic solar system completed in Israel
- Sliding window mean filter for avr microcontroller AD conversion
- What does call mean in the detailed explanation of ABB robot programming instructions?
- STMicroelectronics discloses its 2027-2028 financial model and path to achieve its 2030 goals
- 2024 China Automotive Charging and Battery Swapping Ecosystem Conference held in Taiyuan
- State-owned enterprises team up to invest in solid-state battery giant
- The evolution of electronic and electrical architecture is accelerating
- The first! National Automotive Chip Quality Inspection Center established
- BYD releases self-developed automotive chip using 4nm process, with a running score of up to 1.15 million
- GEODNET launches GEO-PULSE, a car GPS navigation device
- Should Chinese car companies develop their own high-computing chips?
- Infineon and Siemens combine embedded automotive software platform with microcontrollers to provide the necessary functions for next-generation SDVs
- Continental launches invisible biometric sensor display to monitor passengers' vital signs
- Application skills/Network fire alarm system composed of Rabbit2000 microprocessor
- [liklon plays with GD32F350] 1. Unboxing and testing demo
- I bought a ZT303 multimeter.
- Design techniques for machine learning algorithm generation (provided by ST official, Chinese subtitles)
- Add a startup program to the itop4412 development board
- IWR1642 Vehicle Occupant Detection Routine Problem
- Due to the epidemic, you are under home quarantine. Has your salary been reduced?
- ARM9-compatible soft-core processor design: based on FPGA
- 5G era promotes PCB development in multiple fields
- What is the principle of keyless entry for cars?