一、唤醒定时器介绍
二、实现代码
- 1、中断模式 1
- 2、中断模式 2
- 3、轮询模式
一、唤醒定时器介绍
有关 32kHz 时钟见:低速(32kHz)系统时钟
JN5169 上有两个 41 位唤醒定时器,由 32 kHz 时钟(该时钟可源自内部或外部)驱动。它们可能会在设备其余大部分设备掉电时的睡眠周期内运行,以计时睡眠周期或应用程序可能需要的其他长时间周期。唤醒定时器不在深度睡眠期间运行,可以选择通过软件控制在睡眠模式下禁用。当唤醒定时器到期时,它通常会产生一个中断。如果设备处于睡眠状态,则该中断可以用作结束睡眠时间的事件。功能包括:
- 41位递减计数器
- (可选)在睡眠期间运行
- 由 32 kHz 系统时钟提供时钟; 32 kHz RC 振荡器,32 kHz 晶振或 32 kHz 时钟输入
唤醒定时器包括一个从所选 32 kHz 时钟开始计时的 41 位递减计数器。当计数器达到零时,会产生中断或唤醒事件。达到零时,计数器将继续递减计数直到停止,这允许测量响应中断的等待时间。如果需要中断或唤醒事件,则应在装入该期间的计数值之前使能定时器中断。一旦加载了计数器值并启动了计数器,便开始递减计数。计数器可以通过软件控制随时停止——计数器将保持其停止时所包含的值,并且不会产生中断。可以读取计时器的状态以指示计时器是否正在运行或已到期;当定时器中断被屏蔽时,这很有用。此操作将重置所有过期的状态标志。
唤醒定时器时钟:
二、实现代码
1、中断模式 1
#include <AppHardwareApi.h>
#include <AppQueueApi.h>
#define UART E_AHI_UART_0
PRIVATE void vPutChar(unsigned char c);
PRIVATE void vPutStrs(unsigned char *str);
PRIVATE void vUartInit(void);
PRIVATE void vWakeTimerInit(void);
PRIVATE uint32 u32WakeTimerClockCycle; //定时 T 秒所需的 32kHz 时钟周期数
#define DURATION_SECONDS 2 //WakeTimer 定时时间(以秒计算),这里示例2秒
PUBLIC void AppColdStart (void)
{
/*等待系统时钟切换为外部32MHz晶振*/
while (bAHI_GetClkSource() == TRUE);
/*优化闪存等待状态*/
vAHI_OptimiseWaitStates();
vAHI_WatchdogStop();
(void)u32AHI_Init();
u32WakeTimerClockCycle = 0;
vUartInit();
vWakeTimerInit();
while (1) {
vAHI_CpuDoze(); /* Doze */
}
}
PUBLIC void AppWarmStart (void)
{
AppColdStart();
}
PRIVATE void vCbWakeTimer (uint32 u32Device, uint32 u32ItemBitmap)
{
if(E_AHI_DEVICE_SYSCTRL == u32Device){ //系统中断
switch(u32ItemBitmap){
case E_AHI_SYSCTRL_WK1_MASK: //WakeTimer1
vPutStrs((uint8*)"E_AHI_SYSCTRL_WK1_MASK\n");
break;
case E_AHI_SYSCTRL_WK0_MASK: //WakeTimer0
vPutStrs((uint8*)"E_AHI_SYSCTRL_WK0_MASK\n");
break;
default:
break;
}
}
/**
* WakeTimer 计数在到达 0 时,定时器触发,翻转到 0x1FFFFFFFFFF,并继续递减。
* 如果使能,在到达0 时产生唤醒定时器中断。
* 每次触发中断之后需要重新设置 32KHz 时钟周期数,不然默认会翻转到 0x1FFFFFFFFFF,并继续递减。
*/
vAHI_WakeTimerStartLarge(E_AHI_WAKE_TIMER_0, u32WakeTimerClockCycle);
}
PRIVATE void vWakeTimerInit(void)
{
/**
* 如果 32KHz 时钟的时钟源是(默认)内部 32KHz RC 振荡器,
* 那么唤醒定时器的运行速度可能快 18%或 慢 18%
* 为了得到更精确的定时,建议先校准时钟,并相应调整指定的计数值
* 通过时钟校准计算所需的唤醒定时器持续时间的 32KHz 时钟周期数 N
* 唤醒定时器 32 个时钟周期等于 1ms
* n = u32AHI_WakeTimerCalibrate()
* 定时时间 T (单位秒)
* 时钟周期数 N = (10000.0 / n) * 32000 * T
*/
vAHI_WakeTimerStop(E_AHI_WAKE_TIMER_0); //使用 u32AHI_WakeTimerCalibrate() 之前需要停止相应的唤醒定时器
u32WakeTimerClockCycle = (uint32)DURATION_SECONDS * 32000 * (10000.0 / u32AHI_WakeTimerCalibrate());
vAHI_WakeTimerEnable(E_AHI_WAKE_TIMER_0, TRUE); //唤醒定时器启动时启用中断
vAHI_WakeTimerStartLarge(E_AHI_WAKE_TIMER_0, u32WakeTimerClockCycle); //启动唤醒定时器
vAHI_SysCtrlRegisterCallback(vCbWakeTimer); //注册中断回调函数
}
/*发送单个字符*/
PRIVATE void vPutChar(unsigned char c)
{
while (!(u8AHI_UartReadLineStatus(UART) & E_AHI_UART_LS_THRE)); /*发送FIFO为空*/
vAHI_UartWriteData(UART, c); /*写入要发送的字符*/
/*
发送移位寄存器为空或者发送FIFO为空,即等待发送完毕
E_AHI_UART_LS_THRE | E_AHI_UART_LS_TEMT = 0x20 | 0x40 = 0x60
*/
while ((u8AHI_UartReadLineStatus(UART) & (E_AHI_UART_LS_THRE | E_AHI_UART_LS_TEMT))
!= (E_AHI_UART_LS_THRE | E_AHI_UART_LS_TEMT));
}
/*发送字符串*/
PRIVATE void vPutStrs(unsigned char *str)
{
while(*str){
vPutChar(*str++);
}
}
/*初始化串口*/
PRIVATE void vUartInit(void)
{
#if (UART == E_AHI_UART_0)
vAHI_UartSetRTSCTS(UART, FALSE); /* UART0 2线模式。Disable use of CTS/RTS */
#endif
vAHI_UartEnable(UART);
//复位指定UART的发送和接收FIFO,并将FIFO触发级别设置为单字节触发
vAHI_UartReset(UART,
TRUE, /* 复位收发FIFO*/
TRUE);
vAHI_UartSetBaudRate(UART, E_AHI_UART_RATE_115200); /* 设置波特率*/
}
效果演示:
2、中断模式 2
与模式 1 相比,少了中断回调函数。
#include <AppHardwareApi.h>
#include <AppQueueApi.h>
#define UART E_AHI_UART_0
PRIVATE void vPutChar(unsigned char c);
PRIVATE void vPutStrs(unsigned char *str);
PRIVATE void vUartInit(void);
PRIVATE void vWakeTimerInit(void);
PRIVATE uint32 u32WakeTimerClockCycle; //定时 T 秒所需的 32KHz 时钟周期数
#define DURATION_SECONDS 2 //WakeTimer 定时时间(以秒计算),这里示例2秒
PUBLIC void AppColdStart (void)
{
/*等待系统时钟切换为外部32MHz晶振*/
while (bAHI_GetClkSource() == TRUE);
/*优化闪存等待状态*/
vAHI_OptimiseWaitStates();
vAHI_WatchdogStop();
(void)u32AHI_Init();
u32WakeTimerClockCycle = 0;
vUartInit();
vWakeTimerInit();
while (1) {
vAHI_CpuDoze(); /* Doze */
//唤醒定时器中断发生后唤醒设备,重新装载计数时钟周期数,然后进入 Doze 模式
/**
* WakeTimer 计数在到达 0 时,定时器触发,翻转到 0x1FFFFFFFFFF,并继续递减。
* 如果使能,在到达0 时产生唤醒定时器中断。
* 每次触发中断之后需要重新设置 32KHz 时钟周期数,不然默认会翻转到 0x1FFFFFFFFFF,并继续递减。
*/
vAHI_WakeTimerStartLarge(E_AHI_WAKE_TIMER_0, u32WakeTimerClockCycle);
vPutStrs((uint8*)"Interrupt Mode 2:E_AHI_SYSCTRL_WK0_MASK\n");
}
}
PUBLIC void AppWarmStart (void)
{
AppColdStart();
}
PRIVATE void vWakeTimerInit(void)
{
/**
* 如果 32KHz 时钟的时钟源是(默认)内部 32KHz RC 振荡器,
* 那么唤醒定时器的运行速度可能快 18%或 慢 18%
* 为了得到更精确的定时,建议先校准时钟,并相应调整指定的计数值
* 通过时钟校准计算所需的唤醒定时器持续时间的 32KHz 时钟周期数 N
* 唤醒定时器 32 个时钟周期等于 1ms
* n = u32AHI_WakeTimerCalibrate()
* 定时时间 T (单位秒)
* 时钟周期数 N = (10000.0 / n) * 32000 * T
*/
vAHI_WakeTimerStop(E_AHI_WAKE_TIMER_0); //使用 u32AHI_WakeTimerCalibrate() 之前需要停止相应的唤醒定时器
u32WakeTimerClockCycle = (uint32)DURATION_SECONDS * 32000 * (10000.0 / u32AHI_WakeTimerCalibrate());
vAHI_WakeTimerEnable(E_AHI_WAKE_TIMER_0, TRUE); //唤醒定时器启动时启用中断
vAHI_WakeTimerStartLarge(E_AHI_WAKE_TIMER_0, u32WakeTimerClockCycle); //启动唤醒定时器
}
/*发送单个字符*/
PRIVATE void vPutChar(unsigned char c)
{
while (!(u8AHI_UartReadLineStatus(UART) & E_AHI_UART_LS_THRE)); /*发送FIFO为空*/
vAHI_UartWriteData(UART, c); /*写入要发送的字符*/
/*
发送移位寄存器为空或者发送FIFO为空,即等待发送完毕
E_AHI_UART_LS_THRE | E_AHI_UART_LS_TEMT = 0x20 | 0x40 = 0x60
*/
while ((u8AHI_UartReadLineStatus(UART) & (E_AHI_UART_LS_THRE | E_AHI_UART_LS_TEMT))
!= (E_AHI_UART_LS_THRE | E_AHI_UART_LS_TEMT));
}
/*发送字符串*/
PRIVATE void vPutStrs(unsigned char *str)
{
while(*str){
vPutChar(*str++);
}
}
/*初始化串口*/
PRIVATE void vUartInit(void)
{
#if (UART == E_AHI_UART_0)
vAHI_UartSetRTSCTS(UART, FALSE); /* UART0 2线模式。Disable use of CTS/RTS */
#endif
vAHI_UartEnable(UART);
//复位指定UART的发送和接收FIFO,并将FIFO触发级别设置为单字节触发
vAHI_UartReset(UART,
TRUE, /* 复位收发FIFO*/
TRUE);
vAHI_UartSetBaudRate(UART, E_AHI_UART_RATE_115200); /* 设置波特率*/
}
效果演示:
3、轮询模式
注意!轮询模式下设备不能进入 休眠(doze)模式 ,因为关闭了唤醒定时器中断,无法唤醒进入休眠模式的设备!
#include <AppHardwareApi.h>
#include <AppQueueApi.h>
#define UART E_AHI_UART_0
PRIVATE void vPutChar(unsigned char c);
PRIVATE void vPutStrs(unsigned char *str);
PRIVATE void vUartInit(void);
PRIVATE void vWakeTimerInit(void);
PRIVATE uint32 u32WakeTimerClockCycle; //定时 T 秒所需的 32KHz 时钟周期数
#define DURATION_SECONDS 2 //WakeTimer 定时时间(以秒计算),这里示例2秒
PUBLIC void AppColdStart (void)
{
/*等待系统时钟切换为外部32MHz晶振*/
while (bAHI_GetClkSource() == TRUE);
/*优化闪存等待状态*/
vAHI_OptimiseWaitStates();
vAHI_WatchdogStop();
(void)u32AHI_Init();
u32WakeTimerClockCycle = 0;
vUartInit();
vWakeTimerInit();
while (1) {
while(u64AHI_WakeTimerReadLarge(E_AHI_WAKE_TIMER_0) == 0){
vPutStrs((uint8*)"E_AHI_SYSCTRL_WK0_MASK\n");
/**
* WakeTimer 计数在到达 0 时,定时器触发,翻转到 0x1FFFFFFFFFF,并继续递减。
* 如果使能,在到达0 时产生唤醒定时器中断。
* 每次触发中断之后需要重新设置 32KHz 时钟周期数,不然默认会翻转到 0x1FFFFFFFFFF,并继续递减。
*/
vAHI_WakeTimerStartLarge(E_AHI_WAKE_TIMER_0, u32WakeTimerClockCycle);
}
}
}
PUBLIC void AppWarmStart (void)
{
AppColdStart();
}
PRIVATE void vWakeTimerInit(void)
{
/**
* 如果 32KHz 时钟的时钟源是(默认)内部 32KHz RC 振荡器,
* 那么唤醒定时器的运行速度可能快 18%或 慢 18%
* 为了得到更精确的定时,建议先校准时钟,并相应调整指定的计数值
* 通过时钟校准计算所需的唤醒定时器持续时间的 32KHz 时钟周期数 N
* 唤醒定时器 32 个时钟周期等于 1ms
* n = u32AHI_WakeTimerCalibrate()
* 定时时间 T (单位秒)
* 时钟周期数 N = (10000.0 / n) * 32000 * T
*/
vAHI_WakeTimerStop(E_AHI_WAKE_TIMER_0); //使用 u32AHI_WakeTimerCalibrate() 之前需要停止相应的唤醒定时器
u32WakeTimerClockCycle = (uint32)DURATION_SECONDS * 32000 * (10000.0 / u32AHI_WakeTimerCalibrate());
vAHI_WakeTimerEnable(E_AHI_WAKE_TIMER_0, FALSE); //唤醒定时器启动时关闭中断
vAHI_WakeTimerStartLarge(E_AHI_WAKE_TIMER_0, u32WakeTimerClockCycle); //启动唤醒定时器
}
/*发送单个字符*/
PRIVATE void vPutChar(unsigned char c)
{
while (!(u8AHI_UartReadLineStatus(UART) & E_AHI_UART_LS_THRE)); /*发送FIFO为空*/
vAHI_UartWriteData(UART, c); /*写入要发送的字符*/
/*
发送移位寄存器为空或者发送FIFO为空,即等待发送完毕
E_AHI_UART_LS_THRE | E_AHI_UART_LS_TEMT = 0x20 | 0x40 = 0x60
*/
while ((u8AHI_UartReadLineStatus(UART) & (E_AHI_UART_LS_THRE | E_AHI_UART_LS_TEMT))
!= (E_AHI_UART_LS_THRE | E_AHI_UART_LS_TEMT));
}
/*发送字符串*/
PRIVATE void vPutStrs(unsigned char *str)
{
while(*str){
vPutChar(*str++);
}
}
/*初始化串口*/
PRIVATE void vUartInit(void)
{
#if (UART == E_AHI_UART_0)
vAHI_UartSetRTSCTS(UART, FALSE); /* UART0 2线模式。Disable use of CTS/RTS */
#endif
vAHI_UartEnable(UART);
//复位指定UART的发送和接收FIFO,并将FIFO触发级别设置为单字节触发
vAHI_UartReset(UART,
TRUE, /* 复位收发FIFO*/
TRUE);
vAHI_UartSetBaudRate(UART, E_AHI_UART_RATE_115200); /* 设置波特率*/
}
效果演示: