极客工坊

 找回密码
 注册

QQ登录

只需一步,快速开始

查看: 5731|回复: 2

在pcDuino上使用定时器中断

[复制链接]
发表于 2013-12-20 10:47:40 | 显示全部楼层 |阅读模式
首先给大家说一个简单的故事,有二位老师甲和乙,二人分别带一门课程。学校每天晚上都上自习,甲老师每次在上自习的时候都是隔一段时间就在教室里四处走动,看看学生们是否有问题询问,并为其解答。乙老师则不在班里走动,而是在讲台上备课或者批改作业,但是他告诉学生们,有问题就到讲台上去询问。甲老师是主动的方式去为学生解答,乙老师则是采取被动的方式去为学生解答。

我再来解释下这个故事,甲老师在教室走动的过程中,如果没有学生提出问题,他又回到座位去做自己的事情,如果学生有疑问,他就会帮学生解答,解答完后,老师便又会做自己的工作,那么这位有疑问的学生就中断了老师的工作。 乙老师在讲台上工作,过了一会有个学生前来提问,乙老师便会放下手头的工作为那位学生解答,解答完后就会继续自己的工作。甲老师的工作方式称为轮询中断,而乙老师的工作方式则是需要发起中断请求。

一、中断的相关概念

能够发出中断请求信号的来源统称为中断源,一个系统的中断源(打断老师工作的学生即是中断源)可以有很多个,比如说老师工作的时候,有多个同学有问题,那么他们都是中断源,老师处理学生提出的疑问则称为中断服务程序。中断源分为可屏蔽中断源和不可屏蔽的中断源,可屏蔽的中断源,则可选择是否处理该中断。中断源也存在优先级,优先级高的可以打断优先级低的。

例如,老师解答过程中,突然手机铃声响起打断了老师的解答,学校规定老师在课堂上是不许接电话的,老师挂掉电话为学生继续解答,这个中断便被屏蔽掉了。如果这时候在教室门口有另外一位老师有很急的事情找这位正在解答的老师,一般老师便会告诉学生,让他等待一下,处理那位老师的急事后,再回来继续为他解答,那个学生便会等待老师回来继续解答。因为是急事,这个老师产生的中断则不可屏蔽,而且优先级高于学生的优先级(注意:不要认为中断优先级与中断是否可屏蔽有关),而那个等待学生产生的中断便处于等待状态,称为中断挂起。

二、定时器的使用

上面介绍了中断,那么我们开始解答如何使用定时器中断:pcDuino运行的ubuntu为Linux的一个版本,Linux提供一种定时服务的机制,它在某个特定的时间唤醒某个进程,来做一些工作。

定时器中断需要使用到的结构体:

struct itimerval

{

   struct timeval it_interval;   /* next value */

   struct timeval it_value;    /* current value */

}

struct timeval

{

    long tv_sec;                /* seconds */

    long tv_usec;               /* microseconds */

}

it_value: 设置第一次定时器到达并发送中断信号的时间

it_interval: 设置定时器终止后的重设值:若为0则定时器在终止后将失效;若不为0,则定时器终止后,将会以该值进行重新定时。

tv_sec: 设置定时器的时间参数,单位‘s’

tv_usec:设置定时器的时间参数,单位‘us’

定时器设置函数:

int setitimer(int which, const struct itimerval *new_value,struct itimerval *old_value)

变量which的取值如下:

(1)ITIMER_REAL :以系统真实的时间来计算,它送出SIGALRM信号

(2)ITIMER_VIRTUAL:以该进程在用户态下花费的时间来计算,它送出SIGVTALRM    信号

(3)ITIMER_PROF :以该进程在用户态下和内核态下所费的时间来计算,它送出SIGPROF信号

设置中断信号的对应处理函数(所在头文件signal.h):

typedef void (*sighandler_t)(int);

sighandler_t signal(int signum, sighandler_t handler);

signum:设置需要处理的中断信号,定时器来的中断信号有:SIGALRM、SIGVTALRM、SIGPROF

handler:用于设置中断信号的处理函数
#include <core.h>

#include <signal.h>



#define REFRESH_TIME_S  1

#define REFRESH_TIME_US 500000



void time_initialization(long s,long us)

{

        struct itimerval interrupt_time;

        interrupt_time.it_value.tv_sec = s;

        interrupt_time.it_value.tv_usec =us;

        interrupt_time.it_interval.tv_sec = s;

        interrupt_time.it_interval.tv_usec = us;

        setitimer(ITIMER_REAL, &interrupt_time, NULL);

        signal(SIGALRM, timer_handler);

        printf(“set interrupt time: %lds , %ldus\n”, s, us);

}



void timer_handler(int irq)

{

  switch(irq)

  {

    case SIGALRM:

         digitalWrite(13,(digitalRead(13)^0×01));

         break;

   default:

         break;

  }

}



void setup()

{

  pinMode(13,OUTPUT);

  time_initialization(REFRESH_TIME_S,REFRESH_TIME_US);

}



void loop()

{

}
这里虽然是一个简单的闪灯实验,但是是利用定时器中断实现的,我们可以看到void loop()函数是空循环,闪灯的动作是由中断服务程序void timer_handler(int irq)来完成的。

定时器设定的时间通过设置:REFRESH_TIME_S 和 REFRESH_TIME_US ,程序中设置为1.5秒。

下载运行代码:





在D13上接一个LED便可以看到每隔1.5秒闪烁一次:


示例代码
首先给大家说一个简单的故事,有二位老师甲和乙,二人分别带一门课程。学校每天晚上都上自习,甲老师每次在上自习的时候都是隔一段时间就在教室里四处走动,看看学生们是否有问题询问,并为其解答。乙老师则不在班里走动,而是在讲台上备课或者批改作业,但是他告诉学生们,有问题就到讲台上去询问。甲老师是主动的方式去为学生解答,乙老师则是采取被动的方式去为学生解答。

我再来解释下这个故事,甲老师在教室走动的过程中,如果没有学生提出问题,他又回到座位去做自己的事情,如果学生有疑问,他就会帮学生解答,解答完后,老师便又会做自己的工作,那么这位有疑问的学生就中断了老师的工作。 乙老师在讲台上工作,过了一会有个学生前来提问,乙老师便会放下手头的工作为那位学生解答,解答完后就会继续自己的工作。甲老师的工作方式称为轮询中断,而乙老师的工作方式则是需要发起中断请求。

中断相关的概念
定时器的使用

三、示例代码

测试运行能够发出中断请求信号的来源统称为中断源,一个系统的中断源(打断老师工作的学生即是中断源)可以有很多个,比如说老师工作的时候,有多个同学有问题,那么他们都是中断源,老师处理学生提出的疑问则称为中断服务程序。中断源分为可屏蔽中断源和不可屏蔽的中断源,可屏蔽的中断源,则可选择是否处理该中断。中断源也存在优先级,优先级高的可以打断优先级低的。

例如,老师解答过程中,突然手机铃声响起打断了老师的解答,学校规定老师在课堂上是不许接电话的,老师挂掉电话为学生继续解答,这个中断便被屏蔽掉了。如果这时候在教室门口有另外一位老师有很急的事情找这位正在解答的老师,一般老师便会告诉学生,让他等待一下,处理那位老师的急事后,再回来继续为他解答,那个学生便会等待老师回来继续解答。因为是急事,这个老师产生的中断则不可屏蔽,而且优先级高于学生的优先级(注意:不要认为中断优先级与中断是否可屏蔽有关),而那个等待学生产生的中断便处于等待状态,称为中断挂起。
上面介绍了中断,那么我们开始解答如何使用定时器中断:pcDuino运行的ubuntu为Linux的一个版本,Linux提供一种定时服务的机制,它在某个特定的时间唤醒某个进程,来做一些工作。

定时器中断需要使用到的结构体:

struct itimerval

{

   struct timeval it_interval;   /* next value */

   struct timeval it_value;    /* current value */

}

struct timeval

{

    long tv_sec;                /* seconds */

    long tv_usec;               /* microseconds */

}

it_value: 设置第一次定时器到达并发送中断信号的时间

it_interval: 设置定时器终止后的重设值:若为0则定时器在终止后将失效;若不为0,则定时器终止后,将会以该值进行重新定时。

tv_sec: 设置定时器的时间参数,单位‘s’

tv_usec:设置定时器的时间参数,单位‘us’

定时器设置函数:

int setitimer(int which, const struct itimerval *new_value,struct itimerval *old_value)

变量which的取值如下:

(1)ITIMER_REAL :以系统真实的时间来计算,它送出SIGALRM信号

(2)ITIMER_VIRTUAL:以该进程在用户态下花费的时间来计算,它送出SIGVTALRM    信号

(3)ITIMER_PROF :以该进程在用户态下和内核态下所费的时间来计算,它送出SIGPROF信号

设置中断信号的对应处理函数(所在头文件signal.h):

typedef void (*sighandler_t)(int);

sighandler_t signal(int signum, sighandler_t handler);

signum:设置需要处理的中断信号,定时器来的中断信号有:SIGALRM、SIGVTALRM、SIGPROF

handler:用于设置中断信号的处理函数

五、运行代码

这里虽然是一个简单的闪灯实验,但是是利用定时器中断实现的,我们可以看到void loop()函数是空循环,闪灯的动作是由中断服务程序void timer_handler(int irq)来完成的。

定时器设定的时间通过设置:REFRESH_TIME_S 和 REFRESH_TIME_US ,程序中设置为1.5秒。

下载运行代码:
pic1.jpg pic2.jpg
在D13上接一个LED便可以看到每隔1.5秒闪烁一次:
pic4-577x1024.jpg pic3-577x1024.jpg



回复

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

Archiver|联系我们|极客工坊 ( 浙ICP备09023225号 )

GMT+8, 2020-7-16 22:07 , Processed in 0.128810 second(s), 27 queries .

Powered by Discuz! X3.4 Licensed

© 2001-2017 Comsenz Inc.

快速回复 返回顶部 返回列表