STM32F103C8T6 Pulse Width Modulation (PWM)

About STM32F103C8T6 Project File Self-Credit-Free Download This is just a core project file, just add the following code yourself.

STM32F103C8T6 Pulse Width Modulation

Introduction to PWM

Pulse Width Modulation (PWM), short for Pulse Width Modulation, is a very effective technology to control analog circuits by using the digital output of microprocessor.A simple point is to control the pulse width.
_STM32 timers except TIM6 and 7.Other timers can be used to generate PWM output.The advanced timers TIM1 and TIM8 can produce up to 7 PWM outputs simultaneously.The universal timer can also produce up to 4 PWM outputs at the same time, so that STM32 can produce up to 30 PWM outputs at the same time!Only CH1 from TIM1 is used here to produce a PWM output.
_To make the advanced timer TIM1 of STM32 produce PWM output, in addition to the registers (ARR, PSC, CR1, etc.) described in the previous chapter, we will use four registers (only three universal timers) to control the output of PWM.The four registers are: capture/compare mode registers (TIMx_CCMR1/2), Capture/Compare Enabled Register (TIMx_CCER), Capture/Comparison Register (TIMx_CCR1~4) and Brake and Dead Zone Register TIMx_BDTR).
_Briefly introduce these four registers.First is the capture/compare mode register (TIMx_CCMR1/2), a total of two registers, TIMx CCMR1 and TIMx CCMR2.TIMx_CCMR1 controls CH1 and CH2, while TIMx_CCMR2 controls CH3 and CH4.
_TIMx_CCMR1 Register Description:

_Introduction to Capture/Compare Enabled Registers (TIMx_CCER), which controls the switching of input and output channels.
**TIMx CCER Register Description**

Capture/Compare Registers (TIMx_CCR1~4), which has four registers corresponding to four
Transport channels CH1~4.Because these four registers are all similar, just TIMx_CCR1 is introduced as an example.
**Register TIMx CCR1 Everyone Description**

In output mode, the value of this register is compared with the value of CNT, and the corresponding actions are generated based on the comparison results.Using this, the output pulse width of the PWM can be controlled by modifying the value of this register.
_If you have a universal timer, configuring the above three registers is sufficient, but if you have an advanced timer, you also need to configure: Brake and Dead Zone Registers (TIMx_BDTR), the register is described in Figure 4.

_This register, we only need to focus on the highest bit: MOE bit, in order for the PWM output of the advanced timer to be normal, the MOE bit must be set to 1, otherwise there will be no output.Note: This is not required for universal timers.

Configuration steps:

_1) Turn on TIM1 clock and configure PA8 for multiplexed output.To use TIM1, we must first turn on the TIM1 clock.Here we will also configure PA8 as a multiplexed output (and, of course, a PORTA clock) because of TIM1_The CH1 channel will use the multiplexing function of PA8 as output.The library functions enable TIM3 clocks by:

RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); //Enable timer 3 clock

Set PA8 as the multiplex function transport and list a line of code for GPIO initialization:

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //Multiplex push-pull output

_2) Set ARR and PSC for TIM1.
After turning on the TIM1 clock, we need to set the ARR and PSC registers to control the output PWM cycle.When the PWM cycle is too slow (less than 50Hz), we will clearly feel the flicker.Therefore, the PWM cycle should not be set too small here.This is done by TIM_in the library functionThe TimeBaseInit function is implemented.

TIM_TimeBaseStructure.TIM_Period = arr; //Set auto reload value
TIM_TimeBaseStructure.TIM_Prescaler =psc; //Set Pre-frequency Value
TIM_TimeBaseStructure.TIM_ClockDivision = 0; //Set clock division: TDTS = Tck_tim
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //Up Count Mode
TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure); //Initializes TIMx's

_3) Set TIM1_The PWM mode and channel direction of CH1 enable CH1 output from TIM1.Next, we're going to set TIM1_CH1 is in PWM mode (frozen by default), configuring TIM1_Correlated bits of CCMR1 to control TIM1_Mode of CH1.In library functions, the PWM channel setting is through the function TIM_OC1Init()~TIM_OC4Init() to set, different channel settings function is different, here we use channel 1, so the function used is TIM_OC1Init().

void TIM_OC1Init(TIM_TypeDef* TIMx, TIM_OCInitTypeDef* TIM_OCInitStruct)

Look directly at the structure TIM_Definition of OCInitTypeDef:

ypedef struct
uint16_t TIM_OCMode;
uint16_t TIM_OutputState;
uint16_t TIM_OutputNState; 
uint16_t TIM_Pulse;
uint16_t TIM_OCPolarity;
uint16_t TIM_OCNPolarity;
uint16_t TIM_OCIdleState;
uint16_t TIM_OCNIdleState;
} TIM_OCInitTypeDef;

