Homework for Weeks 8-9–Timer & PWM Application Programming

Experimental tasks:

Have an in-depth understanding of the STM32 timer principle and master the pulse width modulation pwm generation method.

1. Use Tim2~Tim5 of STM32F103 to connect a certain channel pin of the timer (multiplexed with the GPIOx pin, see the figure below), and use the timer counting mode to control the LED to light up periodically at a frequency of 2s. -Destroy.

2. Connect it, use the timer pwm mode, let the LED gradually brighten and fade out in the way of a breathing light, with a cycle of 1~2 seconds, and adjust to a satisfactory effect. Use Keil virtual oscilloscope to observe the pwm output waveform.

3. Connect it again, use another channel of the timer, program to collect the above pwm output signal, obtain its period and pulse width, and redirect the output to the serial port display.

1. STM32 timer principle:

Timers in STM32 can be divided into three categories: advanced timers, general timers, and basic timers. They are all driven by a programmable 16-bit prescaler (TIMX_PSC).

Composed of autoload counter (TIMX_CNT). The differences between these three timers are as follows:

2. Universal timer
1. Functional characteristics of universal timer
1. Located on the low-speed APB1 bus (APB1)

2. 16-bit up, down, up/down (center-aligned) counting mode, automatic loading counter (TIMx_CNT).

3. 16-bit programmable (can be modified in real time) prescaler (TIMx_PSC), division coefficient of counter clock frequency

It is any value between 1 and 65535.

4. 4 independent channels (TIMx_CH1~4), these channels can be used as:

input capture
Output comparison
PWM generation (edge or center aligned mode)
Single pulse mode output
5. External signals (TIMx_ETR) can be used to control the synchronization circuit of timers and timer interconnections (one timer can be used to control another timer).

2. Events that can generate interrupts or DMA
1. Update: counter overflows/underflows, counter initialization (via software or internal/external trigger)

2. Trigger events (counter start, stop, initialization or internal/external trigger counting)

3. Input capture

4. Output comparison

5. Support incremental (quadrature) encoder and Hall sensor circuits for positioning

6. Trigger input as external clock or periodic current management

3. Counter mode
1. Up counting mode: The counter counts from 0 to the automatic load value (TIMx_ARR), then starts counting from 0 again and generates a counter overflow event.

2. Down counting mode: The counter starts counting down from the automatically loaded value (TIMx_ARR) to 0, then restarts from the automatically loaded value, and generates a counter overflow event.

3. Center-aligned mode (counting up/down): The counter starts counting from 0 to the automatically loaded value -1, generating a counter overflow event, then counts down to 1 and generates a counter overflow event; then starts counting from 0 Start counting again.

4. Working process
Driven by the selected clock source (can be internal or external) and the prescaler TIMX_PSC, automatically according to the set counting mode (up, down, center aligned)

Load counter TIMX_CNT starts counting; if the corresponding event (update event, trigger event, input capture, output comparison) is enabled, the corresponding interrupt will be generated

If the input and output are not enabled, only the automatic loading after the counter overflows is enabled. It can be used as a simple timer, and the counter starts counting cycles by itself.
If the channel input capture is turned on, when the corresponding edge on the ICx signal is detected, the current value of the counter (CNT) is latched into the capture/compare register (TIMx_CCRx) and can be read out through an interrupt, assuming it is n1. Then change the signal level of the input capture (rising edge or falling edge). When the corresponding edge on the ICx signal is detected again, the current value of the counter (CNT) is latched into the capture/compare register (TIMx_CCRx) again, assuming it is n2; n2-n1 sections can calculate the duration of the level
If output control is enabled, a PWM signal with a frequency determined by the TIMx_ARR register and a duty cycle determined by the TIMx_CCRx register can be generated.
If you choose an external synchronous clock signal (TI1F_ED, TI1FP1, TI2FP2) as the clock source of the counter, it can be used to count pulses and realize the pulse frequency acquisition function.

2. Application of timer.

1. Use the Tim2~Tim5 of STM32F103 to connect a certain channel pin of the timer (multiplexed with the GPIOx pin, see the figure below), and use the timer counting mode to control the LED to light up periodically at a frequency of 2s. -Destroy.

Code:

#include "led.h"

