简介
STM32微控制器提供了一系列的定时器模块(TIM),不同型号的STM32有不同数目和类型的定时器。常见的有:
- 基本定时器(TIM6, TIM7等):
- 主要用于定时和触发一些基础事件,如ADC转换启动。
- 只具有基础的计数功能,没有外围的输入捕获或输出比较功能。
- 通用定时器(TIM2, TIM3, TIM4, TIM5等):
- 功能比基本定时器更加丰富。
- 具备外围事件的输入捕获、输出比较、PWM输出等。
- 编码器接口功能,可用于读取旋转编码器信息。
- 高级定时器(TIM1, TIM8等):
- 提供更为复杂的功能,如电机控制。
- 支持更高分辨率的PWM输出。
- 死区时间管理,防止电源瞬间短路。
- 多重输入捕获和输出比较功能。
工作原理
- 核心原理: 当TIM被启用时,其中的计数器开始根据预分频器(Prescaler)和时钟源的配置定时增加或减少(向上或向下计数)。一旦计数器值达到设定的自动重装载寄存器(ARR)的值,根据定时器的设置,它可能会重置(溢出),并可能触发中断或其他事件,如DMA传输请求。
- 预分频器: 定时器的输入时钟(通常来自系统时钟或外部时钟源)首先会被预分频器降低频率。预分频器实际上是一个除法计数器,它的输出确定了TIM计数器的计数速率。
- 自动重装载寄存器(ARR): 定时器的上溢点由ARR决定。在自动重装载寄存器溢出后,计数器可以重置为0(向上计数器)或重置为ARR(向下计数器),这取决于定时器的配置。
- 计数方向: 计数器可以配置为向上计数或向下计数。这个选择通常取决于特定的应用需求,例如,PWM输出通常使用向上计数。
- 捕获/比较单元: 定时器的输入捕获功能允许它在外部事件(如引脚变化)发生时捕获计数器的值,这可以用来测量外部信号的频率或宽度。 输出比较单元允许定时器在计数器达到特定值时触发一个动作或事件,例如输出翻转或中断。
- PWM功能: 使用输出比较模式,定时器可以生成PWM波形。当计数器值等于输出比较寄存器(OCR)设置的比较值时,输出管脚的状态会改变,从而生成PWM信号。
- 中断和DMA交互: 定时器可以在ARR溢出或捕获/比较事件时触发中断;此外,它还可以配合DMA控制器进行内存交换,这有助于减轻CPU负担。
预分频器的作用是什么?
预分频器的作用是对定时器的输入时钟信号进行分频,以降低定时器计数器的计数速率。这允许定时器以更慢的速度对事件进行计时,扩展了定时器的计时范围,使其可以用于较长时间的计时。简单来说,它就像是一个缩小器,能够将高速的时钟信号缩减成定时器能够使用的更低频率的信号。这对于创建定时任务或者测量较长时间间隔非常有用。
定时器的ARR寄存器有什么作用?
定时器的ARR(Auto-Reload Register)寄存器的主要作用是确定定时器计数器的最大值。当计数器的值达到ARR设定的值后,会发生以下几件事:
- 计数器被重置:在向上计数模式下,计数器值会回到零;在向下计数模式下,计数器会重置为ARR的值。
- 更新事件:到达ARR值通常会产生一个更新事件(Update Event),这个事件可以用来触发中断,执行特定的服务例程。
- PWM周期:在使用定时器产生PWM信号时,ARR的值确定了PWM周期的长度。计数器从0计数到ARR,代表了PWM波形的一个完整周期。
所以,ARR寄存器是调整定时器时间基准的关键部分,它定义了定时器溢出的时间点,从而影响定时器中断生成的频率或PWM波形的频率。
代码示例
// 使能对应的GPIO时钟RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);// 配置GPIOA的第5脚作为输出模式GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;GPIO_Init(GPIOA, &GPIO_InitStructure);// 使能TIM2时钟RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);// 定义并初始化TIM_TimeBaseInitTypeDef结构体变量TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;TIM_TimeBaseStructure.TIM_Period = 10000 - 1; // 自动重装载寄存器的值TIM_TimeBaseStructure.TIM_Prescaler = 8400 - 1; // 设置预分频TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; // 设置分频,这里没有分频TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; // 计数器计数模式,向上计数// 初始化定时器TIM2TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);// 使能或者清除TIM2更新中断TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);// 初始化NVIC中断控制器NVIC_InitTypeDef NVIC_InitStructure;NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;NVIC_Init(&NVIC_InitStructure);// 启用定时器TIM2TIM_Cmd(TIM2, ENABLE);while(1) {// 主循环内容// 其他的应用逻辑代码可以放在这里}
}
// TIM2中断服务函数
void TIM2_IRQHandler(void) {// 检查TIM2更新中断发生与否if (TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET) {// 清除TIM2更新中断标志 TIM_ClearITPendingBit(TIM2, TIM_IT_Update);// 切换PA5端口状态GPIO_WriteBit(GPIOA, GPIO_Pin_5, (BitAction)(1-GPIO_ReadOutputDataBit(GPIOA, GPIO_Pin_5)));}
}