Basic knowledge of STM32 timer

STM32 timers

PWM mode

#include "stm32f4xx.h"

void GPIO_Configuration(void);
void TIM3_Configuration(void);

int main(void)
{
    
    
    GPIO_Configuration();
    TIM3_Configuration();
    
    while (1)
    {
    
    
        // 在这里可以根据需要调整电机的运动状态
    }
}

void GPIO_Configuration(void)
{
    
    
    GPIO_InitTypeDef GPIO_InitStructure;

    // 使能GPIOB时钟
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);

    // 配置PB4引脚为复用功能,用于TIM3的通道1
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; // 复用功能
    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; // 推挽输出
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; // 上拉
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz; // 100MHz
    GPIO_Init(GPIOB, &GPIO_InitStructure);

    // 配置PB4引脚为TIM3的通道1
    GPIO_PinAFConfig(GPIOB, GPIO_PinSource4, GPIO_AF_TIM3);
}

void TIM3_Configuration(void)
{
    
    
    TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
    TIM_OCInitTypeDef TIM_OCInitStructure;

    // 使能TIM3时钟
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);

    // 配置TIM3的基本参数
    TIM_TimeBaseStructure.TIM_Period = 999; // PWM周期为1000个时钟周期
    TIM_TimeBaseStructure.TIM_Prescaler = 8399; // 时钟预分频为8400,使定时器时钟为10kHz
    TIM_TimeBaseStructure.TIM_ClockDivision = 0;
    TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
    TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);

    // 配置TIM3的通道1为PWM模式1
    TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
    TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
    TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
    TIM_OC1Init(TIM3, &TIM_OCInitStructure);

    // 启动TIM3的通道1
    TIM_OC1PreloadConfig(TIM3, TIM_OCPreload_Enable);

    // 启动TIM3
    TIM_Cmd(TIM3, ENABLE);
}

In the above example, we used timer 3 of STM32 and pin 4 of GPIOB to control the movement of the motor.

First, we need to enable the clock of GPIOB in the GPIO configuration function, and configure the PB4 pin as an alternate function for channel 1 of TIM3.

Then, in the timer configuration function, we enable the clock of TIM3, and configure the basic parameters of TIM3 and the PWM mode of channel 1.

Finally, we can adjust the motion state of the motor as needed in the main function.

In the above code, we use channel 1 of timer 3 of STM32 to output PWM signal . In the configuration function of TIM3, we use TIM_OCMode_PWM1mode to configure channel 1 as PWM output mode 1.

In PWM mode 1, when the value of the counter is less than or equal to the comparison value of the channel, the output is high level ; when the value of the counter is greater than the comparison value of the channel, the output is low level . By adjusting the size of the comparison value, we can control the duty cycle of the PWM signal, thereby controlling the motion state of the motor .

In the above code, we set the cycle of TIM3 to 999, that is, the PWM cycle is 1000 clock cycles. We set the prescaler of TIM3 to 8399, so that the clock frequency of TIM3 is 10kHz. In this way, we can control the duty cycle of the PWM signal by adjusting the comparison value (that is, the value of the comparison register of channel 1 of TIM3).

For example, if we set the comparison value to 500, then the duty cycle of the PWM signal will be 50% (500 clock cycles at high level, 500 clock cycles at low level), and the motor will move at a certain speed. If we set the comparison value to 100, then the duty cycle of the PWM signal will be 10% (100 clock cycles high, 900 clock cycles low), and the motor will move at a slower speed.

In the main function, we can adjust the size of the comparison value as needed , so as to control the motion state of the motor .


在上述代码中,电机的控制周期是通过定时器TIM3的配置来确定的。具体来说,我们将TIM3的周期设置为999,即PWM周期为1000个时钟周期。同时,我们将TIM3的预分频器设置为8399,使得TIM3的时钟频率为10kHz。因此,电机的控制周期为1000个时钟周期,即每个周期的时间为1000个时钟周期的时间。由于TIM3的时钟频率为10kHz,因此电机的控制周期为1000个时钟周期的时间,即0.1秒。

需要注意的是,电机的控制周期可以根据实际需求进行调整。在上述代码中,我们将TIM3的预分频器设置为8399,使得TIM3的时钟频率为10kHz,以便实现较高的控制精度。如果需要更快的控制周期,可以调整预分频器的值和TIM3的周期的值。
在代码中,我们将TIM3的预分频器设置为8399,使得TIM3的时钟频率为10kHz。而TIM3的周期被设置为999,即PWM周期为1000个时钟周期。因此,每个时钟周期的时间是由TIM3的时钟频率决定的,即100us(1 / 10kHz)。

由于TIM3的周期被设置为999,所以PWM信号的一个完整周期需要1000个时钟周期,即100ms(100us * 1000)。这个周期内,PWM信号的高电平时间(占空比)由比较值(TIM3的通道1的比较寄存器的值)决定。

所以,每个时钟周期的时间并不是1000个时钟周期,而是由TIM3的时钟频率决定的。在上述代码中,TIM3的时钟频率为10kHz,因此每个时钟周期的时间为100us。

encoder mode

The following is a sample code that uses STM32's timer 4 to set the encoder mode and judge the motor rotation position by the number of pulses:

