发布新日志

  • 使用定时器实现小灯闪烁 (单片机 LM3S811) .

    2013-04-17 17:28:17

    上次我们讲了如何使用延时来做小灯闪烁的程序,相信大家都有所了解了,这次我们来看如何使用定时器实现小灯闪烁。

     

    1、不使用中断的方法

     

         首先我们还是来看头文件,因为这次使用了定时器(timer),所以头文件要包含timer.h。

         选择闪烁的小灯,在此我们选择PC5小灯,将其使能,作为output。

         下一步是使能定时器的过程。有如下步骤:

              1、在系统中使能定时器。   函数:SysCtlPeripheralEnable()

              2、选择定时器的使用类型,函数:TimerConfigure(),  参数可以写 TIMER_CFG_32_BIT_PER (32位周期)/                                         TIMER_CFG_16_BIT_PAIR|TIMER_CFG_A_PERIODIC  (16位TIMER0A周期)  TIMER_CFG_A_CAP_COUNT(计数模式)等..

                  (注:LM3S811一共有4个计数器TIMER0/1/2/3 ,默认使用减计数模式, 每个timer可以作为一个32位计数器使用,也可以作为两个16位计数器使用。具体使用方法请看技术文档)

              3、给定时器装载值:使用TimerLoadSet() 函数。

              4、使能定时器。

     

          剩下的思路很简单,让程序进入一个死循环。使用轮询检测定时器是否溢出,如果溢出则改变小灯的亮灭。因为系统的频率是一定的(在本程序中是6MHZ),所以通过改变定时器中装载的数值就可以控制小灯亮灭的时间。

          代码如下:

     

     

     

    1. //使用定时器实现小灯闪烁   
    2. #include "inc/hw_types.h"   
    3. #include "inc/hw_memmap.h"   
    4. #include "driverlib/sysctl.h"   
    5. #include "driverlib/gpio.h"   
    6. #include "driverlib/timer.h"                //包含定时器操作的API   
    7. int main()  
    8. {  
    9.     SysCtlClockSet(SYSCTL_OSC_MAIN|SYSCTL_XTAL_6MHZ|SYSCTL_USE_OSC|SYSCTL_SYSDIV_1);  
    10.     SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOC);  
    11.       
    12.     GPIODirModeSet(GPIO_PORTC_BASE,GPIO_PIN_5,GPIO_DIR_MODE_OUT);  
    13.     GPIOPadConfigSet(GPIO_PORTC_BASE,GPIO_PIN_5,GPIO_STRENGTH_2MA,GPIO_PIN_TYPE_STD);  
    14.       
    15.     SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER0);                                      //使能定时器0   
    16.     TimerConfigure(TIMER0_BASE,TIMER_CFG_32_BIT_PER);                            //配置定时器为32bit周期计数模式   
    17.     TimerLoadSet(TIMER0_BASE,TIMER_A,SysCtlClockGet()/2);                         //设置装载寄存器值   
    18.     TimerEnable(TIMER0_BASE,TIMER_A);                                                        //使能定时器0   
    19.     while(1)  
    20.     {  
    21.         while(!(TimerIntStatus(TIMER0_BASE,false)&TIMER_TIMA_TIMEOUT));       //等待Timer0溢出   
    22.         TimerIntClear(TIMER0_BASE,TIMER_TIMA_TIMEOUT);                                //清除溢出标志   
    23.         GPIOPinWrite(GPIO_PORTC_BASE,GPIO_PIN_5,0xff);                                  //PC5=1   
    24.         while(!(TimerIntStatus(TIMER0_BASE,false)&TIMER_TIMA_TIMEOUT));        //等待Timer0溢出   
    25.         TimerIntClear(TIMER0_BASE,TIMER_TIMA_TIMEOUT);                                //清除溢出标志   
    26.         GPIOPinWrite(GPIO_PORTC_BASE,GPIO_PIN_5,0x00);                                 //PC5=0   
    27.     }  
    28. }  
     

           设置timer的装载值为 SysCtlClockGet()/2,即为系统时钟的一半,即0.5秒溢出一次,所以小灯每秒亮灭一次。

     

    2、使用中断的方法:


          中断是单片机中很重要的一部分,可以说一个完成的程序一般都会用到中断。中断,顾名思义就是在程序正常执行的时候用来打断CPU进程的,比如:当我们的程序在死循环中执行时,外部收到一个按钮的信号,这时程序就先执行我们的中断代码,接着才会继续进行循环操作。可以提高程序的效率。

          更加深刻的了解可以在http://zhidao.baidu.com/question/14979539里查找到一些有趣的解释。

       (1) 初步设置

          因为使用了中断,在头文件中我们要加入 #include "inc/hw_ints.h" 和 #include "driverlib/interrupt.h"。(定义了与中断相关的宏 和 包含中断控制器的API)

          熟练地设置好主频、输出口、定时器之后,为了使用中断我们要学习以下几个函数:

           TimerPrescaleSet(TIMER0_BASE,TIMER_A,100);  这个函数将TIMER0A 设为分频100,即现在为6MHZ/100=60000HZ

          然后用TimerLoadSet()给TIMER0A装载30000这个数值,这样就是每0.5秒造成计数器溢出一次。

          TimerIntEnable() 设置定时器的中断模式,前面一个参数是选择定时器,后面是溢出模式,有TIMER_TIMA_TIMEOUT(溢出) TIMER_CAPA_MATCH(匹配)等,我们以后都会使用。

          IntEnable()用来使中断控制器接受定时器的中断请求, IntMasterEnable()用来让全局的中断使能。

           然后主程序就可以进入死循环,因为我们的小灯会通过中断来控制。

     

        (2) 写中断函数

          在程序中断后,会自动跳转到我们预先写好的中断函数,执行我们的命令。

          在此我们写中断函数 void Timer0ATimeoutIntHandler(void) ; 在函数里我们用TimerIntClear()将中断清除,防止再次进入中断,然后控制小灯的值反向。

          写好后要在程序的最前面声明,并且在startup.s中的相应位置上写好。首先打开工程中的startup.s文件,然后将TIMER0A前的函数改为我们自定义的函数,如图:

          

     

    再在上面进行声明:

     

    小提示,在这里面写的时候,函数只有自己的名字,没有括号,返回值类型等东西。在写的时候,不要顶格写,笔者就因为这个错误郁闷了半天。

     

    下面我们来看看整个程序的代码:

    1. #include "inc/hw_memmap.h"   
    2. #include "inc/hw_types.h"   
    3. #include "inc/hw_ints.h"                                                                                  //定义了与中断相关的宏   
    4. #include "driverlib/sysctl.h"   
    5. #include "driverlib/gpio.h"   
    6. #include "driverlib/timer.h"   
    7. #include "driverlib/interrupt.h"                      //包含中断控制器的API   
    8. void Timer0ATimeoutIntHandler(void);  
    9. int main()  
    10. {  
    11.     SysCtlClockSet(SYSCTL_SYSDIV_1|SYSCTL_USE_OSC|SYSCTL_OSC_MAIN|SYSCTL_XTAL_6MHZ);  
    12.     SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOC);  
    13.     GPIOPinTypeGPIOOutput(GPIO_PORTC_BASE,GPIO_PIN_4);  
    14.      
    15.     SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER0);  
    16.     TimerConfigure(TIMER0_BASE,TIMER_CFG_16_BIT_PAIR|TIMER_CFG_A_PERIODIC);    //配置Timer0   
    17.     TimerPrescaleSet(TIMER0_BASE,TIMER_A,100);                                   //设置预分频值   
    18.     TimerLoadSet(TIMER0_BASE,TIMER_A,30000);                                     //设置装载值   
    19.     TimerIntEnable(TIMER0_BASE,TIMER_TIMA_TIMEOUT);           //使能TIMER0A的溢出中断   
    20.     IntEnable(INT_TIMER0A);                                   //使中断控制器接受TIMER0A的中断请求   
    21.     IntMasterEnable();                                         //使能全局中断   
    22.     TimerEnable(TIMER0_BASE,TIMER_A);                     //使能Timer0A   
    23.     while(1);                                         //死循环   
    24. }  
    25. void Timer0ATimeoutIntHandler(void)                 //中断服务进程   
    26. {  
    27.     TimerIntClear(TIMER0_BASE,TIMER_TIMA_TIMEOUT);                    //清除中断标志位   
    28.     GPIOPinWrite(GPIO_PORTC_BASE,GPIO_PIN_4,~GPIOPinRead(GPIO_PORTC_BASE,GPIO_PIN_4));    //PC4取反   
    29. }  
     

          在此给大家说一个小技巧,在设定GPIO端口的模式时,另外有一个函数是 GPIOPinTypeGPIOOutput() ,使用此函数能达到上面第一个代码中GPIODirModeSet()加上GPIOPadConfigSet()的效果,更简单,如GPIOPinTypeGPIOOutput(GPIO_PORTC_BASE,GPIO_PIN_4) 就可以直接将PC4设为输出口,当然如果有高级设置,比如设置上拉电流,还是要使用代码中的方法的。

Open Toolbar