LPC1114系统定时器(SysTick)
系统定时器也位于“私有外设总线”(Private peripheral bus)内,其地址为0xE000E010~0xE000E01F。下面先来看一下SysTick的内部结构,如下图所示。
本文引用地址:https://www.eepw.com.cn/article/201611/316325.htm从上图中可以看出,SysTick定时器的位长度是24位,即最长的计数次数为16777216次,且计数为倒数计数形式,递减到0时产生中断请求。计数的脉冲可直接取系统时钟,也可取半系统时钟。下表给出了和SysTick相关的寄存器。


{
__IO uint32_t CTRL; /*!< Offset: 0x000 (R/W) SysTick Control and Status Register */
__IO uint32_t LOAD; /*!< Offset: 0x004 (R/W) SysTick Reload Value Register */
__IO uint32_t VAL; /*!< Offset: 0x008 (R/W) SysTick Current Value Register */
__I uint32_t CALIB; /*!< Offset: 0x00C (R/ ) SysTick Calibration Register */
} SysTick_Type;
SysTick定时器组的基址为0xE000E000,所以要将基址指针强制转换为上述结构体,还要加上下面的定义。
#define SysTick_BASE (SCS_BASE + 0x0010UL) /*!< SysTick Base Address */
#define SysTick ((SysTick_Type *) SysTick_BASE ) /*!< SysTick configuration struct */
{
系统定时中断服务程序部分
}
接下来讨论一下系统定时器的初始值设置,因为定时的时长由系统时钟频率、系统时钟选择和载入的初始值共同决定。假设系统时钟为48MHz,默认情况下SysTick的CLKSOURCE值为0,即选择半系统时钟频率。这样,输入给定时器计数的时钟就是48/2=24MHz,计数周期为1/(24MHz)=1/24us,则计24次就是1us的定时,但实际上SysTick采用的是倒数计数方式,即从最大值依次递减计数直到0产生溢出信号。所以24次计数实际上是0~23次,即最大值要减1,即24-1=23。同时要注意,由于计数位宽是24位,所以最大计数值不能超过2的24次方(即16777216),由此,可得出微秒级的初始值计算公式,如下:
LOAD=((24*us)-1),其中us取值范围1~699000
同理可得出毫秒级的初始值计算公式:
LOAD=((24000*ms)-1),其中ms取值范围1~699
上升到一般情况,定时初始值可用下面的公式来计算:

上式中,系统时钟SysClk的单位是MHz,CLKSOURCE的值是0或1,得到的是微秒级别的定时,要注意LOAD的值不能大于16777216。
下面来看一下前面第一个演示示例中的延时部分,代码如下:
static volatile uint32_t TimeTick = 0; //设置全局变量
void SysTick_Handler(void)
{
TimeTick++; //系统定时中断中,全局变量加1
}
void delay_ms(uint32_t ms)
{
SysTick->LOAD = (((24000)*ms)-1); //载入初始值
SysTick->VAL = 0;//写当前值寄存器使其清零
SysTick->CTRL |= ((1<<1)|(1<<0)); //打开中断,启动定时器,选择关系统时钟
while(!TimeTick);
TimeTick = 0; //当定时时间到时,全局变量清零
SysTick->CTRL =0;//关闭定时器
}
可见上述定时是毫秒级别的,最长可定时699ms。
至此,第一个演示示例中的全部内容就都讨论完了,可见在LPC1114中要实现一个简单的十二个LED交替闪烁,涉及到的内容还是很多的。下面再来看一个流水灯的例子,要求实现一个12位的流水灯,时间间隔为100ms。假设LED采用共阳接法接在GPIO2端口,参考代码如下:
#include
//===================系统定时器中断服务程序============================
void SysTick_Handler(void)
{
uint32_t temp;//定义临时中间变量
temp = LPC_GPIO2->DATA;//读取当前端口2的值
temp = ~temp; //把中间变量进行取反
temp<<=1; //把中间变量进行左移一位
temp = ~temp; //再次把中间变量进行取反
LPC_GPIO2->DATA = temp; //把左移后的量赋给端口2
if(temp==0xFFF) //如果左移到头,则从头开始
{
LPC_GPIO2->DATA = 0xFFE;
}
}
//========================系统定时器初始化=============================
void SysTick_init(void)
{
SysTick->LOAD = (((24000)*100)-1);//设置100ms的定时
SysTick->VAL = 0; //计数清零
SysTick->CTRL |= ((1<<1)|(1<<0)); //允许中断,选择半系统时钟,启动定时器
}
//============================主函数==================================
int main(void)
{
LPC_GPIO2->DIR = 0xFFF; //设置端口2为输出方向
LPC_GPIO2->DATA = 0xFFE;//端口2最低位输出0,点亮最末一个LED
SysTick_init();//调用系统定时器
while(1)
{
;//空循环
}
}
把程序编译后下载到LPC1114中,给系统上电,可看到接到端口2上的12个LED在闪烁流动。
评论