问小白 wenxiaobai
资讯
历史
科技
环境与自然
成长
游戏
财经
文学与艺术
美食
健康
家居
文化
情感
汽车
三农
军事
旅行
运动
教育
生活
星座命理

如何使用C语言实现精准定时

创作时间:
作者:
@小白创作中心

如何使用C语言实现精准定时

引用
1
来源
1.
https://docs.pingcode.com/baike/1210949

在C语言开发中,精准定时是一个常见且重要的需求,特别是在嵌入式系统和实时应用中。本文将详细介绍如何在C语言中实现精准定时,包括使用系统提供的定时器功能、利用硬件定时器、结合多线程编程等方法,并提供具体的代码示例。

一、使用系统提供的定时器功能

现代操作系统通常提供了丰富的定时器API,C语言可以调用这些API实现定时任务。以下是常见的系统定时器功能及其用法。

1.1 使用POSIX定时器

POSIX标准提供了一套定时器API,可以用于实现高精度定时。POSIX定时器通过timer_createtimer_settimetimer_gettime等函数来操作。

示例代码

#include <stdio.h>
#include <time.h>  
#include <signal.h>  

void timer_handler(int signum) {  
    static int count = 0;  
    printf("Timer expired %d times\n", ++count);  
}  

int main() {  
    struct sigaction sa;  
    struct sigevent sev;  
    struct itimerspec its;  
    timer_t timerid;  

    // Setup signal handler  
    sa.sa_flags = SA_SIGINFO;  
    sa.sa_sigaction = timer_handler;  
    sigemptyset(&sa.sa_mask);  
    if (sigaction(SIGRTMIN, &sa, NULL) == -1) {  
        perror("sigaction");  
        return 1;  
    }  

    // Create the timer  
    sev.sigev_notify = SIGEV_SIGNAL;  
    sev.sigev_signo = SIGRTMIN;  
    sev.sigev_value.sival_ptr = &timerid;  
    if (timer_create(CLOCK_REALTIME, &sev, &timerid) == -1) {  
        perror("timer_create");  
        return 1;  
    }  

    // Start the timer  
    its.it_value.tv_sec = 1;  
    its.it_value.tv_nsec = 0;  
    its.it_interval.tv_sec = 1;  
    its.it_interval.tv_nsec = 0;  
    if (timer_settime(timerid, 0, &its, NULL) == -1) {  
        perror("timer_settime");  
        return 1;  
    }  

    // Wait for timer to expire  
    while (1) {  
        pause();  
    }  

    return 0;  
}  

在这个例子中,使用POSIX定时器实现了每秒触发一次的定时任务。通过设置定时器和信号处理函数,可以在定时器到期时执行特定的操作。

1.2 使用Windows定时器

在Windows平台上,可以使用SetTimerKillTimer函数实现定时任务。Windows定时器通过消息机制通知应用程序定时器到期。

示例代码

#include <windows.h>  
#include <stdio.h>  

VOID CALLBACK TimerProc(HWND hWnd, UINT message, UINT_PTR idTimer, DWORD dwTime) {  
    static int count = 0;  
    printf("Timer expired %d times\n", ++count);  
}  

int main() {  
    MSG msg;  
    UINT_PTR timerId = SetTimer(NULL, 0, 1000, TimerProc);  
    if (timerId == 0) {  
        printf("Failed to create timer\n");  
        return 1;  
    }  

    while (GetMessage(&msg, NULL, 0, 0)) {  
        TranslateMessage(&msg);  
        DispatchMessage(&msg);  
    }  

    KillTimer(NULL, timerId);  
    return 0;  
}  

在这个例子中,使用Windows定时器实现了每秒触发一次的定时任务。通过设置定时器和回调函数,可以在定时器到期时执行特定的操作。

二、利用硬件定时器

在嵌入式系统中,通常需要使用硬件定时器来实现高精度定时。硬件定时器通常由微控制器提供,可以通过直接访问寄存器来配置定时器。

2.1 基本原理

硬件定时器通常包括一个计数器和一个预分频器,通过配置计数器和预分频器,可以实现不同的定时时间。当计数器溢出时,可以触发一个中断,通知CPU定时器到期。

2.2 示例代码

以下是一个基于ARM Cortex-M微控制器的硬件定时器示例代码:

#include "stm32f4xx.h"  

void TIM2_IRQHandler(void) {  
    if (TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET) {  
        TIM_ClearITPendingBit(TIM2, TIM_IT_Update);  
        // Timer expired, perform action  
        GPIO_ToggleBits(GPIOD, GPIO_Pin_12);  
    }  
}  

