autoquad源码分析:STM32定时器使用

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

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函数进行定时触发函数的功能。如果觉得写的不错就点个赞吧

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值