前言:
通过本次课程学会定时器的使用,定时器的分类,定时器的配置
定时器的分类
定时器的使用场景
GD32 定时器资源概述
定时器的原理
如果定时器的的时钟频率为120Mhz的时钟主频,那么计时的周期就是1/120us如果是从0开始计数那么对应的时间就是120 * 1 /120 us,过去的时间就是1us。
如果定时器的值计数值计数到12000的时候计数值清除为0,然后系统会产生一个定时中断,定时器计时的时间就是12000 * (1 /120)us = 100us ,预分频器也就是调整进入到计数器的时钟频率
定时器配置
更新事件,计数值达到重装载数值的时候产生一次更新中断
注意:定时器在配置的过程中预分频器的值和自动重装载寄存器的值需要配置为 -1 因为计数的值是从0开始的,是从0到...
定时器的计数模式有向上计数,向下计数,当定时器的计数值达到CAR重装计数器的值时,就会触犯一个定时中断,这个时候计数值清除为0,开始下一轮周期的计数
定时器的使用场景
1:输入捕获
2:输出比较
3:基本的计时功能,在计时时间到时产生中断去处理一些工作
使能定时器的时钟
// 使能定时器时钟
rcu_periph_clock_enable(RCU_TIMER4);
复位定时器:
对定时器进行复位的原因是,先回复定时器的初始值,后面再进行自己的配置
// 复位定时器
timer_deinit(TIMER4);
初始化定时器结构体
// 初始化定时器结构体
timer_parameter_struct timerInitPara;
定时器设置默认数值,防止出现无需的配置参数
// 结构体变量初始化函数,定时器没有初始化赋值之前值是不确定的,通过这个初始化赋值
timer_struct_para_init(&timerInitPara);
设置预分频器的值
预分频:什么是预分频,简单来说就是120MHz的时钟频率如果经过2分频那么就是60MHz的时钟频率,但是GD32这款单片机的时钟频率一直是维持在120MHz的时钟频率。
设置重装计数器的值
// 设置重装载数值
timerInitPara.prescaler = 120 - 1;
timerInitPara.period = periodUs - 1;
使能定时器更新中断
// 使能定时器更新中断
timer_interrupt_enable(TIMER4,TIMER_INT_UP);
使能定时器中断优先级
这个步骤也就是操作nvic,嵌套中断向量控制器,同时使能定时器
// 使能定时器中断和优先级,设置优先级为最高
nvic_irq_enable(TIMER4_IRQn,0,0);
// 使能定时器
timer_enable(TIMER4);
定时器中断函数
void TIMER4_IRQHandler(void)
{
// 获取中断标志位
if(timer_interrupt_flag_get(TIMER4,TIMER_INT_FLAG_UP) == SET)
{
// 清除中断标志位
timer_interrupt_flag_clear(TIMER4,TIMER_INT_FLAG_UP);
// LED1对应的gpio口反转
ToggleLed(LED1);
}
}
定时器驱动所有代码文件
#include <stdint.h>
#include "gd32f30x.h"
#include "led_drv.h"
#if 0
// 初始化定时器
static void TimerInit(uint32_t periodUs)
{
// 使能定时器时钟
rcu_periph_clock_enable(RCU_TIMER0);
// 复位定时器
timer_deinit(TIMER0);
// 初始化定时器结构体
timer_parameter_struct timerInitPara;
// 结构体变量初始化函数,定时器没有初始化赋值之前值是不确定的,通过这个初始化赋值
timer_struct_para_init(&timerInitPara);
// 设置重装载数值
timerInitPara.prescaler = 120 - 1;
timerInitPara.period = periodUs - 1;
// 使能定时器更新中断
timer_interrupt_enable(TIMER0,TIMER_INT_UP);
// 使能定时器中断和优先级,设置优先级为最高
nvic_irq_enable(TIMER0_UP_IRQn,0,0);
// 使能定时器
timer_enable(TIMER0);
}
void TIMER0_UP_IRQHandler(void)
{
// 获取中断标志位
if(timer_interrupt_flag_get(TIMER0,TIMER_INT_FLAG_UP) == SET)
{
// 清除中断标志位
timer_interrupt_flag_clear(TIMER0,TIMER_INT_FLAG_UP);
// LED1对应的gpio口反转
ToggleLed(LED1);
}
}
#else
static void TimerInit(uint32_t periodUs)
{
// 使能定时器时钟
rcu_periph_clock_enable(RCU_TIMER4);
// 复位定时器
timer_deinit(TIMER4);
// 初始化定时器结构体
timer_parameter_struct timerInitPara;
// 结构体变量初始化函数,定时器没有初始化赋值之前值是不确定的,通过这个初始化赋值
timer_struct_para_init(&timerInitPara);
// 设置重装载数值
timerInitPara.prescaler = 120 - 1;
timerInitPara.period = periodUs - 1;
// 使能定时器更新中断
timer_interrupt_enable(TIMER4,TIMER_INT_UP);
// 使能定时器中断和优先级,设置优先级为最高
nvic_irq_enable(TIMER4_IRQn,0,0);
// 使能定时器
timer_enable(TIMER4);
}
void TIMER4_IRQHandler(void)
{
// 获取中断标志位
if(timer_interrupt_flag_get(TIMER4,TIMER_INT_FLAG_UP) == SET)
{
// 清除中断标志位
timer_interrupt_flag_clear(TIMER4,TIMER_INT_FLAG_UP);
// LED1对应的gpio口反转
ToggleLed(LED1);
}
}
#endif
// 初始化定时器接口函数
void TIMER_Init(void)
{
// 参数表示定时的周期单位是us
TimerInit(1000);
}
定时器驱动头文件
#ifndef _TIMING_DRV_H_
#define _TIMING_DRV_H_
#include <stdint.h>
void TIMER_Init(void);
#endif
main函数调用
后记
以上的内容基于本人现阶段对定时器知识点的了解,学习自郭天祥老师的ARM32课程,仅供学习参考。