【说明】
S3C6410带有5个32位定时器,其中定时器4是内部定时器,没有引出外部引脚的,这一节我们就来试试操作定时器中断。学了这个定时器操作之后,我们再利用它来写一个进程调度程序,实现最最简单的进程并发。
【原理】
S3C6410的5个定时器中,定时器0和1有PWM功能,其他没有
PWM具有两种操作,即自动装载模式和一次触发模式,
所提供的定时器有双缓冲功能,对定时器的操作不会影响定时器当前的运作
看看电路图
1)源时钟为PCLK,我们在时钟初始化的时候将其设置为了66MHZ
2)源时钟要进过两次分频才到达逻辑控制单元,所以显然我们得设置这2个分频咯
【寄存器操作】
定时器的寄存器比较少所以操作起来非常简单
1】定时器配置寄存器
1)这个寄存器就是第一个分频器的设置,我们要用定时器0,所以就设置前面8位
2)设置第二次分频。。我们设置为0100
2】设置定时时间
1)往这个寄存器写入的就是定时的时间,当然,具体数值需要和最终的时钟频率有关。
2)其实定时器本身并不是利用这个寄存器计时的,而是用TCNTN0,但是那是一个内部寄存器,无法直接操作。
3)当TCNTN0到时的时候,若设置为自动装载模式,则TCNTB0的值会被复制到TCNTN0
3】设置比较时间
1)这个一般设置为0,就是说TCNTB0里面的数值减少到什么值的时候产生中断的。
4】控制寄存器
1)我们需要设置一下手动更新位,然后再清手动更新位。。。为什么呢?我也知道。。。
2)启动计时器
3)自动装载模式
5】使能中断
1)这个使能定时器,使其能发送中断
2)在中断控制器中使能
【中断处理】
我们只是简单得在串口打印一句话。然后清中断。
【源代码】
#include "stdio.h" #define EINT0CON0 (*((volatile unsigned long *)0x7F008900)) #define EINT0MASK (*((volatile unsigned long *)0x7F008920)) #define EINT0PEND (*((volatile unsigned long *)0x7F008924)) #define PRIORITY (*((volatile unsigned long *)0x7F008280)) #define SERVICE (*((volatile unsigned long *)0x7F008284)) #define SERVICEPEND (*((volatile unsigned long *)0x7F008288)) #define VIC0IRQSTATUS (*((volatile unsigned long *)0x71200000)) #define VIC0FIQSTATUS (*((volatile unsigned long *)0x71200004)) #define VIC0RAWINTR (*((volatile unsigned long *)0x71200008)) #define VIC0INTSELECT (*((volatile unsigned long *)0x7120000c)) #define VIC0INTENABLE (*((volatile unsigned long *)0x71200010)) #define VIC0INTENCLEAR (*((volatile unsigned long *)0x71200014)) #define VIC0PROTECTION (*((volatile unsigned long *)0x71200020)) #define VIC0SWPRIORITYMASK (*((volatile unsigned long *)0x71200024)) #define VIC0PRIORITYDAISY (*((volatile unsigned long *)0x71200028)) #define VIC0ADDRESS (*((volatile unsigned long *)0x71200f00)) #define PWMTIMER_BASE (0x7F006000) #define TCFG0 ( *((volatile unsigned long *)(PWMTIMER_BASE+0x00)) ) #define TCFG1 ( *((volatile unsigned long *)(PWMTIMER_BASE+0x04)) ) #define TCON ( *((volatile unsigned long *)(PWMTIMER_BASE+0x08)) ) #define TCNTB0 ( *((volatile unsigned long *)(PWMTIMER_BASE+0x0C)) ) #define TCMPB0 ( *((volatile unsigned long *)(PWMTIMER_BASE+0x10)) ) #define TCNTO0 ( *((volatile unsigned long *)(PWMTIMER_BASE+0x14)) ) #define TCNTB1 ( *((volatile unsigned long *)(PWMTIMER_BASE+0x18)) ) #define TCMPB1 ( *((volatile unsigned long *)(PWMTIMER_BASE+0x1C)) ) #define TCNTO1 ( *((volatile unsigned long *)(PWMTIMER_BASE+0x20)) ) #define TCNTB2 ( *((volatile unsigned long *)(PWMTIMER_BASE+0x24)) ) #define TCMPB2 ( *((volatile unsigned long *)(PWMTIMER_BASE+0x28)) ) #define TCNTO2 ( *((volatile unsigned long *)(PWMTIMER_BASE+0x2C)) ) #define TCNTB3 ( *((volatile unsigned long *)(PWMTIMER_BASE+0x30)) ) #define TCMPB3 ( *((volatile unsigned long *)(PWMTIMER_BASE+0x34)) ) #define TCNTO3 ( *((volatile unsigned long *)(PWMTIMER_BASE+0x38)) ) #define TCNTB4 ( *((volatile unsigned long *)(PWMTIMER_BASE+0x3C)) ) #define TCNTO4 ( *((volatile unsigned long *)(PWMTIMER_BASE+0x40)) ) #define TINT_CSTAT ( *((volatile unsigned long *)(PWMTIMER_BASE+0x44)) ) void irq_init(void) { /* 在中断控制器里使能timer0中断 */ VIC0INTENABLE |= (1<<23); } // timer0中断的中断处理函数 void do_irq() { static int i=1; printf("%d Timer0 interrupt occur\r\n",i++); unsigned long uTmp; //清timer0的中断状态寄存器 uTmp = TINT_CSTAT; TINT_CSTAT = uTmp; } // 初始化timer void timer_init(unsigned long utimer,unsigned long uprescaler,unsigned long udivider,unsigned long utcntb,unsigned long utcmpb) { unsigned long temp0; // 定时器的输入时钟 = PCLK / ( {prescaler value + 1} ) / {divider value} = PCLK/(65+1)/16=62500hz //设置预分频系数为66 temp0 = TCFG0; temp0 = (temp0 & (~(0xff00ff))) | ((uprescaler-1)<<0); TCFG0 = temp0; // 16分频 temp0 = TCFG1; temp0 = (temp0 & (~(0xf<<4*utimer))& (~(1<<20))) |(udivider<<4*utimer); TCFG1 = temp0; // 1s = 62500hz TCNTB0 = utcntb; TCMPB0 = utcmpb; // 手动更新 TCON |= 1<<1; // 清手动更新位 TCON &= ~(1<<1); // 自动加载和启动timer0 TCON |= (1<<0)|(1<<3); // 使能timer0中断 temp0 = TINT_CSTAT; temp0 = (temp0 & (~(1<<utimer)))|(1<<(utimer)); TINT_CSTAT = temp0; }