查看: 1346|回复: 0

​Atmel SAM4S学习笔记(八)——RTC(实时时钟)

[复制链接]
  • TA的每日心情
    慵懒
    2016-10-17 12:07
  • 签到天数: 306 天

    连续签到: 1 天

    [LV.8]以坛为家I

    发表于 2014-12-1 19:37:16 | 显示全部楼层 |阅读模式
    分享到:
    现在单片机RTC时钟已成为标配了。SAM4S系列的Real-time Clock是一个为低功耗设计的,为了达到最优的功能,需要由外部32.768Khz的晶振提供时钟信号。他包括一天的完整的带警报功能的时钟,和200年的Gregorian或者Persian日历,能产生周期性的可编程中断。警报和日历都可以通过32位数据总线访问。时间和日历的数值都是以BCD编码的。时间的格式有24小时和AM/PM格式。
    特性:
    超低功耗
    全异步设计
    Greforian日历可是计时到2099年或者Persian日历
    可编程周期中断
    安全特性:
            有效时间和日期程序检查
            有效传输时间和日期程序检查,
    晶体振荡时钟校准
    波形发生器
    寄存器写保护
    下面这幅图是RTC时钟的框架图如图8-1所示

                                                 
    从图上可以看出来,RTC的中断源连接到中断控制器的一个中断源上。中断处理需要在配置RTC之前对中断控制器进行编程。
    下图是RTC的寄存器如图8-2所示

      
    RTC_CR:控制寄存器
    RTC_MR:模式寄存器
    RTC_TIMR:时间寄存器
    RTC_CALR:日期寄存器
    RTC_TIMALR:时间警报寄存器
    RTC_CALALR:日历警报寄存器
    RTC_SR:状态寄存器
    RTC_SCCR:状态清除指令寄存器
    RTC_IER:中断允许寄存器
    RTC_IDR:中断禁止寄存器
    RTC_IMR:中断屏蔽寄存器
    RTC_VER:有效入口寄存器
    具体的应用,附上ASF提供的代码供大家参考,详细可以去ASF的框架中找例程。
    Atmel SAM4S Xplained pro学习笔记(一)-- 开发套件介绍
    Atmel SAM4S 学习笔记(二)-- 开发环境搭建
    Atmel SAM4S 学习笔记(三)-- 示例代码分析
    Atmel SAM4S学习笔记(四)——ASF详解
    Atmel SAM4S学习笔记(五)——GPIO
    Atmel SAM4S学习笔记(六)--CHIPID(芯片编号)
    Atmel SAM4S学习笔记(七)——实时定时器 (RTT)
    #include "asf.h"#include "stdio_serial.h"#include "conf_clock.h"#include "conf_board.h"/* Main menu is being displayed. */#define STATE_MENU             0/* Time is being edited. */#define STATE_SET_TIME         1/* Date is being edited. */#define STATE_SET_DATE         2/* Time alarm is being edited. */#define STATE_SET_TIME_ALARM   3/* Date alarm is being edited. */#define STATE_SET_DATE_ALARM   4/* Wave generating is being edited. */#define STATE_WAVEFORM         5/* Maximum size of edited string. */#define MAX_EDIT_SIZE          10/* Macro for converting char to digit. */#define char_to_digit(c) ((c) - '0')#define STRING_EOL    "\r"#define STRING_HEADER "-- RTC Example --\r\n" \                "-- "BOARD_NAME" --\r\n" \                "-- Compiled: "__DATE__" "__TIME__" --"STRING_EOL/* Current state of application. */static uint32_t gs_ul_state = STATE_MENU;/* Edited hour. */static uint32_t gs_ul_new_hour;/* Edited minute. */static uint32_t gs_ul_new_minute;/* Edited second. */static uint32_t gs_ul_new_second;/* Edited year. */static uint32_t gs_ul_new_year;/* Edited month. */static uint32_t gs_ul_new_month;/* Edited day. */static uint32_t gs_ul_new_day;/* Edited day-of-the-week. */static uint32_t gs_ul_new_week;/* Indicate if alarm has been triggered and not yet cleared */static uint32_t gs_ul_alarm_triggered = 0;/* Time string */static uint8_t gs_uc_rtc_time[8 + 1] =                { '0', '0', ':', '0', '0', ':', '0', '0', '\0' };/* Date string */static uint8_t gs_uc_date[10 + 1] =                { '0', '0', '/', '0', '0', '/', '0', '0', '0', '0', '\0' };/* Week string */static uint8_t gs_uc_day_names[7][4] =                { "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun" };/* Flag for refreshing menu */static uint32_t gs_ul_menu_shown = 0;/** *  Configure UART console. */static void configure_console(void){        const usart_serial_options_t uart_serial_options = {                .baudrate = CONF_UART_BAUDRATE,                .paritytype = CONF_UART_PARITY        };        /* Configure console UART. */        sysclk_enable_peripheral_clock(CONSOLE_UART_ID);        stdio_serial_init(CONF_UART, &uart_serial_options);}/** * \brief Get new time. Successful value is put in gs_ul_new_hour, * gs_ul_new_minute, gs_ul_new_second. */static uint32_t get_new_time(void){        uint8_t uc_key;        uint32_t i = 0;        /* Clear setting variable. */        gs_ul_new_hour = 0xFFFFFFFF;        gs_ul_new_minute = 0xFFFFFFFF;        gs_ul_new_second = 0xFFFFFFFF;        /* Use gs_uc_rtc_time[] as a format template. */        while (1) {                while (uart_read(CONSOLE_UART, &uc_key));                /* End input */                if (uc_key == 0x0d || uc_key == 0x0a) {                        puts("\r");                        break;                }                /* DEL or BACKSPACE */                if (uc_key == 0x7f || uc_key == 0x08) {                        if (i > 0) {                                /* End of gs_uc_rtc_time[], then one more back of index */                                if (!gs_uc_rtc_time) {                                        --i;                                }                                puts("\b \b");                                --i;                                /* Delimiter ':' for time is uneditable */                                if (!((gs_uc_rtc_time) >= '0' && (gs_uc_rtc_time) <= '9')                                                && i > 0) {                                        puts("\b \b");                                        --i;                                }                        }                }                /*                 * End of gs_uc_rtc_time[], no more input except the above DEL/BS,                 * or enter to end.                 */                if (!gs_uc_rtc_time) {                        continue;                }                while (uart_write(CONSOLE_UART, uc_key));                gs_uc_rtc_time[i++] = uc_key;        }        if (i == 0) {                return 0;        }        if (i != 0 && gs_uc_rtc_time != '\0') {                /* Failure input */                return 1;        }        gs_ul_new_hour = char_to_digit(gs_uc_rtc_time[0]) * 10 +                        char_to_digit(gs_uc_rtc_time[1]);        gs_ul_new_minute = char_to_digit(gs_uc_rtc_time[3]) * 10 +                        char_to_digit(gs_uc_rtc_time[4]);        gs_ul_new_second = char_to_digit(gs_uc_rtc_time[6]) * 10 +                        char_to_digit(gs_uc_rtc_time[7]);        /* Success input. Verification of data is left to RTC internal Error Checking. */        return 0;}/** * \brief Calculate week from year, month, day. */static uint32_t calculate_week(uint32_t ul_year, uint32_t ul_month,                uint32_t ul_day){        uint32_t ul_week;        if (ul_month == 1 || ul_month == 2) {                ul_month += 12;                --ul_year;        }        ul_week = (ul_day + 2 * ul_month + 3 * (ul_month + 1) / 5 + ul_year +                        ul_year / 4 - ul_year / 100 + ul_year / 400) % 7;        ++ul_week;        return ul_week;}/** * \brief Get new time. Successful value is put in gs_ul_new_year, * gs_ul_new_month, gs_ul_new_day, gs_ul_new_week. */static uint32_t get_new_date(void){        uint8_t uc_key;        uint32_t i = 0;        /* Clear setting variable */        gs_ul_new_year = 0xFFFFFFFF;        gs_ul_new_month = 0xFFFFFFFF;        gs_ul_new_day = 0xFFFFFFFF;        gs_ul_new_week = 0xFFFFFFFF;        /* Use gs_uc_rtc_time[] as a format template */        while (1) {                while (uart_read(CONSOLE_UART, &uc_key));                /* End input */                if (uc_key == 0x0d || uc_key == 0x0a) {                        puts("\r");                        break;                }                /* DEL or BACKSPACE */                if (uc_key == 0x7f || uc_key == 0x08) {                        if (i > 0) {                                /* End of date[], then one more back of index */                                if (!gs_uc_date) {                                        --i;                                }                                puts("\b \b");                                --i;                                /* Delimiter '/' for date is uneditable */                                if (!((gs_uc_date) >= '0' && (gs_uc_date) <='9')                                                && i > 0) {                                        puts("\b \b");                                        --i;                                }                        }                }                /*                 * End of gs_uc_rtc_time[], no more input except the above DEL/BS,                 * or enter to end.                 */                if (!gs_uc_date) {                        continue;                }                while (uart_write(CONSOLE_UART, uc_key));                gs_uc_date[i++] = uc_key;        }        if (i == 0) {                return 0;        }        if (i != 0 && gs_uc_date != '\0' && i != 6) {                /* Failure input */                return 1;        }        /* MM-DD-YY */        gs_ul_new_month = char_to_digit(gs_uc_date[0]) * 10                        + char_to_digit(gs_uc_date[1]);        gs_ul_new_day = char_to_digit(gs_uc_date[3]) * 10                        + char_to_digit(gs_uc_date[4]);        if (i != 6) {                /* For 'Set Date' option, get the input new year and new week. */                gs_ul_new_year = char_to_digit(gs_uc_date[6]) * 1000 +                                char_to_digit(gs_uc_date[7]) * 100 +                                char_to_digit(gs_uc_date[8]) * 10 +                                char_to_digit(gs_uc_date[9]);                gs_ul_new_week = calculate_week(gs_ul_new_year, gs_ul_new_month,                                gs_ul_new_day);        }        /*         * Success input. Verification of data is left to RTC internal Error         * Checking.         */        return 0;}/** * \brief Display the user interface on the terminal. */static void refresh_display(void){        uint32_t ul_hour, ul_minute, ul_second;        uint32_t ul_year, ul_month, ul_day, ul_week;        if (gs_ul_state != STATE_MENU) {                /* Not in menu display mode, in set mode. */        } else {                /* Retrieve date and time */                rtc_get_time(RTC, &ul_hour, &ul_minute, &ul_second);                rtc_get_date(RTC, &ul_year, &ul_month, &ul_day, &ul_week);                /* Display */                if (!gs_ul_menu_shown) {                        puts("\n\rMenu:\n\r"                                        "  t - Set time\n\r"                                        "  d - Set date\n\r"                                        "  i - Set time alarm\n\r"                                        "  m - Set date alarm\r");#if ((SAM3S8) || (SAM3SD8) || (SAM4S) || (SAM4C) || (SAM4CP) || (SAM4CM))                        puts("  w - Generate Waveform\r");#endif                        if (gs_ul_alarm_triggered) {                                puts("  c - Clear alarm notification\r");                        }                        printf("\n\r");                        gs_ul_menu_shown = 1;                }                /* Update current date and time */                puts("\r");                printf(" [Time/Date: u:u:u, u/u/u %s ][Alarm status:%s]",                        (unsigned int)ul_hour, (unsigned int)ul_minute, (unsigned int)ul_second,                        (unsigned int)ul_month, (unsigned int)ul_day, (unsigned int)ul_year,                        gs_uc_day_names[ul_week-1], gs_ul_alarm_triggered?"Triggered!":"");        }}/** * \brief Interrupt handler for the RTC. Refresh the display. */void RTC_Handler(void){        uint32_t ul_status = rtc_get_status(RTC);        /* Second increment interrupt */        if ((ul_status & RTC_SR_SEC) == RTC_SR_SEC) {                /* Disable RTC interrupt */                rtc_disable_interrupt(RTC, RTC_IDR_SECDIS);                refresh_display();                rtc_clear_status(RTC, RTC_SCCR_SECCLR);                rtc_enable_interrupt(RTC, RTC_IER_SECEN);        } else {                /* Time or date alarm */                if ((ul_status & RTC_SR_ALARM) == RTC_SR_ALARM) {                        /* Disable RTC interrupt */                        rtc_disable_interrupt(RTC, RTC_IDR_ALRDIS);                        gs_ul_alarm_triggered = 1;                        refresh_display();                        /* Show additional menu item for clear notification */                        gs_ul_menu_shown = 0;                        rtc_clear_status(RTC, RTC_SCCR_ALRCLR);                        rtc_enable_interrupt(RTC, RTC_IER_ALREN);                }        }}/** * \brief Application entry point for RTC example. * * \return Unused (ANSI-C compatibility). */int main(void){        uint8_t uc_key;        /* Initialize the SAM system */        sysclk_init();        board_init();        /* Initialize the console uart */        configure_console();        /* Output example information */        puts(STRING_HEADER);        /* Default RTC configuration, 24-hour mode */        rtc_set_hour_mode(RTC, 0);        /* Configure RTC interrupts */        NVIC_DisableIRQ(RTC_IRQn);        NVIC_ClearPendingIRQ(RTC_IRQn);        NVIC_SetPriority(RTC_IRQn, 0);        NVIC_EnableIRQ(RTC_IRQn);        rtc_enable_interrupt(RTC, RTC_IER_SECEN | RTC_IER_ALREN);        /* Refresh display once */        refresh_display();        /* Handle keypresses */        while (1) {                while (uart_read(CONSOLE_UART, &uc_key));                /* Set time */                if (uc_key == 't') {                        gs_ul_state = STATE_SET_TIME;                        do {                                puts("\n\r\n\r Set time(hh:mm:ss): ");                        } while (get_new_time());                        /* If valid input, none of the variables for time is 0xff. */                        if (gs_ul_new_hour != 0xFFFFFFFF && (gs_uc_rtc_time[2] == ':')                                        && (gs_uc_rtc_time[5] == ':')) {                                if (rtc_set_time(RTC, gs_ul_new_hour, gs_ul_new_minute,                                                gs_ul_new_second)) {                                        puts("\n\r Time not set, invalid input!\r");                                }                        } else {                                gs_uc_rtc_time[2] = ':';                                gs_uc_rtc_time[5] = ':';                                puts("\n\r Time not set, invalid input!\r");                        }                        gs_ul_state = STATE_MENU;                        gs_ul_menu_shown = 0;                        refresh_display();                }                /* Set date */                if (uc_key == 'd') {                        gs_ul_state = STATE_SET_DATE;                        do {                                puts("\n\r\n\r Set date(mm/dd/yyyy): ");                        } while (get_new_date());                        /* If valid input, none of the variables for date is 0xff(ff). */                        if (gs_ul_new_year != 0xFFFFFFFF && (gs_uc_date[2] == '/')                                        && (gs_uc_date[5] == '/')) {                                if (rtc_set_date(RTC, gs_ul_new_year, gs_ul_new_month,                                                gs_ul_new_day, gs_ul_new_week)) {                                        puts("\n\r Date not set, invalid input!\r");                                }                        } else {                                gs_uc_date[2] = '/';                                gs_uc_date[5] = '/';                                puts("\n\r Time not set, invalid input!\r");                        }                        /* Only 'mm/dd' is input. */                        if (gs_ul_new_month != 0xFFFFFFFF &&                                                gs_ul_new_year == 0xFFFFFFFF) {                                puts("\n\r Not Set for no year field!\r");                        }                        gs_ul_state = STATE_MENU;                        gs_ul_menu_shown = 0;                        refresh_display();                }                /* Set time alarm */                if (uc_key == 'i') {                        gs_ul_state = STATE_SET_TIME_ALARM;                        rtc_clear_date_alarm(RTC);                        do {                                puts("\n\r\n\r Set time alarm(hh:mm:ss): ");                        } while (get_new_time());                        if (gs_ul_new_hour != 0xFFFFFFFF && (gs_uc_rtc_time[2] == ':')                                        && (gs_uc_rtc_time[5] == ':')) {                                if (rtc_set_time_alarm(RTC, 1, gs_ul_new_hour,                                                1, gs_ul_new_minute, 1, gs_ul_new_second)) {                                        puts("\n\r Time alarm not set, invalid input!\r");                                } else {                                        printf("\n\r Time alarm is set at u:u:u!",                                                (unsigned int)gs_ul_new_hour, (unsigned int)gs_ul_new_minute,                                                (unsigned int)gs_ul_new_second);                                }                        } else {                                gs_uc_rtc_time[2] = ':';                                gs_uc_rtc_time[5] = ':';                                puts("\n\r Time not set, invalid input!\r");                        }                        gs_ul_state = STATE_MENU;                        gs_ul_menu_shown = 0;                        gs_ul_alarm_triggered = 0;                        refresh_display();                }                /* Set date alarm */                if (uc_key == 'm') {                        gs_ul_state = STATE_SET_DATE_ALARM;                        rtc_clear_time_alarm(RTC);                        do {                                puts("\n\r\n\r Set date alarm(mm/dd/yyyy): ");                        } while (get_new_date());                        if (gs_ul_new_year != 0xFFFFFFFF && (gs_uc_date[2] == '/')                                        && (gs_uc_date[5] == '/')) {                                if (rtc_set_date_alarm(RTC, 1, gs_ul_new_month, 1,                                                gs_ul_new_day)) {                                        puts("\n\r Date alarm not set, invalid input!\r");                                } else {                                        printf("\n\r Date alarm is set on u/u/%4u!",                                                        (unsigned int)gs_ul_new_month, (unsigned int)gs_ul_new_day,                                                        (unsigned int)gs_ul_new_year);                                }                        } else {                                gs_uc_date[2] = '/';                                gs_uc_date[5] = '/';                                puts("\n\r Date alarm not set, invalid input!\r");                        }                        gs_ul_state = STATE_MENU;                        gs_ul_menu_shown = 0;                        gs_ul_alarm_triggered = 0;                        refresh_display();                }#if ((SAM3S8) || (SAM3SD8) || (SAM4S) || (SAM4C) || (SAM4CP) || (SAM4CM))                /* Generate Waveform */                if (uc_key == 'w') {                        gs_ul_state = STATE_WAVEFORM;                        puts("\n\rMenu:\n\r"                                        "  0 - No Waveform\n\r"                                        "  1 - 1 Hz square wave\n\r"                                        "  2 - 32 Hz square wave\n\r"                                        "  3 - 64 Hz square wave\n\r"                                        "  4 - 512 Hz square wave\n\r"                                        "  5 - Toggles when alarm flag rise\n\r"                                        "  6 - Copy of the alarm flag\n\r"                                        "  7 - Duty cycle programmable pulse\n\r"                                        "  8 - Quit\r");                        while (1) {                                while (uart_read(CONSOLE_UART, &uc_key));                                if ((uc_key >= '0') && (uc_key <= '7')) {                                        rtc_set_waveform(RTC, 0, char_to_digit(uc_key));                                }                                if (uc_key == '8') {                                        gs_ul_state = STATE_MENU;                                        gs_ul_menu_shown = 0;                                        refresh_display();                                        break;                                }                        }                }#endif                /* Clear trigger flag */                if (uc_key == 'c') {                        gs_ul_alarm_triggered = 0;                        gs_ul_menu_shown = 0;                        refresh_display();                }        }}
    回复

    使用道具 举报

    您需要登录后才可以回帖 注册/登录

    本版积分规则

    关闭

    站长推荐上一条 /2 下一条

    手机版|小黑屋|与非网

    GMT+8, 2024-4-26 03:20 , Processed in 0.125699 second(s), 18 queries , MemCache On.

    ICP经营许可证 苏B2-20140176  苏ICP备14012660号-2   苏州灵动帧格网络科技有限公司 版权所有.

    苏公网安备 32059002001037号

    Powered by Discuz! X3.4

    Copyright © 2001-2024, Tencent Cloud.