最近在维护别人写的代码,其中有一个睡眠定时器问题,我怎么都看不出来问题在哪里?
代码在下面,做了一点简化。该段程序由睡眠定时器来实现所有的定时功能,当需要定时器时,添加到SysTimerTable表中,每产生一次定时中断,从SysTimerTable表中各个活动的定时器countDown值减去定时器的值,如果时间到,调用回调函数。然后再从SysTimerTable表中找到最近的定时器。
原来代码中nextInterruptTick = 0xFFFFF;使用时一直使用的最长的定时时间是30秒(32768x30=0xF0000),10秒,20秒也没问题。
最近项目需要,想使用定时时间到几分钟,发现有问题,最长时间也就30几秒(因为nextInterruptTick = 0xFFFFF)。睡眠定时器是24位的,然后我改成nextInterruptTick = 0xFFFFFF,时间是延长了,但不是想要的,比如设了两分钟,50几秒就来中断了,设了8分钟,40秒不到就中断了。
我已经检查了好几遍了,有人遇到过这个问题吗?
typedef uint32_t tick_t;
static uint32_t tickExt;
#define EnterCritical(lock) HAL_INT_LOCK(lock)
#define ExitCritical(lock) HAL_INT_UNLOCK(lock)
tick_t TickGet(void)
{
uint8_t hwlock;
static tick_t preTick=0;
tick_t curTick;
uint8_t st0,st1,st2;
EnterCritical(hwlock);
st0 = ST0;
st1 = ST1;
st2 = ST2;
curTick = tickExt;
curTick <<= 8;
curTick |= st2&0xFF;
curTick <<= 8;
curTick |= st1&0xFF;
curTick <<= 8;
curTick |= st0&0xFF;
if (curTick < preTick)
{
tickExt ++;
curTick += 0x1000000;
}
preTick = curTick;
ExitCritical(hwlock);
return curTick;
}
/* 设置下一次定时器中断时间 */
void SleepTimeCompSet(tick_t tick)
{
tick_t next = tick + TickGet();
uint8_t st0,st1,st2;
st0 = next&0xFF;
next>>=8;
st1 = next&0xFF;
next>>=8;
st2 = next&0xFF;
while(!(STLOAD&0x01));
ST2 = st2;
ST1 = st1;
ST0 = st0;
STIF = 0;
STIE = 1;
}
void SysTimerTask(event_t event)
{
tick_t tick1, tick2;
tick_t deltaTick;
tick_t ticksdiff;
tick_t nextInterruptTick;
static tick_t previousTick = 0;
SysTimerID_t timerID;
SysTimerStatus_t status;
uint8_t hwlock;
tick1 = TickGet();
deltaTick = tick1 - previousTick;
previousTick = tick1;
for (timerID = 0; timerID < MAX_SYSTIMERS; timerID ++)
{
EnterCritical(hwlock);
status = SysTimerStatusGet(timerID);
if (status != SYSTIMER_STATUS_ACTIVE)
goto CONTINUE;
if (SysTimerTable[timerID].countDown > deltaTick)
{
SysTimerTable[timerID].countDown -= deltaTick;
goto CONTINUE;
}
SysTimerDisable(timerID);
if (SysTimerTable[timerID].pCallBack != NULL)
(SysTimerTable[timerID].pCallBack)(timerID);
CONTINUE:
ExitCritical(hwlock);
}
/* 接下来找出最近的一个 active timer */
nextInterruptTick = 0xFFFFFF;
EnterCritical(hwlock);
for (timerID = 0; timerID < MAX_SYSTIMERS; ++timerID)
{
if (SysTimerStatusGet(timerID) == SYSTIMER_STATUS_ACTIVE)
{
if (nextInterruptTick > SysTimerTable[timerID].countDown)
{
nextInterruptTick = (tick_t)(SysTimerTable[timerID].countDown);
}
}
}
ExitCritical(hwlock);
SleepTimeCompSet(nextInterruptTick);
} |