在arch/arm/plat-samsung/Devs.c文件内,系统定义了RTC平台设备及其资源:

static struct resource s3c_rtc_resource[] = {

[0]= DEFINE_RES_MEM(S3C24XX_PA_RTC,SZ_256),

[1]= DEFINE_RES_IRQ(IRQ_RTC),

[2]= DEFINE_RES_IRQ(IRQ_TICK),

};

struct platform_device s3c_device_rtc = {

.name = "s3c2410-rtc",

.id = -1,

.num_resources = ARRAY_SIZE(s3c_rtc_resource),

.resource = s3c_rtc_resource,

};

因为RTC一共有两个中断源:报警中断和时间节拍中断,所以RTC资源中也相应的定义了两个中断——IRQ_RTC和IRQ_TICK。在arch/arm/mach-s3c24xx/Mach-zhaocj2440.c文件内,系统把RTC平台设备添加到了zhaocj2440_devices数组内:

static struct platform_device *zhaocj2440_devices[]__initdata = {

……

&s3c_device_rtc,

……

};

最后在zhaocj2440_init函数内,通过下列语句把RTC平台设备添加到了总线内:

platform_add_devices(zhaocj2440_devices,ARRAY_SIZE(zhaocj2440_devices));

上面介绍的是RTC平台设备,而它的平台驱动是在drivers/rtc/Rtc-s3c.c文件内定义的:

static struct platform_driver s3c_rtc_driver = {

.probe = s3c_rtc_probe,

.remove = __devexit_p(s3c_rtc_remove),

.suspend = s3c_rtc_suspend,

.resume = s3c_rtc_resume,

.id_table = s3c_rtc_driver_ids,

.driver = {

.name = "s3c-rtc",

.owner = THIS_MODULE,

.of_match_table = s3c_rtc_dt_match,

},

};

由于定义了RTC平台设备列表s3c_rtc_driver_ids,因此平台驱动通过这个列表与平台设备相互匹配:

static struct platform_device_id s3c_rtc_driver_ids[] = {

{

.name = "s3c2410-rtc",

.driver_data = TYPE_S3C2410,

},{

.name = "s3c2416-rtc",

.driver_data = TYPE_S3C2416,

},{

.name = "s3c2443-rtc",

.driver_data = TYPE_S3C2443,

},{

.name = "s3c64xx-rtc",

.driver_data = TYPE_S3C64XX,

},

{}

};

在上面这个列表中,有s3c2410-rtc,因此RTC设备与驱动匹配上了。下面我们再来看看s3c_rtc_probe函数:

static int __devinit s3c_rtc_probe(struct platform_device *pdev)

{

structrtc_device *rtc;

structrtc_time rtc_tm;

structresource *res;

intret;

inttmp;

pr_debug("%s:probe=%p\n", __func__, pdev);

/*find the IRQs */

//得到RTC的时间节拍中断号

s3c_rtc_tickno = platform_get_irq(pdev,1);

if(s3c_rtc_tickno < 0) {

dev_err(&pdev->dev,"no irq for rtc tick\n");

return-ENOENT;

}

//得到RTC的报警中断号

s3c_rtc_alarmno = platform_get_irq(pdev,0);

if(s3c_rtc_alarmno < 0) {

dev_err(&pdev->dev, "no irqfor alarm\n");

return-ENOENT;

}

pr_debug("s3c2410_rtc: tick irq %d, alarm irq%d\n",

s3c_rtc_tickno,s3c_rtc_alarmno);

/*get the memory region */

//得到RTC的内存资源

res= platform_get_resource(pdev, IORESOURCE_MEM, 0);

if(res == NULL) {

dev_err(&pdev->dev,"failed to get memory region resource\n");

return-ENOENT;

}

//申请内存资源

s3c_rtc_mem =request_mem_region(res->start, resource_size(res),

pdev->name);

if(s3c_rtc_mem == NULL) {

dev_err(&pdev->dev,"failed to reserve memory region\n");

ret= -ENOENT;

gotoerr_nores;

}

//将内存重新映射

s3c_rtc_base = ioremap(res->start,resource_size(res));

if(s3c_rtc_base == NULL) {

dev_err(&pdev->dev,"failed ioremap()\n");

ret= -EINVAL;

gotoerr_nomap;

}

//得到RTC的时钟信号

rtc_clk= clk_get(&pdev->dev, "rtc");

if(IS_ERR(rtc_clk)) {

dev_err(&pdev->dev,"failed to find rtc clock source\n");

ret = PTR_ERR(rtc_clk);

rtc_clk = NULL;

goto err_clk;

}

//RTC时钟信号有效

clk_enable(rtc_clk);

/* check to seeif everything is setup correctly */

//使能RTC,并对RTCCON寄存器进行设置;如果该函数的第二个参数为0,则无效RTC

s3c_rtc_enable(pdev, 1);

pr_debug("s3c2410_rtc: RTCCON=%02x\n",

readw(s3c_rtc_base+ S3C2410_RTCCON));

//唤醒RTC设备

device_init_wakeup(&pdev->dev,1);

/*register RTC and exit */

//注册RTC类

rtc= rtc_device_register("s3c",&pdev->dev, &s3c_rtcops,

THIS_MODULE);

if(IS_ERR(rtc)) {

dev_err(&pdev->dev,"cannot attach rtc\n");

ret= PTR_ERR(rtc);

gotoerr_nortc;

}

//得到当前CPU的类型,因为该驱动是通用的,也适用于其他s3c类型的处理器

s3c_rtc_cpu_type = s3c_rtc_get_driver_data(pdev);

/*Check RTC Time */

//得到RTC的当前时间

s3c_rtc_gettime(NULL, &rtc_tm);

//如果RTC的当前时间无效,则重新设置

if(rtc_valid_tm(&rtc_tm)) {

rtc_tm.tm_year = 100;

rtc_tm.tm_mon = 0;

rtc_tm.tm_mday = 1;

rtc_tm.tm_hour = 0;

rtc_tm.tm_min = 0;

rtc_tm.tm_sec = 0;

//设置RTC当前时间

s3c_rtc_settime(NULL, &rtc_tm);

dev_warn(&pdev->dev,"warning: invalid RTC value so initializing it\n");

}

//依据CPU的类型,设置RTC节拍

if(s3c_rtc_cpu_type != TYPE_S3C2410)

rtc->max_user_freq= 32768;

else

rtc->max_user_freq= 128;

if(s3c_rtc_cpu_type == TYPE_S3C2416 || s3c_rtc_cpu_type == TYPE_S3C2443) {

tmp= readw(s3c_rtc_base + S3C2410_RTCCON);

tmp|= S3C2443_RTCCON_TICSEL;

writew(tmp,s3c_rtc_base + S3C2410_RTCCON);

}

//保存平台总线设备的私有数据,

platform_set_drvdata(pdev, rtc);

//设置TICNT寄存器

s3c_rtc_setfreq(&pdev->dev, 1);

//申请RTC报警中断

ret= request_irq(s3c_rtc_alarmno,s3c_rtc_alarmirq,

0, "s3c2410-rtcalarm", rtc);

if(ret) {

dev_err(&pdev->dev,"IRQ%d error %d\n", s3c_rtc_alarmno,ret);

gotoerr_alarm_irq;

}

//申请RTC时间节拍中断

ret= request_irq(s3c_rtc_tickno,s3c_rtc_tickirq,

0, "s3c2410-rtctick", rtc);

if(ret) {

dev_err(&pdev->dev,"IRQ%d error %d\n", s3c_rtc_tickno,ret);

free_irq(s3c_rtc_alarmno, rtc);

gotoerr_tick_irq;

}

//RTC时钟无效

clk_disable(rtc_clk);

return0;

err_tick_irq:

free_irq(s3c_rtc_alarmno, rtc);

err_alarm_irq:

platform_set_drvdata(pdev,NULL);

rtc_device_unregister(rtc);

err_nortc:

s3c_rtc_enable(pdev, 0);

clk_disable(rtc_clk);

clk_put(rtc_clk);

err_clk:

iounmap(s3c_rtc_base);

err_nomap:

release_resource(s3c_rtc_mem);

err_nores:

returnret;

}

下面介绍一下2440的RTC操作集——s3c_rtcops:

static const struct rtc_class_ops s3c_rtcops = {

.read_time = s3c_rtc_gettime, //读取当前时间

.set_time = s3c_rtc_settime, //设置当前时间

.read_alarm = s3c_rtc_getalarm, //读取报警时间

.set_alarm = s3c_rtc_setalarm, //设置报警时间

.proc = s3c_rtc_proc,

.alarm_irq_enable= s3c_rtc_setaie, //用于设置RTCALM寄存器

};

在上面介绍过的s3c_rtc_probe函数内,用到了rtc_device_register函数来注册RTC设备,该函数在drivers/rtc/Class.c文件内被定义。Class.c文件主要定义了RTC子系统。在该文件中,有:

subsys_initcall(rtc_init);

说明系统启动后会执行rtc_init函数:

static int __init rtc_init(void)

{

//创建RTC子类

rtc_class= class_create(THIS_MODULE, "rtc");

if(IS_ERR(rtc_class)) {

printk(KERN_ERR"%s: couldn't create class\n", __FILE__);

returnPTR_ERR(rtc_class);

}

rtc_class->suspend= rtc_suspend;

rtc_class->resume= rtc_resume;

//RTC设备初始化

rtc_dev_init();

rtc_sysfs_init(rtc_class);

return0;

}

上面函数中的rtc_dev_init函数是在drivers/rtc/Rtc-dev.c文件内定义的:

void __init rtc_dev_init(void)

{

interr;

//申请一个字符设备,RTC也是一个字符设备

err= alloc_chrdev_region(&rtc_devt, 0, RTC_DEV_MAX, "rtc");

if(err < 0)

printk(KERN_ERR"%s: failed to allocate char dev region\n",

__FILE__);

}

通过上面分析可看出,系统启动后会自动申请RTC,而具体的注册该设备是靠前面提到的rtc_device_register函数来完成的。我们再来看看这个函数:

struct rtc_device*rtc_device_register(const char *name, struct device *dev,

conststruct rtc_class_ops *ops,

structmodule *owner)

{

structrtc_device *rtc;

structrtc_wkalrm alrm;

intid, err;

//得到一个新的ID

id= ida_simple_get(&rtc_ida, 0, 0, GFP_KERNEL);

if(id < 0) {

err= id;

gotoexit;

}

//为RTC设备分配一块内存,并清零

rtc= kzalloc(sizeof(struct rtc_device), GFP_KERNEL);

if(rtc == NULL) {

err= -ENOMEM;

gotoexit_ida;

}

//为RTC设备赋值

rtc->id= id;

rtc->ops= ops;

rtc->owner= owner;

rtc->irq_freq= 1;

rtc->max_user_freq= 64;

rtc->dev.parent= dev;

rtc->dev.class= rtc_class;

rtc->dev.release= rtc_device_release;

mutex_init(&rtc->ops_lock);

spin_lock_init(&rtc->irq_lock);

spin_lock_init(&rtc->irq_task_lock);

init_waitqueue_head(&rtc->irq_queue);

/* Init timerqueue */

//初始化定时器队列

timerqueue_init_head(&rtc->timerqueue);

//在rtc->irqwork队列中添加rtc_timer_do_work任务,也就是当程序出现schedule_work(&rtc->irqwork)这个语句中,实际是调用的rtc_timer_do_work函数

INIT_WORK(&rtc->irqwork,rtc_timer_do_work);

/*Init aie timer */

rtc_timer_init(&rtc->aie_timer,rtc_aie_update_irq, (void *)rtc);

/*Init uie timer */

rtc_timer_init(&rtc->uie_rtctimer,rtc_uie_update_irq, (void *)rtc);

/* Init pie timer */

hrtimer_init(&rtc->pie_timer,CLOCK_MONOTONIC, HRTIMER_MODE_REL);

rtc->pie_timer.function = rtc_pie_update_irq;

rtc->pie_enabled= 0;

/*Check to see if there is an ALARM already set in hw */

//检查是否硬件已发生了报警

err= __rtc_read_alarm(rtc, &alrm);

if(!err && !rtc_valid_tm(&alrm.time))

rtc_initialize_alarm(rtc,&alrm);

strlcpy(rtc->name,name, RTC_DEVICE_NAME_SIZE);

dev_set_name(&rtc->dev,"rtc%d", id);

rtc_dev_prepare(rtc);

//注册RTC设备

err= device_register(&rtc->dev);

if(err) {

put_device(&rtc->dev);

gotoexit_kfree;

}

rtc_dev_add_device(rtc);

//在sysfs文件系统中添加RTC设备

rtc_sysfs_add_device(rtc);

//在proc文件系统中添加RTC设备

rtc_proc_add_device(rtc);

dev_info(dev,"rtc core: registered %s as %s\n",

rtc->name,dev_name(&rtc->dev));

returnrtc;

exit_kfree:

kfree(rtc);

exit_ida:

ida_simple_remove(&rtc_ida,id);

exit:

dev_err(dev,"rtc core: unable to register %s, err = %d\n",

name,err);

returnERR_PTR(err);

}

