autoquad使用定时器用作系统获取时间的来源。该部分在初始化时调用timerInit()函数用来初始化定时器,其内部具体内容如下
void timerInit(void)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_OCInitTypeDef TIM_OCInitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
// Enable the TIMER_TIM global Interrupt
NVIC_InitStructure.NVIC_IRQChannel = TIMER_IRQ_CH;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
TIMER_EN;
// stop timer when core halted (debug)
DBGMCU_APB1PeriphConfig(TIMER_CORE_HALT, ENABLE);
/* Time base configuration for 1MHz (us)*/
TIM_TimeBaseStructure.TIM_Period = 0xFFFFFFFF;
TIM_TimeBaseStructure.TIM_Prescaler = (TIMER_CLOCK / 1000000) - 1;
TIM_TimeBaseStructure.TIM_ClockDivision = 0;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIMER_TIM, &TIM_TimeBaseStructure);
// reset
TIM_SetCounter(TIMER_TIM, 0);
timerCancelAlarm1();
timerCancelAlarm2();
timerCancelAlarm3();
timerCancelAlarm4();
// Output Compare for alarms
TIM_OCStructInit(&TIM_OCInitStructure);
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_Inactive;
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
TIM_OC1Init(TIMER_TIM, &TIM_OCInitStructure);
TIM_OC1PreloadConfig(TIMER_TIM, TIM_OCPreload_Disable);
TIM_OC2Init(TIMER_TIM, &TIM_OCInitStructure);
TIM_OC2PreloadConfig(TIMER_TIM, TIM_OCPreload_Disable);
TIM_OC3Init(TIMER_TIM, &TIM_OCInitStructure);
TIM_OC3PreloadConfig(TIMER_TIM, TIM_OCPreload_Disable);
TIM_OC4Init(TIMER_TIM, &TIM_OCInitStructure);
TIM_OC4PreloadConfig(TIMER_TIM, TIM_OCPreload_Disable);
// go...
TIM_Cmd(TIMER_TIM, ENABLE);
}
这里需要注意的是TIMER_TIM为宏定义,可以在aq_timer.h里找到
#define TIMER_TIM TIM5 // can only use 32bit timers TIM2 or TIM5
这里强调必须使用TIM2 or TIM5,因为在stm32f405系列只有这两个定时器为32位的。并且其下面配置定时器的周期和分频系数,代码如下
/* Time base configuration for 1MHz (us)*/
TIM_TimeBaseStructure.TIM_Period = 0xFFFFFFFF;
TIM_TimeBaseStructure.TIM_Prescaler = (TIMER_CLOCK / 1000000) - 1;
可以看到其溢出计数值为0xFFFFFFFF即最大的32位数,为2^32-1,其分频系数根据TIMER_CLOCK进行分频,使其正好分频到1MHZ,即计数器每过1us自加1。这样计数器的CNT值即代表从定时器开始运行到目前的时间,并且是以us为单位。
autoquad源码中多次调用获取时间的函数原型为获取定时器CNT的宏定义
#define timerMicros() TIMER_TIM->CNT
这样从定时器初始化完成后即可调用timerMicros()获取当前时间。如果你认为定时器只起到一个计数的作用那你就还是太小瞧autoquad代码了。定时器还有比较器的功能,其初始化完计数器功能后下面又初始化其比较器部分功能,调用四个取消比较器的功能函数
timerCancelAlarm1();
timerCancelAlarm2();
timerCancelAlarm3();
timerCancelAlarm4();
这四个函数内容基本一致,我们只看第一个,代码如下:
void timerCancelAlarm1(void) {
TIMER_TIM->DIER &= (uint16_t)~TIM_IT_CC1;
TIM_ClearITPendingBit(TIMER_TIM, TIM_IT_CC1);
}
这里只是禁止定时器的捕获/比较 1中断以及清除中断标志位。下面的代码即代表初始化定时器捕获/比较功能。所以到现在我们还不知道他开启捕获功能是干嘛用的。下面还有一个函数用来设置比较/捕获功能:
void timerSetAlarm1(int32_t us, timerCallback_t *callback, int parameter) {
// schedule it
timerData.alarm1Callback = callback;
timerData.alarm1Parameter = parameter;
TIMER_TIM->SR = (uint16_t)~TIM_IT_CC1;
TIMER_TIM->CCR1 = TIMER_TIM->CNT + us;
TIMER_TIM->DIER |= TIM_IT_CC1;
}
从名字上来看这是设置通道1的捕获功能函数,输入参数为us时间,该参数用在如下位置:
TIMER_TIM->CCR1 = TIMER_TIM->CNT + us;
可以看出其将比较器的捕获时间设置为当前时间+us的时间,然后启动捕获比较的中断功能,也就代表当该函数被调用us时间后会进入定时器比较中断函数。
还有后面两个参数timerCallback_t *callback, int parameter,其直接赋值到结构体成员变量上,这两个变量为定时器结构体下的回调函数指针和参数,具体形式如下:
typedef void timerCallback_t(int);
typedef struct {
timerCallback_t *alarm1Callback, *alarm2Callback, *alarm3Callback, *alarm4Callback;
int alarm1Parameter, alarm2Parameter, alarm3Parameter, alarm4Parameter;
uint32_t timerStart;
} timerStruct_t;
然后我们大概已经猜出比较器的用途了,其调用timerSetAlarm函数指定延时时间,当达到比较器阈值后触发比较器中断,这时候在比较器中断函数里调用回调函数,即我们在调用timerSetAlarm时指定的函数,就可以达到定时一段时间后运行某个函数的功能。查看定时器中断函数内容,可以看到如下内容:
if ((itEnable & TIM_IT_CC1) != RESET && (itStatus & TIM_IT_CC1) != RESET) {
TIMER_TIM->SR = (uint16_t)~TIM_IT_CC1;
// Disable the Interrupt
TIMER_TIM->DIER &= (uint16_t)~TIM_IT_CC1;
timerData.alarm1Callback(timerData.alarm1Parameter);
}
可以看到其在中断函数内调用了回调函数。这里我们举例子说明该部分用法。比如想实现1s后点亮LED灯的功能,可以编写如下代码:
timerSetAlarm1(1000000, turnOnLed, 0);
这样1s后即会执行turnOnLed函数,注意这里turnOnLed函数必须和指定的回调函数结构类似,如下内容:
void turnOnLed(int unuse)
{
//点亮LED具体实现
}
即其返回值和参数类型必须和回调函数定义的typedef void timerCallback_t(int)一样。
这就是autoquad关于定时器的使用,其功能主要搭建工程的时间相关功能,后面可以调用timerMicros()获取系统时间,也可以调用timerSetAlarm1函数进行定时触发函数的功能。如果觉得写的不错就点个赞吧

本文详细介绍了autoquad项目中STM32定时器的使用,包括初始化、计数、比较捕获等功能。通过分析代码,揭示了定时器如何实现系统时间获取、定时任务触发以及中断回调机制,展示了定时器在无人机控制系统中的核心作用。
1万+

被折叠的 条评论
为什么被折叠?