void init_timer(void) {  
    TIM_TimeBaseInitTypeDef timerInitStructure;  
    NVIC_InitTypeDef nvicStructure;  

    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);  

    timerInitStructure.TIM_Prescaler = 16000 - 1; // 1 ms  
    timerInitStructure.TIM_CounterMode = TIM_CounterMode_Up;  
    timerInitStructure.TIM_Period = 1000 - 1; // 1 second  
    timerInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;  
    timerInitStructure.TIM_RepetitionCounter = 0;  

    TIM_TimeBaseInit(TIM2, &timerInitStructure);  
    TIM_Cmd(TIM2, ENABLE);  
    TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);  

    nvicStructure.NVIC_IRQChannel = TIM2_IRQn;  
    nvicStructure.NVIC_IRQChannelPreemptionPriority = 0;  
    nvicStructure.NVIC_IRQChannelSubPriority = 1;  
    nvicStructure.NVIC_IRQChannelCmd = ENABLE;  
    NVIC_Init(&nvicStructure);  
}  

int main(void) {  
    // Initialize hardware  
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, ENABLE);  

    GPIO_InitTypeDef GPIO_InitStructure;  
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;  
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;  
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;  
    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;  
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;  
    GPIO_Init(GPIOD, &GPIO_InitStructure);  

    init_timer();  

    while (1) {  
        // Main loop  
    }  
}  

在这个例子中,使用STM32微控制器的TIM2定时器实现了每秒触发一次的定时任务。通过配置定时器和中断处理函数,可以在定时器到期时执行特定的操作。

三、结合多线程编程

在多线程环境中,可以使用定时器与线程结合来实现精准定时。通过使用线程库(如POSIX线程或Windows线程),可以创建一个专门用于定时任务的线程。

3.1 POSIX线程

POSIX线程库提供了一套线程API,可以用于创建和管理线程。通过结合POSIX定时器和POSIX线程,可以实现精准定时。

示例代码

#include <pthread.h>  
#include <stdio.h>  
#include <unistd.h>  
#include <time.h>  

void *timer_thread(void *arg) {  
    struct timespec ts;  
    ts.tv_sec = 1;  
    ts.tv_nsec = 0;  

    while (1) {  
        nanosleep(&ts, NULL);  
        printf("Timer expired\n");  
    }  

    return NULL;  
}  

int main() {  
    pthread_t thread;  
    pthread_create(&thread, NULL, timer_thread, NULL);  

    while (1) {  
        // Main loop  
    }  

    return 0;  
}  

在这个例子中,创建了一个POSIX线程用于定时任务。通过nanosleep函数实现每秒触发一次的定时任务。

3.2 Windows线程

在Windows平台上,可以使用Windows线程库创建一个专门用于定时任务的线程。

示例代码

#include <windows.h>  
#include <stdio.h>  

DWORD WINAPI TimerThread(LPVOID lpParam) {  
    while (1) {  
        Sleep(1000);  
        printf("Timer expired\n");  
    }  

    return 0;  
}  

int main() {  
    HANDLE hThread;  
    DWORD dwThreadId;  

    hThread = CreateThread(NULL, 0, TimerThread, NULL, 0, &dwThreadId);  
    if (hThread == NULL) {  
        printf("Failed to create thread\n");  
        return 1;  
    }  

    WaitForSingleObject(hThread, INFINITE);  
    CloseHandle(hThread);  

    return 0;  
}  

在这个例子中,创建了一个Windows线程用于定时任务。通过Sleep函数实现每秒触发一次的定时任务。

四、总结

通过本文的介绍,读者可以了解到在C语言中实现精准定时的多种方法,包括使用系统提供的定时器功能、利用硬件定时器和结合多线程编程。每种方法都有其适用的场景和优缺点,读者可以根据具体需求选择合适的方法。

使用系统提供的定时器功能在大多数情况下是最方便和通用的选择,特别是在桌面系统和服务器应用中。利用硬件定时器则是嵌入式系统中实现高精度定时的最佳选择。结合多线程编程可以在多线程环境中实现高效的定时任务。

无论选择哪种方法,理解其基本原理和正确使用相关API都是实现精准定时的关键。希望本文能够为读者提供有价值的参考,并帮助读者在实际项目中实现精准定时。

© 2023 北京元石科技有限公司 ◎ 京公网安备 11010802042949号