在上面的函数中用到了rtc_dev_prepare和rtc_dev_add_device函数,这两个函数都是在drivers/rtc/Rtc-dev.c文件内定义的:

void rtc_dev_prepare(struct rtc_device*rtc)

{

if(!rtc_devt)

return;

//RTC设备不能多于16个

if(rtc->id >= RTC_DEV_MAX) {

pr_debug("%s:too many RTC devices\n", rtc->name);

return;

}

rtc->dev.devt= MKDEV(MAJOR(rtc_devt), rtc->id);

#ifdef CONFIG_RTC_INTF_DEV_UIE_EMUL

INIT_WORK(&rtc->uie_task,rtc_uie_task);

setup_timer(&rtc->uie_timer,rtc_uie_timer, (unsigned long)rtc);

#endif

//初始化字符设备结构

cdev_init(&rtc->char_dev,&rtc_dev_fops);

rtc->char_dev.owner= rtc->owner;

}

voidrtc_dev_add_device(struct rtc_device *rtc)

{

//为系统添加RTC字符设备

if (cdev_add(&rtc->char_dev,rtc->dev.devt, 1))

printk(KERN_WARNING"%s: failed to add char device %d:%d\n",

rtc->name,MAJOR(rtc_devt), rtc->id);

else

pr_debug("%s:dev (%d:%d)\n", rtc->name,

MAJOR(rtc_devt),rtc->id);

}

在rtc_dev_prepare函数中提到了rtc_dev_fops,它就是RTC的操作集:

static const struct file_operationsrtc_dev_fops = {

.owner = THIS_MODULE,

.llseek = no_llseek,

.read = rtc_dev_read,

.poll = rtc_dev_poll,

.unlocked_ioctl = rtc_dev_ioctl,

.open = rtc_dev_open,

.release = rtc_dev_release,

.fasync = rtc_dev_fasync,

};

我们在这里只分析rtc_dev_ioctl函数:

static long rtc_dev_ioctl(struct file*file,

unsignedint cmd, unsigned long arg)

