前面一直用直接读写寄存器的方法编程,需要经常翻lm3s8962.h来查询宏名称,非常不方便,而且代码不易维护,下面我们学习用TI提供的driverlib来写程序。这个driverlib不仅可以用在8962上,也可以用在其他流明系列ARM上。
驱动库的代码全部存放在StellarisWare\driverlib文件夹下
驱动库会用到inc文件夹里的头文件,inc文件夹中的头文件描述了外设的所有寄存器以及寄存器中的位子段。
先写个最简单的——小灯闪烁blinky
建立工程,添加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文件中相应中断向量的方法实现中断服务,见下图
我们还可以通过
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();