一、高级定时器简介
1、STM32F103有两个高级定时器,分别是TIM1和TIM8。
2、主要特性
- 16位递增、递减、中心对齐计数器(计数值:0~65535)
- 16位预分频器(分频系数:1~65536)
- 可用于触发DAC、ADC
- 在更新事件、触发事件、输入捕获、输出比较时,会产生中断/DMA请求4个独立通道,可用于:输入捕获、输出比较、输出PWM、单脉冲模式使用外部信号控制定时器且可实现多个定时器互连的同步电路支持编码器和霍尔传感器电路等
- 重复计数器
死区时间带可编程的互补输出 - 断路输入,用于将定时器的输出信号置于用户可选的安全配置中
3、高级定时器框图
高级定时器的时钟源部分跟通用定时器是一样的,主要区别在重复计数器、互补输出部分、刹车输入。
重复计数器:通用定时器在计数器溢出的时候,就会产生更新事件和更新中断。而高级定时器多了重复计数器,计数器溢出后,需要经过重复计数器才会产生更新事件或者更新中断。首先往RCR寄存器里边写入值REP,每当计数器值溢出的时候,重复计数器的值就减一,当重复计数器的值递减到0的时候,再次溢出就会产生更新事件或者更新中断。
互补输出部分:通用定时器只有CH1、CH2、CH3、CH4,而高级定时器除了这些通道以外,还有CH1N、CH2N、CH3N三个互补通道。通道4是没有互补通道的,DTG是用于设置死区时间的。
刹车输入:TIMx_BKIN引脚,信号BRK进来以后,首先经过一个极性选择,看是高电平有效还是低电平有效。经过一个或门,产生刹车中断(BI)。或门信号还可以来自时钟安全系统CSS。
二、高级定时器输出指定个数PWM实验原理
1、重复计数器特性
计数器每次上溢或下溢都能使重复计数器减1,减到0时,再发生一次溢出就会产生更新事件
当TIMx_RCR寄存器的值设置为0的时候,没,每当计数器溢出时,由于 重复计数器的值已经是0了,所以每次计数器溢出时,都会产生更新事件。
当TIMx_RCR寄存器的值设置为3的时候,当计数器的值溢出三次后,重复计数器的值递减到0了,当计数器的值再次溢出时,则产生更新事件。
再同步:由于RCR重复计数寄存器的存在影子寄存器,实际起作用的是影子寄存器,当软件产生更新事件以后,RCR寄存器里边的值会转移到影子寄存器里边,比如当影子寄存器里边已经递减到1了,软件更新事件产生后,影子寄存器的值会恢复为3,因此需要计数器再溢出4次才能产生更新事件或者更新中断。有点像影子寄存器复位的意思。
如果设置RCR为N,更新事件将在N+1次溢出时发生。
2、实验原理
- 配置边沿对齐模式输出PWM
- 指定输出N个PWM,则把N-1写入RCR
- 在更新中断内,关闭计数器
注意:高级定时器通道输出必须把MOE位置1
三、高级定时器输出指定个数PWM实验配置步骤
1、HAL_TIM_PWM_Init()函数,配置定时器基础工作参数。这个函数与HAL_TIM_Base_init()函数功能是一样的。
2、HAL_TIM_PWM_MspInit(),配置NVIC、CLOCK、GPIO等。
3、HAL_TIM_PWM _Configchannel()函数,配置PWM模式/比较值。‘
4、HAL NVIC SetPriority()、HAL_NVIC_EnablelRQ()函数,设置优先级,使能中断
5、HAL_TIM_PWM _Start()函数,使能输出、主输出、启动计数器。
6、__HAL TIM ENABLE IT()宏定义,使能定时器更新中断
7、TIMx_IROHandler()等>HAL_TIM_IROHandler()函数,编写中断服务函数
8、HAL_TIM_PeriodElapsedCallback()函数,编写更新中断回调函数
四、高级定时器输出指定个数PWM实验配置步骤
实验:通过定时器1通道1实现指定个数PWM输出,用于控制LED1的亮灭
PWM.h头文件程序
#ifndef __PWM_H
#define __PWM_H
#include "stm32f1xx.h"
void PWM_Init(void);
#endif
PWM.c源程序
#include "./BSP/TIMER/PWM.h"
TIM_HandleTypeDef htim;
void PWM_Init(void)
{
htim.Instance = TIM1;
htim.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE;
htim.Init.CounterMode = TIM_COUNTERMODE_UP;
htim.Init.Period = 72000000/20000 - 1;
htim.Init.Prescaler = 9999;
//设置重复计数器值
htim.Init.RepetitionCounter = 9;
HAL_TIM_PWM_Init(&htim);
TIM_OC_InitTypeDef sConfig = {0};
sConfig.OCMode = TIM_OCMODE_PWM1;
sConfig.OCPolarity =TIM_OCPOLARITY_HIGH;
sConfig.Pulse = 0.5 * (TIM1->ARR + 1);
//设置PWM输出通道
HAL_TIM_PWM_ConfigChannel(&htim,&sConfig,TIM_CHANNEL_1);
//使能更新中断
__HAL_TIM_ENABLE_IT(&htim, TIM_IT_UPDATE);
///使能主输出和定时器
HAL_TIM_PWM_Start(&htim,TIM_CHANNEL_1);
}
void HAL_TIM_PWM_MspInit(TIM_HandleTypeDef *htim)
{
if(htim->Instance == TIM1)
{
//开启定时器1时钟
__HAL_RCC_TIM1_CLK_ENABLE();
//开启GPIOA时钟
__HAL_RCC_GPIOA_CLK_ENABLE();
GPIO_InitTypeDef GPIO_Init;
GPIO_Init.Mode = GPIO_MODE_AF_PP;
GPIO_Init.Pin = GPIO_PIN_8;
//上下拉只有输入有用
GPIO_Init.Pull = GPIO_NOPULL;
GPIO_Init.Speed = GPIO_SPEED_FREQ_HIGH;
//设置PA8为复用推挽输出
HAL_GPIO_Init(GPIOA, &GPIO_Init);
HAL_NVIC_SetPriority(TIM1_UP_IRQn, 2, 2);
HAL_NVIC_EnableIRQ(TIM1_UP_IRQn);
}
}
void TIM1_UP_IRQHandler(void)
{
HAL_TIM_IRQHandler(&htim);
}
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
if(htim->Instance == TIM1)
{
//关闭计数器
TIM1->CR1 &= ~(1 << 0);
//这个函数里边判断了输出通道和输出互补通道是否已经关闭了
//没关闭 不可以关闭计数器
//__HAL_TIM_DISABLE(htim);
}
}
注意: __HAL_TIM_DISABLE(htim);宏定义的使用在程序里说明了
main.c主函数程序
#include "./SYSTEM/sys/sys.h"
#include "./SYSTEM/usart/usart.h"
#include "./SYSTEM/delay/delay.h"
#include "./BSP/LED/led.h"
#include "./BSP/TIMER/PWM.h"
int main(void)
{
HAL_Init(); /* 初始化HAL库 */
sys_stm32_clock_init(RCC_PLL_MUL9); /* 设置时钟, 72Mhz */
delay_init(72); /* 延时初始化 */
//led_Init(); /* LED初始化 */
PWM_Init();
while(1)
{
// LED0(1);
// LED1(0);
// delay_ms(500);
//
// LED0(0);
// LED1(1);
delay_ms(500);
}
}