本文是基于韦东山视频的学习笔记
总汇
根据手册的示意图,PLCK给出的时钟后,通过预分频器(Prescaler)后,再通过多通道选择器(5:1 MUX)分频,到达定时器。
定时器里有
- 定时初值,当初值减到0时就会产生中断。
- 加载值,硬件可以设置为自动加载,当初值为0时便自动为加载值
- 对比值(这次不用)
定时器中断,类比按键中断,有几个额外工作要做
- 设置定时器初值(通过前面的几个分频器设置)
- 设置加载值(设置寄存器)
- 使能定时器中断(还有使能总中断)
寄存器
计算方式
Timer input clock Frequency = PCLK / {prescaler value+1} / {divider value}
{prescaler value} = 0~255
{divider value} = 2, 4, 8, 16
寄存器
[TCFG0] Configures the two 8-bit prescalers(设置预分频)
[TCFG1] 5-MUX & DMA mode selection register(设置分频)
[TCON] Timer control register (需要设置)
[TCNTB0] Timer 0 count buffer register (设置加载值)
[TCNTO0] Timer 0 count observation register (只读)
[TCFG0 寄存器] 设置预分频
- 地址:0x51000000
- [7:0] = 99 = 0x63 :Prescaler 0
[TCFG1 寄存器] 设置分频
- 地址:0x51000004
- [3:0] = 3 :MUX 0 ( 设置为timer 0 为1/16分频)
[TCON 寄存器] 控制寄存器
- 地址:0x51000008
- [0] = 0x1 :Timer 0 start/stop ( Start for Timer 0)
- [1] = 0x1 :Timer 0 manual update 1(Update TCNTB0 & TCMPB0)
- [3] = 0x1 :Timer 0 auto reload on/off (auto reload)
[TCNTB0 寄存器] Timer 0 计数缓冲寄存器
- 地址:0x5100000C
- [15:0] = 15625
代码
void timer_init()
{
/*
[TCFG0 寄存器] 设置预分频
- 地址:0x51000000
- [7:0] = 99 = 0x63 :Prescaler 0
[TCFG1 寄存器] 设置分频
- 地址:0x51000004
- [3:0] = 0x0011 :MUX 0 ( 设置为timer 0 为1/16分频)
[TCON 寄存器] 控制寄存器
- 地址:0x51000008
- [0] = 0x1 :Timer 0 start/stop ( Start for Timer 0)
- [1] = 0x1 :Timer 0 manual update [^note](Update TCNTB0 & TCMPB0)
- [3] = 0x1 :Timer 0 auto reload on/off (auto reload)
[^note]: The bit has to be cleared at next writing.
[TCNTB0 寄存器] Timer 0 计数缓冲寄存器
- 地址:0x5100000C
- [15:0] = 15625
*/
TCFG0 = 99;
TCFG1 &= (0xF);
TCFG1 |= 3;
TCNTB0 = 15625;
TCON |= (1<<1);
TCON &= ~(1<<1); //The bit has to be cleared at next writing.
TCON |= ((1<<0) | (1<<3));
}
void timer_irq()
{
static int val = 4;
GPFDAT |= (7<<4); /* 把GPFDAT 4~6置1,即熄灭LED */
GPFDAT &= ~(1<<val); /* 循环点亮 */
val++;
if(val==7) val=4;
}
优化
typedef void(*irq_func)(int);
irq_func irq_array[32];
/* 注册中断的指针函数, 附加使能总中断
* irq - 第几个处理函数,fp - 传入的中断处理函数
*/
void register_irq(int irq, irq_func fp)
{
irq_array[irq] = fp;
/* [INTMSK] 寄存器 中断屏蔽寄存器
* 置1是屏蔽中断源,置0是使能,默认是全部屏蔽,所以需要设置。
- 地址:0X4A000008
- [0] : EINT0 = 0x0(S2 - EINT0)
- [2] : EINT2 = 0x0(S3 ~ EINT2)
- [5] : EINT8_23 = 0x0(S4 ~ EINT11,S5 ~ EINT19)
- 即 [0X4A000008] &= ((0<<0) | (0<<2) | (0<<5))
*/
INTMSK &= ~(1<<irq);
}
The bit has to be cleared at next writing. ↩︎