当前位置: 首页 > 工具软件 > PIT > 使用案例 >

PIT systick

魏雅惠
2023-12-01

说起PIT周期中断定时器,那就是一句话,So easy!写这个模块的教程简直是太轻松了,PIT的功能就是它名字本身的字面意思,如果非要深究严谨的说的话,就是周期中断或触发定时器。我们常用的就是它的周期中断功能,其实他还可以作为周期定时触发功能,至于触发什么,当然是DMA或PDB啦!


PIT工作原理

即使你不用固件库来编程,PIT也绝对是不会让你望而却步的一个东西,打开技术文档看看它的寄存器数量,你就会惊喜的发现,这货才5个寄存器,简直是业界良心啊有木有。这绝对是新手入门级的模块,如果你能用寄存器编程来搞定这个模块,你也可以自豪的跟别人说,哥也是会写K60驱动的人啊。那么今天就破例讲讲这些寄存器是干嘛的吧!(有点凑字儿嫌疑)

  • PIT_MCR-PIT模块控制寄存器。别看这个寄存器是32位的,但其实他就俩位可编写,一个是FRZ位,用来控制PIT在DEBUG模式下是否工作(这位你压根就不用管);另一个是MDIS位,用来使能PIT模块时钟,要想配置PIT其他寄存器,你就必须首先使能它。
  • PIT_LDVALn-定时器加载值寄存器n。这个寄存器是存放计数值的,当这里的数减到0时,PIT就会中断一次或者触发一次。当然,这里说减数并不真的是这个寄存器的数值在自减,而是PIT的另一个寄存器的数值在自减,当减到0后,PIT会重新把LDVAL的值重新加载到那个自减的计数器中。
  • PIT_CVALn-当前定时器值寄存器n。这个就是刚刚说到的自减计数器。
  • PIT_TCTRLn-定时器控制寄存器。这货也是虚有其表,明明是32位的寄存器,才2位能用。TEN定时器使能位,用来使能定时器开始工作的,这里指的开始工作就是定时器值开始自减;TIE定时器中断使能位,用来使能是否产生定时中断,当使能后,PIT会在计数器减到0后产生中断。当然不管使能与否,PIT都会在计数器减到0后产生触发信号。
  • PIT_TFLGn-定时器标志寄存器。这货就1位可用,TIF定时中断标志。

如果你真打算拿PIT来试试手,那么请按照这个顺序来初始化:使能SIM_SCGC6寄存器的PIT时钟位->使能MCR寄存器的MDIS位,开启PIT时钟->使能中断(如果不用中断可忽略)->给LDVAL寄存器赋值(决定定时周期)->使能TCTRL的TEN开启PIT定时器。

其中你可能会关心的PIT定时器的时钟频率是多少,PIT的时钟源只有1个,就是总线时钟,你需要通过你的总线时钟和你要中断的周期来计算加载值LDVAL。


1

//计算公式:LDVAL=周期ns*总线频率hz



PIT例程讲解

通过了解PIT的工作原理,相信你也应该知道使用固件库编程肯定也是一件轻松的事情了。事实确实如此,打开例程“LPLD_PeriodicInterrupt”,编译并运行后,可以从串口调试助手看到PIT0和PIT1分别以2秒和1秒的周期产生中断。

首先看初始化函数pit_init()


01

  pit0_init_struct.PIT_Pitx = PIT0;

02

  pit0_init_struct.PIT_PeriodS = 2;     //定时周期2秒

03

  pit0_init_struct.PIT_Isr = pit0_isr;  //设置中断函数

04

  LPLD_PIT_Init(pit0_init_struct);  

05


06

  pit1_init_struct.PIT_Pitx = PIT1;

07

  pit1_init_struct.PIT_PeriodMs = 1000; //定时周期1000毫秒

08

  pit1_init_struct.PIT_Isr = pit1_isr;  //设置中断函数

09

  LPLD_PIT_Init(pit1_init_struct);

10


11

  LPLD_PIT_EnableIrq(pit0_init_struct);

12

  LPLD_PIT_EnableIrq(pit1_init_struct);



Line 1:使用PIT0模块。PIT一共有4个通道,分别是0~3。

Line 2:配置成员变量PIT_PeriodS,使PIT0的定时周期为2秒。

Line 3:设置中断函数为pit0_isr。

Line 4:初始化pit0。

Line 7:这里配置pit1的周期为1000ms即1s,用的是PIT_PeriodMs成员变量,当热你也可以用PIT_PeriodUs,周期是微秒,这三个变量配置其一即可,也可以组合使用,周期是所有时间的相加。

