STM32F103 - description and function of general timer

preface

In this section, we will describe and introduce the general timer function of STM32, and also summarize STM32 (VI) and STM32 (VII)

---------------------—

catalogue

1. Introduction to general timer

2. Timer initialization function

3. PWM wave

---------------------—

I Introduction of timer

-------

1. What is a universal timer?

The general timer of STM32F1 is composed of a 16 bit free load counter (CNT) driven by a programmable prescaler (PSC). The general TIMx (2, 3, 4, 5) timer can be used to measure the pulse length of the input signal (input acquisition) or generate the output waveform (output comparison ^ PWM), etc

-------

2. Timer function

(1) 16 bit up-down} automatic load counter (TIMx_CNT)

(2) 16 bit programmable (real-time modifiable) prescaler (TIMx_PSC)

(3) 4 # independent channels (TIMx_CH1~4), which can be used as:

PWM, input capture, output comparison, single pulse mode output

  __________________________   

3. Conditions for interruption

A. update: counter overflow upward / downward, counter initialization (triggered by software or internal / external)
B. trigger events (counter start, stop, initialization or counting by internal / external trigger)
C. input capture
D. output comparison
E. support incremental (quadrature) encoder and Hall sensor circuits for positioning
F. trigger input as external clock or current management by cycle
--------

4. TIM clock source

Here, there are four clock sources of the timer:
(1) internal clock (CK_INT)
(2) external clock mode 1: external input pin (TIx)
(3) external clock mode 2: external trigger input (ETR)
(4) internal trigger input (ITRx): use timer A as prescaler of timer B (A provides clock for B)
--------
Note that TIMx_CNT} register, which is the counter of the timer. This register stores the count value of the current timer. Next, let's take a look at the following flow chart

 ---------------------

II Timer initialization function

_______________________________

Let's go through the general process of initialization

(1) No matter what peripheral it is, as long as it is used, we must enable the corresponding clock

(2) Initialization function (timer)

(3) Turn on the corresponding interrupt and configure the NVIC

(4) Enable timer

(5) Write the interrupt service function, which is used in the above interrupt
--------

First of all, we must define our function. Here, we define a function filled with two parameters

void TIM3_Int_Init(u16 arr,u16 psc);

arr: automatic reload value} psc: pre division frequency

Calculation method of clock:

When initializing with the SystenInit function, the clock frequencies are as follows:
SYSCLK = 72M
AHB clock = 72M
APB1 clock = 36M
Therefore, the frequency division coefficient of APB1 = AHB/APB1=2
Thus, CK can be obtained_ The clock frequency of int is 2*36M = 72M
The final frequency of the counter needs to be calculated by PSC prescaler

The generation time is mainly determined by TIMx_PSC and TIMx_ARR is determined by two register values, which is the cycle of the timer

Let's set timx first_ The value of arr register is 9999, that is, when TIMx_CNT is calculated from 0, which is just equal to the event generated at 9999, counting 10000 times in total. If the clock source cycle is 100us at this time, a timing cycle of just 1s can be obtained.
The next problem is to set TIMx_PSC register value makes CK_ The CNT output is a clock of 100us cycle (10000Hz). Input clock ck of Prescaler_ The PSC is 90MHz, so setting the prescaler value to (9000-1) is sufficient
--------

Next, we officially enter our configuration process

----------

1. Clock enable

void TIM3_Int_Init(u16 arr,u16 psc)
{
    TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
	NVIC_InitTypeDef NVIC_InitStructure;

	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); //Clock enable

We have added several definitions to facilitate the following initialization functions. Similarly, we need to use the general timer 3 next, so we enable TIM3 (note which channel it is attached to)

--------

2. Initialize timer

TIM_TimeBaseStructure.TIM_Period = arr; //Sets the value of the auto reload register cycle of the load activity at the next update event

TIM_TimeBaseStructure.TIM_Prescaler =psc; //Sets the prescaled value used as the divisor of TIMx clock frequency

TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; //Set clock division: TDTS = Tck_tim

TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  //TIM up count mode

TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); //Initializes the time base unit of TIMx according to the specified parameters

We talked about our arr and psc earlier. Let's take a look at its counting mode

(1) Count up mode: the counter counts from 0 to the automatic loading value (arr), then generates a counter overflow event, and then starts counting from 0 again

(2) Count down mode: the counter starts counting from arr to 0, then generates a counter overflow event, and then starts counting from 0 #

(3) Up / down counting mode: the counter starts counting from 0 to arr - 1, generates an overflow event, then starts counting from this value to 1, generates an overflow event, and then starts counting from 0

-------

3. Enable interrupt and configure NVIC

    TIM_ITConfig(TIM3,TIM_IT_Update,ENABLE ); //Enables the specified TIM3 interrupt and allows the update interrupt

	NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn;  //TIM3 interrupt
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;  //Preemption priority level 0
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;  //From priority level 3
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ channel enabled
	NVIC_Init(&NVIC_InitStructure);  //Initialize NVIC register

The following NVIC has been explained earlier. Let's take a look

TIM_ITConfig(TIM3,TIM_IT_Update,ENABLE );

static void TI3_Config(TIM_TypeDef* TIMx, uint16_t TIM_ICPolarity, uint16_t TIM_ICSelection,uint16_t TIM_ICFilter);

We can see that this function requires us to fill in three parameters: TIMx (channel), interrupt mode (we have selected a newer interrupt) and enable

___________________________________

4. Enable timer

TIM_Cmd(TIM3, ENABLE);  //Enable TIMx	

----------

5. Configure interrupt function

void TIM3_IRQHandler(void)   //TIM3 interrupt
{
	if (TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET)  //Check whether the TIM3 update interrupt occurs
		{
		TIM_ClearITPendingBit(TIM3, TIM_IT_Update  );  //Clear TIMx update interrupt flag 
		LED1=!LED1;
		}
}

Here we are just giving an example. Let's explain it:

We check our interrupt flag bit TIM_GetITStatus 

If we detect that he is 1 (interrupt occurs), let the LED light change his state (on / off); Of course, we'd better clear our flag bit, or he'll get stuck in it_ ClearITPendingBit   

We usually put him last

--------

In this way, our timer configuration is completed. Let's see how to use it

 int main(void)
 {		
 
	delay_init();	    	 //Delay function initialization	  
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //Set NVIC interrupt packet 2: 2-bit preemption priority and 2-bit response priority
	uart_init(115200);	 //The serial port is initialized to 115200
 	LED_Init();			     //LED port initialization
	TIM3_Int_Init(4999,7199);//The counting frequency of 10Khz is 500ms when counting to 5000  
   	while(1)
	{
		LED0=!LED0;
		delay_ms(200);		   
	}	 

 
}	 

LED0 here is a comparison with LED1 to see if our timer is accurate

---------------------

III PWM wave

-------

1. What is PWM?

Pulse Width Modulation (PWM), the abbreviation of "Pulse Width Modulation", is a very effective technology to control analog circuits by using the digital output of microprocessor. It is widely used in many fields from measurement, communication to power control and conversion.

-------

2. How is PWM generated?

Speaking of this, we will explain it in the figure above (STM (VII))

 ---

With the accumulation of the count value, it will reach the {orange line we set before. When it arrives, it will send an overflow signal, and then the count value will be cleared. Each cycle represents} a PWM cycle


One cycle of PWM:
The timer counts up from 0
When segment 0-t1, timer counter TIMx_CNT value is less than CCRx value, output low level
t1-t2 segment, timer counter TIMx_CNT value is greater than CCRx value, output high level
When timx_ When the CNT value reaches ARR, the timer overflows and counts up again Cycle this process
At this point, one PWM cycle is completed
 

The next question is how to produce high and low level changes in this cycle