{

interr = 0;

structrtc_device *rtc = file->private_data;

conststruct rtc_class_ops *ops = rtc->ops;

structrtc_time tm;

structrtc_wkalrm alarm;

void __user *uarg = (void __user*) arg;

err =mutex_lock_interruptible(&rtc->ops_lock);

if(err)

return err;

/*check that the calling task has appropriate permissions

* for certain ioctls. doing this check here iSUSEful

* to avoid duplicate code in each driver.

*/

//对有些命令先进行预处理,如果不符合要求,就提前退出

switch(cmd) {

caseRTC_EPOCH_SET:

caseRTC_SET_TIME:

if(!capable(CAP_SYS_TIME))

err= -EACCES;

break;

caseRTC_IRQP_SET:

if(arg > rtc->max_user_freq && !capable(CAP_SYS_RESOURCE))

err= -EACCES;

break;

caseRTC_PIE_ON:

if(rtc->irq_freq > rtc->max_user_freq &&

!capable(CAP_SYS_RESOURCE))

err= -EACCES;

break;

}

if(err)

gotodone;

/*

* Drivers *SHOULD NOT* provide ioctlimplementations

* for these requests. Instead, provide methods to

* support the following code, so that theRTC's main

* features are accessible without usingioctls.

*

* RTC and alarm times will be in UTC, bypreference,

* but dual-booting with MS-Windows impliesRTCs must

* use the local wall clock time.

*/

switch(cmd) {

caseRTC_ALM_READ: //读报警时间

mutex_unlock(&rtc->ops_lock);

//读取报警时间,最终调用的是Rtc-s3c.c文件中的s3c_rtc_getalarm函数

err= rtc_read_alarm(rtc, &alarm);

if(err < 0)

returnerr;

if(copy_to_user(uarg, &alarm.time, sizeof(tm)))

err= -EFAULT;

returnerr;

caseRTC_ALM_SET: //设置报警时间

mutex_unlock(&rtc->ops_lock);

if(copy_from_user(&alarm.time, uarg, sizeof(tm)))

return-EFAULT;

alarm.enabled= 0;

alarm.pending= 0;

alarm.time.tm_wday= -1;

alarm.time.tm_yday= -1;

alarm.time.tm_isdst= -1;

/*RTC_ALM_SET alarms may be up to 24 hours in the future.

* Rather than expecting every RTC to implement"don't care"

* for day/month/year fields, just force thealarm to have

* the right values for those fields.

*

* RTC_WKALM_SET should be used instead. Not only does it

* eliminate the need for a separate RTC_AIE_ONcall, it

* doesn't have the "alarm 23:59:59 in the future" race.

*

* NOTE: some legacy code may have used invalid fields as

* wildcards, exposing hardware "periodicalarm" capabilities.

* Not supported here.

*/

{

unsignedlong now, then;

//读取当前时间,最终调用的是Rtc-s3c.c文件中的s3c_rtc_gettime函数

err= rtc_read_time(rtc, &tm);

if(err < 0)

returnerr;

//转换当前时间格式

rtc_tm_to_time(&tm,&now);

alarm.time.tm_mday= tm.tm_mday;

alarm.time.tm_mon = tm.tm_mon;

alarm.time.tm_year= tm.tm_year;

err = rtc_valid_tm(&alarm.time);

if(err < 0)

returnerr;

//转换报警时间格式

rtc_tm_to_time(&alarm.time,&then);

/*alarm may need to wrap into tomorrow */

//比较报警时间和当前时间,如果报警时间小于当前时间,则设置第二天的同一时间报警

if(then < now) {

rtc_time_to_tm(now+ 24 * 60 * 60, &tm);

alarm.time.tm_mday= tm.tm_mday;

alarm.time.tm_mon = tm.tm_mon;

alarm.time.tm_year = tm.tm_year;

}

}

//设置报警时间,最终调用的是Rtc-s3c.c文件中的s3c_rtc_setalarm函数

returnrtc_set_alarm(rtc, &alarm);

caseRTC_RD_TIME: //读取RTC时间

mutex_unlock(&rtc->ops_lock);

//读取当前时间,最终调用的是Rtc-s3c.c文件中的s3c_rtc_gettime函数

err= rtc_read_time(rtc, &tm);

if(err < 0)

returnerr;

if(copy_to_user(uarg, &tm, sizeof(tm)))

err= -EFAULT;

returnerr;

caseRTC_SET_TIME: //设置RTC时间

mutex_unlock(&rtc->ops_lock);

if(copy_from_user(&tm, uarg, sizeof(tm)))

return-EFAULT;

//设置RTC时间,最终调用的是Rtc-s3c.c文件中的s3c_rtc_settime函数

returnrtc_set_time(rtc, &tm);

caseRTC_PIE_ON:

err= rtc_irq_set_state(rtc, NULL, 1);

break;

caseRTC_PIE_OFF:

err= rtc_irq_set_state(rtc, NULL, 0);

break;

caseRTC_AIE_ON: //报警中断有效

mutex_unlock(&rtc->ops_lock);

//设置报警中断,最终调用的是Rtc-s3c.c文件中的s3c_rtc_setaie函数

returnrtc_alarm_irq_enable(rtc, 1);

caseRTC_AIE_OFF: //报警中断无效

mutex_unlock(&rtc->ops_lock);

returnrtc_alarm_irq_enable(rtc, 0);

caseRTC_UIE_ON:

mutex_unlock(&rtc->ops_lock);

returnrtc_update_irq_enable(rtc, 1);

caseRTC_UIE_OFF:

mutex_unlock(&rtc->ops_lock);

returnrtc_update_irq_enable(rtc, 0);

caseRTC_IRQP_SET:

err= rtc_irq_set_freq(rtc, NULL, arg);

break;

caseRTC_IRQP_READ:

err= put_user(rtc->irq_freq, (unsigned long __user *)uarg);

break;

#if 0

caseRTC_EPOCH_SET:

#ifndef rtc_epoch

/*

* There were no RTC clocks before 1900.

*/

if(arg < 1900) {

err= -EINVAL;

break;

}

rtc_epoch= arg;

err= 0;

#endif

break;

caseRTC_EPOCH_READ:

err= put_user(rtc_epoch, (unsigned long __user *)uarg);

break;

#endif

caseRTC_WKALM_SET:

mutex_unlock(&rtc->ops_lock);

if(copy_from_user(&alarm, uarg, sizeof(alarm)))

return-EFAULT;

returnrtc_set_alarm(rtc, &alarm);

caseRTC_WKALM_RD:

mutex_unlock(&rtc->ops_lock);

err= rtc_read_alarm(rtc, &alarm);

if(err < 0)

returnerr;

if(copy_to_user(uarg, &alarm, sizeof(alarm)))

err= -EFAULT;

returnerr;

default:

/*Finally try the driver's ioctl interface */

if(ops->ioctl) {

err= ops->ioctl(rtc->dev.parent, cmd, arg);

if(err == -ENOIOCTLCMD)

err= -ENOTTY;

}else

err= -ENOTTY;

break;

}

done:

mutex_unlock(&rtc->ops_lock);

returnerr;

}

驱动介绍完了,下面介绍应用。

系统的默认配置已经添加了RTC的部分,因此不用再修改,而且当系统启动后,会读取RTC中的时钟,以更新同步系统时间。

系统启动后,从打印出的信息来看,RTC已加载:

s3c-rtc s3c2410-rtc: rtc disabled, re-enabling

s3c-rtc s3c2410-rtc: rtc core: registered s3c as rtc0

s3c-rtc s3c2410-rtc: warning: invalid RTC value so initializingit

并且还有下面一句:

s3c-rtcs3c2410-rtc: setting systemclock to 2000-01-01 00:00:00 UTC (946684800)

说明系统已进行了时钟同步。

系统启动后,我们可以通过命令来查看系统的时间:

[root@zhaocj/]#date

SatJan 1 00:01:04 UTC 2000

下面我们就写一段应用程序来查看和修改RTC时间:

/**************

***mydate.c***

**************/

#include

#include

#include

#include

#include

#include

#include

#include

#include

intmain(int argc, char **argv)

{

int fd, retval;

struct rtc_time rtc_tm;

fd = open("/dev/rtc0", O_RDONLY);

if (fd == -1) {

perror("/dev/rtc0");

exit(errno);

}

printf("\n\tRTC Driver Test Example.\n");

if(argc == 1)

goto test_READ;

if(argc !=7)

{

printf( "wrong!\n");

return 1;

}

//为时间变量赋值

//要把字符串转换成整型

//年和月比较特殊

rtc_tm.tm_year =atoi(argv[1])-1900;

rtc_tm.tm_mon=atoi(argv[2])-1;;

rtc_tm.tm_mday=atoi(argv[3]);

rtc_tm.tm_hour=atoi(argv[4]);

rtc_tm.tm_min=atoi(argv[5]);

rtc_tm.tm_sec=atoi(argv[6]);

retval = ioctl(fd, RTC_SET_TIME, &rtc_tm); //设置RTC时间

if (retval == -1) {

perror("RTC_RD_TIME ioctl");

exit(errno);

}

test_READ:

retval = ioctl(fd, RTC_RD_TIME, &rtc_tm); //读取RTC时间

if (retval == -1) {

perror("RTC_RD_TIME ioctl");

exit(errno);

}

printf("\nCurrent RTC date/time is %d-%d-%d, %02d:%02d:%02d.\n",

rtc_tm.tm_year + 1900, rtc_tm.tm_mon + 1,rtc_tm.tm_mday,

rtc_tm.tm_hour, rtc_tm.tm_min, rtc_tm.tm_sec);

done:

printf("\n\t *** Test complete ***\n");

close(fd);

return 0;

}

编译后下载到temp目录下,运行:

[root@zhaocj/temp]#./mydate

RTC Driver Test Example.

CurrentRTC date/time is 2000-1-1, 0:20:31.

*** Test complete ***

如果mydate没有带参数,表示只读取RTC时间。

[root@zhaocj/temp]#./mydate 2013 7 12 11 29 30

RTC Driver Test Example.

CurrentRTC date/time is 2013-7-12, 11:29:30.

*** Test complete ***

如果mydate带有表示年、月、日、时、分、秒的参数,则表示设置RTC时间。

下面我们再一段应用RTC报警中断的应用程序:

/***************

***myalm.c***

***************/

#include

#include

#include

#include

#include

#include

#include

#include

#include

intmain(int argc, char **argv)

