精华内容
下载资源
问答
  • 定时器中断标志位理解

    千次阅读 2020-03-20 21:55:19
    1、定时器中断标志位程序 ITStatus TIM_GetITStatus(TIM_TypeDef* TIMx, uint16_t TIM_IT) { ITStatus bitstatus = RESET; uint16_t itstatus = 0x0, itenable = 0x0; /* Check the parameters */ assert_param(IS_...

    1、定时器中断标志位程序

    ITStatus TIM_GetITStatus(TIM_TypeDef* TIMx, uint16_t TIM_IT)
    {
    ITStatus bitstatus = RESET;
    uint16_t itstatus = 0x0, itenable = 0x0;
    /* Check the parameters */
    assert_param(IS_TIM_ALL_PERIPH(TIMx));
    assert_param(IS_TIM_GET_IT(TIM_IT));

    itstatus = TIMx->SR & TIM_IT;

    itenable = TIMx->DIER & TIM_IT;
    if ((itstatus != (uint16_t)RESET) && (itenable != (uint16_t)RESET))
    {
    bitstatus = SET;
    }
    else
    {
    bitstatus = RESET;
    }
    return bitstatus;
    }
    该程序主要设置DMA/中断使能寄存器(TIMx_DIER)、状态寄存器(TIMx_SR)两个寄存器,第一个入口参数为结构体指针定时器几TIM1\TIM2…,第二个入口参数为需要开启的中断类型TIM_IT_Update、TIM_IT_CC1、TIM_IT_CC2、TIM_IT_CC3、TIM_IT_CC4、TIM_IT_Trigger、TIM_IT_Break。

    2、以定时器2的更新中断为例。

    TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE);允许开启TIM_2的更新中断
    (TIMx_DIER)的第0位: UIE:允许更新中断 (Update interrupt enable)
    0:禁止更新中断;
    1:允许更新中断。

    3、中断事件(即中断发生的条件)

    1、定时器溢出:TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure); //根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位
    2、TIM_Cmd(TIM2,ENABLE ); //使能定时器2

    4、定时器中断标志位

    1、当定时器设置值arr溢出:TIM_TimeBaseStructure.TIM_Period = arr; 计数器自动重装值
    2、 UIF: 更新中断标记 (Update interrupt flag)
    当产生更新事件时该位由硬件置’1’。它由软件清’0’。
    0:无更新事件产生;
    1:更新中断等待响应。当寄存器被更新时该位由硬件置’1’:
    − 若TIMx_CR1寄存器的UDIS=0、 URS=0,当TIMx_EGR寄存器的UG=1时产生更新事件
    (软件对计数器CNT重新初始化);
    − 若TIMx_CR1寄存器的UDIS=0、 URS=0,当计数器CNT被触发事件重初始化时产生更新
    事件。 (参考同步控制寄存器的说明)
    3、 当上述条件满足时:TIMx_SR的最低位 :UIF由硬件置1,程序(itstatus != (uint16_t)RESET) && (itenable != (uint16_t)RESET)为真,此时bitstatus = SET;为1函数返回为1.

    5、清零中断标志位

    1、TIM_ClearITPendingBit(TIM2, TIM_IT_Update); //清除中断标志位
    目的: 软件清零中断标志位为下次中断做准备或为其他类型中断做准备。
    注意: 有的是自动清除,有的必须手动清除。比如串口,接收到数据,你读取数据硬件就自动清除掉了中断标志,你就可以不清除而只是读,但是有的定时器中断就得自己软件清除,要不执行完终端服务后,cpu检测到中断标志,又会马上进中断,这样就会跟你的设计相悖。所以为了统一还有就是确保清除标志,最好所有的中断都手动清除标志。

    展开全文
  • 通用定时器中断标志位需要软件清除

    通用定时器中断标志位需要软件清除

    展开全文
  • 定时器中断

    2019-11-07 16:15:19
    文章目录定时器中断时钟定时器POSIX定时器定时器操作timer_create()(创建定时器)timer_settime()(初始化定时器)timer_gettime()(获得一个活动定时器的剩余时间)timer_getoverrun()(取得一个定时器的超限运行次数)...

    定时器中断

    设置时钟定时中断,首先设置时间定时器,定时器到期,产生信号,触发中断,执行中断处理函数。整体流程如下:


    1.设置好sigevt信号事件相关(如何处理该信号,信号做标记,…)

    2.timer_creat() 创建定时器

    3.timer_settime() 设置定时器相关信息


    4.信号捕捉函数,捕捉到信号后,进行中断处理函数执行或其他


    时钟定时器

    POSIX定时器

    POSIX 1003.16标准为用户态程序引入了一种新型软定时器,尤其是针对各线程和实时应用程序。这些定时器常被称作POSIX定时器。

    要执行每个POSIX定时器必须向用户态程序提供些POSIX时钟,也就是说,虚拟时间源预定义了分辨度和属性。只要应用程序想使用POSIX定时器,它就创建一个新的定时器资源并指定一个现存的POSIX时钟来作为定时基准。表6-3列出了允许用户来处理POSIX时钟和定时器的一些系统调用。

    表6-3:与POSIX定时器和时钟相关的系统调用系统调用

    系统调用说明
    clock_gettime()获得一个POSIX时钟的当前值
    clock_settime()设置一个POSIX时钟的当前值
    clock_getres()获得一个POSIX时钟的分辨率
    timer_creat()在指定POSIX时钟基础上创建一个新的POSIX时钟的定时器
    timer_gettime()获得一个POSIX定时器的当前值和增量
    timer_settime()设置一个POSIX定时器的当前值和增量
    timer_getoverrun()获得到期POSIX定时器的当前值和增量
    timer_delete()销毁一个POSIX定时器
    clock_nanosleep()使进程进入睡眠状态并使用一个POSIX时钟作为事件源

    Linux 2.6内核提供两种类型的POSIX时钟:

    • CLOCK FBALTIME
      该虚拟时钟表示系统的实时时钟-本质上是xtime变量的值.clock_getres()系统调用返回的分辨率为999848ns,对应1s内更新xtitme大约1000次。
    • CLOCK JMONCTONIC
      该虚拟时钟表示由于与外部时间源的同步,每次回到初值的系统实时时钟,实际上,该虚拟时钟由xtime和wall_to_monotonic两个变量的和表示.

    Linux内核使用动态定时器来实现POSIX定时置,因此,它们与我们在前面一节描述的ITIMER_ REAL间隔定时器相似。不过,POSIX定时器比传统间隔定时器更灵活,更可靠。它们之间有两个显著区别:

    • 当传统间隔定时器到期时,内核会发送一个SIGALRM信号给进程来激话定时器。而当一个POSIX定时器到期时,内核可以发送各种信号给整个多线程应用程序,也可以发送给单个指定的线程,内核还能在应用程序的某个线程上强制执行一个通告器函数,或者甚至什么也不做(这取决于处理事件的用户态函数库)。

    • 如果一个传统间隔定时器到期了很多次但用户态进程不能接收SIGALRM信号(例如由于信号被阻塞或者进程不处于运行态),那么只有第一个信号被接收到,其他所有SIGALRM信号都丢失了。对于POSIX定时器来说会发生同样的情况,但进程可以调用timer_getoverrun()系统调用来得到自第一个信号产生以来定时器到期的次数。

    定时器操作

    最强大的定时器接口来自POSIX时钟系列,其创建、初始化以及删除一个定时器的行动被分为三个不同的函数:

    timer_create()(创建定时器)

    #include <signal.h>
    #include <time.h>
    函数声明:
    int timer_create(clockid_t clockid, struct sigevent *sevp,  timer_t *timerid);
    功能:创建一个POSIX标准的进程定时器
    参数:
         @clockid 可选系统系统的宏,比如 CLOCK_REALTIME
         @sevp 环境值,结构体struct sigevent变量的地址
         @timerid 定时器标识符,结构体timer_t变量的地址
         link with -lrt.
    返回值:
    0 - 成功;-1 - 失败,errno被设置。
    

    进程可以通过调用timer_create()创建特定的定时器,定时器是每个进程自己的,不是在fork时继承的。

    • clock_id

    clock_id说明定时器是基于哪个时钟的,*timerid装载的是被创建的定时器的ID。该函数创建了定时器,并将他的ID 放入timerid指向的位置中。

    clock_id取值为以下:

    clock_id说明
    CLOCK_REALTIMESystemwide realtime clock.
    CLOCK_MONOTONICRepresents monotonic time. Cannot be set.
    CLOCK_PROCESS_CPUTIME_IDHigh resolution per-process timer.
    CLOCK_THREAD_CPUTIME_IDThread-specific timer.
    CLOCK_REALTIME_HRHigh resolution version of CLOCK_REALTIME.
    CLOCK_MONOTONIC_HRHigh resolution version of CLOCK_MONOTONIC.
    struct sigevent
    {
    int sigev_notify; //notification type
    int sigev_signo; //signal number   (见signum:要操作的信号。)
    union sigval   sigev_value; //signal value
    void (*sigev_notify_function)(union sigval);
    pthread_attr_t *sigev_notify_attributes;
    }
    
    union sigval
    {
    int sival_int; //integer value
    void *sival_ptr; //pointer value
    }
    
    • evp

    参数evp指定了定时器到期要产生的异步通知。如果evp为NULL,那么定时器到期会产生默认的信号,对 CLOCK_REALTIMER来说,默认信号就是SIGALRM。如果要产生除默认信号之外的其它信号,程序必须将 evp->sigev_signo设置为期望的信号码。

    struct sigevent 结构中的成员evp->sigev_notify说明了定时器到期时应该采取的行动。通常,这个成员的值为SIGEV_SIGNAL,这个值说明在定时器到期时,会产生一个信号。程序可以将成员evp->sigev_notify设为SIGEV_NONE来防止定时器到期时产生信号。

    如果几个定时器产生了同一个信号,处理程序可以用 evp->sigev_value来区分是哪个定时器产生了信号。要实现这种功能,程序必须在为信号安装处理程序时,使用struct sigaction的成员sa_flags中的标志符SA_SIGINFO。

    通过将evp->sigev_notify设定为如下值来定制定时器到期后的行为:

    SIGEV_NONE:什么都不做,只提供通过timer_gettime和timer_getoverrun查询超时信息。
    SIGEV_SIGNAL:当定时器到期,内核会将sigev_signo所指定的信号传送给进程。在信号处理程序中,si_value会被设定会sigev_value。
    SIGEV_THREAD:当定时器到期,内核会(在此进程内)以sigev_notification_attributes为线程属性创建一个线程,并且让它执行sigev_notify_function,传入sigev_value作为为一个参数。

    timer_settime()(初始化定时器)

    timer_create()所创建的定时器并未启动。要将它关联到一个到期时间以及启动时钟周期,可以使用timer_settime()。

    **int timer_settime(timer_t timerid, int flags, const struct itimerspec value, struct itimerspect ovalue);

    头文件:
    #include <time.h>
    函数声明:
    int timer_settime(timer_t timerid, int flags, const struct itimerspec *new_value,struct itimerspec *old_value);
    
    int timer_gettime(timer_t timerid, struct itimerspec *curr_value);
    功能:设置或者获得定时器时间值
    参数:
         @timerid 定时器标识
         @flags 0标识相对时间,1标识绝对时间
         @new_value 定时器的新初始值和间隔,如下面的it
         @old_value 取值通常为0NULL,若不为NULL,则返回定时器前一个值
         link with -lrt.
    
    struct itimespec{
    
        struct timespec it_interval; 
    
        struct timespec it_value;   
    
    }; 
    

    如同settimer(),it_value用于指定当前的定时器到期时间。当定时器到期,it_value的值会被更新成it_interval 的值。如果it_interval的值为0,则定时器不是一个时间间隔定时器,一旦it_value到期就会回到未启动状态。timespec的结构提供了纳秒级分辨率:

    struct timespec{
    
        time_t tv_sec;
    
        long tv_nsec;  
    
    };
    

    如果flags的值为TIMER_ABSTIME,则value所指定的时间值会被解读成绝对值(此值的默认的解读方式为相对于当前的时间)。这个经修改的行为可避免取得当前时间、计算“该时间”与“所期望的未来时间”的相对差额以及启动定时器期间造成竞争条件。

    如果ovalue的值不是NULL,则之前的定时器到期时间会被存入其所提供的itimerspec。如果定时器之前处在未启动状态,则此结构的成员全都会被设定成0。

    timer_gettime()(获得一个活动定时器的剩余时间)

    int timer_gettime(timer_t timerid,struct itimerspec *value);

    timer_getoverrun()(取得一个定时器的超限运行次数)

    int timer_getoverrun(timer_t timerid);

    有可能一个定时器到期了,而同一定时器上一次到期时产生的信号还处于挂起状态。在这种情况下,其中的一个信号可能会丢失。这就是定时器超限。程序可以通过调用timer_getoverrun来确定一个特定的定时器出现这种超限的次数。定时器超限只能发生在同一个定时器产生的信号上。由多个定时器,甚至是那些使用相同的时钟和信号的定时器,所产生的信号都会排队而不会丢失。

    执行成功时,timer_getoverrun()会返回定时器初次到期与通知进程(例如通过信号)定时器已到期之间额外发生的定时器到期次数。举例来说,在我们之前的例子中,一个1ms的定时器运行了10ms,则此调用会返回9。如果超限运行的次数等于或大于DELAYTIMER_MAX,则此调用会返回DELAYTIMER_MAX。

    执行失败时,此函数会返回-1并将errno设定会EINVAL,这个唯一的错误情况代表timerid指定了无效的定时器。

    timer_delete()(删除一个定时器)

    int timer_delete (timer_t timerid);

    一次成功的timer_delete()调用会销毁关联到timerid的定时器并且返回0。执行失败时,此调用会返回-1并将errno设定会 EINVAL,这个唯一的错误情况代表timerid不是一个有效的定时器。

    例程

    例程1 采用新线程派驻的通知方式

    #include <stdio.h> 
    #include <signal.h> 
    #include <time.h> 
    #include <string.h> 
    #include <stdlib.h> 
    #include <unistd.h> 
     
    void timer_thread(union sigval v) 
    { 
        printf("timer_thread function! %d\n", v.sival_int); 
    } 
     
    int main() 
    { 
        timer_t timerid; 
        struct sigevent evp; 
        memset(&evp, 0, sizeof(struct sigevent));       //清零初始化 
     
        evp.sigev_value.sival_int = 111;                //也是标识定时器的,回调函数可以获得 
        evp.sigev_notify = SIGEV_THREAD;                //线程通知的方式,派驻新线程 
        evp.sigev_notify_function = timer_thread;       //线程函数地址 
     
        if (timer_create(CLOCK_REALTIME, &evp, &timerid) == -1) 
        {   
            perror("fail to timer_create"); 
            exit(-1); 
        }   
     
        /* 第一次间隔it.it_value这么长,以后每次都是it.it_interval这么长,就是说it.it_value变0的时候会>装载it.it_interval的值 */
        struct itimerspec it; 
        it.it_interval.tv_sec = 1;  // 回调函数执行频率为1s运行1次
        it.it_interval.tv_nsec = 0; 
        it.it_value.tv_sec = 3;     // 倒计时3秒开始调用回调函数
        it.it_value.tv_nsec = 0; 
     
        if (timer_settime(timerid, 0, &it, NULL) == -1) 
        {   
            perror("fail to timer_settime"); 
            exit(-1); 
        }   
     
        //pause();
        while (1);
     
        return 0; 
    } 
    /*
     * int timer_gettime(timer_t timerid, struct itimerspec *curr_value);
     * 获取timerid指定的定时器的值,填入curr_value
     */
    

    例程2 通知方式为信号的处理方式

    #include <stdio.h> 
    #include <time.h> 
    #include <stdlib.h> 
    #include <signal.h> 
    #include <string.h> 
    #include <unistd.h> 
     
    #define CLOCKID CLOCK_REALTIME 
     
    void sig_handler(int signo) 
    { 
        printf("timer_signal function! %d\n", signo); 
    } 
     
    int main() 
    { 
        // XXX int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact); 
        // signum--指定的信号编号,可以指定SIGKILL和SIGSTOP以外的所有信号编号 
        // act结构体--设置信号编号为signum的处理方式 
        // oldact结构体--保存上次的处理方式 
        // 
        // struct sigaction   
        // { 
        // void (*sa_handler)(int);         //信号响应函数地址 
        // void (*sa_sigaction)(int, siginfo_t *, void *);   //但sa_flags为SA——SIGINFO时才使用 
        // sigset_t sa_mask;         //说明一个信号集在调用捕捉函数之前,会加入进程的屏蔽中,当捕捉函数返回时,还原 
        // int sa_flags; 
        // void (*sa_restorer)(void);   //未用 
        // }; 
        // 
        timer_t timerid; 
        struct sigevent evp; 
     
        struct sigaction act; 
        memset(&act, 0, sizeof(act)); 
        act.sa_handler = sig_handler; 
        act.sa_flags = 0; 
     
        // XXX int sigaddset(sigset_t *set, int signum);  //将signum指定的信号加入set信号集
        // XXX int sigemptyset(sigset_t *set);          //初始化信号集 
     
        sigemptyset(&act.sa_mask); 
     
        if (sigaction(SIGUSR1, &act, NULL) == -1) 
        { 
            perror("fail to sigaction"); 
            exit(-1); 
        } 
     
        memset(&evp, 0, sizeof(struct sigevent)); 
        evp.sigev_signo = SIGUSR1; 
        evp.sigev_notify = SIGEV_SIGNAL; 
        if (timer_create(CLOCK_REALTIME, &evp, &timerid) == -1) 
        { 
            perror("fail to timer_create"); 
            exit(-1); 
        } 
     
        struct itimerspec it; 
        it.it_interval.tv_sec = 2; 
        it.it_interval.tv_nsec = 0; 
        it.it_value.tv_sec = 1; 
        it.it_value.tv_nsec = 0; 
        if (timer_settime(timerid, 0, &it, 0) == -1) 
        { 
            perror("fail to timer_settime"); 
            exit(-1); 
        } 
     
        pause(); 
     
        return 0; 
    }
    

    中断与中断处理函数(信号捕捉函数)

    信号捕捉函数

    signal 函数的使用方法简单,但并不属于 POSIX 标准,在各类 UNIX 平台上的实现不尽相同,因此其用途受到了一定的限制。POSIX标准定义的信号处理接口是**sigaction()**函数,其接口头文件及原型如下:

     #include <signal.h>
    //修改信号处理动作(通常在Linux用其来注册一个信号的捕捉函数)
     int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact);
    
    • signum:要操作的信号:
    SignalValueActionComment
    SIGHUP1TermHangup detected on controlling terminal or death of controlling process
    SIGINT2TermInterrupt from keyboard
    SIGQUIT3CoreQuit from keyboard
    SIGILL4CoreIllegal Instruction
    SIGABRT6CoreAbort signal from abort(3)
    SIGFPE8CoreFloating point exception
    SIGKILL9TermKill signal
    SIGSEGV11CoreInvalid memory reference
    SIGPIPE13TermBroken pipe: write to pipe with no readers
    SIGALRM14TermTimer signal from alarm(2)
    SIGTERM15TermTermination signal
    SIGUSR130,10,16TermUser-defined signal 1
    SIGUSR231,12,17TermUser-defined signal 2
    SIGCHLD20,17,18IgnChild stopped or terminated
    SIGCONT19,18,25ContContinue if stopped
    SIGSTOP17,19,23StopStop process
    SIGTSTP18,20,24StopStop typed at tty
    • act:要设置的对信号的新处理方式。
    • oldact:原来对信号的处理方式。
    • 返回值:0 表示成功,-1 表示有错误发生。

    sigaction结构体

    struct sigaction 类型用来描述对信号的处理,定义如下:

     struct sigaction
     {
      void     (*sa_handler)(int);
      void     (*sa_sigaction)(int, siginfo_t *, void *);
      sigset_t  sa_mask;
      int       sa_flags;
      void     (*sa_restorer)(void);
     };
    

    在这个结构体中,

    • 成员 sa_handler 是一个函数指针,其含义与 signal 函数中的信号处理函数类似。它指定信号捕捉后的处理函数名(即注册函数)。也可赋值为SIG_IGN表忽略 或 SIG_DFL表执行默认动作

    • sa_sigaction 则是另一个信号处理函数,它有三个参数,可以获得关于信号的更详细的信息。

      • 当sa_flags成员的值包含了SA_SIGINFO标志时,系统将使用sa_sigaction函数作为信号处理函数,即是sigaction.sa_sigaction = dig_op_function
        .否则使用sa_handler作为信号处理函数,sigaction.sa_handler = dig_op_function

      如果不设置sa_flags的话,初始化为void (*sa_handler)(int);//这个就和signal差不多了哦
      void handler(int signo);
      如果设置了SA_SIGINFO则,初始化为void (*sa_sigaction)(int, siginfo_t , void );
      //多了个siginfo,这个结构体的定义参见APUE,还有个econtext,用于标识信号传递时进程的上下文
      void handler(int signo, siginfo_t
      info, void
      context);

      • 在某些系统中,成员sa_handler 与 sa_sigaction 被放在联合体中,因此使用时不要同时设置。
    • sa_mask 成员用来指定在信号处理函数执行期间需要被屏蔽的信号,

      • 特别是当某个信号被处理时,它自身会被自动放入进程的信号掩码,因此在信号处理函数执行期间这个信号不会再度发生。
      • 调用信号处理函数时,所要屏蔽的信号集合(信号屏蔽字)。注意:仅在处理函数被调用期间屏蔽生效,是临时性设置。
    • sa_flags 成员用于指定信号处理的行为,它可以是一下值的“按位或”组合。

      • SA_RESTART:使被信号打断的系统调用自动重新发起。
      • SA_NOCLDSTOP:使父进程在它的子进程暂停或继续运行时不会收到 SIGCHLD 信号。
      • SA_NOCLDWAIT:使父进程在它的子进程退出时不会收到 SIGCHLD 信号,这时子进程如果退出也不会成为僵尸进程。
      • SA_NODEFER:使对信号的屏蔽无效,即在信号处理函数执行期间仍能发出这个信号。
      • SA_RESETHAND:信号处理之后重新设置为默认的处理方式。
      • SA_SIGINFO:使用 sa_sigaction 成员而不是 sa_handler 作为信号处理函数。
      • 通常设置为0,表使用默认属性。

      sa_flags的取值在sigaction.h中,如下:

    <sigaction.h>
    /* Bits in `sa_flags'.  */
    #define	SA_NOCLDSTOP  1		 /* Don't send SIGCHLD when children stop.  */
    #define SA_NOCLDWAIT  2		 /* Don't create zombie on child death.  */
    #define SA_SIGINFO    4		 /* Invoke signal-catching function with
    				    three arguments instead of one.  */
    #if defined __USE_XOPEN_EXTENDED || defined __USE_MISC
    # define SA_ONSTACK   0x08000000 /* Use signal stack by using `sa_restorer'. */
    #endif
    #if defined __USE_XOPEN_EXTENDED || defined __USE_XOPEN2K8
    # define SA_RESTART   0x10000000 /* Restart syscall on signal return.  */
    # define SA_NODEFER   0x40000000 /* Don't automatically block the signal when
    				    its handler is being executed.  */
    # define SA_RESETHAND 0x80000000 /* Reset to SIG_DFL on entry to handler.  */
    #endif
    #ifdef __USE_MISC
    # define SA_INTERRUPT 0x20000000 /* Historical no-op.  */
    
    /* Some aliases for the SA_ constants.  */
    # define SA_NOMASK    SA_NODEFER
    # define SA_ONESHOT   SA_RESETHAND
    # define SA_STACK     SA_ONSTACK
    #endif
    

    sigaction.sa_flags控制内核对该信号的处理标记
    SA_NODEFER: 一般情况下,当信号处理函数运行时,内核将阻塞<该给定信号–SIGINT>。但是如果设置了SA_NODEFER标记,那么在该信号处理函数运行时,内核将不会阻塞该信号。SA_NODEFER是这个标记的正式的POSIX名字(还有一个名字SA_NOMASK,为了软件的可移植性,一般不用这个名字)
    SA_RESETHAND: 当调用信号处理函数时,将信号的处理函数重置为缺省值。SA_RESETHAND是这个标记的正式的POSIX名字(还有一个名字SA_ONESHOT,为了软件的可移植性,一般不用这个名字)
    上面是对sa_flags中常用的两个值的解释.

    • re_restorer 成员则是一个已经废弃的数据域,不要使用。

    例程1

    下面用一个例程来说明 sigaction 函数的使用(handler处理方式),代码如下

    #include <stdio.h>
    #include <unistd.h>
    #include <signal.h>
    #include <errno.h>
     
    static void sig_usr(int signum)
    {
        if(signum == SIGUSR1)
        {
            printf("SIGUSR1 received\n");
        }
        else if(signum == SIGUSR2)
        {
            printf("SIGUSR2 received\n");
        }
        else
        {
            printf("signal %d received\n", signum);
        }
    }
     
    int main(void)
    {
        char buf[512];
        int  n;
        struct sigaction sa_usr;
        sa_usr.sa_flags = 0;
        sa_usr.sa_handler = sig_usr;   //信号处理函数
        
        sigaction(SIGUSR1, &sa_usr, NULL);
        sigaction(SIGUSR2, &sa_usr, NULL);
        
        printf("My PID is %d\n", getpid());
        
        while(1)
        {
            if((n = read(STDIN_FILENO, buf, 511)) == -1)
            {
                if(errno == EINTR)
                {
                    printf("read is interrupted by signal\n");
                }
            }
            else
            {
                buf[n] = '\0';
                printf("%d bytes read: %s\n", n, buf);
            }
        }
        
        return 0;
    }
    

    在这个例程中使用 sigaction 函数为 SIGUSR1 和 SIGUSR2 信号注册了处理函数,然后从标准输入读入字符。程序运行后首先输出自己的 PID,如:My PID is 5904

    这时如果从另外一个终端向进程发送 SIGUSR1 或 SIGUSR2 信号,用类似如下的命令:kill -USR1 5904

    则程序将继续输出如下内容:

     SIGUSR1 received
     read is interrupted by signal
    

    这说明用 sigaction 注册信号处理函数时,不会自动重新发起被信号打断的系统调用。如果需要自动重新发起,则要设置 SA_RESTART 标志,比如在上述例程中可以进行类似一下的设置:sa_usr.sa_flags = SA_RESTART;

    例程2

    sigaction 函数的使用(sigaction处理方式),代码如下

    #include <sys/types.h>
    #include <unistd.h>
    #include <stdio.h>
    #include <signal.h>
    
    /*
      struct siginfo
      {
       int si_signo;
       int si_errno;
       int si_code;
       pid_t si_pid;
       uid_t si_uid;
       void* si_addr;
       int si_status;
       long s_band
      }
    */
    void sig_op(int signo, siginfo_t* info, void* context)
    {
      printf("the signo is %d\n",signo);
      printf("sig pid is %d\n", (int)(info->si_pid));
      printf("sig uid is %d\n", (int)(info->si_uid));
    }
    
    int main(int argc,char** argv)
    {
     struct sigaction act;
     struct sigaction oact;
     
     pid_t pid;
     
     pid=getpid();
     sigemptyset(&act.sa_mask);
     act.sa_handler=sig_op; 
     act.sa_flags=SA_SIGINFO;
     
     printf("the pid is %d",pid);
     if(sigaction(SIGPIPE,&act,&oact)==-1)
      //这里还可以保存原来的signal处理方式,以便有的时候需要恢复oact。
      //sigaction(sig,&oact,NULL)
      printf("%s","install error~!\n");
    
     while(1)
      {
       sleep(1);
       printf("%s","wait for signal\n");
      }
      
      return 0;
    }
    
    [kenthy@kenthy c_c]$ ./sig
    the pid is 3904
    wait for signal
    wait for signal
    wait for signal
    wait for signal
    wait for signal
    wait for signal
    the signo is 13 //这个时候另一个terminal   kill -s SIGPIPE 3904
    sig pid is 3135
    sig uid is 500
    wait for signal
    wait for signal
    
    

    参考资料

    深入理解LINUX内核 pp. 256-257

    【C程序】timer_create系列定时器函数

    定时器、sigevent结构体详解

    linux中sigaction函数详解

    Linux信号:sigaction函数sa_flags各标志影响的实例讲解

    linux的信号捕捉函数详解

    Linux系统sigaction函数的使用示例

    Linux时间子系统之(六):POSIX timer

    Linux Programmer’s Manual

    展开全文
  • 定时器中断实验

    2020-11-23 22:47:37
    今天看了并实际做了一次正点原子的定时器中断实验,实验结果并不重要,这部分教程的意义在于让我们学会如何去配置一个定时器中断。 想要使用定时器中断,我们要进行各种配置,将它们整合到一个初始化函数里,在这个...

    今天看了并实际做了一次正点原子的定时器中断实验,实验结果并不重要,这部分教程的意义在于让我们学会如何去配置一个定时器中断。

    想要使用定时器中断,我们要进行各种配置,将它们整合到一个初始化函数里,在这个函数中我们要做的事主要有:
    1.定义NVIC和定时器初始化的结构体。
    2.使能定时器时钟。
    3.配置NVIC和定时器的各个参数,并调用相应的初始化参数将它们初始化。
    4.使能定时器中断。
    5.使能定时器。

    初始化函数定义好后就要编写中断处理函数了,每次定时器记数到设定值时就会触发中断函数,函数的一开始要先获取定时器中断的状态,如果确实发生了中断,先清楚标志位,再进行下一步(中断函数具体要做的事)。

    过程中有一个比较重要的公式,关于定时器中断的间隔时间,其公式为:
    在这里插入图片描述
    假设系统时钟频率为72Mhz,psc=7199,我想产生一个1ms的定时器中断,则
    1000=arr*7200/72
    arr=10

    展开全文
  • 1、单片机定时器中断后计数器是否还会计数 解决:单片机定时器中断后计数器还是会计数的,如果重新赋值,会按照设置的时间进行计时。如果没有,则从0开始。 2、单片机在执行定时器中断时,是否在没执行当前中断...
  • 51定时器中断控制流水灯

    千次阅读 2021-01-01 15:34:11
    2、了解定时器中断的方法。 3、了解定时器初始化设置的方法。 二、实验内容 1、完成读取定时器溢出标志位来控制流水灯 2、完成定时器中断服务函数控制流水灯 三、实验原理 只用一个定时器: 定时器级联: 四、实验...
  • Matlab定时器中断

    2021-03-02 22:27:31
    Matlab定时器中断前言一、timer的基本用法二、测试例子运行结果 前言 matlab中与单片机进行交互时需要用到定时器timer,用它可以模拟单片机的定时器中断服务。在此基础上进行拓展,可用串口(serial)+定时器...
  • 1.定时器种类 ...3.定时器中断触发条件 4.定时器计数模式 分为向上,向下,向上向下模式 5.通用定时器作用用途 测量输入输出波长度等 说明:每个定时器完全独立没有共享内存 6.工作过程 红色重点关注 ...
  • 定时器使能时中断标志触发,允许中断后会立马进入中断 解决方案: 在使能定时器中断前插入定时器中断清除语句即可 以定时器 Timer13为例,设置100us中断 void timer13_init(void) { timer_parameter_s...
  • 51单片机入门教程(5)——定时器中断

    万次阅读 多人点赞 2018-11-25 22:53:58
    51单片机入门教程(5)——定时器中断一、中断的概念二、定时器中断2.1 软件延时的不足2.2 中断寄存器2.2.1 中断允许控制寄存器 IE2.2.2 定时器工作方式寄存器 TMOD2.2.3 定时器控制寄存器 TCON2.2.4 定时器初值...
  • dsp定时器中断方式实验报告通信0203班 王建超 02211272一.中断初始化及服务程序的编写5402DSP中断有两大类,一类是可屏蔽中断:可以用软件来屏蔽或开放的硬件和软件中断。在5402中有INT3 ~INT0(外部中断),BRINT0,...
  • STM32定时器中断

    千次阅读 2017-12-04 10:48:09
    本实验的目的是通过定时器中断控制LED灯的亮灭。 笔者所用IDE为IAR,采用标准库(3.5固件库),通过定时器产生中断来控制LED。 led.h文件 #ifndef __LED_H #define __LED_H #include "stm32f10x_gpio.h" #...
  • stm32通用定时器中断

    千次阅读 2019-04-03 22:27:45
    其中定时器中断只涉及了(1)(2)两个部分: 定时器中断流程如下: (1)选择时钟源,需要操作从模式控制寄存器TIMx_SMCR的低3位,默认为000,预分频器直接由内部时钟驱动。 (2)设置预分频寄存器TIMx_PSC ...
  • STM32定时器详解(定时器中断实验)

    万次阅读 多人点赞 2019-04-18 21:19:09
    文章目录STM32定时器分类定时器中断实验计数器时钟频率计数器模式向上计数模式库函数操作 STM32定时器分类 STM32的定时器分为很多类,按照功能的不同可以分为: 高级定时器(TIM1和TIM8) 通用定时器(TIM2-TIM5) ...
  • 定时器中断实验操作

    2020-05-24 16:10:41
    定时器中断实验 1、先了解定时器的工作过程 2、计数器时钟可以由下列时钟源提供: 内部时钟(CK_INT) 外部时钟模式1:外部输入脚(TIx) 外部时钟模式2:外部触发输入(ETR) 内部触发输入(ITRx):使用一个定时器作为另一...
  • 14 . 定时器中断实验

    2021-05-17 16:12:40
    定时器中断实验 我们介绍了STM32F1 的外部中断,这一章我们来学习下定时器中断。STM32F1 的定时器功能非常强大,其包含 2 个基本定时器(TIM6、TIM7)、4 个通用定时器(TIM2-TIM5)和2 个高级定时器(TIM1、TIM8)...
  • CubeMX,HAL库使用定时和定时器中断CubeMX配置MDK代码 CubeMX配置 配置为1ms 计算公式: ARR: 自动重装载寄存器( AutoReload Register )(16位数据) PSC:预分频器(16位数据) TIM_CLK: ADC时钟频率(注意单位HZ...
  • 要学习51单片机中断的朋友,拥有这一篇博文就够了,深入浅出,里面包含了寄存器,外部中断、定时器中断、中断嵌套等的讲解,还有代码实战。快一万字,写得不容易,还请大家点赞支持一下,后续持续更新(一)寄存器1....
  • 单片机定时器中断

    千次阅读 2018-05-11 16:44:15
    就在前不久,我觉得我虽然书上的内容我已经看了不少,但是我觉得我对前面的内容还是...所以这次我就来分享一下我所了解的定时器中断吧。 其实中断的概念大家都很容易懂,简单的讲,就是单片机在处理某一件事情的时...
  • zynq 的定时器中断实验

    千次阅读 2018-04-01 00:43:44
    本文通过定时器中断实验,介绍zynq 的中断和定时器的基本使用方法。本文是在helloworld 实验的基础上完成的,所以必须先完成了helloworld 的实验。这个可以学习本博客的helloworld 实验,或者开发板提供的helloworld...
  • STM32单片机(5) 定时器中断实验

    千次阅读 2014-08-06 01:11:42
    定时器中断实验
  • 通用定时器中断实验 定时器中断时钟源解析 教你如何看逻辑信号图 向上计数模式(时钟分频因子=1) 中央对齐计数模式(时钟分频因子=1,ARR=6) 相关寄存器简介 事件产生寄存器(TIMx_EGR) 状态寄存器(TIMx_SR)...
  • 《STM32中文参考手册V10》-第14章通用定时器   STM32的定时器 STM32F103ZET6一共有8个定时器,其中分别为: 高级定时器(TIM1、TIM8);通用定时器(TIM2、TIM3、TIM4、TIM5);基本定时器(TIM6、TIM7)。 ...
  • 定时器中断学习和简单应用

    千次阅读 2019-12-25 22:03:28
    定时器中断&简单应用定时器中断基本介绍清楚明白工作原理定时器结构主要内容两个寄存器初始化程序简单应用-秒表基本功能代码详解 彩蛋:对于独立按键的使用 没啥硬核内容,就是初学者萌新入门,学长大佬请移步 ...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 28,463
精华内容 11,385
关键字:

定时器的中断标志