嵌入式中的时间和定时

开发软件经常会用到时间,不同的场合用到的时间也不尽相同,有时候我们需要的是年月日时分秒这样很容易理解的格式,也有时候我们只是想知道系统开机了之后运行了多久,还有的时候我们不需要知道具体时间,只是想像设定一个闹钟一样,时间到了叫我干活就行。

在操作系统的内核里也一样,没了时间做基础,什么时间片、周期调度、延迟处理都没办法实现,这些关于时间的服务(也可以叫功能),总结下来是下面这两类:

  • 获取时间

  • 定时服务

那这两个功能是怎么实现的呢?世上没有免费的午餐,想用到什么功能,就得有相应的软硬件来支持,我们先来看看要想获取时间和定时在硬件上都需要什么,下面是一个硬件框图,基本在单片机或者嵌入式linux都适用。

这些框框都用来干嘛呢?RTC(Real Time Clock)就是实时时钟,主要用来提供时间基准,有独立的芯片也有些MCU是内置的,一般会有单独的电池供电,就像电脑主板上一样,即使关了机RTC的时间也是在继续走的。RTC提供的时间通常是UTC时间,年月日时分秒,很容易阅读,缺点是精度不高,如果想做到毫秒级别的延迟或者定时RTC就不合适了,更常见的用法是设备上电读取RTC获得初始时间,之后通过ms级的周期中断来计算当前的时间,这样可以获得比秒更高的时间精度,也就能提供系统时间了,如果只是想知道开机运行了多久,使用周期中断计数就可以获得。

那问题来了,谁来提供周期中断呢?大家可能也猜到了,旁边的定时器就是干的这件事情,关于定时器有几个很基本的概念,也很好理解

  • 定时精度,或者叫分辨率,是能够定时的最小单位,通常是系统时钟经过分频的一个值,这里提到的的系统时钟是晶振的脉冲倍频又分频的一个参考时钟,不是软件概念

  • 计数器,counter,开始定时之后conter就不断的加一,假如分辨率是1ms,counter值就代表时间过去了多少ms

  • 比较值,counter值会不断和这个值比较,当两个值相等时就产生中断

  • 模式,如果计数值和比较值相等的时候定时器停止,并且计数值和比较值复位,就叫oneshot,只干一次,下次想定时要再设置一次;如果计数值和比较值相等的时候定时器不停止,比较值重新装载,计数值清零,定时器间隔相同的周期会再次发生中断,除非我们主动停掉,就叫period模式。

这下我们知道,使用oneshot的模式可以设定定时器产生中断的时间,也就实现了定时功能。

有了RTC和定时器这两种硬件做基础,在软件上实现时间的获取和定时功能也就不难了,那我们在日常编程的时候提到的定时器、高精度定时器是这个概念吗?

在裸机(前后台)系统里,我们可以直接操作硬件获取时间和定时,只要资源足够,RTC和定时器只给某个功能用也没啥问题,实际上有不少产品就是这么开发出来的。简单系统这么干可以,但当软件功能复杂,定时器资源不那么充分的时候,就要考虑如何利用好既有的硬件了,如果再考虑到软件的可移植性,功能代码和具体硬件绑定就不是很好的选择。

我们可以选择自己做一层薄薄的封装,也可以选择让操作系统为我们提供时间和定时服务,这时应用编程使用到的时间和定时虽然硬件上还是RTC和定时器作为基础,但已经是系统封装之后提供的服务,具体硬件信息被屏蔽掉,实际上这个时候我们也不太关心硬件上具体是用的哪个定时器了。下面是一个Linux(X86)的例子可以很好的说明这一点。

Linux把获取时间的设备封装成clocksource,因此clocksource主要提供的接口就是read(),用来获取当前时间,而clock-event device就是用来提供定时功能的设备,包含了PERIODIC和ONESHOT等多种模式,主要提供的接口是set_next_event,用来设置下一次定时中断事件什么事件产生。

以这两种设备为基础,Linux内核里提供了最基本的jiffies(每个tick中断加1)和xtime(从RTC获得初值),还提供了timer和hrtimer两种定时器,又通过系统调用提供到用户态去使用,不过基本上我们不需要直接去进行系统调用,C库帮我们做了这件事情。

在实际嵌入式开发中,前后台大循环、RTOS、Linux,都是可能的方案,不管是选哪种方案,实现或者利用好获取时间和定时这两个功能都会让开发起来更容易。

已标记关键词 清除标记
©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页