{

int fd, retval;

unsigned long data;

struct rtc_time rtc_tm;

fd = open("/dev/rtc0",O_RDONLY);

if (fd == -1) {

perror("/dev/rtc0");

exit(errno);

}

printf("\nt\tRTC Driver TestExample.\n");

retval = ioctl(fd, RTC_RD_TIME,&rtc_tm); //读取当前时间

if (retval == -1) {

perror("RTC_RD_TIMEioctl");

exit(errno);

}

printf("\nCurrent RTC date/time is%d-%d-%d, %02d:%02d:%02d.\n",

rtc_tm.tm_year + 1900,rtc_tm.tm_mon + 1,rtc_tm.tm_mday,

rtc_tm.tm_hour, rtc_tm.tm_min,rtc_tm.tm_sec);

rtc_tm.tm_sec += 5; // 设置5秒后报警

//时间溢出调整

if (rtc_tm.tm_sec >= 60) {

rtc_tm.tm_sec %= 60;

rtc_tm.tm_min++;

}

if (rtc_tm.tm_min == 60) {

rtc_tm.tm_min = 0;

rtc_tm.tm_hour++;

}

if (rtc_tm.tm_hour == 24)

rtc_tm.tm_hour= 0;

retval = ioctl(fd, RTC_ALM_SET,&rtc_tm); //设置RTC报警时间

if (retval == -1) {

if (errno == ENOTTY) {

fprintf(stderr,"\n...AlarmIRQs not supported.\n");

}

perror("RTC_ALM_SETioctl");

exit(errno);

}

retval = ioctl(fd, RTC_ALM_READ,&rtc_tm); //读取报警时间

if (retval == -1) {

perror("RTC_ALM_READioctl");

exit(errno);

}

fprintf(stderr, "Alarm time now setto %02d:%02d:%02d.\n",

rtc_tm.tm_hour, rtc_tm.tm_min,rtc_tm.tm_sec);

retval = ioctl(fd, RTC_AIE_ON, 0); //使能RTC报警中断

if (retval == -1) {

perror("RTC_AIE_ONioctl");

exit(errno);

}

fprintf(stderr, "Waiting 5 secondsfor alarm...");

/* This blocks until the alarm ring causes an interrupt */

retval = read(fd, &data,sizeof(unsigned long)); //等待RTC报警中断的发生

if (retval == -1) {

perror("read");

exit(errno);

}

fprintf(stderr, " okay. Alarmrang.\n");

retval = ioctl(fd, RTC_AIE_OFF, 0); //关闭RTC报警

if (retval == -1) {

perror("RTC_AIE_OFFioctl");

exit(errno);

}

printf("\n\t\t *** Test complete ***\n");

close(fd);

return 0;

}

[root@zhaocj/temp]#./myalm

RTC Driver Test Example.

CurrentRTC date/time is 2013-7-12, 12:48:23.

Alarmtime now set to 12:48:28.

Waiting5 seconds for alarm... okay. Alarm rang.

*** Test complete ***

由于系统的RTC报警中断只能是24小时内,因此不能设置RTC报警中断的年、月、日。