Line 11:使能PIT0的中断控制器,下同。如果不使用此函数,则不会触发中断请求,只会产生触发信号。

接下来的中断函数就没什么好看的了,你可以在里面做任何事情,当然你也不用去清除任何标志位,因为底层函数已经为你做好这些事情了。


关于这几个定时器

好多人问PIT、Systick、LPTMR、PDB到底有什么不同呢,他们不都是定时器吗?干嘛非得用PIT,不用其他的呢?

其实这是一个比较尴尬的问题,如同问自行车、汽车、飞机不都是交通工具吗?都可以从甲地到乙地,干嘛非用某某呢?

好了,一开始我们就说了,PIT是最简单的定时器,用起来极其简单,如果你想周期性的产生中断,OK,用PIT就足够了。

Systick是什么呢,它是Cortex内核的定时器,也就是说不管是M3\M4,不管是ST的单片机还是飞思卡尔的单片机,这个定时器的结构和用法是一样的,它也可以产生周期中断,也可以作为精准延时函数。但是他的真正用武之地值操作系统的嘀嗒时钟,也就是为uC/OS等操作系统提供时钟节拍。一来他是内核级别的时钟,中断优先级比其他外设模块要高;二来他比较通用,可以不用改任何代码就移植到其他单片机上。

那么LPTMR、PDB呢?这两个是飞思卡尔Kinetis特有的外设模块,也可以用来做定时器,产生周期中断,但是他们也是各自有各自特殊的用途的,LPTMR可以用来做脉冲累加器,用来测量脉冲波的频率;PDB是可编程延时模块,他的主打功能是产生DAC、ADC模块的硬件触发信号,来使他们能够自主的、不需要用户软件来进行工作。


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定时器的用法


systick

系统滴答时间。这个定时器之前的文章已经讲过。这个是一个递减的定时器,有个模数寄存器。在此不多说。就是一个系统的模块,这个模块是集成在ARM M0+内核中的,其实主要是集成在NVIC 中的,NVIC也是ARM 内部模块,该模块的定时器,用该模块的时钟源来使能该定时器。以及模数计数器。总共只有四个寄存器。控制状态寄存器:主要包含一个COUNTFLAG 中断标志位,当计数器计数到0的时候标志该位,CLKSOURCE :可选择时钟源,默认为内核始终,有的厂家还会提供其他外设始终。TICKINT中断使能位,ENABLE计数器使能位。

RVR重载寄存器:每次计数器计数到0 的时候,都重载该值。

CVR计数器的值,记录当前的值。

CALIB校准寄存器:有的厂家将计算好的10ms的ticks值放入该寄存器。也就是说是厂商决定的,厂商烧入,则有,没有设置则没有。

TPM

这个寄存器是递增的。有三个模块,

分为主计数器,和通道计数器,也就是相当于一个计数器,分一个主模数,一个次模数。状态和控制寄存器(SC)中,通过CMOD 可以选计数的模式通过该计数模式可以选择时钟,是选择模块时钟还是选择时钟失效,还是选择异步外设时钟,。再经过PS分频,2(PS次幂)代表分频值,即将该时钟降频。   CPWMS:中心对齐PWM选择(即计数器的计数模式,这个也算该计数器的一个特色吧。比如一般来说计数器是1,2,3,4,5, 然后1,2,3,4,5 。通过该位置1,可以设置成1,2,3,4,5,4,3,2,1)。所以置1只能配出中央对齐的PWM.

该定时器有一个总的MOD模数值,该值用来控制该模块的一个总的中断请求置状态寄存器的TOF位,当计数器达到该值时,该请求。当然一定有一个中断使能位,就是TOIE中断使能位,。两个值一并即触发了中断服务历程。

TPM的分通道。每个模块也有自己的模数寄存器的值。就相当于,主计数器模数是5,从1数到5,通道模数是3,即从1数到3的时候就出发了通道相应的事件。

其实也就是说通过将该模块的计数值。当前通道通过一定的配置 ,根据计数器来进行相应的处理。通道中分为MSnB:MSnA该位控制模式的。ELSNB:ELSNA该两位控制的是边沿和等级。模式有0:输入捕捉(01上升沿,10下降沿,11上升或下降捕捉),1,输出比较(在通道的模数值和计数器的值相等的时候,01翻转电平,10清除电平即置0,11设置电平即置1),2边沿对其PWM(10重新加载的时候是高电平,匹配的时候是低电平,即先高后低,01或11先低电平后高电平),11输出比较(10在匹配的时候打出低电平,X1在匹配的是打出高电平)。后面两种其实是一种,不同的就是在重新加载计数器的时候是否有操作。