——Flag value of duty cycle - (therefore, there is our red line, and CCRx determines the duty cycle). When CCRx is exceeded, the level changes from 0 to 1 (whether it changes to 0 or 1 depends on our configuration later. Here is an example)
------

Here is his output flow

 -----

3. PWM library function configuration

PWM configuration is based on TIM (timer) configuration

-----

First, define the initialization function. As before TIM, you need to configure arr and psc

void TIM3_PWM_Init(u16 arr,u16 psc)

-----

1. Enable timer (define structure)

void TIM3_PWM_Init(u16 arr,u16 psc)
{  
	GPIO_InitTypeDef GPIO_InitStructure;
	TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
	TIM_OCInitTypeDef  TIM_OCInitStructure;
	

	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);	//Enable timer 3 clock
 	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB  | RCC_APB2Periph_AFIO, ENABLE);  
    //Enable GPIO peripheral and AFIO multiplexing function module clock

We need lights to show the effect of our PWM, so we turn on GPIO and won't introduce it later

-----

   //Set this pin as the multiplexing output function to output the PWM pulse waveform of TIM3 CH2 	 GPIOB. five
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5; //TIM_CH2
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;  //Multiplexed push-pull output
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOB, &GPIO_InitStructure);//Initialize GPIO
 
   //Initialize TIM3
	TIM_TimeBaseStructure.TIM_Period = arr; 
   //Sets the value of the auto reload register cycle of the load activity at the next update event
	TIM_TimeBaseStructure.TIM_Prescaler =psc; //Sets the prescaled value used as the divisor of TIMx clock frequency 
	TIM_TimeBaseStructure.TIM_ClockDivision = 0; //Set clock division: TDTS = Tck_tim
	TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  //TIM up count mode
	TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); 
   //According to Tim_ The parameter specified in timebaseinitstruct initializes the time base unit of TIMx

-----

2. Configure PWM mode

	//Initialize TIM3 Channel2 PWM mode	 
	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 enable
	TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; //Output polarity: TIM output has high polarity
	TIM_OC2Init(TIM3, &TIM_OCInitStructure);  //Initialize the peripheral TIM3 OC2 according to the parameters specified by T

The polarity here means to set the effective high / low level, which requires us to cooperate with the above timer mode

The PWM mode in STM32 only distinguishes when the active level is, but does not determine whether the high level is active or the low level is active, and which is the polarity setting

-----

3. Enable channel

Operation timx_ CC1P bit of CCER, modify channel polarity

void TIM_OC1NPolarityConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCNPolarity);
	TIM_OC2PreloadConfig(TIM3, TIM_OCPreload_Enable);  //Enable TIM3 preload register on CCR2
	TIM_Cmd(TIM3, ENABLE);  //Enable TIM3


-------

After configuration, let's see how to use it

 int main(void)
 {		
 	u16 led0pwmval=0;
	u8 dir=1;	
	delay_init();	    	 //Delay function initialization	  
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); 	
    //Set NVIC interrupt packet 2: 2-bit preemption priority and 2-bit response priority
	uart_init(115200);	     //The serial port is initialized to 115200
 	LED_Init();			     //LED port initialization
 	TIM3_PWM_Init(899,0);	 //No frequency division. PWM frequency = 72000000/900=80Khz
   	while(1)
	{
 		delay_ms(10);	 
		if(dir1 == 1)// dir is originally assigned to 1
             led0pwmval++;
		else 
             led0pwmval--;

 		if(led0pwmval>300)dir=0;
		if(led0pwmval==0)dir=1;										 
		TIM_SetCompare2(TIM3,led0pwmval);		   
	}	 
 }

-----

TIM_SetCompare2(TIM3,led0pwmval); / / change the comparison value tim3 - > CCR2 to adjust the duty cycle

Our comparison value is a variable, so it can be changed constantly

---------------------

Keywords: Single-Chip Microcomputer stm32 ARM linq p2p

Added by McChicken on Tue, 18 Jan 2022 06:18:00 +0200