SysTick 基本操作,中断控制方法

来源:互联网 发布:淘宝上买生活用品 编辑:程序博客网 时间:2024/05/12 15:12

第1章  系统节拍定时(SysTick)
函 数 原 型  页码
void SysTickPeriodSet(unsigned long ulPeriod)  1
unsigned long SysTickPeriodGet(void)  1
void SysTickEnable(void)  2
void SysTickDisable(void)  2
unsigned long SysTickValueGet(void)  2
void SysTickIntEnable(void)  3
void SysTickIntDisable(void)  3
void SysTickIntRegister(void (*pfnHandler)(void))  3
void SysTickIntUnregister(void)  4
 
1.1 SysTick 功能简介
SysTick 是一个简单的系统时钟节拍计数器,它属于 ARM Cortex-M3 内核嵌套向量中断
控制器 NVIC 里的一个功能单元,而非片内外设 SysTick常用于操作系统(如:μC/OS-II
FreeRTOS等)的系统节拍定时 
由于 SysTick是属于 ARM Cortex-M3 内核里的一个功能单元,因此使用 SysTick 作为操
作系统节拍定时,使得操作系统代码在不同厂家的 ARM Cortex-M3 内核芯片上都能够方便
地进行移植 
当然,在不采用操作系统的场合下 SysTick 完全可以作为一般的定时/计数器来使用 

SysTick 是一个 24 位的计数器,采用倒计时方式 SysTick 设定初值并使能后,每经过 1 个
系统时钟周期,计数值就减 1 0 时,SysTick 计数器自动重装初值并继续运行,同
时申请中断,以通知系统下一步做何动作 
 
1.2 SysTick 基本操作
利用 Stellaris外设驱动库 操作 SysTick 是非常简单的 无论是配置还是操作,SysTick
的用法都比一般片内外设简单 
表1  函数SysTickPeriodSet( )
功能
设置SysTick计数器的周期值
原型
void SysTickPeriodSet(unsigned long ulPeriod)
参数
ulPeriod:是SysTick计数器每个周期的时钟节拍数,取值1 16777216
返回

 
表2  函数SysTickPeriodGet( )
功能
获取SysTick计数器的周期值
原型
unsigned long SysTickPeriodGet(void)
参数

返回
1 16777216

 

表3  函数SysTickEnable( )
功能
使能SysTick计数器,开始倒计数
原型
void SysTickEnable(void)
参数

返回

 
表4  函数SysTickDisable( )
功能
关闭SysTick计数器,停止计数
原型
void SysTickDisable(void)
参数

返回

 
表5  函数SysTickValueGet( )
功能
获取SysTick计数器的当前值
原型
unsigned long SysTickValueGet(void)
参数

返回
SysTick计数器的当前值,该值的范围是:0 SysTickPeriodSet( )设定的初值-1
 
程序清单 1.1 是 SysTick 的一个简单应用,能利用其计算一段程序的执行时间,结果通
过 UART 输出 中,被计算执行时间的是 SysCtlDelay( )这个函数,延时时间为
50000μs,最终实际运行的结果是 50004μs,误差很小 

程序清单1.1  SysTick例程:计算一段程序的执行时间
#include  "systemInit.h"
#include  "uartGetPut.h"
#include  <systick.h>
#include  <stdio.h>
 
//  主函数(程序入口)
int main(void)
{
  unsigned long ulStart, ulStop;
  unsigned long ulInterval;
 char s[40];
 
 jtagWait( );           //  防止JTAG 失效,重要!
 clockInit( );           //  时钟初始化:晶振,6MHz
 uartInit( );            //  UART初始化
 
 SysTickPeriodSet(6000000UL);        //   设置SysTick计数器的周期值 
 SysTickEnable( );          //  使能SysTick计数器
 
 ulStart = SysTickValueGet( );        //  读 SysTick当前值(初
 SysCtlDelay(50 * (TheSysClock / 3000));      //   延时一段时间
 ulStop = SysTickValueGet( );        //   读 SysTick当前值(终
 
 SysTickDisable( );          //  关闭SysTick计数器
 ulInterval = ulStart - ulStop;        //  计算时间间隔
 
 sprintf(s, "%ld us/r/n", ulInterval / 6);       //  输出结果,单位:微秒
 uartPuts(s);
 
 for (;;)
 {
 }
}
 
