GD32 Timr定时器看起来比较复杂啊。一看GD32E10x 的SPEC:一个高级定时器,三个通用定时器,还有一个基本定时器。
项目上想用来做分时处理程序都不知道用哪个?
就用通用的定时器 timer1
看下clock tree
TIMER1的时钟是CK_TIMER1,要提供CK_TIMER1需要TIMER1 enable并且需要提供具体的时钟
具体的时钟
if(APB1 prescale = 1 ) x 1 else x 2
这个是什么意思?
我们的CK_SYS时钟(系统时钟)经过Prescaler之后最大频率是CK_AHB(120MHz)
然后经过预分频,APB1频率最大到60MHz,如果预分频系数是1的话,则提供到TIMER的频率是x2。
也就是60*2 = 120MHz
所以TIMER1的时钟就用基于120MHz去分频
我想每200ms 获取一次timer1的中断。改怎么办?
有两个参数可以一起去实现这个功能。
1个事TIMER的prescale 可以先把这个120MHz分频,比如我分频为1MHz,那么prescale就是120,不过这里timer_initpara.prescaler不能设置为120,要设置为119.
因为具体的计算方式是120MHz/(prescaler+1)
这样拿到了1MHz的clock.那获取每200ms的中断再要做什么呢?
这里有reload 参数timer_initpara.period ,官方成为“TIMER counter auto reload register”
这个reload参数意思是:当计数计到period参数的时候就做一次更新,从0开始重新计算,中断就产生一次。
前面1MHz 意思是1s 可以计数1000 000次。也就是1ms 可以计数1000次,我需要200ms更新一次,那就说我需要计数 200 * 1000,所以reload就是200 * 1000 = 200 000
timer_initpara.period 就是写为200 000
看有一篇文章是基于STM32介绍的Timer
STM32的可能是需要将200000 再减去 1
具体链接是 https://blog.csdn.net/private_void_main/article/details/81491015
可以参考下。
我还没验证过GD32的,但是我看GD的官方例子上是按我说的方式去写的
这是关于中断周期的设置。
另外一个我的疑惑是关于clockdivision的设置
timer_initpara.clockdivision = TIMER_CKDIV_DIV1;
网上那位兄弟说是“设置与进行输入捕获相关的分频 设置的这个值不会影响定时器的时钟频率,我们一般设置为TIM_CKD_DIV1,也就是不分频"
我具体也没再继续研究。
总体上关于timer的设置就是这些了。
贴下代码:
void timer_config(void)
{
/* TIMER0 configuration: generate PWM signals with different duty cycles:
TIMER0CLK = SystemCoreClock / 120 = 1MHz */
timer_parameter_struct timer_initpara;
rcu_periph_clock_enable(RCU_TIMER0);
timer_deinit(TIMER0);
/* TIMER0 configuration */
timer_initpara.prescaler = 119;
timer_initpara.alignedmode = TIMER_COUNTER_EDGE;
timer_initpara.counterdirection = TIMER_COUNTER_UP;
timer_initpara.period = 200000;
timer_initpara.clockdivision = TIMER_CKDIV_DIV1;
timer_initpara.repetitioncounter = 0;
timer_init(TIMER0,&timer_initpara);
/* auto-reload preload enable */
timer_auto_reload_shadow_enable(TIMER0);
timer_enable(TIMER0);
}
这里验证的时候遇到问题了period 设置为了200000,发现中断会一直产生。
当我把这个值设置小了之后,同时prescaler也改变
/* TIMER1 configuration */
timer_initpara.prescaler = 1199;
timer_initpara.alignedmode = TIMER_COUNTER_EDGE;
timer_initpara.counterdirection = TIMER_COUNTER_UP;
timer_initpara.period = 19999;
timer_initpara.clockdivision = TIMER_CKDIV_DIV1;
timer_initpara.repetitioncounter = 0;
timer_init(TIMER1,&timer_initpara);
这样就可以了按照200ms一次来一个中断。
猜测是不是period溢出了?
果然,让我把period设置为65535的时候,中断周期正常,设置为65536的时候就没有中断了。
当我再设置为65537的时候,中断就不停的出现了。
看下这个数据类型
uint32_t period; /*!< period value */
是u32类型的啊,为什么会有这样的问题呢?
看下具体的寄存器
在timer_init中
/* configure the autoreload value */
TIMER_CAR(timer_periph) = (uint32_t)initpara->period;
#define TIMER_CAR(timerx) REG32((timerx) + 0x2CU) /*!< TIMER counter auto reload register */
/* bit operations */
#define REG32(addr) (*(volatile uint32_t *)(uint32_t)(addr))
#define TIMER1 (TIMER_BASE + 0x00000000U)
/* advanced peripheral bus 1 memory map */
#define TIMER_BASE (APB1_BUS_BASE + 0x00000000U) /*!< TIMER base address */
/* peripheral memory map */
#define APB1_BUS_BASE ((uint32_t)0x40000000U) /*!< apb1 base address */
为什么呢?。。。。。