TA的每日心情 | 慵懒 2016-10-17 12:07 |
---|
签到天数: 306 天 连续签到: 1 天 [LV.8]以坛为家I
|
现在单片机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(); } }} |
|