[原创] 菜鸟学习笔记3---定时器,中断

blackwc2006   2010-12-23 13:22 楼主
前面一直用直接读写寄存器的方法编程,需要经常翻lm3s8962.h来查询宏名称,非常不方便,而且代码不易维护,下面我们学习用TI提供的driverlib来写程序。这个driverlib不仅可以用在8962上,也可以用在其他流明系列ARM上。

驱动库的代码全部存放在StellarisWare\driverlib文件夹下
驱动库会用到inc文件夹里的头文件,inc文件夹中的头文件描述了外设的所有寄存器以及寄存器中的位子段。

先写个最简单的——小灯闪烁blinky
1.JPG
建立工程,添加main.c文件,还需要添加driverlib/rvmdk/driverlib.lib文件,这个文件是用来将driverlib文件夹中的*.h文件和*.c文件关联起来,否则我们就得把每一个用到的*.c文件添加到工程中。

#include "inc/hw_memmap.h"    //这个头文件中定义了各种外设的基地址
#include "inc/hw_types.h"    //这个头文件中定义了一些变量类型,
#include"driverlib/sysctl.h"    //包含了系统控制的API(时钟控制,系统运行模式,获取系统信息等等)
#include"driverlib/gpio.h"    //包含了GPIO的API

int main()
{
    SysCtlClockSet(SYSCTL_SYSDIV_1|SYSCTL_USE_OSC|SYSCTL_OSC_MAIN|SYSCTL_XTAL_8MHZ);
    //系统主时钟设置,系统预分频为1,直接使用晶振(不用PLL),使用外部主振荡器,外部振荡器频率为8MHZ
    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF);
    //使能外设(为外设提供时钟)GPIOF,实质上就是写RCGC寄存器
    GPIOPinTypeGPIOOutput(GPIO_PORTF_BASE,GPIO_PIN_0);
    //将GPIO的引脚设为输出模式(PF0);
    while(1)
    {
        GPIOPinWrite(GPIO_PORTF_BASE,GPIO_PIN_0,1);    //向GPIO引脚写数据(设置引脚输出电平),PF=1;
        SysCtlDelay(2666667);                //延时函数,延时2666667*3个时钟周期,约为1秒
        GPIOPinWrite(GPIO_PORTF_BASE,GPIO_PIN_0,0);    //PF=0;
        SysCtlDelay(2666667);                //延时
    }
}

在周立功的“Stellaris驱动库用户指南”中有对各个API的讲解,如果想更详细的了解每一个函数的用法可以打开相应的*.c文件,里面有详细的注释。

下面我们用定时器写小灯闪烁程序

#include "inc/hw_memmap.h"
#include "inc/hw_types.h"
#include "driverlib/sysctl.h"
#include "driverlib/gpio.h"
#include "driverlib/timer.h"    //包含定时器的API

int main()
{
    SysCtlClockSet(SYSCTL_SYSDIV_1|SYSCTL_USE_OSC|SYSCTL_OSC_MAIN|SYSCTL_XTAL_8MHZ);
    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF);
    GPIOPinTypeGPIOOutput(GPIO_PORTF_BASE,GPIO_PIN_0);
   
    SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER0);                //给定时器0提供时钟
    TimerConfigure(TIMER0_BASE,TIMER_CFG_16_BIT_PAIR|TIMER_CFG_A_PERIODIC);    //将Timer0设置为16位周期计数模式
    TimerPrescaleSet(TIMER0_BASE,TIMER_A,0x007f);                //设置TIMERA预分频
    TimerLoadSet(TIMER0_BASE,TIMER_A,0xffff);                //设置装载值
    TimerEnable(TIMER0_BASE,TIMER_A);                    //使能TIMER

    while(1)
    {
        GPIOPinWrite(GPIO_PORTF_BASE,GPIO_PIN_0,1);           
        while(!(TimerIntStatus(TIMER0_BASE,false)&TIMER_TIMA_TIMEOUT));    //查询原始中断状态的TimerA溢出位是否为1;
        TimerIntClear(TIMER0_BASE,TIMER_TIMA_TIMEOUT);            //清除原始中断状态的TimerA溢出标志
        GPIOPinWrite(GPIO_PORTF_BASE,GPIO_PIN_0,0);
        while(!(TimerIntStatus(TIMER0_BASE,false)&TIMER_TIMA_TIMEOUT));
        TimerIntClear(TIMER0_BASE,TIMER_TIMA_TIMEOUT);
    }
}

上面的程序是用轮询原始中断标志位的方法实现溢出事件捕捉,我们还可以用溢出中断来实现。
使用中断需包含头文件"driverlib/interrupt.h",使用IntMasterEnable()来使能全局中断,IntMasterDisable()禁能全局中断。
在board\ek-lm3s8962\timers例程中也使用了中断,但是它是通过修改startup.s文件中相应中断向量的方法实现中断服务,见下图
2.JPG
3.JPG
我们还可以通过
void
TimerIntRegister(unsigned long ulBase, unsigned long ulTimer,void (*pfnHandler)(void))
这个函数来修改中断向量。函数的三个参数分别为:定时器基址,TIMER_A或TIMER_B或TIMER_BOTH,中断服务程序指针。
可以用
void
TimerIntUnregister(unsigned long ulBase, unsigned long ulTimer)
函数取消中断与中断服务程序的关联。


#include "inc/hw_memmap.h"
#include "inc/hw_types.h"
#include "driverlib/sysctl.h"
#include "driverlib/gpio.h"
#include "driverlib/timer.h"
#include "driverlib/interrupt.h"

void Timer0ATimeoutIntHandler(void);

int main()
{
    SysCtlClockSet(SYSCTL_SYSDIV_1|SYSCTL_USE_OSC|SYSCTL_OSC_MAIN|SYSCTL_XTAL_8MHZ);
    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF);
    GPIOPinTypeGPIOOutput(GPIO_PORTF_BASE,GPIO_PIN_0);
   
//    IntMasterEnable();                            //使能全局中断
    SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER0);
    TimerConfigure(TIMER0_BASE,TIMER_CFG_16_BIT_PAIR|TIMER_CFG_A_PERIODIC);
    TimerPrescaleSet(TIMER0_BASE,TIMER_A,0x007f);
    TimerLoadSet(TIMER0_BASE,TIMER_A,0xffff);
    TimerIntEnable(TIMER0_BASE,TIMER_TIMA_TIMEOUT);                //使能TIMER0A的溢出中断
    TimerIntRegister(TIMER0_BASE,TIMER_A,Timer0ATimeoutIntHandler);        //将TIMER0A中断服务进程设置为void Timer0ATimeoutIntHandler(void)
    TimerEnable(TIMER0_BASE,TIMER_A);
    while(1);
}

void Timer0ATimeoutIntHandler(void)
{
    TimerIntClear(TIMER0_BASE,TIMER_TIMA_TIMEOUT);                //清除中断标志位
    GPIOPinWrite(GPIO_PORTF_BASE,GPIO_PIN_0,~GPIOPinRead(GPIO_PORTF_BASE,GPIO_PIN_0));    //PF0取反
}

这样我们就通过中断实现小灯闪烁,需要注意的是TimerIntRegister这个函数会使能全局中断,如果不想使能全局中断就要在该函数后加IntMasterDisable();

回复评论 (2)

支持一下
点赞  2010-12-23 15:24
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 京公网安备 11010802033920号
    写回复