嵌入式智能万年历设计
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
任务要求:
用ARM—M3芯片设计一个智能万年历,要求能够正确显示近100 年时间,星期几,时间格式为****年**月**日(星期**) **:**:**(时:分:秒),能够识别出闰年(计时范围能够从1970年1月1日到2100年左右)。
该程序设计工程里包含有main.c(相关配置、和终端联系,提醒输出初始时间、输出实时时间)/date.c(计算实时时间)/stm32f10x_it.c三个文件,各文件内容如下。
Main.c文件:
#include "stm32f10x.h"
#include "stdio.h"
#include "date.h"
__IO uint32_t TimeDisplay = 0;
void RCC_Configuration(void);
void NVIC_Configuration(void);
void GPIO_Configuration(void);
void USART_Configuration(void);
int fputc(int ch, FILE *f);
void RTC_Configuration(void);
void Time_Regulate(struct rtc_time *tm);
void Time_Adjust(void);
void Time_Display(uint32_t TimeVar);
void Time_Show(void);
u8 USART_Scanf(u32 value);
#define RTCClockSource_LSE
u8 const *WEEK_STR[] = {"日", "一", "二", "三", "四", "五", "六"};
struct rtc_time systmtime;
int main()
{
RCC_Configuration();
NVIC_Configuration();
GPIO_Configuration();
USART_Configuration();
/*在启动时检查备份寄存器BKP_DR1,如果内容不是0xA5A5,则需重新配置时间并询问用户调整时间*/
printf("\r\n\n RTC not yet configured....");
RTC_Configuration();
printf("\r\n RTC configured....");
Time_Adjust();
BKP_WriteBackupRegister(BKP_DR1, 0xA5A5);
}
else
{
/*启动无需设置新时钟*/
/*检查是否掉电重启*/
if (RCC_GetFlagStatus(RCC_FLAG_PORRST) != RESET)
{
printf("\r\n\n Power On Reset occurred....");
}
/*检查是否Reset复位*/
else if (RCC_GetFlagStatus(RCC_FLAG_PINRST) != RESET)
{
printf("\r\n\n External Reset occurred....");
}
printf("\r\n No need to configure RTC....");
/*等待寄存器同步*/
RTC_WaitForSynchro();
/*允许RTC秒中断*/
RTC_ITConfig(RTC_IT_SEC, ENABLE);
/*等待上次RTC寄存器写操作完成*/
RTC_WaitForLastTask();
}
#ifdef RTCClockOutput_Enable
RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE); PWR_BackupAccessCmd(ENABLE);
BKP_TamperPinCmd(DISABLE);
BKP_RTCOutputConfig(BKP_RTCOutputSource_CalibClock);
RCC_ClearFlag();
Time_Show();
}
void RCC_Configuration()
{
SystemInit();
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA, ENABLE);
}
void NVIC_Configuration()
{
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
NVIC_InitStructure.NVIC_IRQChannel = RTC_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
void GPIO_Configuration()
{
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOA, &GPIO_InitStructure);
}
void USART_Configuration()
{
USART_InitTypeDef USART_InitStructure;
USART_ART_WordLength = USART_WordLength_8b;
USART_ART_StopBits = USART_StopBits_1;
USART_ART_Parity = USART_Parity_No ;
USART_ART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_ART_Mode = USART_Mode_Rx | USART_Mode_Tx;
USART_Init(USART1, &USART_InitStructure);
USART_Cmd(USART1, ENABLE);
}
int fputc(int ch, FILE *f)
{
/* 将Printf内容发往串口 */
USART_SendData(USART1, (unsigned char) ch);
while (!(USART1->SR & USART_FLAG_TXE));
return (ch);
}
void RTC_Configuration()
{
/*允许PWR和BKP时钟*/
RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE);
/*允许访问BKP域*/
PWR_BackupAccessCmd(ENABLE);
/*复位备份域*/
BKP_DeInit();
#ifdef RTCClockSource_LSI
/*允许LSI*/
RCC_LSICmd(ENABLE);
/*等待LSI准备好*/
while(RCC_GetFlagStatus(RCC_FLAG_LSIRDY)==RESET)
{
}
/*选择LSI作为RTC时钟源*/
RCC_RTCCLKConfig(RCC_RTCCLKSource_LSI);
#elif defined RTCClockSource_LSE
/*允许LSE*/
RCC_LSEConfig(RCC_LSE_ON);
/*等待LSE准备好*/
while(RCC_GetFlagStatus(RCC_FLAG_LSERDY)==RESET)
{
}
/*选择LSE作为RTC时钟源*/
RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE);
#endif
/* Enable RTC Clock */
RCC_RTCCLKCmd(ENABLE);
#ifdef RTCClockOutput_Enable
/*禁止Tamper引脚*/
BKP_TamperPinCmd(DISABLE);/*为了将RTCCLK/64在Tamper引脚输出,Tamper功能必须被禁止*/
/*允许RTC时钟在Tamper引脚上输出*/
BKP_RTCCalibrationClockOutputCmd(ENABLE);
#endif
/*等待寄存器同步*/
RTC_WaitForSynchro();
/*等待上次RTC寄存器写操作完成*/
RTC_WaitForLastTask();
/*允许RTC秒中断*/
RTC_ITConfig(RTC_IT_SEC, ENABLE);
/*等待上次RTC寄存器写操作完成*/
RTC_WaitForLastTask();
#ifdef RTCClockSource_LSI
/*设置分频系数*/
RTC_SetPrescaler(31999); /*RTC周期=RTCCLK/RTC_PR=(32.000kHz/(31999+1))*/
#elif defined RTCClockSource_LSE
RTC_SetPrescaler(32767); /*RTC周期=RTCCLK/RTC_PR=(32.768kHz/(31767+1))*/ #endif
/*等待上次RTC寄存器写操作完成*/
RTC_WaitForLastTask();
}
void Time_Regulate(struct rtc_time *tm)
{
u32 Tmp_YY = 0xFF, Tmp_MM = 0xFF, Tmp_DD = 0xFF, Tmp_HH = 0xFF, Tmp_MI = 0xFF, Tmp_SS = 0xFF;
printf("\r\n=========================Time Settings==================");
printf("\r\n 请输入年份(Please Set Years): 20");
while (Tmp_YY == 0xFF)
{
Tmp_YY = USART_Scanf(99);
}
printf("\n\r 年份被设置为: 20%0.2d\n\r", Tmp_YY);
tm->tm_year = Tmp_YY+2000;
Tmp_MM = 0xFF;
printf("\r\n 请输入月份(Please Set Months): ");
while (Tmp_MM == 0xFF)
{
Tmp_MM = USART_Scanf(12);
}
printf("\n\r 月份被设置为: %d\n\r", Tmp_MM);
tm->tm_mon= Tmp_MM;
Tmp_DD = 0xFF;
printf("\r\n 请输入日期(Please Set Dates): ");
while (Tmp_DD == 0xFF)
{
Tmp_DD = USART_Scanf(31);
}
printf("\n\r 日期被设置为: %d\n\r", Tmp_DD);
tm->tm_mday= Tmp_DD;
Tmp_HH = 0xFF;
printf("\r\n 请输入时钟(Please Set Hours): ");
while (Tmp_HH == 0xFF)
{
Tmp_HH = USART_Scanf(23);
}
printf("\n\r 时钟被设置为: %d\n\r", Tmp_HH );
tm->tm_hour= Tmp_HH;
Tmp_MI = 0xFF;
printf("\r\n 请输入分钟(Please Set Minutes): ");
while (Tmp_MI == 0xFF)
{
Tmp_MI = USART_Scanf(59);
}
printf("\n\r 分钟被设置为: %d\n\r", Tmp_MI);
tm->tm_min= Tmp_MI;
Tmp_SS = 0xFF;
printf("\r\n 请输入秒钟(Please Set Seconds): ");
while (Tmp_SS == 0xFF)
{
Tmp_SS = USART_Scanf(59);
}
printf("\n\r 秒钟被设置为: %d\n\r", Tmp_SS);
tm->tm_sec= Tmp_SS;
}
void Time_Adjust()
RTC_WaitForLastTask();
Time_Regulate(&systmtime);
GregorianDay(&systmtime);
RTC_SetCounter(mktimev(&systmtime));
RTC_WaitForLastTask();
}
void Time_Display(uint32_t TimeVar)
{
to_tm(TimeVar, &systmtime);
printf("\r 当前时间为: %d年 %d月 %d日 (星期%s) %0.2d:%0.2d:%0.2d", systmtime.tm_year, systmtime.tm_mon, systmtime.tm_mday, WEEK_STR[systmtime.tm_wday], systmtime.tm_hour,
systmtime.tm_min, systmtime.tm_sec);
}
void Time_Show()
{
printf("\n\r");
/* Infinite loop */
while (1)
{
/* 每过1s */
if (TimeDisplay == 1)
{
Time_Display(RTC_GetCounter());
TimeDisplay = 0;
}
}
}
u8 USART_Scanf(u32 value)
{
u32 index = 0;
u32 tmp[2] = {0, 0};
{
while (USART_GetFlagStatus(USART1, USART_FLAG_RXNE) == RESET)
{
}
tmp[index++] = (USART_ReceiveData(USART1));
if ((tmp[index - 1] < 0x30) || (tmp[index - 1] > 0x39)) /*数字0到9的ASCII 码为0x30至0x39*/
{
if((index == 2) && (tmp[index - 1] == '\r'))
{
tmp[1] = tmp[0];
tmp[0] = 0x30;
}
else
{
printf("\n\rPlease enter valid number between 0 and 9 -->: ");
index--;
}
}
}
/* 计算输入字符的相应ASCII值*/
index = (tmp[1] - 0x30) + ((tmp[0] - 0x30) * 10);
/* Checks */
if (index > value)
{
printf("\n\rPlease enter valid number between 0 and %d", value);
return 0xFF;
}
return index;
}
Date.c文件内容如下:
#include "date.h"
#define FEBRUARY 2
#define STARTOFTIME 1970
#define SECDAY 86400L
#define SECYR (SECDAY * 365)
#define leapyear(year) ((year) % 4 == 0)
#define days_in_month(a) (month_days[(a) - 1])
static int month_days[12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
/*计算公历*/
void GregorianDay(struct rtc_time * tm)
{
int leapsToDate;
int lastYear;
int day;
int MonthOffset[] = { 0,31,59,90,120,151,181,212,243,273,304,334 };
lastYear=tm->tm_year-1;
/*计算到计数的前一年之中一共经历了多少个闰年*/
leapsToDate = lastYear/4 - lastYear/100 + lastYear/400;
/*如若计数的这一年为闰年,且计数的月份在2月之后,则日数加1,否则不加1*/ if((tm->tm_year%4==0) && ((tm->tm_year%100!=0) || (tm->tm_year%400==0)) && (tm->tm_mon>2))
{
day=1;
}
else
{
day=0;
}
day += lastYear*365 + leapsToDate + MonthOffset[tm->tm_mon-1] + tm->tm_mday; /*计算从计数元年元旦到计数日期一共有多少天*/
tm->tm_wday=day%7;
}
u32 mktimev(struct rtc_time *tm)
{
if (0 >= (int) (tm->tm_mon -= 2))
{
tm->tm_mon += 12;
tm->tm_year -= 1;
}
return ((((u32) (tm->tm_year/4 - tm->tm_year/100 + tm->tm_year/400 + 367*tm->tm_mon/12 + tm->tm_mday)
}
void to_tm(u32 tim, struct rtc_time * tm)
{
register u32 i;
register long hms, day;
day = tim / SECDAY;
hms = tim % SECDAY;
tm->tm_hour = hms / 3600;
tm->tm_min = (hms % 3600) / 60;
tm->tm_sec = (hms % 3600) % 60;
/*算出当前年份,起始的计数年份为1970年*/
for (i = STARTOFTIME; day >= days_in_year(i); i++) {
day -= days_in_year(i);
}
tm->tm_year = i;
/*计算当前的月份*/
if (leapyear(tm->tm_year))
{
days_in_month(FEBRUARY) = 29;
}
for (i = 1; day >= days_in_month(i); i++)
{
day -= days_in_month(i);
}
days_in_month(FEBRUARY) = 28;
tm->tm_mon = i;
/*计算当前日期*/
tm->tm_mday = day + 1;
GregorianDay(tm);
}
stm32f10x_it.c文件内容:
#include "stm32f10x_it.h"
extern uint32_t TimeDisplay;
void NMI_Handler(void)
{
}
/**
* @brief This function handles Hard Fault exception.
* @param None
* @retval : None
*/
void HardFault_Handler(void)
{
/* Go to infinite loop when Hard Fault exception occurs */
while (1)
{
}
}
/**
* @brief This function handles Memory Manage exception.
* @param None
* @retval : None
*/
void MemManage_Handler(void)
{
/* Go to infinite loop when Memory Manage exception occurs */ while (1)
{
}
}
/**
* @brief This function handles Bus Fault exception.
* @param None
* @retval : None
*/
void BusFault_Handler(void)
{
/* Go to infinite loop when Bus Fault exception occurs */
while (1)
{
}
}
* @brief This function handles Usage Fault exception.
* @param None
* @retval : None
*/
void UsageFault_Handler(void)
{
/* Go to infinite loop when Usage Fault exception occurs */ while (1)
{
}
}
/**
* @brief This function handles SVCall exception.
* @param None
* @retval : None
*/
void SVC_Handler(void)
{
}
/**
* @brief This function handles Debug Monitor exception.
* @param None
* @retval : None
*/
void DebugMon_Handler(void)
{
}
/**
* @brief This function handles PendSVC exception.
* @param None
* @retval : None
*/
void PendSV_Handler(void)
{
}
/**
* @brief This function handles SysTick Handler.
* @param None
* @retval : None
*/
}
void RTC_IRQHandler(void)
{
if (RTC_GetITStatus(RTC_IT_SEC) != RESET)
{
/* Clear the RTC Second interrupt */
RTC_ClearITPendingBit(RTC_IT_SEC);
/* Enable time update */
TimeDisplay = 1;
/* Wait until last write operation on RTC registers has finished */ RTC_WaitForLastTask();
/* Reset RTC Counter when Time is 23:59:59 */
if (RTC_GetCounter() == 0x00015180)
{
RTC_SetCounter(0x0);
/* Wait until last write operation on RTC registers has finished */ RTC_WaitForLastTask();
}
}
}。