STM32F407ZGT6——10-1高级定时器输出指定个数 PWM 实验

一、高级定时器简介

高级定时器的框图和通用定时器框图很类似,只是添加了其它的一些功能,如:重复计数器、带死区控制的互补输出通道、断路输入等。
高级定时器的时钟来自APB2, 而PCLK2 = 168Mhz, 我们设置PPRE2不分频, 因此高 级定时器时钟 = 168Mhz。
STM32F407ZGT6——10-1高级定时器输出指定个数 PWM 实验_第1张图片

1、重复计数器

在学习基本定时器和通用定时器的时候,我们知道定时器发生上溢或者下溢时,会直接生成更新事件。有重复计数器的定时器并不完全是这样的,定时器每次发生上溢或下溢时, 重复计数器的值会减一,当重复计数器的值为 0 时,再发生一次上溢或者下溢才会生成定时器更新事件

2、输出比较

第②部分的 TIMx_CH1N、TIMx_CH2N 和 TIMx_CH3N 分别是定时器通道 1、通道 2 和通道 3的互补输出通道,通道4 是没有互补输出通道的。DTG 是死区发生器,死区时间由DTG[7:0]位来配置。如果不使用互补通道和死区时间控制,那么高级定时器 TIM1 和 TIM8 和通用定时器的输出比较部分使用方法基本一样, 只是要注意 MOE 位得置1 定时器才能输出。

3、断路功能

断路功能也称刹车功能,一般用于电机控制的刹车。F4 系列有一个断路通道,断路源可以是刹车输入引脚(TIMx_BKIN),也可以是一个时钟失败事件。时钟失败事件由复位时钟控制器中的时钟安全系统产生。系统复位后,断路功能默认被禁止,MOE 位为低。
使能断路功能的方法:将TIMx_BDTR 的位 BKE 置1。断路输入引脚 TIMx_BKIN 的输入有效电平可通过TIMx_BDTR 寄存器的位BKP 设置。
使能刹车功能后:由 TIMx_BDTR 的MOE、OSSI、OSSR 位,TIMx_CR2 的OISx、OISxN位,TIMx_CCER 的CCxE、CCxNE 位控制OCx 和OCxN 输出状态。无论何时,OCx 和OCxN输出都不能同时处在有效电平。 
当发生断路输入后,会怎么样?
1,MOE 位被异步地清零,OCx 和OCxN 为无效、空闲或复位状态(由OSSI 位选择)。 
2,OCx 和 OCxN 的状态:由相关控制位状态决定,当使用互补输出时:根据情况自动控制输出电平,参考《STM32F4xx 参考手册_V4(中文版).pdf》手册第382 页的表73 具有断路功能的互补通道Ocx 和 OcxN 的控制位。
3,BIF 位置1,如果使能了 BIE 位,还会产生刹车中断;如果使能了TDE 位,会产生DMA请求。
4,如果AOE 位置 1,在下一个更新事件 UEV 时,MOE 位被自动置1。
高级定时器框图部分就简单介绍到这里,下面通过实际的实验来学习高级定时器。
STM32F407ZGT6——10-1高级定时器输出指定个数 PWM 实验_第2张图片
STM32F407ZGT6——10-1高级定时器输出指定个数 PWM 实验_第3张图片

二、实验内容

本实验使用板子为stm32f4探索者V2,我们设置 TIM8 的通道1 为PWM1 模式,使用杜邦线把PC6 与PF10 进行连接,因为我们的LED1(连接 PF10)是低电平亮,而我们希望输出最后一个PWM 波的时候,LED1 就灭,所以我们设置输出比较极性为高。捕获/比较寄存器的值(即比较值)设置为自动重装载值的一半,即PWM 占空比为 50%。并且本次实验不设置限制脉冲输出个数(正点原子设置最多256个)。

三、相关配置函数

pwm波形由高级定时器的输出比较产生。
STM32F407ZGT6——10-1高级定时器输出指定个数 PWM 实验_第4张图片

1、atim.c文件

#include "./BSP/TIMER/atim.h"

static uint16_t npwm_remain;

TIM_HandleTypeDef atim_timx_chy_oc_handle;

