现在单片机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学习笔记(六)--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]) { --i; } puts("\b \b"); --i; /* Delimiter ':' for time is uneditable */ if (!((gs_uc_rtc_time[i]) >= '0' && (gs_uc_rtc_time[i]) <= '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[i]) { 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[i] != '\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]) { --i; } puts("\b \b"); --i; /* Delimiter '/' for date is uneditable */ if (!((gs_uc_date[i]) >= '0' && (gs_uc_date[i]) <='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[i]) { 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[i] != '\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(); } } }
创建讨论帖子
登录 后参与评论