#include "stm32f4xx.h"

#define ENCODER_PULSES_PER_REVOLUTION 1000 // 每转脉冲数
#define MOTOR_GEAR_RATIO 10 // 电机齿轮比

volatile int32_t encoder_count = 0; // 编码器计数器

void TIM4_IRQHandler(void)
{
    
    
    if (TIM_GetITStatus(TIM4, TIM_IT_Update) != RESET) {
    
    
        // 每次定时器溢出中断发生时,更新编码器计数器
        encoder_count += (TIM4->CR1 & TIM_CR1_DIR) ? -1 : 1;
        TIM_ClearITPendingBit(TIM4, TIM_IT_Update);
    }
}

void configure_encoder(void)
{
    
    
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE);

    TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
    TIM_TimeBaseStructure.TIM_Period = 0xFFFF;
    TIM_TimeBaseStructure.TIM_Prescaler = 0;
    TIM_TimeBaseStructure.TIM_ClockDivision = 0;
    TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
    TIM_TimeBaseInit(TIM4, &TIM_TimeBaseStructure);

    TIM_EncoderInterfaceConfig(TIM4, TIM_EncoderMode_TI12, TIM_ICPolarity_Rising, TIM_ICPolarity_Rising);
    TIM_SetAutoreload(TIM4, 0xFFFF);

    TIM_ClearFlag(TIM4, TIM_FLAG_Update);
    TIM_ITConfig(TIM4, TIM_IT_Update, ENABLE);

    NVIC_InitTypeDef NVIC_InitStructure;
    NVIC_InitStructure.NVIC_IRQChannel = TIM4_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);

    TIM_Cmd(TIM4, ENABLE);
}

int32_t get_motor_position(void)
{
    
    
    int32_t pulses_per_revolution = ENCODER_PULSES_PER_REVOLUTION * MOTOR_GEAR_RATIO;
    return (encoder_count * 360) / pulses_per_revolution;
}

int main(void)
{
    
    
    configure_encoder();

    while (1) {
    
    
        int32_t position = get_motor_position();
        // 在这里使用获取到的位置进行相应的操作
    }
}

In this sample code, we first define the number of pulses per revolution and the motor gear ratio, and then declare a global encoder_countvariable to store the encoder pulse count.

In TIM4_IRQHandlerthe interrupt handler function, we update the variable every time the timer overflow interrupt occurs encoder_count. Whether to increase or decrease the count is judged according to the direction bit of the timer.

configure_encoderThe function is used to configure timer 4 as encoder mode, and set the clock frequency division, counting mode and encoder interface of the timer.

get_motor_positionThe function is used to calculate the position of the motor, and the position of the motor is calculated according to the encoder count and the set pulse number and gear ratio.

In mainthe function, we configure_encoderconfigure the encoder by calling the function, and then keep getting the position of the motor in an infinite loop and operate accordingly.

Note that the above code is just an example, and the specific implementation may need to be appropriately modified according to your specific hardware and needs.

Timer 4 encoder mode in code

以上代码是使用STM32的定时器4设置为编码器模式,并实时输出脉冲数的示例。

首先,在Encoder_Init_TIM4函数中,进行了以下设置:
1. 使能TIM4时钟和PORTB时钟。
2. 配置GPIOB的PB6和PB7引脚为浮空输入模式。
3. 初始化TIM4的预分频器和计数器自动重装值。
4. 选择时钟分频为不分频,选择计数模式为边沿对齐模式。
5. 配置输入捕获1滤波器和所有输入上升沿和下降沿都有效。
6. 设定计数器初始值。
7. 使能定时器。

然后,Read_Encoder函数用于单位时间读取编码器计数。根据传入的TIMX参数,选择相应的定时器,并返回其计数值。
在Encoder_Init_TIM4函数中,设置了定时器的计数器初始值为TIM4->CNT = 10000; 这里将计数器初始值设为一个固定值,可以根据实际需求进行调整。

然后,在Read_Encoder函数中,根据传入的TIMX参数选择相应的定时器,通过读取对应定时器的CNT寄存器,即可获取到编码器的计数值。

例如,如果传入的TIMX为4,则通过读取TIM4的CNT寄存器来获取编码器的计数值:
Encoder_TIM= (short)TIM4 -> CNT;

注意,这里使用了(short)进行类型转换,将CNT寄存器的值转换为一个有符号的短整型,以适应不同的计数范围。具体的计数范围可以根据实际的编码器和定时器配置进行调整。
(int)TIM4->CNT; 是将 TIM4 的 CNT 寄存器的值强制转换为 int 类型的数据。CNT 寄存器是定时器/计数器的计数器值寄存器,用于存储当前的计数器值。

在编码器模式下,TIM4 的 CNT 寄存器会根据编码器的脉冲输入进行自动计数。每当编码器的脉冲信号发生一个上升沿或下降沿时,CNT 寄存器的值就会相应地增加或减少。

通过读取 CNT 寄存器的值,可以获取当前的编码器计数值。在示例代码中,通过将 CNT 寄存器的值强制转换为 int 类型,可以将计数值作为整数返回。

Guess you like

Origin blog.csdn.net/shouchen1/article/details/131453185