NXP JN5169使用滴答定时器进行精准延时



一、滴答定时器介绍

滴答定时器是一个硬件定时器,它来自外设时钟并且可以用来执行下面的操作:
        1、软件的定时中断;
        2、常规事件,例如软件定时器或操作系统的节拍;
        3、高精度定时参考;
        4、系统监控超时,比如在看门狗定时器中使用。

        注:对于高精度的滴答定时器操作,外设时钟应在 16MHz 频率下运行,系统时钟源是外部晶体振荡器。

滴答定时器特点:
        1、32位计数器
        2、28位匹配值
        3、可屏蔽定时器中断
        4、单次触发,可重启和连续运行模式


二、滴答定时器系统图

在这里插入图片描述

1、系统图介绍

        滴答定时器由一个连续的16 MHz时钟提供时钟,该时钟由模式控制模块的信号选通,馈入一个32位宽的可复位递增计数器。 匹配寄存器允许比较计数器和编程值。 通过软件对以16 MHz时钟周期测量的匹配值进行编程,范围为0至0x0FFFFFFF。 比较的输出可用于生成中断(如果允许中断),并可用于在不同模式下控制计数器。 配置定时器模式后,计数器也会复位。

2、单次触发模式

        如果将模式编程为单次触发,则计数器将从零开始计数,直到达到匹配值为止。 将产生匹配信号,这将引起中断(如果允许),并且计数器将停止计数。 通过重新编程模式可以重启计数器。

3、可重启模式

        如果将模式编程为可重启模式,则计数器的操作与单次模式相同,不同之处在于,当达到匹配值时,计数器将复位并从零开始计数。 当达到匹配值时(如果使能)将产生一个中断。

4、连续运行模式

        连续模式操作类似于可重启模式,不同之处在于,当达到匹配值时,计数器不会复位,而是继续计数。 当达到匹配值时(如果使能),将产生一个中断。


三、系统时钟

        系统控制器给 JN516x 微控制器提供时钟,分成 4 个主要模块:系统时钟域、外设时钟域、CPU 时钟域和一个 32kHz 的时钟域

1、系统时钟域

        系统时钟是一个高速参考时钟,芯片正式工作时外围时钟和 CPU 时钟都来自于该时钟。这个域的时钟来源于下面其中一个时钟源:

  • 外部 32MHz 晶体振荡器;
  • 内部高速 RC 振荡器;

        晶体振荡器由器件引脚 4 和 5 连接的 32MHz 外部晶体来驱动。在晶体振荡器的作用下,这个域产生一个 32MHz 的系统时钟。
        未校准的 RC 振荡器通常在 27MHz 下运行,但经过校准后可以运行在近似 32MHz 下。由于 RC 振荡器比晶体振荡器启动快得多,因此主要用于睡眠后的全速启动。
        当系统时钟由 RC 振荡器提供时,无线收发器和一些外设不应该使用。

2、外设时钟域

        外设时钟来自于系统时钟,用作包括调制解调器和基带处理器在内的片内外设的时钟参考。外设时钟的工作频率是系统时钟频率的一半。当系统时钟由外部 32MHz 的晶体振荡器提供时,外设时钟运行在 16MHz

3、CPU 时钟域

        CPU 时钟由系统时钟分频得到,用作微处理器和存储器子系统的时钟参考。

4、32kHz 时钟域

        32kHz 时钟域主要在低功耗睡眠期间使用(还供 JN516x 器件上的随机数发生器使用)。当处于睡眠模式时,CPU 不运行,依靠中断来唤醒。中断可以由一个片内唤醒定时器产生,或者由一个外部源通过一个 DIO 引脚、一个片内比较器或一个片内脉冲计数器来产生。唤醒定时器由 32kHz域来驱动。这个域的 32kHz 时钟可以来源于下面其中一个时钟源:

  • 内部 RC 振荡器;
  • 外部晶体;
  • 外部时钟模块;

        晶体振荡器由 DIO9 和 DIO10 连接的一个外部 32kHz 晶体来驱动。如果使用外部晶体,外部时钟模块就连接到 DIO9。32kHz 域在芯片正常工作时仍然有效,可以以外设时钟为基准进行校准来提高计时精度。

四、滴答定时器集成外设API函数介绍

