转载请注明出处:http://blog.csdn.net/icyfox_bupt/archive/2011/06/01/6460074.aspx
本来想把驱动库,原理图,内部原理都上传到百度文库的 ,结果被和谐了不让上传,需要的朋友留下邮箱,我会打包给你发过去的。这些文档确实很好用,对于函数的参数,内部的连线结构介绍的很清楚,真是编程必备呀!
上次我们讲了如何使用延时来做小灯闪烁的程序,相信大家都有所了解了,这次我们来看如何使用定时器实现小灯闪烁。
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),所以通过改变定时器中装载的数值就可以控制小灯亮灭的时间。
代码如下:
//使用定时器实现小灯闪烁 #include "inc/hw_types.h" #include "inc/hw_memmap.h" #include "driverlib/sysctl.h" #include "driverlib/gpio.h" #include "driverlib/timer.h" //包含定时器操作的API int main() { SysCtlClockSet(SYSCTL_OSC_MAIN|SYSCTL_XTAL_6MHZ|SYSCTL_USE_OSC|SYSCTL_SYSDIV_1); SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOC); GPIODirModeSet(GPIO_PORTC_BASE,GPIO_PIN_5,GPIO_DIR_MODE_OUT); GPIOPadConfigSet(GPIO_PORTC_BASE,GPIO_PIN_5,GPIO_STRENGTH_2MA,GPIO_PIN_TYPE_STD); SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER0); //使能定时器0 TimerConfigure(TIMER0_BASE,TIMER_CFG_32_BIT_PER); //配置定时器为32bit周期计数模式 TimerLoadSet(TIMER0_BASE,TIMER_A,SysCtlClockGet()/2); //设置装载寄存器值 TimerEnable(TIMER0_BASE,TIMER_A); //使能定时器0 while(1) { while(!(TimerIntStatus(TIMER0_BASE,false)&TIMER_TIMA_TIMEOUT)); //等待Timer0溢出 TimerIntClear(TIMER0_BASE,TIMER_TIMA_TIMEOUT); //清除溢出标志 GPIOPinWrite(GPIO_PORTC_BASE,GPIO_PIN_5,0xff); //PC5=1 while(!(TimerIntStatus(TIMER0_BASE,false)&TIMER_TIMA_TIMEOUT)); //等待Timer0溢出 TimerIntClear(TIMER0_BASE,TIMER_TIMA_TIMEOUT); //清除溢出标志 GPIOPinWrite(GPIO_PORTC_BASE,GPIO_PIN_5,0x00); //PC5=0 } }
设置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前的函数改为我们自定义的函数,如图:
再在上面进行声明:
小提示,在这里面写的时候,函数只有自己的名字,没有括号,返回值类型等东西。在写的时候,不要顶格写,笔者就因为这个错误郁闷了半天。
下面我们来看看整个程序的代码:
#include "inc/hw_memmap.h" #include "inc/hw_types.h" #include "inc/hw_ints.h" //定义了与中断相关的宏 #include "driverlib/sysctl.h" #include "driverlib/gpio.h" #include "driverlib/timer.h" #include "driverlib/interrupt.h" //包含中断控制器的API void Timer0ATimeoutIntHandler(void); int main() { SysCtlClockSet(SYSCTL_SYSDIV_1|SYSCTL_USE_OSC|SYSCTL_OSC_MAIN|SYSCTL_XTAL_6MHZ); SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOC); GPIOPinTypeGPIOOutput(GPIO_PORTC_BASE,GPIO_PIN_4); SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER0); TimerConfigure(TIMER0_BASE,TIMER_CFG_16_BIT_PAIR|TIMER_CFG_A_PERIODIC); //配置Timer0 TimerPrescaleSet(TIMER0_BASE,TIMER_A,100); //设置预分频值 TimerLoadSet(TIMER0_BASE,TIMER_A,30000); //设置装载值 TimerIntEnable(TIMER0_BASE,TIMER_TIMA_TIMEOUT); //使能TIMER0A的溢出中断 IntEnable(INT_TIMER0A); //使中断控制器接受TIMER0A的中断请求 IntMasterEnable(); //使能全局中断 TimerEnable(TIMER0_BASE,TIMER_A); //使能Timer0A while(1); //死循环 } void Timer0ATimeoutIntHandler(void) //中断服务进程 { TimerIntClear(TIMER0_BASE,TIMER_TIMA_TIMEOUT); //清除中断标志位 GPIOPinWrite(GPIO_PORTC_BASE,GPIO_PIN_4,~GPIOPinRead(GPIO_PORTC_BASE,GPIO_PIN_4)); //PC4取反 }
在此给大家说一个小技巧,在设定GPIO端口的模式时,另外有一个函数是 GPIOPinTypeGPIOOutput() ,使用此函数能达到上面第一个代码中GPIODirModeSet()加上GPIOPadConfigSet()的效果,更简单,如GPIOPinTypeGPIOOutput(GPIO_PORTC_BASE,GPIO_PIN_4) 就可以直接将PC4设为输出口,当然如果有高级设置,比如设置上拉电流,还是要使用代码中的方法的。