linux下利用rtc 实现精确定时器

时间:2022-12-05 08:55:36

rtc是linux系统中的一个时间设备,可以open打开,通过ioctl设置频率,然后就可以进行循环read操作,每次read的耗时是(1/频率 单位:秒)

先上代码

#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <linux/rtc.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>
#include <unistd.h>
#define FREQ 2048
#define USEC_PER_SECOND 1000000
typedef int MILLSEC;

int g_fd = 0;

int calc_cnt(MILLSEC millseconds )
{
return (int)(millseconds * 1000.0 / USEC_PER_SECOND * FREQ + 0.5); //add 0.5 to meet precision in common
}

void rtc_open()
{
g_fd = open ("/dev/rtc", O_RDONLY);
if(g_fd < 0)
{
perror("open");
exit(errno);
}
printf("opened.\n");
}

void set_freq()
{
/*Set the freq*/
if(ioctl(g_fd, RTC_IRQP_SET, FREQ ) < 0)
{
perror("ioctl(RTC_IRQP_SET)");
close(g_fd);
exit(errno);
}
/* Enable periodic interrupts */
if(ioctl(g_fd, RTC_PIE_ON, 0) < 0)
{
perror("ioctl(RTC_PIE_ON)");
close(g_fd);
exit(errno);
}
}

void rtc_task()
{
printf("start counting...\n");
struct timeval tvs,tve;
unsigned long i = 0;
unsigned long data = 0;
while(true)
{
int time_to_wait;
printf("please input time to wait in millsecond, -1 to break\n");
scanf("%d",&time_to_wait);
if(time_to_wait < 0)
break;
//calc how many times to loop
int cnt = calc_cnt(time_to_wait);
gettimeofday( &tvs , 0 );
for(i = 0; i < cnt; i++)
{
if(read(g_fd, &data, sizeof(unsigned long)) < 0)
{
perror("read");
ioctl(g_fd, RTC_PIE_OFF, 0);
close(g_fd);
exit(errno);
}
}
gettimeofday(&tve,0);
printf("[%ld]timer usec\n" , (tve.tv_sec - tvs.tv_sec) * 1000000LL + (tve.tv_usec-tvs.tv_usec));
}
/* Disable periodic interrupts */
ioctl(g_fd, RTC_PIE_OFF, 0);
close(g_fd);
}

int main(int argc, char* argv[])
{
rtc_open();
set_freq();
rtc_task();
return 0;
}
例子采用的频率是2048,频率可用范围是2~8192,一定要是2的n次方,否则会运行时错误,频率代表一秒中可以执行多少次,如果是2048次,那么一次的时间就是1.0/2048(秒),由此来确定time to wait 时间需要执行多少次。