• ARM9 S3C2440 定时器中断


    在讲解之前,先介绍一下s3c2440时钟系统。一般来说,MCU的主时钟源主要是外部晶振或外部时钟,而用的最多的是外部晶振。在正确情况下,系统内所使用的时钟都是外部时钟源经过一定的处理得到的。由于外部时钟源的频率一般不能满足系统所需要的高频条件,所以往往需要PLL(锁相环)进行倍频处理。在s3c2440中,有2个不同的PLL,一个是MPLL,另一个是UPLL。UPLL是给USB提供48MHz。在这里,我们主要介绍MPLL。外部时钟源经过MPLL处理后能够得到三个不同的系统时钟:FCLK、HCLK和PCLK。FCLK是主频时钟,用于ARM920T内核;HCLK用于AHB总线设备,如ARM920T,内存控制,中断控制,LCD控制,DMA以及USB主模块;PCLK用于APB总线设备,如外围设备的看门狗,IIS,I2C,PWM,MMC接口,ADC,UART,GPIO,RTC以及SPI。这三个系统时钟(FCLK、HCLK和PCLK)是有一定的比例关系,这种关系是通过寄存器CLKDIVN中的HDIVN位和PDIVN位来控制的,因此我们只要知道了FCLK,再通过这两位的控制,就能确定HCLK和PCLK。而FCLK是如何得到的呢?它是通过输入时钟(即外部时钟源)的频率,经过一个计算公式(具体公式请查阅数据手册)得到的,这个计算公式还需要三个参数(MDIV、PDIV、SDIV),而这三个参数是经过寄存器MPLLCON配置得到的。最后,我们用最清晰的线路来绘制一下时钟的产生过程:外部时钟源→通过寄存器MPLLCON得到FCLK→再通过寄存器CLKDIVN得到HCLK和PCLK。这个配置过程在启动文件中就已完成。在本开发板上,外部晶振为12MHz,进过MPLL倍频以后得到400MHz的FCLK,而FCLK、HCLK、PCLK之间的比例关系为1:4:8,因此HCLK为100MHz,PCLK为50MHz。

    s3c2440的时钟系统就介绍到这里,我们再回到定时器的配置上来。如何才能得到精确的定时呢?那就要靠TCFG0和TCFG1这两个寄存器来配置定时器的频率,即要确定TCNTOn每递减一个数所需要的时间,它们之间是倒数的关系。具体的计算公式为:

    定时器输出时钟频率=PCLK ÷ (prescaler+1) ÷ divider

    其中prescaler值由TCFG0决定,divider值由TCFG1决定,而prescaler只能取0~255之间的整数,divider只能取2、4、8和16。比如已知PCLK为50MHz,而我们想得到某一定时器的输出时钟频率为25kHz,则依据公式可以使prescaler等于249,divider等于8。有了这个输出时钟频率,理论上我们通过设置寄存器TCNTBn就可以得到任意与0.04毫秒(1÷25000×1000)成整数倍关系的时间间隔了。例如我们想要得到1秒钟的延时,则使TCNTBn为25000(1000÷0.04)即可。

    下面我们通过一段程序来演示利用定时器得到精确延时。这里我们用到的是定时器4。这段程序的作用是让蜂鸣器每隔2秒钟响一次,持续时间为0.5秒,蜂鸣器响的同时伴随着LED亮。

    #define _ISR_STARTADDRESS 0x33ffff00

    #define U32 unsigned int

    #define pISR_TIMER4         (*(unsigned *)(_ISR_STARTADDRESS+0x58))

     

    #define rSRCPND     (*(volatile unsigned *)0x4a000000)     //Interrupt request status

    #define rINTMSK     (*(volatile unsigned *)0x4a000008)      //Interrupt mask control

    #define rINTPND     (*(volatile unsigned *)0x4a000010)      //Interrupt request status

    #define rGPBCON    (*(volatile unsigned *)0x56000010)      //Port B control

    #define rGPBDAT    (*(volatile unsigned *)0x56000014)       //Port B data

    #define rGPBUP     (*(volatile unsigned *)0x56000018) //Pull-up control B

    #define rTCFG0 (*(volatile unsigned *)0x51000000)      //Timer 0 configuration

    #define rTCFG1 (*(volatile unsigned *)0x51000004)      //Timer 1 configuration

    #define rTCON   (*(volatile unsigned *)0x51000008)      //Timer control

    #define rTCNTB4 (*(volatile unsigned *)0x5100003c)       //Timer count buffer 4

    void __irq Timer4_ISR(void)

    {

           static int count;

           count ++;

           rSRCPND = rSRCPND | (0x1<<14);

           rINTPND = rINTPND | (0x1<<14);

           //每隔2秒蜂鸣器响一次,持续时间为0.5秒,并伴随着LED亮

           if (count % 4 ==0)

                  rGPBDAT = ~0x1e0;            //蜂鸣器响,LED亮

           else if (count % 4 ==1)

                  rGPBDAT = 0x1e0;      //蜂鸣器不响,LED灭

    }

     

    void Main(void)

    {

           rGPBCON = 0x155555;               //B0输出,给蜂鸣器;B5~B8输出,给LED

           rGPBUP = 0x7ff;

          

           rGPBDAT = 0x1e0;      //蜂鸣器不响,LED灭

          

           rSRCPND = rSRCPND | (0x1<<14);

           rINTPND = rINTPND | (0x1<<14);

           rINTMSK = ~(0x1<<14);            //打开定时器4中断

            

           rTCFG0 &= 0xFF00FF;

           rTCFG0 |= 0xf900;        // prescaler等于249

           rTCFG1 &= ~0xF0000;   

           rTCFG1 |= 0x20000;     //divider等于8,则设置定时器4的时钟频率为25kHz

           rTCNTB4 = 12500;              //让定时器4每隔0.5秒中断一次

          

           rTCON &= ~0xF00000;

           rTCON |= 0x700000;

           rTCON &= ~0x200000 ;              //定时器4开始工作

          

              

           pISR_TIMER4 = (U32)Timer4_ISR;

         

           while(1)

           {

                  ;         

           }    

    }

  • 相关阅读:
    LeetCode15题: 寻找三数和,附完整代码
    LeetCode 11 水池蓄水问题
    分布式初探——分布式事务与两阶段提交协议
    高等数学——讲透求极限两大方法,夹逼法与换元法
    书籍推荐——一本老书,吴军老师《数学之美》
    概率统计——期望、方差与最小二乘法
    算法浅谈——递归算法与海盗分金问题
    机器学习基础——带你实战朴素贝叶斯模型文本分类
    线性代数精华——从正交向量到正交矩阵
    LeetCode10 Hard,带你实现字符串的正则匹配
  • 原文地址:https://www.cnblogs.com/hnrainll/p/2092383.html
Copyright © 2020-2023  润新知