void LED_Config(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
\t
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
\t
GPIO_InitStruct.GPIO_Mode=GPIO_Mode_Out_PP;
GPIO_InitStruct.GPIO_Pin=GPIO_Pin_0;
GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOB, & amp;GPIO_InitStruct);
}

void LED_Toggle(void)
{
GPIOB->ODR ^= GPIO_Pin_0;
}


led.h

#ifndef __LED_H
#define __LED_H

#include "stm32f10x.h"

void LED_Config(void);
void LED_Toggle(void);

#endif

tim_timebase.c

#include "tim_timebase.h"
#include "led.h"

int a = 0;

static void NVIC_Config(void)
{
NVIC_InitTypeDef NVIC_InitStruct;
\t
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
\t
NVIC_InitStruct.NVIC_IRQChannel=TIM3_IRQn;
NVIC_InitStruct.NVIC_IRQChannelCmd=ENABLE;
NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority=1;
NVIC_InitStruct.NVIC_IRQChannelSubPriority=1;
NVIC_Init( & amp;NVIC_InitStruct);
}

void TIM3_Config(void)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
\t
NVIC_Config();
\t
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
\t
TIM_TimeBaseInitStruct.TIM_Period=71;
TIM_TimeBaseInitStruct.TIM_Prescaler=1000;//1ms
TIM_TimeBaseInit(TIM3, & amp;TIM_TimeBaseInitStruct);
\t
TIM_ClearFlag(TIM3, TIM_FLAG_Update);
\t
TIM_ITConfig(TIM3, TIM_IT_Update, ENABLE);
\t
TIM_Cmd(TIM3, ENABLE);
}

void TIM3_IRQHandler(void)
{
if(TIM_GetITStatus(TIM3, TIM_IT_Update)) a + + ;
if(a == 1000)
{
LED_Toggle();
a = 0;
}
TIM_ClearITPendingBit(TIM3, TIM_IT_Update);
}

tim_timebase.h

#ifndef __TIM_TIMEBASE_H
#define __TIM_TIMEBASE_H

#include "stm32f10x.h"

void TIM3_Config(void);

#endif

main.c

#include "stm32f10x.h"
#include "led.h"
#include "tim_timebase.h"

int main(void)
{
LED_Config();
TIM3_Config();
\t
while(1)
{
\t\t
}
}

3. Application of PWM

  1. Connect it, use the timer PWM mode, let the LED gradually brighten and fade out in the way of a breathing light, with a cycle of 1~2 seconds, and adjust it to a satisfactory effect. Use Keil virtual oscilloscope to observe the PWM output waveform.

code
PWM.c

#include "stm32f10x.h" // Device header

void PWM_Init(void)
{
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
\t
// RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
//GPIO_PinRemapConfig(GPIO_PartialRemap1_TIM2, ENABLE);
//GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE);
\t
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; //GPIO_Pin_15;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, & amp;GPIO_InitStructure);
\t
TIM_InternalClockConfig(TIM2);
\t
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInitStructure.TIM_Period = 100 - 1; //ARR
TIM_TimeBaseInitStructure.TIM_Prescaler = 720 - 1; //PSC
TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;
TIM_TimeBaseInit(TIM2, & amp;TIM_TimeBaseInitStructure);
\t
TIM_OCInitTypeDef TIM_OCInitStructure;
TIM_OCStructInit( & amp;TIM_OCInitStructure);
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitStructure.TIM_Pulse = 0; //CCR
TIM_OC1Init(TIM2, & amp;TIM_OCInitStructure);
\t
TIM_Cmd(TIM2, ENABLE);
}

void PWM_SetCompare1(uint16_t Compare)
{
TIM_SetCompare1(TIM2, Compare);
}
main.c

#include "stm32f10x.h" // Device header
#include "Delay.h"
#include "OLED.h"
#include "PWM.h"

uint8_t i;

int main(void)
{
OLED_Init();
PWM_Init();
\t
while (1)
{
for (i = 0; i <= 100; i + + )
{
PWM_SetCompare1(i);
Delay_ms(5);
}
for (i = 0; i <= 100; i + + )
{
PWM_SetCompare1(100 - i);
Delay_ms(5);
}
}
}

Use Keil virtual oscilloscope to observe the PWM output waveform

It is marked as bit display and represented by a green line. The obtained waveform result is as shown in the figure below: