定时器中断的作用
要回答这个问题,我们首先要搞清楚,这个定时器中断所为何用。
我想不到太多,只能想到两个:
1.作为一个粗糙的时间片机制——它就是说,我们要在定时器中断里,放一些函数(或说任务)让它执行;
2.作为一个异步的定时器。
这里对 异步 做一个最简单的解释。
在程序里,当我们需要延迟时,我们是怎么干的呢?
因为指令的执行需要时间,所以计数(计算执行指令的数目),就可以定时。
最简单的方法当然就是
可是这个方法有N多个理由让你不会大量使用,特别是当延迟时间比较长的时候。
什么叫长(对于一个 1M单周期系统,CPU一个机器周期是1us,那么1ms就是1000个机器周期,这算不算作孽?10ms呢? 100ms呢?简直是罪无可恕。)
所以,我们会采用另一种方法:
在定时器中断里不断累加一个 静态定时器或者全局定时器,然后外部根据这个定时器的数值来判断过了多少时间。
这样做的好处是 定时并不阻塞CPU继续执行其他任务。
---------------------
总结一下,我们可以这样认为,我们要在定时器中断Isr里放的东西无非两种
不断累积(或者递减)的 静态定时器(其实就是变量);
函数;
而这样的 静态定时器,,函数,不仅是在我们的 main函数里有,在uSer里也可能有。
但是前面我们已经严格做了限制:
我们不能让uSer和Apper相互勾搭,狼狈为奸。
所以,我们解决的方案是
通过一个回调函数,让我们在Apper里实现的 定时器初始化,和 TimerIsr可以被uSer调用。
这样,uSer就可以在 Apper还没实现(实际上那个时候,Apper还在娘胎里)的时候,提前调用这个 定时器中断。
------------------------
最后一个问题是
你会质问我,既然你想要uSer可以调用定时器中断,为什么不直接在uSer里实现定时中断机制呢?(就是 定时器初始化 和 编写 定时器Isr函数)
这个更好解释。
因为针对不同的单片机,它们的定时器初始化,所设置的寄存器是不一样的,它们的中断函数格式也是完全不一样的。
而我希望uSer的实现与单片机无关。
所以,我不能在uSer里实现定时器中断机制。
另外就是,即便,我不在乎这点,我在uSer里实现了定时器中断机制。
那么,我的TimerIsr就被藏在uSer里。
我又能怎样让外部的Apper来使用它呢?
放入Apper自己的 函数 和 静态定时器?
在此前不久,对此我也可以实现,我使用的是一种限制同名函数的方式。
以下举个简单例子
- /*
- 例如
- uSer里 实现的 void TimerIsr(void);
- */
- void TimerIsr_4_Apper(void);
- void TimerIsr(void)
- {
- // uSer 里使用的;
- TimerIsr_4_Apper();
- }
- /////==============================
- /*
- 在Apper里,现在我要把函数或者静态计时器植入 TimerIsr,我只需把它们写在TimerIsr_4_Apper()的函数体里就可以了
- */
- void TimerIsr_4_Apper(void)
- {
- // 你可以为所欲为......
- }
上面这个方案也可以实现。
唯一的限制只是名字定死了,当然,这算不得什么很要命的事情。
但是,名字是无所谓。
但是如果我的函数声明不一样呢?我是说带形参?带返回值?
当然,你仍然可以认为无所谓,因为我把它全部包含在 TimerIsr_4_Apper()这个函数里就可以了。
就像结构体封装各类散乱的不一致的数据类型一样。
我一点不关心内部的实现方式。
但相比这种带有限制(就我们现在就已经知道了两个,并且有一个还是实质性的功能性限制)的方案。
使用 回调函数 的方式,你几乎不受任何限制。
你会选择哪一种呢?