s3c2416运行JAVA_实时时钟RTC - 基于S3C2440的Linux-3.6.6移植_Linux编程_Linux公社-Linux系统门户网站...相关推荐

  1. STM32学习心得二十一:实时时钟RTC和备份寄存器BKP特征、原理及相关实验代码解读

    记录一下,方便以后翻阅~ 主要内容 1) RTC特征与原理: 2) BKP备份寄存器特征与原理: 3) RTC常用寄存器+库函数介绍: 4) 相关实验代码解读. 实验内容: 因为没有买LCD屏,所以计 ...

  2. 【嵌入式】MSP430系统实时时钟RTC学习日志(完善中)

    目录 MSP430系统实时时钟RTC [时钟初始化]系统时钟初始化需要注意的问题 MSP430F149时钟源选择(部分转) MSP430 系统时钟 ACLK.MCLK.SMCLK [MSP430时钟] ...

  3. stm32之实时时钟RTC(掉电计时保持、秒中断、闹钟中断、溢出中断)

    前言:stm32系列产品普遍都有实时时钟RTC模块,它提供一个掉电保持计时功能,掉电后由后备供电区域供电.除了提供时间和日期之外,还可以设置闹钟提醒,且可以在待机模式下设置闹钟唤醒系统.在一些小容量. ...

  4. ESP8266-Arduino编程实例-PCF8563实时时钟(RTC)驱动

    PCF8563实时时钟(RTC)驱动 1.PCF8563介绍 PCF8563 是针对低功耗优化的 CMOS 实时时钟 (RTC) 和日历. 还提供了可编程时钟输出.中断输出和低电压检测器. 所有地址和 ...

  5. 【STM32学习】实时时钟 —— RTC

    [STM32学习]实时时钟 -- RTC 零.参考 一.工作原理 1.RTC介绍 2.工作过程 二.相关寄存器 三.代码说明 1.rtc初始化 2.关于中断 3.中断配置代码(仅供参考) 3.1 秒中 ...

  6. linux设备树例程,iTOP-iMX6-设备树内核-实时时钟RTC以及Linux-c测试例程

    当 Linux 开发者谈论一个实时时钟,他们通常指的是某种能记录墙上时间,并且有备用电 池,以至于在系统关机的时候仍然可以工作的器件. Linux 有两个系列广泛兼容的用户空间 RTC 设备节点: • ...

  7. ESP32设备驱动-DS3231实时时钟(RTC)驱动

    DS3231实时时钟(RTC)驱动 1.DS3231介绍 DS3231 是一款低成本.极其精确的 I2C 实时时钟 (RTC),具有集成的温度补偿晶体振荡器 (TCXO) 和晶体. 该设备包含电池输入 ...

  8. imx6 linux 时钟,迅为-iMX6开发板-驱动-实时时钟RTC以及Linux-c测试例程

    当Linux开发者谈论一个实时时钟,他们通常指的是某种能记录墙上时间,并且有备用电 池,以至于在系统关机的时候仍然可以工作的器件. Linux 有两个系列广泛兼容的用户空间 RTC 设备节点: /de ...

  9. 以太网卡驱动程序移植linux,基于S3C2440的DM9000网卡驱动的移植

    摘  要: 主要研究了基于Linux内核的网卡驱动的移植.Linux网络设备驱动程序的体系结构可以分为4层,首先分析了各层的具体功能实现,并在此基础上充分利用S3C2440开发板完成DM9000网卡驱 ...

  10. 了解实时时钟RTC的原理并通过stm32实现STM32的日历读取、设置和输出

    文章目录 前言 一.RTC是什么? 1.定义 2.原理 二.配置项目 三.配置代码 1.重定向printf函数 2.效果(1) 3.添加星期 4.效果(2) 四.总结 五.参考资料 前言 硬件:stm ...

最新文章

  1. Python检查系统可疑用户
  2. linux进程 面试题,Linux面试题,浅析常见Linux命令面试题及答案
  3. Powershell 查看软件是否成功安装
  4. CF603E-Pastoral Oddities【CDQ分治,可撤销并查集】
  5. idea 升级到2020后 无法启动_升级iOS 14尝鲜后,无法降级 iOS13.5.1?
  6. 上班族如何当老板 五大模式任你选
  7. zabbix3.2通过snmp v2采集Dell服务器iDRAC口信息监控硬件
  8. 20160220 - JavaScript for OS X Automation 调试技巧
  9. JDY-24M级蓝牙简介
  10. python生成泊松分布_Python Numpy泊松分布
  11. 项目管理到底是一个什么样的职位,具体都做些什么事情?
  12. Coreset-Based Neural Network Compression简记
  13. Word 2003 视频教程(转)
  14. ARM——开发工具—编译器
  15. 使用Python发送邮件(QQ邮箱为例)
  16. JQuery入门(1) - 选择器
  17. ubuntu 误使用dpkg --clear-selections修复
  18. 无线电监测,适用带宽总结,信号分析代表信号频段
  19. Python 打印阿姆斯特朗数
  20. 菜鸟教程java的list_Java菜鸟教程

热门文章

  1. 原来PDF解密有这么多方法,你知道几个?
  2. 闲聊人工智能产品经理(AIPM)—定义人工智能产品经理
  3. 【电脑控制手机屏幕】windows11、10自带投屏功能,三步解决
  4. 带大家认识下Kvaser CAN总线协议
  5. ps cc 2014 智能切图
  6. 海康/大华/华为等摄像头或者录像机无法通过GB28181注册到国标平台LiveGBS的问题排查方法...
  7. SILVACO 学习笔记第一章
  8. mac电脑投屏到小米盒子_电脑投屏到小米盒子
  9. Java解析JSON,按规则获取JSON节点内容
  10. java 淘口令_简单实现淘口令