目录
1.2.4、rt_tick_from_millisecond()函数
2.2.3、rt_timer_list_next_timeout()函数
2.2.4、rt_timer_count_height()函数
2.2.13、rt_soft_timer_check()函数
2.2.14、rt_thread_timer_entry()函数
2.2.15、rt_system_timer_init()函数
2.2.16、rt_system_timer_thread_init()函数
1、时钟节拍
任何操作系统都需要提供一个时钟节拍,以供系统处理所有和时间有关的事件,如线程的延时、线程的时间片轮转调度以及定时器超时等。时钟节拍是特定的周期性中断,这个中断可以看做是系统心跳,中断之间的时间间隔取决于不同的应用,一般是 1ms–100ms,时钟节拍率越快,系统的额外开销就越大,从系统启动开始计数的时钟节拍数称为系统时间。
RT-Thread 中, 时 钟 节 拍 的 长 度 可 以 根 据 RT_TICK_PER_SECOND 的 定 义 来 调 整, 等 于 1/RT_TICK_PER_SECOND 秒。
1.1、时钟节拍的实现方式
时钟节拍由配置为中断触发模式的硬件定时器产生,当中断到来时,将调用一次rt_tick_increase(),通知操作系统已经过去一个系统时钟;
1.2、函数
1.2.1、rt_tick_increase()函数
此函数将通知内核经过了一个tick,该函数通常由时钟ISR调用。
1)递增tick
2)当前线程remaining_tick减1,当减为0时让出CPU控制权并进行调度
3)检查硬件定时器是否超时
void rt_tick_increase(void)
{
struct rt_thread *thread;
++ rt_tick; //rt_tick加1
thread = rt_thread_self(); //获取当前线程
/* 检 查 时 间 片 */
-- thread->remaining_tick; //线程remaining_tick减1
if (thread->remaining_tick == 0) //线程remaining_tick为0
{
thread->remaining_tick = thread->init_tick; //设置线程的remaining_tick为init_tick
rt_thread_yield(); //让出控制权,重新进行一次调度
}
rt_timer_check(); //检查硬件定时器
}
1.2.2、rt_tick_get()函数
此函数将返回当前的tick。
rt_tick_t rt_tick_get(void)
{
return rt_tick; //返回rt_tick
}
1.2.3、rt_tick_set()函数
此函数将设置当前的tick。
void rt_tick_set(rt_tick_t tick)
{
rt_base_t level;
level = rt_hw_interrupt_disable(); //关中断
rt_tick = tick; //设置tick
rt_hw_interrupt_enable(level); //开中断
}
1.2.4、rt_tick_from_millisecond()函数
此函数用于将ms转换为节拍数。
舍入方式为向上舍入。以值666为例:
RT_TICK_PER_SECOND | 传入时间ms | 传出tick值 |
1000 | 666 | 666 |
100 | 666 | 67 |
10 | 666 | 7 |
2、定时器
RT-thread有2种定时器:软件定时器和硬件定时器。
1) 硬件定时器是芯片本身提供的定时功能(在系统中断中检查定时器是否超时)。
2) 软件定时器是由操作系统提供的一类系统接口,它构建在硬件定时器基础之上,使系统能够提供不受数目限制的定时器服务(开一个软件定时器线程,在线程中检查定时器是否超时)。
2.1、工作流程
2.1.1、硬件定时器工作流程
注:不同硬件定时器中断实现都不同。
2.1.2、软件定时器工作流程
2.2、函数
2.2.1、_rt_timer_init()函数
此函数初始化定时器。
static void _rt_timer_init(rt_timer_t timer,
void (*timeout)(void *parameter),
void *parameter,
rt_tick_t time,
rt_uint8_t flag)
{
int i;
timer->parent.flag = flag; //设置标志
timer->parent.flag &= ~RT_TIMER_FLAG_ACTIVATED; //取消定时器RT_TIMER_FLAG_ACTIVATED标志
timer->timeout_func = timeout; //设置超时回调函数
timer->parameter = parameter; //设置超时回调函数参数
timer->timeout_tick = 0; //设置定时器timeout_tick为0
timer->init_tick = time; //设置定时器init_tick为time
/* 初始化定时器链表数组 */
for (i = 0; i < RT_TIMER_SKIP_LIST_LEVEL; i++)
{
rt_list_init(&(timer->row[i]));
}
}
2.2.2、_rt_timer_remove()函数
此函数用于移除定时器链表。
rt_inline void _rt_timer_remove(rt_timer_t timer)
{
int i;
/* 移除定时器链表 */
for (i = 0; i < RT_TIMER_SKIP_LIST_LEVEL; i++)
{
rt_list_remove(&timer->row[i]);
}
}
2.2.3、rt_timer_list_next_timeout()函数
此函数获取定时器链表中下一个超时时间。
static rt_tick_t rt_timer_list_next_timeout(rt_list_t timer_list[])
{
struct rt_timer *timer;
if (rt_list_isempty(&timer_list[RT_TIMER_SKIP_LIST_LEVEL - 1]))
return RT_TICK_MAX;
timer = rt_list_entry(timer_list[RT_TIMER_SKIP_LIST_LEVEL - 1].next,
struct rt_timer, row[RT_TIMER_SKIP_LIST_LEVEL - 1]);
return timer->timeout_tick;
}
2.2.4、rt_timer_count_height()函数
计算定时器跳表当前高度。
static int rt_timer_count_height(struct rt_timer *timer)
{
int i, cnt = 0;
for (i = 0; i < RT_TIMER_SKIP_LIST_LEVEL; i++)
{
if (!rt_list_isempty(&timer->row[i]))
cnt++;
}
return cnt;
}
2.2.5、rt_timer_dump()函数
打印定时器链表中各个定时器节点跳表的当前高度。
void rt_timer_dump(rt_list_t timer_heads[])
{
rt_list_t *list;
for (list = timer_heads[RT_TIMER_SKIP_LIST_LEVEL - 1].next;
list != &timer_heads[RT_TIMER_SKIP_LIST_LEVEL - 1];
list = list->next)
{
struct rt_timer *timer = rt_list_entry(list,
struct rt_timer,
row[RT_TIMER_SKIP_LIST_LEVEL - 1]);
rt_kprintf("%d", rt_timer_count_height(timer));
}
rt_kprintf("\n");
}
2.2.6、rt_timer_init()函数
此函数用于静态定时器初始化。
1)初始化定时器对象
2)初始化定时器
void rt_timer_init(rt_timer_t timer,
const char *name,
void (*timeout)(void *parameter),
void *parameter,
rt_tick_t time,
rt_uint8_t flag)
{
RT_ASSERT(timer != RT_NULL); //断言timer != RT_NULL
rt_object_init((rt_object_t)timer, RT_Object_Class_Timer, name); //定时器对象初始化
_rt_timer_init(timer, timeout, parameter, time, flag); //定时器初始化
}
2.2.7、rt_timer_create()函数
此函数用于创建动态定时器,并初始化。
1)分配定时器对象,并初始化定时器对象
2)初始化定时器
rt_timer_t rt_timer_create(const char *name,
void (*timeout)(void *parameter),
void *parameter,
rt_tick_t time,
rt_uint8_t flag)
{
struct rt_timer *timer;
timer = (struct rt_timer *)rt_object_allocate(RT_Object_Class_Timer, name); //分配定时器内存
if (timer == RT_NULL) //分配失败
{
return RT_NULL; //返回RT_NULL
}
_rt_timer_init(timer, timeout, parameter, time, flag); //定时器初始化
return timer; //返回定时器
}
2.2.7、rt_timer_detach()函数
此函数用于从脱离静态定时器。
1)从定时器链表中移除定时器
2)从定时器对象链表中移除定时器对象
rt_err_t rt_timer_detach(rt_timer_t timer)
{
register rt_base_t level;
/* 参数检查 */
RT_ASSERT(timer != RT_NULL); //断言timer != RT_NULL
RT_ASSERT(rt_object_get_type(&timer->parent) == RT_Object_Class_Timer); //断言对象时定时器
RT_ASSERT(rt_object_is_systemobject(&timer->parent)); //断言对象时静态的
level = rt_hw_interrupt_disable(); //关中断
_rt_timer_remove(timer); //从链表中移除定时器
timer->parent.flag &= ~RT_TIMER_FLAG_ACTIVATED; //关定时器
rt_hw_interrupt_enable(level); //开中断
rt_object_detach((rt_object_t)timer); //定时器对象脱离
return RT_EOK; //返回RT_EOK
}
2.2.8、rt_timer_delete()函数
此函数用于从删除动态定时器。
1)从定时器链表中移除定时器
2)从定时器对象链表中移除定时器对象,并释放定时器对象
rt_err_t rt_timer_delete(rt_timer_t timer)
{
register rt_base_t level;
/* 参数检查 */
RT_ASSERT(timer != RT_NULL); //断言timer != RT_NULL
RT_ASSERT(rt_object_get_type(&timer->parent) == RT_Object_Class_Timer); //断言对象时定时器
RT_ASSERT(rt_object_is_systemobject(&timer->parent) == RT_FALSE); //断言对象不是静态的
level = rt_hw_interrupt_disable(); //关中断
_rt_timer_remove(timer); //从链表中移除定时器
timer->parent.flag &= ~RT_TIMER_FLAG_ACTIVATED; //关定时器
rt_hw_interrupt_enable(level); //开中断
rt_object_delete((rt_object_t)timer); //定时器对象删除
return RT_EOK; //返回RT_EOK
}
2.2.9、rt_timer_start()函数
此函数用于启动定时器。
1)从定时器链表移除定时器
2)设置定时器对象的状态为未激活
3)调用回调钩子函数
4)设置超时时间(当前时间+时间片)
5)在定时器链表合适位置插入
6)设置定时器对象的状态为激活
7)如果使用软件定时器,且当前定时器线程不是就绪态,恢复定时器线程,并进行一次调度
rt_err_t rt_timer_start(rt_timer_t timer)
{
unsigned int row_lvl;
rt_list_t *timer_list;
register rt_base_t level;
rt_list_t *row_head[RT_TIMER_SKIP_LIST_LEVEL];
unsigned int tst_nr;
static unsigned int random_nr;
/* 参数检查 */
RT_ASSERT(timer != RT_NULL); //断言timer != RT_NULL
RT_ASSERT(rt_object_get_type(&timer->parent) == RT_Object_Class_Timer); //断言对象是定时器
level = rt_hw_interrupt_disable(); //关中断
/* remove timer from list */
_rt_timer_remove(timer); //从链表中移除定时器
timer->parent.flag &= ~RT_TIMER_FLAG_ACTIVATED; //取消定时器
rt_hw_interrupt_enable(level); //开中断
RT_OBJECT_HOOK_CALL(rt_object_take_hook, (&(timer->parent))); //回调函数
RT_ASSERT(timer->init_tick < RT_TICK_MAX / 2); //断言timer->init_tick < RT_TICK_MAX / 2
timer->timeout_tick = rt_tick_get() + timer->init_tick; //设置超时时间为rt_tick_get() + timer->init_tick
level = rt_hw_interrupt_disable(); //关中断
#ifdef RT_USING_TIMER_SOFT
if (timer->parent.flag & RT_TIMER_FLAG_SOFT_TIMER) //使用软件定时器
{
timer_list = rt_soft_timer_list; //设置timer_list为rt_soft_timer_list
}
else //使用硬件定时器
#endif
{
timer_list = rt_timer_list; //设置timer_list为rt_timer_list
}
/* 如果使用跳表,设置跳表链表 */
row_head[0] = &timer_list[0];
for (row_lvl = 0; row_lvl < RT_TIMER_SKIP_LIST_LEVEL; row_lvl++)
{
for (; row_head[row_lvl] != timer_list[row_lvl].prev;
row_head[row_lvl] = row_head[row_lvl]->next)
{
struct rt_timer *t;
rt_list_t *p = row_head[row_lvl]->next;
t = rt_list_entry(p, struct rt_timer, row[row_lvl]);
if ((t->timeout_tick - timer->timeout_tick) == 0)
{
continue;
}
else if ((t->timeout_tick - timer->timeout_tick) < RT_TICK_MAX / 2)
{
break;
}
}
if (row_lvl != RT_TIMER_SKIP_LIST_LEVEL - 1)
row_head[row_lvl + 1] = row_head[row_lvl] + 1;
}
random_nr++;
tst_nr = random_nr;
/* 找到合适的节点插入 */
rt_list_insert_after(row_head[RT_TIMER_SKIP_LIST_LEVEL - 1],
&(timer->row[RT_TIMER_SKIP_LIST_LEVEL - 1]));
for (row_lvl = 2; row_lvl <= RT_TIMER_SKIP_LIST_LEVEL; row_lvl++)
{
if (!(tst_nr & RT_TIMER_SKIP_LIST_MASK))
rt_list_insert_after(row_head[RT_TIMER_SKIP_LIST_LEVEL - row_lvl],
&(timer->row[RT_TIMER_SKIP_LIST_LEVEL - row_lvl]));
else
break;
/* 调表偏移量*/
tst_nr >>= (RT_TIMER_SKIP_LIST_MASK + 1) >> 1;
}
timer->parent.flag |= RT_TIMER_FLAG_ACTIVATED; //激活定时器
/* 开中断 */
rt_hw_interrupt_enable(level);
#ifdef RT_USING_TIMER_SOFT
if (timer->parent.flag & RT_TIMER_FLAG_SOFT_TIMER)
{
/* 检查定时器线程是否就绪 */
if ((timer_thread.stat & RT_THREAD_STAT_MASK) != RT_THREAD_READY)
{
rt_thread_resume(&timer_thread); //唤醒线程
rt_schedule(); //调度
}
}
#endif
return RT_EOK; //返回RT_EOK
}
2.2.10、rt_timer_stop()函数
此函数用于停止定时器。
1)调用钩子回调函数
2)从定时链表移除定时器
3)设置定时器对象的状态为未激活
rt_err_t rt_timer_stop(rt_timer_t timer)
{
register rt_base_t level;
/* 参数检查 */
RT_ASSERT(timer != RT_NULL); //断言timer != RT_NULL
RT_ASSERT(rt_object_get_type(&timer->parent) == RT_Object_Class_Timer); //断言对象是定时器
if (!(timer->parent.flag & RT_TIMER_FLAG_ACTIVATED)) //定时器是未激活状态
return -RT_ERROR; //返回-RT_ERROR
RT_OBJECT_HOOK_CALL(rt_object_put_hook, (&(timer->parent))); //调用回调
level = rt_hw_interrupt_disable(); //关中断
_rt_timer_remove(timer); //从链表中删除定时器
timer->parent.flag &= ~RT_TIMER_FLAG_ACTIVATED; //改变状态
rt_hw_interrupt_enable(level); //开中断
timer->parent.flag &= ~RT_TIMER_FLAG_ACTIVATED; //取消RT_TIMER_FLAG_ACTIVATED标志
return RT_EOK; //返回RT_EOK
}
2.2.11、rt_timer_control()函数
此函数将获取或设置定时器的一些选项。
RT_TIMER_CTRL_GET_TIME | 获取定时器时间片 |
RT_TIMER_CTRL_SET_TIME | 设置定时器时间片 |
RT_TIMER_CTRL_SET_ONESHOT | 设置定时器为单次运行 |
RT_TIMER_CTRL_SET_PERIODIC | 设置定时器为周期运行 |
RT_TIMER_CTRL_GET_STATE | 获取定时器状态 |
rt_err_t rt_timer_control(rt_timer_t timer, int cmd, void *arg)
{
/* 参数检查 */
RT_ASSERT(timer != RT_NULL); //断言timer != RT_NULL
RT_ASSERT(rt_object_get_type(&timer->parent) == RT_Object_Class_Timer); //断言对象是定时器
switch (cmd)
{
case RT_TIMER_CTRL_GET_TIME:
*(rt_tick_t *)arg = timer->init_tick; //获取定时器init_tick为arg
break;
case RT_TIMER_CTRL_SET_TIME:
timer->init_tick = *(rt_tick_t *)arg; //设置定时器init_tick为arg
break;
case RT_TIMER_CTRL_SET_ONESHOT:
timer->parent.flag &= ~RT_TIMER_FLAG_PERIODIC; //取消RT_TIMER_FLAG_PERIODIC标志
break;
case RT_TIMER_CTRL_SET_PERIODIC:
timer->parent.flag |= RT_TIMER_FLAG_PERIODIC; //设置RT_TIMER_FLAG_PERIODIC标志
break;
case RT_TIMER_CTRL_GET_STATE:
if(timer->parent.flag & RT_TIMER_FLAG_ACTIVATED)
{
/* 定时器正在运行 */
*(rt_tick_t *)arg = RT_TIMER_FLAG_ACTIVATED;
}
else
{
/* 定时器停止 */
*(rt_tick_t *)arg = RT_TIMER_FLAG_DEACTIVATED;
}
break;
}
return RT_EOK; //返回RT_EOK
}
2.2.12、rt_timer_check()函数
此函数将检查定时器列表,如果发生超时事件,将调用相应的超时函数。
1)遍历定时器
2)从定时器链表移除定时器
3)调用定时器超时处理函数
4)调用钩子回调函数
5)如果是单次定时器,则暂停定时器;如果是周期定时器则再次启动定时器
void rt_timer_check(void)
{
struct rt_timer *t;
rt_tick_t current_tick;
register rt_base_t level;
RT_DEBUG_LOG(RT_DEBUG_TIMER, ("timer check enter\n")); //打印信息
current_tick = rt_tick_get(); //获取时间
level = rt_hw_interrupt_disable(); //关中断
while (!rt_list_isempty(&rt_timer_list[RT_TIMER_SKIP_LIST_LEVEL - 1]))
{
t = rt_list_entry(rt_timer_list[RT_TIMER_SKIP_LIST_LEVEL - 1].next,
struct rt_timer, row[RT_TIMER_SKIP_LIST_LEVEL - 1]); //获取定时器
if ((current_tick - t->timeout_tick) < RT_TICK_MAX / 2) //到了定时时间
{
RT_OBJECT_HOOK_CALL(rt_timer_enter_hook, (t)); //调用回调
_rt_timer_remove(t); //从链表中移除定时器
t->timeout_func(t->parameter); //调用超时回调函数
current_tick = rt_tick_get(); //获取时间
RT_OBJECT_HOOK_CALL(rt_timer_exit_hook, (t)); //调用回调
RT_DEBUG_LOG(RT_DEBUG_TIMER, ("current tick: %d\n", current_tick)); //打印信息
if ((t->parent.flag & RT_TIMER_FLAG_PERIODIC) &&
(t->parent.flag & RT_TIMER_FLAG_ACTIVATED))
{
t->parent.flag &= ~RT_TIMER_FLAG_ACTIVATED; //取消RT_TIMER_FLAG_ACTIVATED标志
rt_timer_start(t); //启动定时器
}
else
{
t->parent.flag &= ~RT_TIMER_FLAG_ACTIVATED; //取消RT_TIMER_FLAG_ACTIVATED标志
}
}
else
break;
}
rt_hw_interrupt_enable(level); //开中断
RT_DEBUG_LOG(RT_DEBUG_TIMER, ("timer check leave\n")); //打印信息
}
2.2.13、rt_soft_timer_check()函数
此函数进行软件定时器检查。
1)遍历软件定时器
2)调用钩子回调函数
3)从定时器链表移除定时器
4)调用定时器超时函数
5)如果是单次定时器,则暂停定时器;如果是周期定时器则再次启动定时器
void rt_soft_timer_check(void)
{
rt_tick_t current_tick;
rt_list_t *n;
struct rt_timer *t;
RT_DEBUG_LOG(RT_DEBUG_TIMER, ("software timer check enter\n")); //打印信息
current_tick = rt_tick_get(); //获取时间
rt_enter_critical(); //进入临界区
for (n = rt_soft_timer_list[RT_TIMER_SKIP_LIST_LEVEL - 1].next;
n != &(rt_soft_timer_list[RT_TIMER_SKIP_LIST_LEVEL - 1]);)
{
t = rt_list_entry(n, struct rt_timer, row[RT_TIMER_SKIP_LIST_LEVEL - 1]); //获取定时器
if ((current_tick - t->timeout_tick) < RT_TICK_MAX / 2) //定时时间到了
{
RT_OBJECT_HOOK_CALL(rt_timer_enter_hook, (t)); //调用回调
n = n->next;
_rt_timer_remove(t); //从链表中移除定时器
rt_exit_critical(); //退出临界区
t->timeout_func(t->parameter); //调用超时回调函数
current_tick = rt_tick_get(); //获取时间
RT_OBJECT_HOOK_CALL(rt_timer_exit_hook, (t)); //调用回调
RT_DEBUG_LOG(RT_DEBUG_TIMER, ("current tick: %d\n", current_tick)); //打印信息
rt_enter_critical(); //进入临界区
if ((t->parent.flag & RT_TIMER_FLAG_PERIODIC) &&
(t->parent.flag & RT_TIMER_FLAG_ACTIVATED)) //周期定时
{
/* start it */
t->parent.flag &= ~RT_TIMER_FLAG_ACTIVATED;//取消RT_TIMER_FLAG_ACTIVATED标志
rt_timer_start(t); //启动定时器
}
else //单次定时
{
t->parent.flag &= ~RT_TIMER_FLAG_ACTIVATED; //取消RT_TIMER_FLAG_ACTIVATED标志
}
}
else break;
}
rt_exit_critical(); //退出临界区
RT_DEBUG_LOG(RT_DEBUG_TIMER, ("software timer check leave\n")); //打印信息
}
2.2.14、rt_thread_timer_entry()函数
此函数为软件定时器线程入口函数。
1)获取下一超时时间
2)如果软件定时器不存在,挂起线程,并进行调度
3)如果软件定时器存在,等待到达超时时间点
4)调用rt_soft_timer_check()函数进行软件定时器检查
static void rt_thread_timer_entry(void *parameter)
{
rt_tick_t next_timeout;
while (1)
{
next_timeout = rt_timer_list_next_timeout(rt_soft_timer_list); //获取下一个超时时间
if (next_timeout == RT_TICK_MAX) //不存在软件定时器
{
rt_thread_suspend(rt_thread_self()); //挂起本线程
rt_schedule(); //调度
}
else
{
rt_tick_t current_tick;
current_tick = rt_tick_get(); //获取时间
if ((next_timeout - current_tick) < RT_TICK_MAX / 2) //超时时间到了
{
next_timeout = next_timeout - current_tick; //获取还剩多久时间才到达超时时间
rt_thread_delay(next_timeout); //挂起next_timeout时间
}
}
rt_soft_timer_check(); //检查软件定时器
}
}
2.2.15、rt_system_timer_init()函数
此函数将初始化系统硬件定时器。
void rt_system_timer_init(void)
{
int i;
/* 初始化rt_timer_list链表数组 */
for (i = 0; i < sizeof(rt_timer_list) / sizeof(rt_timer_list[0]); i++)
{
rt_list_init(rt_timer_list + i); //链表初始化
}
}
2.2.16、rt_system_timer_thread_init()函数
此函数将初始化系统软件定时器线程。
1)初始化软件定时器链表数组
2)软件定时器线程初始化
3)启动软件定时器线程
void rt_system_timer_thread_init(void)
{
#ifdef RT_USING_TIMER_SOFT
int i;
/* 初始化rt_soft_timer_list链表数组 */
for (i = 0;
i < sizeof(rt_soft_timer_list) / sizeof(rt_soft_timer_list[0]);
i++)
{
rt_list_init(rt_soft_timer_list + i); //链表初始化
}
/* 软件定时器线程初始化 */
rt_thread_init(&timer_thread,
"timer",
rt_thread_timer_entry,
RT_NULL,
&timer_thread_stack[0],
sizeof(timer_thread_stack),
RT_TIMER_THREAD_PRIO,
10);
rt_thread_startup(&timer_thread); //启动线程
#endif
}
3、高精度延时
RT-Thread 定时器的最小精度是由系统时钟节拍所决定的(1 OS Tick = 1/RT_TICK_PER_SECOND 秒,RT_TICK_PER_SECOND 值在 rtconfig.h 文件中定义),定时器设定的时间必须是 OS Tick 的整数倍。当需要实现更短时间长度的系统定时时,例如 OS Tick 是 10ms,而程序需要实现 1ms 的定时或延时,这种时候操作系统定时器将不能够满足要求,只能通过读取系统某个硬件定时器的计数器或直接使用硬件定时器的方式。
3.1、高精度延时示例
Cortex-M3 上的基于 SysTick 的精确延时(需要系统在使能 SysTick 后使用)。
void rt_hw_us_delay(rt_uint32_t us)
{
rt_uint32_t ticks;
rt_uint32_t told, tnow, tcnt = 0;
rt_uint32_t reload = SysTick->LOAD;
/* 获得延时经过的 tick 数 */
ticks = us * reload / (1000000 / RT_TICK_PER_SECOND);
/* 获得当前时间 */
told = SysTick->VAL;
while (1)
{
/* 循环获得当前时间,直到达到指定的时间后退出循环 */
tnow = SysTick->VAL;
if (tnow != told)
{
if (tnow < told)
{
tcnt += told - tnow;
}
else
{
tcnt += reload - tnow + told;
}
told = tnow;
if (tcnt >= ticks)
{
break;
}
}
}
}
注:此接口应该根据具体的芯片特性实现,以上代码仅供参考!