Several member variables:
_Parameter TIM_OCMode setting mode is PWM or output comparison, here we are PWM mode.
_Parameter TIM_OutputState is used to set comparative output enabling, that is, enabling PWM output to the port.
_Parameter TIM_OCPolarity is used to set whether the polarity is high or low.
Other parameters TIM_OutputNState, TIM_OCNPolarity, TIM_OCIdleState and TIM_OCNIdleState is used by advanced timers TIM1 and TIM8.To achieve the scenarios we mentioned above, you can do this by:

IM_OCInitTypeDef TIM_OCInitStructure;
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2; //Select PWM mode 2
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //Compare Output Enables
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; //High output polarity
TIM_OC1Init(TIM1, &TIM_OCInitStructure); //Initialize TIM1 OC1

_4) Enables TIM1.
After that, we need to enable TIM1.The method for enabling TIM1 has been explained earlier:

TIM_Cmd(TIM1, ENABLE); //Enable TIM1

_5) Set MOE output to enable PWM output.
After the normal timer is set above, you can output PWM, but for the advanced timer, we also need to enable the Brake and Dead Zone Registers (TIM1_The MOE bit of the BDTR to enable the entire OCx (or PWM) output.The number is set to:

TIM_CtrlPWMOutputs(TIM1,ENABLE);// MOE Primary Output Enabling

_6) Modify TIM1_CCR1 controls duty cycle.
_Finally, after the above settings, PWM has actually started to output, but its duty cycle and frequency are fixed, and we modify TIM1_CCR1 controls the output duty cycle of CH1.The PWM output is then controlled.
In the library function, modify TIM1_The function of CCR1 duty cycle is:

void TIM_SetCompare1(TIM_TypeDef* TIMx, uint16_t Compare1)

Of course, for other channels, there is a function name in the form TIM_SetComparex(x=1,2,3,4).With the above six steps, we can control the CH1 output PWM wave of TIM1.

main function

#include "led.h"
#include "delay.h"
#include "sys.h"
#include "pwm.h"

 int main(void)
	u16 led0pwmval=0;    
	u8 dir=1;	
	delay_init();	    	 //Delay function initialization	  
	LED_Init();		  	//Initialize the hardware interface to connect to the LED
	TIM1_PWM_Init(899,0);//No frequency division.PWM Frequency=72000/(899+1)=80Khz 
		else led0pwmval--;	
		TIM_SetCompare1(TIM1,led0pwmval);	  //Channel Compare Value Modify TIM1_CCR1 duty cycle


#include "pwm.h"
#include "led.h"
//PWM Output Initialization
//arr: auto-reload value
//psc: clock Prescale frequency
void TIM1_PWM_Init(u16 arr,u16 psc)
	 GPIO_InitTypeDef GPIO_InitStructure;
	TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
	TIM_OCInitTypeDef  TIM_OCInitStructure;

	RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE);// Enabling timer 1
 	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA , ENABLE);  //Enabling GPIO peripheral clock enabling

   //Set the pin as the multiplex output function to output the PWM pulse waveform of TIM1 CH1
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8; //TIM_CH1
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;  //Multiplex push-pull output
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);

	TIM_TimeBaseStructure.TIM_Period = arr; //Set the value of the auto reload register cycle for the next update event load activity 80KHZ
	TIM_TimeBaseStructure.TIM_Prescaler =psc; //Set the Prescale value to be 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 Count Mode
	TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure); //According to TIM_Unit of time base for initializing TIMx with parameters specified in TimeBaseInitStruct

	TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2; //Select timer mode: TIM pulse width modulation mode 2
	TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //Compare Output Enables
	TIM_OCInitStructure.TIM_Pulse = 0; //Set the pulse value of the capture comparison register to load
	TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; //Output Polarity: TIM output is more polar
	TIM_OC1Init(TIM1, &TIM_OCInitStructure);  //According to TIM_Parameters specified in OCInitStruct initialize peripheral TIMx channel 1

  TIM_CtrlPWMOutputs(TIM1,ENABLE);	//MOE Primary Output Enabling	

	TIM_OC1PreloadConfig(TIM1, TIM_OCPreload_Enable);  //CH1 Preloading Enables	 
	TIM_ARRPreloadConfig(TIM1, ENABLE); //Preload register enabling TIMx on ARR
	TIM_Cmd(TIM1, ENABLE);  //Enable TIM1


#ifndef __PWM_H
#define __PWM_H
#include "sys.h"

void TIM1_PWM_Init(u16 arr,u16 psc);


Note: Code source, positive atom.

Keywords: less

Added by xmarcusx on Mon, 15 Jun 2020 19:30:21 +0300