1、void vAHI_TickTimerConfigure(uint8 u8Mode)

        此函数配置滴答定时器的操作模式并启用定时器, 它也可以用来禁用定时器。滴答定时器向上计数,直到计数与预定义的参考值匹配为止。
        使用功能vAHI_TickTimerInterval()设置参考计数。可以启用一个达到参考计数时生成的中断。一旦vAHI_TickTimerConfigure()将其启用为上述任一模式,则滴答定时器将开始运行,而不管其计数器的状态如何。 实际上,要使用滴答计时器:
       1.调用vAHI_TickTimerConfigure()禁用滴答计时器。
        2.调用vAHI_TickTimerWrite()来为计数设置适当的起始值。
        3.调用vAHI_TickTimerInterval()设置参考计数。
        4.再次调用vAHI_TickTimerConfigure(),以所需的模式启动滴答定时器。

        设备上电/复位时,滴答计时器被禁用。但是,建议始终按照上述函数调用顺序来启动计时器。如果在单发模式下启用了滴答定时器,则一旦停止(达到参考计数),即可通过以下方式再次启动计时器,使用vAHI_TickTimerWrite()设置另一个起始值。

形参:u8Mode 滴答定时器操作模式
在达到参考计数时应采取的行动:
        E_AHI_TICK_TIMER_CONT (继续计数)
        E_AHI_TICK_TIMER_RESTART (从零开始)
        E_AHI_TICK_TIMER_STOP(停止计时器)
禁用滴答定时器:
        E_AHI_TICK_TIMER_DISABLE (禁用定时器)


2、void vAHI_TickTimerInterval(uint32 u32Interval)

        此功能设置Tick Timer的28位参考计数。
        这是与滴答定时器的实际计数进行比较的值。 当计数达到该参考值时,将使用函数vAHI_TickTimerConfigure()确定采取的措施。 也可以启用在达到参考计数时生成的中断。

形参:u32Interval
        参考计数(范围从 0 到 0x0FFFFFFF)。


3、void vAHI_TickTimerWrite(uint32 u32Count)

        此函数设置滴答定时器的初始计数。 如果启用了定时器,它将立即从这个值开始计数。 通过指定计数为零,该函数可以用于重置 滴答计时器随时计数为零。
        注:如果在定时器使能时调用这个函数,则定时器将立即从指定的值开始计数。

形参:u32Count
        起始计数(范围从 0 到 0xFFFFFFFF)。


4、uint32 u32AHI_TickTimerRead(void)

        此功能获取时钟计时器的当前值。

返回值:计时器的当前值


5、void vAHI_TickTimerIntEnable(bool_t bIntEnable)

        此功能可用于启用滴答定时器中断,当滴答定时器计数达到使用函数vAHI_TickTimerInterval()指定的参考计数时,将产生该中断。
        可以使用函数vAHI_TickTimerRegisterCallback()注册用户定义的回调函数,该函数在生成中断时调用。
        注:滴答计时器中断可用于将CPU从Doze模式唤醒。

形参:bIntEnable 使能/禁用中断:
        TRUE     使能中断
        FALSE   禁用中断


6、bool_t bAHI_TickTimerIntStatus(void)

        此功能获取滴答定时器的当前中断状态。

返回值:如果中断未决,则为TRUE,否则为FALSE

7、void vAHI_TickTimerIntPendClr(void)

        该功能清除所有待处理的滴答定时器中断。

8、void vAHI_TickTimerRegisterCallback(PR_HWINT_APPCALLBACK prTickTimerCallback)

        该函数注册了一个用户定义的回调函数,该事件将在触发滴答定时器中断时被调用。
        注意,回调函数将在中断上下文中执行。 因此,必须确保它及时返回主程序。
        已注册的回调函数仅在RAM保持供电的睡眠模式下保留。 如果在睡眠期间关闭RAM的电源并需要中断,则必须在唤醒时调用u32AHI_Init()之前重新注册回调函数。

形参:prTickTimerCallback 指向要注册的回调函数的指针

五、实现代码

        使用BeyondStudio for NXP编写,SDK为JN-SW-4170,不带栈协议,仅外设功能实现。

1、宏定义

/* Value enumerations: Tick Timer */
#define E_AHI_TICK_TIMER_DISABLE        (0x00) /* Disable tick timer */
#define E_AHI_TICK_TIMER_RESTART        (0x01) /* Restart timer when match occurs */
#define E_AHI_TICK_TIMER_STOP           (0x02) /* Stop timer when match occurs */
#define E_AHI_TICK_TIMER_CONT           (0x03) /* Timer does not stop when match occurs */

#define TRUE            (1)   /* page 207 K+R 2nd Edition */
#define FALSE           (0)

#define DELAY_TICK_TIME         16000000	/* 1s  */
#define TICK_COUNT              16000       /* 1ms */