1.3 SysTick 中断控制
SysTick 的中断控制也非常简单,配置时只需要使能 SysTick 中断和处理器中断
进入中断服务函数后硬件会自动清除中断状态,无需手工清除

程序清单 1.2是 SysTick 中断的简单示例 在 SysTick 中断服务 数 SysTick_ISR( )里不
需要手工清除中断状态,直接执行用户代码即可 LED会不断闪烁 
程序清单1.2  SysTick例程:中断操作
#include  "systemInit.h"
#include  <systick.h>
 
//  定义LED
#define  LED_PERIPH    SYSCTL_PERIPH_GPIOG
#define  LED_PORT   GPIO_PORTG_BASE
#define  LED_PIN    GPIO_PIN_2
 
//  主函数(程序入口)
int main(void)
{
 jtagWait( );           //  防止JTAG 失效,重要!
 clockInit( );           //  时钟初始化:晶振,6MHz
 
 SysCtlPeriEnable(LED_PERIPH);       //   使能LED所在的GPIO 端口
 GPIOPinTypeOut(LED_PORT, LED_PIN);      //   设置LED所在管脚为输出
 
 SysTickPeriodSet(3000000UL);        //   设置SysTick计数器的周期值
 SysTickIntEnable( );          //  使能SysTick中断
 IntMasterEnable( );          //  使能处理器中断
 SysTickEnable( );          //  使能SysTick计数器 
  for (;;)
 {
 }
}
 
