目录
本例程将在鸭嘴兽wifi音视频开发板上学习操作RTC实时时钟。
准备工作:
wifi音视频开发板一块
N32905内部集成RTC模块,外接32.768KHz的晶振给RTC模块提供时钟源,RTC主要用于给Linux系统提供时间,还可以用于计时和定时。RTC因为是电池供电,当linux系统停止工作后或者掉电,RTC模块仍会继续运行,时间不丢失,依旧还可以给linux提供准确的系统时间。
2.软件设计
2.1 内核配置
以下几步操作是在内核配置菜单中选择支持RTC驱动,首先进入/duckbill/N32905/BSP/linux-2.6.17.14_fa93路径,在命令行执行make menuconfig,进入内核配置主菜单,光标移至Device Drivers并按enter键进入下一级菜单。
光标移至Real Time Clock,按enter键进入下一级菜单。
选择RTC class、sysfs、proc、dev、Nuvotun W55FA93编译进内核。
最后在命令行输入./build spiramfs,按enter键就开始编译内核,内核生成路径在/duckbill/N32905/BSP/image/Kernel.bin.
2.2 RTC应用程序分析
代码路径:/duckbill/N32905/BSP/applications/rtc/rtc.c。rtc代码如下。
/*
* RTC(Real Time Clock) application Program
*
*/
#include <stdio.h>
#include <linux/rtc.h>
#include <sys/ioctl.h>
#include <sys/time.h>
#include <sys/types.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <math.h>
#include <signal.h>
#define RTC_TICK_ON _IO('p', 0x03) /* Update int. enable on */
#define RTC_TICK_OFF _IO('p', 0x04) /* ... off */
#define RTC_TICK_SET _IO('p', 0x05) /* Periodic int. enable on */
#define RTC_TICK_READ _IO('p', 0x06) /* ... off */
#define HR24 1
int fd_all=0;
void alarm_func(){
printf("\n\n*Alarm interrupt come on,the func running!*\n");
}
void ctrl_c_signal (int sig)
{
switch (sig){
printf("/n/n **You have input 'ctrl+c',so must be input 'X' exit DEMO!\n\n");
case SIGTERM:
case SIGINT:
/* Disable alarm interrupts */
ioctl(fd_all, RTC_AIE_OFF, 0);
ioctl(fd_all, RTC_TICK_OFF, 0);
close(fd_all);
return ;
break;
default:
printf ("What?\n");
}
}
//函数功能:设置当前RTC时间
//输入参数:fd:RTC文件描述符
//返回值:空
void setup_time(int fd){
int i,retval;
unsigned long tmp, data;
struct rtc_time rtc_tm;
int scale_type = HR24;
struct rtc_wkalrm rtc_alarmtm;
int ret;
static char year[4], month[4],day[4],hour[4],min[4],sec[4];
printf("Input the adjust time:\n");
printf("You should input 6 words,and must be 'enter' per word!\n");
printf("->year->month->day->hour->min->sec\n");
scanf("%s %s %s %s %s %s", year, month,day,hour,min,sec); //获取年月日时分秒
printf("You input the time is:%s/%s/%s/ %s:%s:%s\n\n", year, month,day,hour,min,sec);
rtc_tm.tm_year = atoi(year) - 1900; //依次将年月日时分秒赋值给结构体rtc_tm
rtc_tm.tm_mon = atoi(month) - 1;
rtc_tm.tm_mday = atoi(day);
rtc_tm.tm_hour = atoi(hour);
rtc_tm.tm_min = atoi(min);
rtc_tm.tm_sec = atoi(sec);
retval = ioctl(fd, RTC_SET_TIME, &rtc_tm); //设置RTC,RTC时间将更新
if (retval <0) {
printf("ioctl RTC_SET_TIME faild!!!\n");
return ;
}
/*print current time*/
printf("Adjust current RTC time as: %04d-%02d-%02d %02d:%02d:%02d\n\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);
printf("Adjust current RTC time test OK!\n");
}
//函数功能:读取当前RTC时间
//输入参数:fd:RTC文件描述符
//返回值:空
void read_time(int fd){
int i,retval;
unsigned long tmp, data;
struct rtc_time rtc_tm;
int scale_type = HR24;
struct rtc_wkalrm rtc_alarmtm;
/*read current time*/
retval=ioctl(fd,RTC_RD_TIME,&rtc_tm); //读取RTC时间,保存在结构体rtc_tm中
if (retval <0) {
printf("ioctl RTC_RD_TIME faild!!!\n");
return ;
}
/*print current time*/
printf("Read current RTC time is: %04d-%02d-%02d %02d:%02d:%02d\n\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);
printf("Read current RTC time test OK!\n");
}
//函数功能:设置RTC闹钟时间
//输入参数:fd:RTC文件描述符
// sec:RTC闹钟时间,即sec秒后,RTC产生中断信号
// void(*func)():函数指针
//返回值:空
void setup_wkalarm(int fd,int sec,void(*func)()){
int i,retval;
unsigned long tmp, data;
struct rtc_time rtc_tm;
int scale_type = HR24;
struct rtc_wkalrm rtc_alarmtm;
/*read current time*/
retval=ioctl(fd,RTC_RD_TIME,&rtc_tm); //读取RTC时间,保存在结构体rtc_tm中
if (retval <0) {
printf("ioctl RTC_RD_TIME faild!!!\n");
return ;
}
printf("read current time is: %04d-%02d-%02d %02d:%02d:%02d\n\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 = rtc_tm.tm_sec+sec;//设置5s的闹钟时间,5s时间一到,RTC中断触发
if (rtc_tm.tm_sec>60)
{
rtc_tm.tm_sec=rtc_tm.tm_sec-60;
rtc_tm.tm_min=rtc_tm.tm_min+1;
}
rtc_alarmtm.enabled=1; //RTC闹钟使能
rtc_alarmtm.time=rtc_tm; //给闹钟时间赋值
/* Set the alarm to 5 sec in the future */
retval = ioctl(fd, RTC_WKALM_SET, &rtc_alarmtm); //设置RTC闹钟时间
if (retval <0) {
printf("ioctl RTC_ALM_SET faild!!!\n");
return ;
}
/* Read the current alarm settings */
retval = ioctl(fd, RTC_WKALM_RD, &rtc_alarmtm); //读取当前的闹钟时间
if (retval <0) {
printf("ioctl RTC_ALM_READ faild!!!\n");
return ;
}
rtc_tm=rtc_alarmtm.time;
printf("read current alarm time is: %04d-%02d-%02d %02d:%02d:%02d\n\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);
/* Enable alarm interrupts */
retval = ioctl(fd, RTC_AIE_ON, 0); //使能RTC中断
if (retval <0) {
printf("ioctl RTC_AIE_ON faild!!!\n");
return ;
}
fprintf(stderr, "Waiting %d seconds for wkalarm...\n\n",sec);
fflush(stderr);
/* This blocks until the alarm ring causes an interrupt */
retval = read(fd, &data, sizeof(unsigned long)); //read函数阻塞,直到有数据可读
if (retval >0) {
func(); //5s闹钟时间到,执行func函数
}else{
printf("!!!alarm faild!!!\n");
return ;
}
/* Disable alarm interrupts */
retval = ioctl(fd, RTC_AIE_OFF, 0); //关闭闹钟中断
if (retval == -1) {
printf("ioctl RTC_AIE_OFF faild!!!\n");
return ;
}
printf("Test week alarm(hour,min,sec) test OK!\n");
}
int main(void) {
int i, fd, retval, irqcount = 0;
unsigned long tmp, data;
struct rtc_time rtc_tm;
int scale_type = HR24;
struct rtc_wkalrm rtc_alarmtm;
unsigned int select;
printf("RTC Sample\n");
fd = open ("/dev/rtc", O_RDONLY); //打开RTC
fd_all=fd;
if (fd<0) {
printf("open rtc faild!!!\n");
return ;
}
signal (SIGTERM, ctrl_c_signal); /* for the TERM signal.. */
signal (SIGINT, ctrl_c_signal); /* for the CTRL+C signal.. */
printf("\n******** RTC Test Demo ***********\n");
printf("1.Read current RTC time ..\n");
printf("2.Adjust current RTC time ..\n");
printf("3.Test week alarm(year,mon,day)..\n");
printf("X.Exit(don't use 'ctrl+c',must be 'X')..\n");
printf("**************************************\n");
printf("Select : \n");
while(1)
{
select = getchar();
switch(select)
{
case 0x31:
read_time(fd); //读取当前RTC时间
break;
case 0x32:
setup_time(fd); //设置当前RTC时间
break;
case 0x33:
setup_wkalarm(fd,5,alarm_func); //设置RTC定时5s
break;
case 0x58: //'x' -- exit the program
case 0x78: //'X'
printf("haha-goto the end now.\n");
goto end;
default :
printf("\n\n\t==>Select command number(1-3) \n");
break;
}
}
end:
close(fd); //关闭RTC
return 0;
} /* end main */
Main函数一进来打印菜单,提示用户输入选择,1代表读RTC时间,2代表设置RTC时间,3代表设置RTC闹钟时间。
读RTC时间:调用系统函数ioctl读RTC时间到结构体rtc_time。
设置RTC时间:把你想设置的时间填充到RTC结构体rtc_time,调用系统函数ioctl就更新RTC时间了。
设置RTC闹钟时间:首先调用系统函数ioctl读当前RTC时间到结构体rtc_time里,在当前RTC时间上修改时间,就得到了闹钟时间。调用系统函数ioctl设置闹钟时间,使能RTC中断,接下来通过read函数等待中断到来,一旦触发就执行中断服务程序func()。
4.编译
在ubuntu下切换路径至/duckbill/N32905/applications/rtc/。
执行make,编译生成可执行文件rtc_demo,rtc_demo将会自动拷贝至例程文件系统目录 /duckbill/N32905/usr/TEST_mini905/mkFilesys下。
执行例程文件系统TEST_mini905/test_mini905/目录下的脚本mkjffs2.sh,生成我们所需的jffs2文件系统。
5.烧录运行
WIFI-Mini905开发板与电脑之间连接好usb电源线(也充当下载线)、usb转串口线,将拨码开关S1拨向Rec位,按下自锁开关K1,开发板通电,N32905进入烧录模式。
使用TurboWriter依次烧录 开发板光盘资料\Mini905光盘资料\BIN\基础例程下的loader(SpiLoader_905.bin)、内核(Kernel.bin)以及刚刚生成的文件系统(TEST_mini905.jffs2.summary),烧录步骤与例程1一致。
烧录完成后将拨码开关S1拨向Nor位,开发板重新通电,电源指示灯亮,N32905进入正常启动模式,等待系统运行起来。
在串口超级终端输入./rtc_demo,执行RTC应用程序。
选择1,读取当前RTC时间,由于WIFI-Mini905开发板未带电池,每次断电后用户设置的RTC时间将会丢失,将会回到默认时间2005-01-01。
选择2,设置RTC时间,我这里设置的是2014-12-8,22-55-0。
选择3,设置闹钟时间,我这里设置5s后RTC触发中断。