(二)非阻塞延时的原理

第一篇中写了一个程序在延时的时候最好把CPU让出, 但是如果只是让出, 什么时候回来不知道, 万一回来的时候还没延时够, 那也不合理. 如下图所示
(二)非阻塞延时的原理_第1张图片
首先程序A yield(), 让出了CPU, 希望等待10ms后再执行下一个步骤, 结果程序B的那一段程序较短, 很快也 yield()回到程序A, 这种情况就没有达到程序A的预期.

那么如何实现非阻塞的延时呢, 既能让出CPU, 还要到时候回来.
我们需要一个定时器, 每一段时间触发一次中断, 中断中对一个计数值自增, 例如每5ms产生一次中断, 计数值tick++, 通过tick的数值, 就可以知道时间过去了多久. 在cortex-M中常常使用systick作为这个定时器.
(二)非阻塞延时的原理_第2张图片

程序A执行完第一段, 需要延时10ms, 让出CPU(此时tick为2), 轮到程序B执行一段程序, B执行完后也让出CPU了, 但此时tick为3, A还没延时够, 又没别的程序执行, 那么CPU就空等, 当tick值增加到4的时候, 说明A肯定延时够了, 再次返回A, 同理B也一样.
这种方式可以实现非阻塞的延时, 但是它的缺点也很明显, 精度不高(图中返回A的时候, 延时其实已经超过10ms了), 跟systick的中断周期有关, 如果需要更高精度, 例如1ms中断一次, 则可减小误差, 但是也会带来更多的中断开销.

###protothread中的定时器

struct timer { 
  int start;          //记录启动时的tick值
  int interval;       //要定时的tick数
};
// 定时器超时判断
static int timer_expired(struct timer *t)
{ 
  // clock_time()会获取当前的tick值, 如果当前值-开始值超过了延时的tick数, 那么就是超时了
  return (int)(clock_time() - t->start) >= (int)t->interval; // 思考:溢出会如何呢?
}

clock_time函数需要返回当前tick值, 那么需要在相应的CPU中启用一个定时器, 并对一个全局的tick变量进行自增操作, 例如

volatile int global_tick;

void systick_handler(void)
{
  global_tick++;
}
int clock_time(void)
{ 
  return (int)global_tick; 
}
void timer_set(struct timer *t, int interval)
{ 
  t->interval = interval;       // 存储需要延时的tick数
  t->start = clock_time();     //获取当前的tick值
}

将timer_set和PT_WAIT_UNTIL配合使用即可完成延时的功能
timer_set将当前的tick值记录起来, PT_WAIT_UNTIL会检测timer_expired是否超时, 超时即可继续执行下面的程序, 这样就可以实现非阻塞延时.

struct timer  input_timer;
PT_THREAD(input_thread(struct pt *pt))
{
  PT_BEGIN(pt);

 
  timer_set(&input_timer, 1000);  // 延时1000个tick
  PT_WAIT_UNTIL(pt, timer_expired(&input_timer));


  timer_set(&input_timer, 100);  // 延时100个tick
  PT_WAIT_UNTIL(pt, timer_expired(&input_timer));
  
  timer_set(&input_timer, 300);
  PT_WAIT_UNTIL(pt, timer_expired(&input_timer));


  timer_set(&input_timer, 2000);
  PT_WAIT_UNTIL(pt, timer_expired(&input_timer));
   
  PT_END(pt);
}

当然这种方式又要定义struct timer input_timer; 还要timer_set还要PT_WAIT_UNTIL什么的一大串, 没有delay_ms那么简洁, 后面再想办法让它优雅起来, 这里只为说明原理.

实例工程代码
https://gitee.com/kalimdorsummer/c_language_program_template.git

你可能感兴趣的:(编程语言)