How to implement PWM waveform with adjustable frequency and duty cycle in STM32

Publisher:心若澄明Latest update time:2018-10-06 Source: eefocusKeywords:STM32 Reading articles on mobile phones Scan QR code
Read articles on your mobile phone anytime, anywhere

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:

How does STM32 implement a PWM waveform with adjustable frequency and duty cycle, and specify the number of output pulses?


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:

How does STM32 implement a PWM waveform with adjustable frequency and duty cycle, and specify the number of output pulses?


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).

How does STM32 implement a PWM waveform with adjustable frequency and duty cycle, and specify the number of output pulses?


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.

How does STM32 implement a PWM waveform with adjustable frequency and duty cycle, and specify the number of output pulses?


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} }


Keywords:STM32 Reference address:How to implement PWM waveform with adjustable frequency and duty cycle in STM32

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

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号