STM32学习笔记(2)通用计时器
· 阅读需 5 分钟
本文章适用于STM32F103RBT6,其他型号可能有所不同
开发模板见我的GitHub仓库skyone-wzw@STM32F103RBT6-template
如果你觉得这篇文章有帮助,请star仓库或评论回复吧~
如果文章有任何错误(包括错别字)可以在这里提交Issue或邮件联系我
使能定时器时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIMx, ENABLE);
使能定时器时钟,对于中容量STM32F103,TIMx可以是:
TIM1
:高级定时器TIM2
~TIM4
通用定时器
例如
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
// 使能通用定时器3
初始化定时器
TIM_TimeBaseInit(TIMx, &TIM_TimeBaseInitTypeDef)
定义计时器的重装载值、预分频系数、计数方式等
对于TIM_TimeBaseInitTypeDef
结构体
typedef struct {
uint16_t TIM_Prescaler;
// 预分频系数,下面有解释
uint16_t TIM_CounterMode;
/* 计数方式,可以是
* 向上计数: `TIM_CounterMode_Up`
* 向下计数: `TIM_CounterMode_Down`
* 中心计数: `TIM_CounterMode_CenterAligned1`
* | `TIM_CounterMode_CenterAligned2`
* | `TIM_CounterMode_CenterAligned3`
*/
uint16_t TIM_Period;
// 重装载值,即tick的次数
// TODO 下面两个暂时不理解,待更新
uint16_t TIM_ClockDivision;
uint8_t TIM_RepetitionCounter;
} TIM_TimeBaseInitTypeDef;
例如:
TIM_TimeBaseInitTypeDef tim3;
tim3.TIM_Period = 4999;
// 重装载值为 4999, tick 5000 次
tim3.TIM_Prescaler = 7199;
// 预分频系数为 7200 = 7199 + 1
// 系统时钟为72MHz, TIM3 的时钟为 72000000 / 2 * 2 / 7200 = 10kHz
// 即一次 0.1ms
tim3.TIM_CounterMode = TIM_CounterMode_Up;
tim3.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseInit(TIM3, &tim3);
开启定时器中断
TIM_ITConfig(TIMx, TIM_IT, ENABLE);
设置什么情况下中断,可以为:
#define TIM_IT_Update ((uint16_t)0x0001)
// 更新中断
#define TIM_IT_CC1 ((uint16_t)0x0002)
#define TIM_IT_CC2 ((uint16_t)0x0004)
#define TIM_IT_CC3 ((uint16_t)0x0008)
#define TIM_IT_CC4 ((uint16_t)0x0010)
#define TIM_IT_COM ((uint16_t)0x0020)
#define TIM_IT_Trigger ((uint16_t)0x0040)
#define TIM_IT_Break ((uint16_t)0x0080)
当然,用到中断就要设置中断优先级,此外,不要忘记在main函数开始时设置中断优先级分组
使能定时器
TIM_Cmd(TIMx, ENABLE);
非常简单,无需解释
写中断服务函数
对于高级定时器,中断服务函数的名字为:
void TIMx_BRK_IRQHandler()
void TIMx_UP_IRQHandler()
void TIMx_TRG_COM_IRQHandler()
void TIMx_CC_IRQHandler()
对于通用定时器,中断服务函数的名字为:
void TIMx_IRQHandler()
TIMx
中的x
换成对应计时器ID
例程
下面给出一个完整的例子
main.c
#include <stm32f10x.h>
#include <system_stm32f10x.h>
void TIM3_IRQHandler() {
if (TIM_GetFlagStatus(TIM3, TIM_FLAG_Update) == SET) {
// 判断发生了 `TIM_FLAG_Update` 中断
// 翻转LED状态
if (GPIO_ReadOutputDataBit(GPIOC, GPIO_Pin_0) == 1) {
GPIO_ResetBits(GPIOC, GPIO_Pin_0);
} else {
GPIO_SetBits(GPIOC, GPIO_Pin_0);
}
// 取消中断标志位
TIM_ClearITPendingBit(TIM3, TIM_FLAG_Update);
}
}
int main() {
SetSysClock();
// 初始化系统时钟为 72MHz
NVIC_SetPriorityGrouping(NVIC_PriorityGroup_2);
// 中断优先级分组为 2
/*
* 初始化通用计时器3
* init_tim3 {
*/
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
// 使能通用计时器 3
TIM_TimeBaseInitTypeDef tim3;
tim3.TIM_Period = 4999;
// 重装载值为 4999, tick 5000 次
tim3.TIM_Prescaler = 7199;
// 预分频系数为 7200
// 系统时钟为72MHz, TIM3 的时钟为 72000000 / 2 * 2 / 7200 = 10kHz
// 即一次 0.1ms
tim3.TIM_CounterMode = TIM_CounterMode_Up;
tim3.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseInit(TIM3, &tim3);
TIM_ITConfig(TIM3, TIM_IT_Update, ENABLE);
// 配置更新中断
NVIC_InitTypeDef nvic_tim3;
nvic_tim3.NVIC_IRQChannel = TIM3_IRQn;
nvic_tim3.NVIC_IRQChannelPreemptionPriority = 2;
nvic_tim3.NVIC_IRQChannelSubPriority = 2;
nvic_tim3.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&nvic_tim3);
// 设置中断优先级
TIM_Cmd(TIM3, ENABLE);
// 使能定时器
/*
* 初始化通用计时器3
* }
*/
/*
* 初始化LED0
* init_LED0 {
*/
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);
GPIO_InitTypeDef led0;
led0.GPIO_Pin = GPIO_Pin_0;
led0.GPIO_Mode = GPIO_Mode_Out_PP;
led0.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOC, &led0);
GPIO_ResetBits(GPIOC, GPIO_Pin_0);
/*
* 初始化LED0
* }
*/
for (;;) { }
}
没有附加依赖,使用定时器中断使LED闪烁,LED用的是GPIOC_0
为了方便分享和复习,所有代码写在一个文件里,实际开发这样做非常不对!