//  SysTick计数器的中断服务 
void SysTick_ISR(void)
{
  unsigned char ucVal;
 
 //  硬件会自动清除SysTick中断状态 
 //  SysTick计数器的中断服务 

  ucVal = GPIOPinRead(LED_PORT, LED_PIN);     //   反转LED
 GPIOPinWrite(LED_PORT, LED_PIN, ~ucVal);


 

 

关于STM32的systick定时器的详细说明

 

 

我不得不说意法半导体确实有点风骚!甚至有点变态。我对ST文档 STM32F10XXX参考手册的编辑水平真是不敢恭维。手册中好多说明都是含糊不清,甚至将好多对初学者来说很重要的地方都一笔带过,让人着实摸不着头脑。比如前面我说过的关于NVIC嵌套向量中断控制器的介绍,这部分我认为是非常重要的,但当你看完他这部分介绍,你根本不会设置中断服务程序,他有哪些寄存器都不知道,更别说去设置了,NVIC的详细介绍是在Cotex-M3中有详细的介绍,不多说。今天我们说的是systick定时器。

systick定时器和我上面说的情况一样,在手册中根本没有介绍。我费了九牛二虎之力才在一个犄角格拉里找到systick定时器的英文版的说明。在Cotex-M3有介绍,为什么要找STM32的介绍,是因为功能设置上还有点区别。首先看一下systick定时器的作用,下面是Cotex-M3里的一段话:

SysTick定时器被捆绑在NVIC中,用于产生SYSTICK异常(异常号:15)。在以前,大多操作系统需要一个硬件定时器来产生操作系统需要的滴答中断,作为整个系统的时基。例如,为多个任务许以不同数目的时间片,确保没有一个任务能霸占系统;或者把每个定时器周期的某个时间范围赐予特定的任务等,还有操作系统提供的各种定时功能,都与这个滴答定时器有关。因此,需要一个定时器来产生周期性的中断,而且最好还让用户程序不能随意访问它的寄存器,以维持操作系统“心跳”的节律。

Cortex‐M3处理器内部包含了一个简单的定时器。因为所有的CM3芯片都带有这个定时器,软件在不同 CM3器件间的移植工作得以化简。该定时器的时钟源可以是内部时钟(FCLK,CM3上的自由运行时钟),或者是外部时钟( CM3处理器上的STCLK信号)。不过,STCLK的具体来源则由芯片设计者决定,因此不同产品之间的时钟频率可能会大不相同,你需要检视芯片的器件手册来决定选择什么作为时钟源。(知道我为什么找ST关于systick的说明了吧)。

下面介绍STM32中的systick,Systick 部分内容属于NVIC控制部分,一共有4个寄存器,名称和地址分别是:

STK_CSR,        0xE000E010  --  控制寄存器
STK_LOAD,     0xE000E014  --  重载寄存器
STK_VAL,        0xE000E018  --  当前值寄存器
STK_CALRB,   0xE000E01C  --   校准值寄存器

首先看STK_CSR控制寄存器:寄存器内有4个位t具有意义

 

 

 

 

 

第0位:ENABLE,Systick 使能位  (0:关闭Systick功能;1:开启Systick功能)
第1位:TICKINT,Systick 中断使能位    (0:关闭Systick中断;1:开启Systick中断)
第2位:CLKSOURCE,Systick时钟源选择  (0:使用HCLK/8 作为Systick时钟;1:使用HCLK作为Systick时钟)
第3位:COUNTFLAG,Systick计数比较标志,如果在上次读取本寄存器后,SysTick 已经数到了0,则该位为1。如果读取该位,该位将自动清零

STK_LOAD  重载寄存器:

 

 

 

 

 

Systick是一个递减的定时器,当定时器递减至0时,重载寄存器中的值就会被重装载,继续开始递减。STK_LOAD  重载寄存器是个24位的寄存器最大计数0xFFFFFF。

 

STK_VAL当前值寄存器:

 

 

 

 

也是个24位的寄存器,读取时返回当前倒计数的值,写它则使之清零,同时还会清除在SysTick 控制及状态寄存器中的COUNTFLAG 标志。

STK_CALRB  校准值寄存器:

 

 

 

 

这个寄存器好像目前的水平我还用不到,大体意思明白点,把英文说明放这吧:

位31 NOREF :1=没有外部参考时钟(STCLK 不可用)0=外部参考时钟可用

位30 SKEW:1=校准值不是准确的1ms 0=校准值是准确的1ms

位[23:0] :Calibration value

Indicates the calibration value when the SysTick counter runs on HCLK max/8 as external clock. The value is product dependent, please refer to the Product Reference Manual, SysTick Calibration Value section. When HCLK is programmed at the maximum frequency, the SysTick period is 1ms. If calibration information is not known, calculate the calibration value required from the frequency of the processor clock or external clock.

SysTick定时器除了能服务于操作系统之外,还能用于其它目的:如作为一个闹铃,用于测量时间等。要注意的是,当处理器在调试期间被喊停(halt)时,则SysTick定时器亦将暂停运作。

下面我们就应用SysTick定时器来裸奔,把它作为一个定时器来用,还是老一套,在寄存器头文件中添加定义寄存器:

//*****************************************************************

//*                               SystemTick-Register                                 

//*******************************************************************

#define SYSTICK_TENMS    (*((volatile unsigned long *)0xE000E01C))

#define SYSTICK_CURRENT  (*((volatile unsigned long *)0xE000E018))

#define SYSTICK_RELOAD   (*((volatile unsigned long *)0xE000E014))

#define SYSTICK_CSR       (*((volatile unsigned long *)0xE000E010))

 

配置systick寄存器:

void SysTick_Configuration(void)

{

   SYSTICK_CURRENT=0; //当前值寄存器

   SYSTICK_RELOAD=20000; //重装载寄存器,系统时钟20M中断一次1mS

   SYSTICK_CSR|=0x06;// HCLK作为Systick时钟,Systick中断使能位

 }

中断处理:

void SysTick_Handler(void) //中断函数

{

extern unsigned long TimingDelay; // 延时时间,注意定义为全局变量

 

SYSTICK_CURRENT=0;

if (TimingDelay != 0x00)

TimingDelay--;

}

利用systick的延时函数:

 

unsigned long TimingDelay;  // 延时时间,注意定义为全局变量

void Delay(unsigned long nTime)  //延时函数

{

SYSTICK_CSR|=0x07;   // 使能SysTick计数器

TimingDelay = nTime; // 读取延时时间

while(TimingDelay != 0); // 判断延时是否结束

SYSTICK_CSR|=0x06;// 关闭SysTick计数器

}

 

int main()

 {

  SystemInit0();    //系统(时钟)初始化

 stm32_GpioSetup (); //GPIO初始化

 

  SysTick_Configuration(); //配置systick定时器

 while(1)

 {

  GPIO_PORTB_ODR|=(1<<5);

Delay(1000); //1S

 GPIO_PORTB_ODR&=~(1<<5);

 Delay(1000); //1S                                                                              

  }

}

完成!Delay(1000);实现了1S的精确延时,利用Delay(unsigned long nTime);配合systick定时器可以实现任意时间的精确延时,当然通过定时器TIMx也是可以这样做的,我只是用它来说明systick定时器的用法