#define LED2                    (1 <<  0)
#define LED3                    (1 <<  1)
#define LED4                    (1 <<  2)
#define LED5                    (1 <<  3)
#define LED6                    (1 <<  4)
#define LED8                    (1 <<  5)
#define LED_DIO                 ((1 << 0) | (1 << 1) | (1 << 2) | (1 << 3) | (1 << 4) | (1 << 5))

#define LED_ON(Led)             vAHI_DioSetOutput(0, Led)
#define LED_OFF(Led)            vAHI_DioSetOutput(Led, 0)

2、x ms延时程序实现

PRIVATE void vAHI_DelayXms(uint32 n)
{
	uint32 temp;
	vAHI_TickTimerConfigure(E_AHI_TICK_TIMER_DISABLE);/* 关闭滴答定时器*/
	vAHI_TickTimerWrite(0);/* 设置起始值*/
	vAHI_TickTimerInterval(TICK_COUNT * n);/* 设置参照值*/
	vAHI_TickTimerConfigure(E_AHI_TICK_TIMER_STOP);/* 到达参考值停止计数*/
	vAHI_TickTimerIntEnable(FALSE);/* 关闭中断*/
	do{
		temp = u32AHI_TickTimerRead();
	}while(temp < TICK_COUNT * n);//向上计数
	vAHI_TickTimerConfigure(E_AHI_TICK_TIMER_DISABLE);/* 关闭滴答定时器 */
}

3、x us延时程序实现

PRIVATE vAHI_DelayXus(uint32 n)
{
	uint32 temp;
	vAHI_TickTimerConfigure(E_AHI_TICK_TIMER_DISABLE);/* 关闭滴答定时器*/
	vAHI_TickTimerWrite(0);/* 设置起始值*/
	vAHI_TickTimerInterval(16 * n);/* 设置参照值*/
	vAHI_TickTimerConfigure(E_AHI_TICK_TIMER_STOP);/* 到达参考值停止计数*/
	vAHI_TickTimerIntEnable(FALSE);/* 关闭中断*/
	do{
		temp = u32AHI_TickTimerRead();
	}while(temp < 16 * n);//向上计数
	vAHI_TickTimerConfigure(E_AHI_TICK_TIMER_DISABLE); /* 关闭滴答定时器*/
}

4、流水灯例程

/*LED初始化IO*/
PRIVATE void vLedsInit (void)
{
    vAHI_DioSetDirection(0, LED_DIO);//DIO设置为输出方向
    vAHI_DioSetPullup(LED_DIO, 0);//DIO设置为上拉模式
}
/*流水灯程序*/
PUBLIC void Flow_LED(void)
{
	LED_ON(LED2);
	LED_OFF(LED3);
	LED_OFF(LED4);
	LED_OFF(LED5);
	LED_OFF(LED6);
	LED_OFF(LED8);
	vAHI_DelayXms(1000);

	LED_OFF(LED2);
	LED_ON(LED3);
	LED_OFF(LED4);
	LED_OFF(LED5);
	LED_OFF(LED6);
	LED_OFF(LED8);
	vAHI_DelayXms(1000);

	LED_OFF(LED2);
	LED_OFF(LED3);
	LED_ON(LED4);
	LED_OFF(LED5);
	LED_OFF(LED6);
	LED_OFF(LED8);
	vAHI_DelayXms(1000);

	LED_OFF(LED2);
	LED_OFF(LED3);
	LED_OFF(LED4);
	LED_ON(LED5);
	LED_OFF(LED6);
	LED_OFF(LED8);
	vAHI_DelayXus(1000000);

	LED_OFF(LED2);
	LED_OFF(LED3);
	LED_OFF(LED4);
	LED_OFF(LED5);
	LED_ON(LED6);
	LED_OFF(LED8);
	vAHI_DelayXus(1000000);

	LED_OFF(LED2);
	LED_OFF(LED3);
	LED_OFF(LED4);
	LED_OFF(LED5);
	LED_OFF(LED6);
	LED_ON(LED8);
	vAHI_DelayXus(1000000);
}

/*主程序*/
PUBLIC void AppColdStart (void)
{
	vAHI_WatchdogStop();
	(void)u32AHI_Init();

    vLedsInit();

    LED_OFF(LED2);
    LED_OFF(LED3);
    LED_OFF(LED4);
    LED_OFF(LED5);
    LED_OFF(LED6);
    LED_OFF(LED8);

    while (1) {
    	Flow_LED();
    }
}
/*热启动*/
PUBLIC void AppWarmStart (void)
{
    AppColdStart();
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

菠萝蚊鸭

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值