每个通道都有一个状态控制寄存器和模数值,包含一个标志通道的中断的标志位,该标志位每个通道都有,还有一个中断使能位,还有就是刚才提到的模式控制和边沿控制,外加一个DMA使能。

模数值和计数器的模数值一样都是16位的,

由于一个模块的通道都比较多,每个通道虽然都有这个中断标志,但是,模块中断只有一个,所以KL25有一个寄存器STATUE将总中断标志位TOF,和每个通道的中断标志位,都映射到一个寄存器中,这个标志都是写1清0的。

有CONFIG配置寄存器,配置计数器的模式,以及时钟源,以及触发方式,比如让计数器不计数,等到输入捕捉到一个上升沿就开始捕捉。等等。还有在调试模式和在等待模式下用的时间基数。

根据以上寄存器的功能可以配置一下的几种功能:

输入捕捉:一般用于编码器

采集输入脉冲的上升沿,下降沿或者上升沿下降沿都采集。采样周期得是计数器时钟的1/4。这其中还涉及到一个Nyquist定律。输入捕捉的时候,CnV就没有用了。

 

输出捕捉功能:一般用于打出方波波形,比如步进电机需要的方波波形

即只有在通道值和模块的计数器的值相等的时候,会操作,可以翻转,默认高,或者默认低。该脉冲周期是计数器周期的两倍

边沿对其的PWM;即在上面的输出比较功能的基础上添加在重载计数器的值得时候进行设置。形成方波脉冲波形。

中心对其的PWM:这个就比较复杂了。周期是模数的两倍。就是1,2,3,4,5,模数是5 ,通道的模数是3 ,当开始和结尾的时候有一次溢出中断,总中断,当1数到3的时候触发一次通道中断,当3数到5 再从5数到3的时候又触发一次通道中断,然后再从3数到1.

 

PIT:  PIT有两个定时器,两个定时器可以连到一起去的。

该计数器的值和上面不一样,它是倒序的,跟systick有点像,从一个值往下递减,减到0的时候重新加载。该定时器还有两个寄存器表示生命周期,可以用来计算该计算机运行了多久,多长时间,对了,该定时器还有一个功能,就是累加(chain)也可以说连接吧,就比如KL25里面有2个TIMER,当第一个TIMER达到0的时候,第二个TIMER减1.

控制寄存器CR也没有几个功能,就是一个模块使能。和一个freeze

每个定时器都有以下的值:

PIT加载值,该值就是该计数器数到0的时候重新加载的值,

PIT当前值:计数当前计数器的值,

PIT时间控制寄存器。可以设置chain累加到前面一个计数器。timer0肯定没有这个功能。TIE中断使能位,TEN时钟使能。

PIT标志位:该位标志了计数器的值达到timer

LPTMR

低功耗定时器:

一共有四个寄存器:控制状态寄存器。预分频寄存器,比较值寄存器,计数寄存器

该定时器可以用外部的脉冲来进行使能,一共有4个外部引脚。

控制寄存器:TCF:定时器比较标志,

                       TIE:中断使能             TPS外部引脚使能    TPP引脚极性(上升沿递增,下降沿递增)  TFC当计数器的值在TCF的时候复位,或者溢出复位。

           TMS:时钟模式选择,定时器或者外部脉冲

TEN:定时器使能。

预分频寄存器:分配值,有2~65535     预分频时钟选择:PCS:与四个外部引脚相对应

比较值寄存器:比较寄存器,存储该值。

RTC:(实时时钟)

 

一共有8个寄存器:秒计数器:闹钟定时器,预分频寄存器,补偿寄存器,控制寄存器,状态寄存器,锁定寄存器,中断使能寄存器:

秒计数器TSR:1s递增一次

闹钟定时器TAR:当TSR达到TAR的值得时候,触发中断。

预分频寄存器,该值是对于32.768晶振来起作用的。预分频晶振的值。

补偿寄存器:可以对预分频进行设置,可以+-127进行配置。

控制寄存器,根据晶振的电容,CLKO晶振使能。OSCE晶振使能。

 

状态寄存器,锁定寄存器,中断使能寄存器:

 

 

 

 



 类似资料:

相关阅读

相关文章

相关问答