void atim_timx_chy_oc_init(uint16_t psc, uint16_t arr)
{
    /* 时钟使能 */
    __HAL_RCC_GPIOC_CLK_ENABLE();
    __HAL_RCC_TIM8_CLK_ENABLE();
    
    /* TIM初始化 */
    atim_timx_chy_oc_handle.Instance = TIM8;
    atim_timx_chy_oc_handle.Init.Prescaler = psc;
    atim_timx_chy_oc_handle.Init.Period = arr;
    atim_timx_chy_oc_handle.Init.CounterMode = TIM_COUNTERMODE_UP;
    atim_timx_chy_oc_handle.Init.RepetitionCounter = 5-1;        /* 默认初始化为输出5个pwm波 */
    atim_timx_chy_oc_handle.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE; /* 使能TIMx_ARR进行缓冲 */
    HAL_TIM_PWM_Init(&atim_timx_chy_oc_handle);
    
    /* GPIO引脚定义 */
    GPIO_InitTypeDef gpio_init_struct;
    gpio_init_struct.Pin = GPIO_PIN_6;                   /* LED0引脚 */
    gpio_init_struct.Mode = GPIO_MODE_AF_PP;            /* 推挽输出 */
    gpio_init_struct.Pull = GPIO_PULLUP;                    /* 上拉 */
    gpio_init_struct.Speed = GPIO_SPEED_FREQ_HIGH;          /* 高速 */
    gpio_init_struct.Alternate = GPIO_AF3_TIM8;
    HAL_GPIO_Init(GPIOC, &gpio_init_struct);             /* 初始化LED0引脚 */
    
//    /* 从模式初始化 */
//    TIM_SlaveConfigTypeDef timx_chy_slave_config = {0};
//    timx_chy_slave_config.SlaveMode = TIM_SLAVEMODE_EXTERNAL1;
//    timx_chy_slave_config.InputTrigger = TIM_TS_TI1FP1;
//    timx_chy_slave_config.TriggerPolarity = TIM_TRIGGERPOLARITY_RISING;
//    timx_chy_slave_config.TriggerPrescaler = TIM_TRIGGERPRESCALER_DIV1;
//    timx_chy_slave_config.TriggerFilter = 0;
//    HAL_TIM_SlaveConfigSynchro(&atim_timx_chy_oc_handle, &timx_chy_slave_config);

    /* 输出比较产生PWM */
    TIM_OC_InitTypeDef timx_chy_oc_config = {0};
    timx_chy_oc_config.OCMode = TIM_OCMODE_PWM1;
    timx_chy_oc_config.Pulse = arr/2;
    timx_chy_oc_config.OCPolarity = TIM_OCPOLARITY_HIGH;
    HAL_TIM_PWM_ConfigChannel(&atim_timx_chy_oc_handle,&timx_chy_oc_config,TIM_CHANNEL_1);
    
    /* 使能定时中断并设置优先级,使能更新中断,使能通道 */

    
    HAL_NVIC_SetPriority(TIM8_UP_TIM13_IRQn,1,3);
    HAL_NVIC_EnableIRQ(TIM8_UP_TIM13_IRQn);
    __HAL_TIM_ENABLE_IT(&atim_timx_chy_oc_handle,TIM_IT_UPDATE);
    HAL_TIM_PWM_Start(&atim_timx_chy_oc_handle, TIM_CHANNEL_1);
    

    
}

void npwm_set(uint16_t npwm)
{
    if(npwm == 0) return;
    
    npwm_remain = npwm;
    HAL_TIM_GenerateEvent(&atim_timx_chy_oc_handle, TIM_EVENTSOURCE_UPDATE); /* 产生一次更新事件,在中断里面处理脉冲输出 */
    __HAL_TIM_ENABLE(&atim_timx_chy_oc_handle);                              /* 使能定时器TIMX */

}
void TIM8_UP_TIM13_IRQHandler(void)
{
    if(__HAL_TIM_GET_FLAG(&atim_timx_chy_oc_handle,TIM_FLAG_UPDATE) != RESET)
    {
        if(npwm_remain)
        {
            TIM8->RCR = npwm_remain - 1;
            HAL_TIM_GenerateEvent(&atim_timx_chy_oc_handle, TIM_EVENTSOURCE_UPDATE); /* 产生一次更新事件,在中断里面处理脉冲输出 */
            __HAL_TIM_ENABLE(&atim_timx_chy_oc_handle);                              /* 使能定时器TIMX */
            npwm_remain = 0;
        }
        else
        {
            TIM8->CR1 &= ~(1 << 0);     /* 1左移0位,CEN置0,关闭定时器TIMX,使用HAL Disable会清除PWM通道信息,此处不用 */
        }
    }
    __HAL_TIM_CLEAR_IT(&atim_timx_chy_oc_handle,TIM_IT_UPDATE); /* 清除定时器溢出中断标志位 */
}

2、main.c文件

#include "./SYSTEM/sys/sys.h"
#include "./SYSTEM/usart/usart.h"
#include "./SYSTEM/delay/delay.h"
#include "./BSP/LED/led.h"
#include "./BSP/KEY/key.h"
#include "./BSP/TIMER/atim.h"


int main(void)
{
    uint8_t t;
    uint8_t key;
    
    HAL_Init();                                 /* 初始化HAL库 */
    sys_stm32_clock_init(336, 8, 2, 7);         /* 设置时钟,168Mhz */
    delay_init(168);                            /* 延时初始化 */
    usart_init(115200);                         /* 串口初始化为115200 */
    led_init();                                 /* 初始化LED */
    key_init();                                 /* 初始化按键 */
    
    
    GPIO_InitTypeDef gpio_init_struct;
    
    gpio_init_struct.Pin = GPIO_PIN_10;                   /* LED1引脚 */
    gpio_init_struct.Mode = GPIO_MODE_INPUT;            /* 推挽输出 */
    gpio_init_struct.Pull = GPIO_PULLUP;                    /* 上拉 */
    gpio_init_struct.Speed = GPIO_SPEED_FREQ_HIGH;          /* 高速 */
    HAL_GPIO_Init(GPIOF, &gpio_init_struct);       /* 初始化LED1引脚 */

    atim_timx_chy_oc_init(8400 - 1, 10000 - 1);
    
    while (1)
    {
        key = key_scan(0);
        if(key)
        {
            npwm_set(5);
        }
        t++;
        if(t > 20)
        {
            t = 0;
            LED0_TOGGLE();
        }
        delay_ms(10);
    }
}

 

四、注意事项

1、时钟使能应该放在初始化函数的最前面。(笔者没有使用映射函数,最开始将时钟使能放到最后面,结果一直没有实验现象)
    /* 时钟使能 */
    __HAL_RCC_GPIOC_CLK_ENABLE();
    __HAL_RCC_TIM8_CLK_ENABLE();
2、

HAL_TIM_PWM_Start(&g_timx_pwm_chy_handle, TIM_CHANNEL_1);

能够把MOE位置1

你可能感兴趣的:(单片机,stm32,嵌入式硬件)