注册 登录
查看: 1628|回复: 19

[其他] 嵌入式智能万年历设计

[复制链接]
发表于 2013-8-27 14:04:15 | 显示全部楼层 |阅读模式
需要设计万年历,因此网上找来了一个 例子。

任务要求:
用ARM—M3芯片设计一个智能万年历,要求能够正确显示近100 年时间,星期几,时间格式为********日(星期**) **:**:**(时:分:秒),能够识别出闰年(计时范围能够从1970年1月1日到2100年左右)。
该程序设计工程里包含有main.c(相关配置、和终端联系,提醒输出初始时间、输出实时时间)/date.c(计算实时时间)/stm32f10x_it.c三个文件,各文件内容如下。



回复

使用道具 举报

 楼主| 发表于 2013-8-27 14:06:17 | 显示全部楼层

Main.c文件

  1. #include "stm32f10x.h"
  2. #include "stdio.h"
  3. #include "date.h"

  4. __IO uint32_t TimeDisplay = 0;

  5. void RCC_Configuration(void);
  6. void NVIC_Configuration(void);
  7. void GPIO_Configuration(void);
  8. void USART_Configuration(void);
  9. int fputc(int ch, FILE *f);
  10. void RTC_Configuration(void);
  11. void Time_Regulate(struct rtc_time *tm);
  12. void Time_Adjust(void);
  13. void Time_Display(uint32_t TimeVar);
  14. void Time_Show(void);
  15. u8 USART_Scanf(u32 value);

  16. #define  RTCClockSource_LSE       

  17. u8 const *WEEK_STR[] = {"日", "一", "二", "三", "四", "五", "六"};

  18. struct rtc_time systmtime;

  19. int main()
  20. {
  21.           RCC_Configuration();
  22.        
  23.           NVIC_Configuration();
  24.        
  25.           GPIO_Configuration();
  26.        
  27.           USART_Configuration();
  28.        
  29.           /*在启动时检查备份寄存器BKP_DR1,如果内容不是0xA5A5,则需重新配置时间并询问用户调整时间*/
  30.         if (BKP_ReadBackupRegister(BKP_DR1) != 0xA5A5)
  31.         {
  32.             printf("\r\n\n RTC not yet configured....");
  33.                
  34.             RTC_Configuration();
  35.                 printf("\r\n RTC configured....");
  36.                
  37.             Time_Adjust();
  38.                
  39.                 BKP_WriteBackupRegister(BKP_DR1, 0xA5A5);
  40.         }
  41.         else
  42.         {
  43.             /*启动无需设置新时钟*/
  44.                 /*检查是否掉电重启*/
  45.                 if (RCC_GetFlagStatus(RCC_FLAG_PORRST) != RESET)
  46.                 {
  47.                     printf("\r\n\n Power On Reset occurred....");
  48.                 }
  49.                 /*检查是否Reset复位*/
  50.                 else if (RCC_GetFlagStatus(RCC_FLAG_PINRST) != RESET)
  51.             {
  52.               printf("\r\n\n External Reset occurred....");
  53.             }
  54.                
  55.                 printf("\r\n No need to configure RTC....");
  56.                
  57.                 /*等待寄存器同步*/
  58.                 RTC_WaitForSynchro();
  59.                
  60.                 /*允许RTC秒中断*/
  61.                 RTC_ITConfig(RTC_IT_SEC, ENABLE);
  62.                
  63.                 /*等待上次RTC寄存器写操作完成*/
  64.                 RTC_WaitForLastTask();
  65.         }

  66.         #ifdef RTCClockOutput_Enable

  67.           RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE);
  68.        
  69.           PWR_BackupAccessCmd(ENABLE);
  70.        
  71.           BKP_TamperPinCmd(DISABLE);
  72.        
  73.           BKP_RTCOutputConfig(BKP_RTCOutputSource_CalibClock);
  74.         #endif
  75.        
  76.           RCC_ClearFlag();
  77.        
  78.           Time_Show();
  79. }

  80. void RCC_Configuration()
  81. {
  82.                 SystemInit();
  83.                 RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA, ENABLE);
  84. }

回复 支持 反对

使用道具 举报

 楼主| 发表于 2013-8-27 14:07:52 | 显示全部楼层

Main.c文件 2


  1. void NVIC_Configuration()
  2. {
  3.           NVIC_InitTypeDef NVIC_InitStructure;
  4.        
  5.           NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
  6.        
  7.           NVIC_InitStructure.NVIC_IRQChannel = RTC_IRQn;
  8.           NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
  9.           NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
  10.           NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  11.           NVIC_Init(&NVIC_InitStructure);
  12. }

  13. void GPIO_Configuration()
  14. {
  15.           GPIO_InitTypeDef GPIO_InitStructure;
  16.        
  17.           GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
  18.           GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
  19.           GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  20.           GPIO_Init(GPIOA, &GPIO_InitStructure);
  21.             
  22.           GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
  23.           GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
  24.           GPIO_Init(GPIOA, &GPIO_InitStructure);

  25. }

  26. void USART_Configuration()
  27. {
  28.             USART_InitTypeDef USART_InitStructure;
  29.        
  30.                 USART_InitStructure.USART_BaudRate = 115200;
  31.                 USART_InitStructure.USART_WordLength = USART_WordLength_8b;
  32.                 USART_InitStructure.USART_StopBits = USART_StopBits_1;
  33.                 USART_InitStructure.USART_Parity = USART_Parity_No ;
  34.                 USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
  35.             USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
  36.        
  37.                 USART_Init(USART1, &USART_InitStructure);
  38.             USART_Cmd(USART1, ENABLE);
  39. }

  40. int fputc(int ch, FILE *f)
  41. {
  42.           /* 将Printf内容发往串口 */
  43.           USART_SendData(USART1, (unsigned char) ch);

  44.           while (!(USART1->SR & USART_FLAG_TXE));
  45.          
  46.           return (ch);
  47. }

  48. void RTC_Configuration()
  49. {
  50.      /*允许PWR和BKP时钟*/
  51.          RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE);
  52.          
  53.          /*允许访问BKP域*/
  54.          PWR_BackupAccessCmd(ENABLE);
  55.          
  56.          /*复位备份域*/
  57.          BKP_DeInit();
  58.          
  59.          #ifdef RTCClockSource_LSI
  60.          
  61.          /*允许LSI*/
  62.          RCC_LSICmd(ENABLE);
  63.          
  64.          /*等待LSI准备好*/
  65.          while(RCC_GetFlagStatus(RCC_FLAG_LSIRDY)==RESET)
  66.          {
  67.          }
  68.          
  69.          /*选择LSI作为RTC时钟源*/
  70.          RCC_RTCCLKConfig(RCC_RTCCLKSource_LSI);
  71.          
  72.          #elif defined  RTCClockSource_LSE
  73.          
  74.          /*允许LSE*/
  75.          RCC_LSEConfig(RCC_LSE_ON);
  76.          
  77.          /*等待LSE准备好*/
  78.          while(RCC_GetFlagStatus(RCC_FLAG_LSERDY)==RESET)
  79.          {
  80.          }
  81.          
  82.          /*选择LSE作为RTC时钟源*/
  83.          RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE);
  84.          #endif
  85.          
  86.          /* Enable RTC Clock */
  87.      RCC_RTCCLKCmd(ENABLE);
  88.          
  89.          #ifdef RTCClockOutput_Enable
  90.          /*禁止Tamper引脚*/
  91.          BKP_TamperPinCmd(DISABLE);/*为了将RTCCLK/64在Tamper引脚输出,Tamper功能必须被禁止*/
  92.          
  93.          /*允许RTC时钟在Tamper引脚上输出*/
  94.          BKP_RTCCalibrationClockOutputCmd(ENABLE);
  95.          #endif
  96.          
  97.          /*等待寄存器同步*/
  98.          RTC_WaitForSynchro();
  99.          
  100.          /*等待上次RTC寄存器写操作完成*/
  101.          RTC_WaitForLastTask();
  102.          
  103.          /*允许RTC秒中断*/
  104.          RTC_ITConfig(RTC_IT_SEC, ENABLE);
  105.          
  106.          /*等待上次RTC寄存器写操作完成*/
  107.          RTC_WaitForLastTask();
  108.          
  109.          #ifdef RTCClockSource_LSI
  110.          /*设置分频系数*/
  111.          RTC_SetPrescaler(31999); /*RTC周期=RTCCLK/RTC_PR=(32.000kHz/(31999+1))*/
  112.          
  113.          #elif defined  RTCClockSource_LSE
  114.          RTC_SetPrescaler(32767); /*RTC周期=RTCCLK/RTC_PR=(32.768kHz/(31767+1))*/
  115.          #endif
  116.          
  117.          /*等待上次RTC寄存器写操作完成*/
  118.          RTC_WaitForLastTask();
  119.        
  120. }

  121. void Time_Regulate(struct rtc_time *tm)
  122. {
  123.           u32 Tmp_YY = 0xFF, Tmp_MM = 0xFF, Tmp_DD = 0xFF, Tmp_HH = 0xFF, Tmp_MI = 0xFF, Tmp_SS = 0xFF;
  124.        
  125.           printf("\r\n=========================Time Settings==================");
  126.        
  127.           printf("\r\n  请输入年份(Please Set Years):  20");

  128.           while (Tmp_YY == 0xFF)
  129.           {
  130.             Tmp_YY = USART_Scanf(99);
  131.           }

  132.           printf("\n\r  年份被设置为:  20%0.2d\n\r", Tmp_YY);

  133.           tm->tm_year = Tmp_YY+2000;
  134.        
  135.           Tmp_MM = 0xFF;

  136.           printf("\r\n  请输入月份(Please Set Months):  ");

  137.           while (Tmp_MM == 0xFF)
  138.           {
  139.             Tmp_MM = USART_Scanf(12);
  140.           }

  141.           printf("\n\r  月份被设置为:  %d\n\r", Tmp_MM);

  142.           tm->tm_mon= Tmp_MM;
  143.        
  144.           Tmp_DD = 0xFF;

  145.           printf("\r\n  请输入日期(Please Set Dates):  ");

  146.           while (Tmp_DD == 0xFF)
  147.           {
  148.             Tmp_DD = USART_Scanf(31);
  149.           }

  150.           printf("\n\r  日期被设置为:  %d\n\r", Tmp_DD);

  151.           tm->tm_mday= Tmp_DD;
  152.        
  153.           Tmp_HH  = 0xFF;

  154.           printf("\r\n  请输入时钟(Please Set Hours):  ");

  155.           while (Tmp_HH == 0xFF)
  156.           {
  157.             Tmp_HH = USART_Scanf(23);
  158.           }

  159.           printf("\n\r  时钟被设置为:  %d\n\r", Tmp_HH );

  160.           tm->tm_hour= Tmp_HH;
  161.             
  162.           Tmp_MI = 0xFF;

  163.           printf("\r\n  请输入分钟(Please Set Minutes):  ");

  164.           while (Tmp_MI == 0xFF)
  165.           {
  166.             Tmp_MI = USART_Scanf(59);
  167.           }

  168.           printf("\n\r  分钟被设置为:  %d\n\r", Tmp_MI);

  169.           tm->tm_min= Tmp_MI;
  170.           
  171.           Tmp_SS = 0xFF;

  172.           printf("\r\n  请输入秒钟(Please Set Seconds):  ");

  173.           while (Tmp_SS == 0xFF)
  174.           {
  175.             Tmp_SS = USART_Scanf(59);
  176.           }

  177.           printf("\n\r  秒钟被设置为:  %d\n\r", Tmp_SS);

  178.           tm->tm_sec= Tmp_SS;
  179. }

  180. void Time_Adjust()
  181. {
  182.           RTC_WaitForLastTask();
  183.        
  184.           Time_Regulate(&systmtime);
  185.           
  186.           GregorianDay(&systmtime);

  187.           RTC_SetCounter(mktimev(&systmtime));

  188.           RTC_WaitForLastTask();
  189. }


  190. void Time_Display(uint32_t TimeVar)
  191. {          
  192.            to_tm(TimeVar, &systmtime);

  193.            printf("\r   当前时间为: %d年 %d月 %d日 (星期%s)  %0.2d:%0.2d:%0.2d",
  194.                             systmtime.tm_year, systmtime.tm_mon, systmtime.tm_mday,
  195.                             WEEK_STR[systmtime.tm_wday], systmtime.tm_hour,
  196.                             systmtime.tm_min, systmtime.tm_sec);

  197. }

  198. void Time_Show()
  199. {
  200.           printf("\n\r");
  201.        
  202.           /* Infinite loop */
  203.           while (1)
  204.           {
  205.             /* 每过1s */
  206.             if (TimeDisplay == 1)
  207.             {
  208.               Time_Display(RTC_GetCounter());
  209.               TimeDisplay = 0;
  210.             }
  211.           }
  212. }

  213. u8 USART_Scanf(u32 value)
  214. {
  215.           u32 index = 0;
  216.           u32 tmp[2] = {0, 0};
  217.        
  218.           while (index < 2)
  219.           {
  220.             while (USART_GetFlagStatus(USART1, USART_FLAG_RXNE) == RESET)
  221.             {
  222.                 }
  223.                
  224.             tmp[index++] = (USART_ReceiveData(USART1));
  225.             if ((tmp[index - 1] < 0x30) || (tmp[index - 1] > 0x39))   /*数字0到9的ASCII码为0x30至0x39*/
  226.             {
  227.                   if((index == 2) && (tmp[index - 1] == '\r'))
  228.                   {
  229.                       tmp[1] = tmp[0];
  230.               tmp[0] = 0x30;
  231.                   }
  232.                   else
  233.                   {
  234.                       printf("\n\rPlease enter valid number between 0 and 9 -->:  ");
  235.               index--;
  236.                   }
  237.             }
  238.           }
  239.           
  240.           /* 计算输入字符的相应ASCII值*/
  241.           index = (tmp[1] - 0x30) + ((tmp[0] - 0x30) * 10);
  242.           /* Checks */
  243.           if (index > value)
  244.           {
  245.             printf("\n\rPlease enter valid number between 0 and %d", value);
  246.             return 0xFF;
  247.           }
  248.           return index;
  249. }

回复 支持 反对

使用道具 举报

 楼主| 发表于 2013-8-27 14:08:36 | 显示全部楼层

Date.c文件

  1. #include "date.h"

  2. #define FEBRUARY                2
  3. #define        STARTOFTIME                1970
  4. #define SECDAY                        86400L
  5. #define SECYR                        (SECDAY * 365)
  6. #define        leapyear(year)                ((year) % 4 == 0)
  7. #define        days_in_year(a)         (leapyear(a) ? 366 : 365)
  8. #define        days_in_month(a)         (month_days[(a) - 1])

  9. static int month_days[12] = {        31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };

  10. /*计算公历*/
  11. void GregorianDay(struct rtc_time * tm)
  12. {
  13.         int leapsToDate;
  14.         int lastYear;
  15.         int day;
  16.         int MonthOffset[] = { 0,31,59,90,120,151,181,212,243,273,304,334 };

  17.         lastYear=tm->tm_year-1;

  18.         /*计算到计数的前一年之中一共经历了多少个闰年*/
  19.         leapsToDate = lastYear/4 - lastYear/100 + lastYear/400;      

  20.      /*如若计数的这一年为闰年,且计数的月份在2月之后,则日数加1,否则不加1*/
  21.         if((tm->tm_year%4==0) && ((tm->tm_year%100!=0) || (tm->tm_year%400==0)) && (tm->tm_mon>2))
  22.         {
  23.                 day=1;
  24.         }
  25.         else
  26.         {
  27.                 day=0;
  28.         }

  29.         day += lastYear*365 + leapsToDate + MonthOffset[tm->tm_mon-1] + tm->tm_mday; /*计算从计数元年元旦到计数日期一共有多少天*/

  30.         tm->tm_wday=day%7;
  31. }

  32. u32 mktimev(struct rtc_time *tm)
  33. {
  34.         if (0 >= (int) (tm->tm_mon -= 2))
  35.         {       
  36.                 tm->tm_mon += 12;       
  37.                 tm->tm_year -= 1;
  38.         }

  39.         return ((((u32) (tm->tm_year/4 - tm->tm_year/100 + tm->tm_year/400 + 367*tm->tm_mon/12 + tm->tm_mday)
  40.          + tm->tm_year*365 - 719499)*24 + tm->tm_hour )*6+ tm->tm_min )*60 + tm->tm_sec;
  41. }

  42. void to_tm(u32 tim, struct rtc_time * tm)
  43. {
  44.         register u32    i;
  45.         register long   hms, day;

  46.         day = tim / SECDAY;
  47.         hms = tim % SECDAY;

  48.         tm->tm_hour = hms / 3600;
  49.         tm->tm_min = (hms % 3600) / 60;
  50.         tm->tm_sec = (hms % 3600) % 60;

  51. /*算出当前年份,起始的计数年份为1970年*/
  52.         for (i = STARTOFTIME; day >= days_in_year(i); i++)
  53.         {
  54.                 day -= days_in_year(i);
  55.         }
  56.         tm->tm_year = i;

  57. /*计算当前的月份*/
  58.         if (leapyear(tm->tm_year))
  59.         {
  60.                 days_in_month(FEBRUARY) = 29;
  61.         }
  62.         for (i = 1; day >= days_in_month(i); i++)
  63.         {
  64.                 day -= days_in_month(i);
  65.         }
  66.         days_in_month(FEBRUARY) = 28;
  67.         tm->tm_mon = i;

  68. /*计算当前日期*/
  69.         tm->tm_mday = day + 1;

  70.         GregorianDay(tm);
  71.        
  72. }

回复 支持 反对

使用道具 举报

 楼主| 发表于 2013-8-27 14:09:26 | 显示全部楼层

stm32f10x_it.c文件


  1. #include "stm32f10x_it.h"

  2. extern uint32_t TimeDisplay;

  3. void NMI_Handler(void)
  4. {
  5. }

  6. /**
  7.   * @brief  This function handles Hard Fault exception.
  8.   * @param  None
  9.   * @retval : None
  10.   */
  11. void HardFault_Handler(void)
  12. {
  13.   /* Go to infinite loop when Hard Fault exception occurs */
  14.   while (1)
  15.   {
  16.   }
  17. }

  18. /**
  19.   * @brief  This function handles Memory Manage exception.
  20.   * @param  None
  21.   * @retval : None
  22.   */
  23. void MemManage_Handler(void)
  24. {
  25.   /* Go to infinite loop when Memory Manage exception occurs */
  26.   while (1)
  27.   {
  28.   }
  29. }

  30. /**
  31.   * @brief  This function handles Bus Fault exception.
  32.   * @param  None
  33.   * @retval : None
  34.   */
  35. void BusFault_Handler(void)
  36. {
  37.   /* Go to infinite loop when Bus Fault exception occurs */
  38.   while (1)
  39.   {
  40.   }
  41. }

  42. /**
  43.   * @brief  This function handles Usage Fault exception.
  44.   * @param  None
  45.   * @retval : None
  46.   */
  47. void UsageFault_Handler(void)
  48. {
  49.   /* Go to infinite loop when Usage Fault exception occurs */
  50.   while (1)
  51.   {
  52.   }
  53. }

  54. /**
  55.   * @brief  This function handles SVCall exception.
  56.   * @param  None
  57.   * @retval : None
  58.   */
  59. void SVC_Handler(void)
  60. {
  61. }

  62. /**
  63.   * @brief  This function handles Debug Monitor exception.
  64.   * @param  None
  65.   * @retval : None
  66.   */
  67. void DebugMon_Handler(void)
  68. {
  69. }

  70. /**
  71.   * @brief  This function handles PendSVC exception.
  72.   * @param  None
  73.   * @retval : None
  74.   */
  75. void PendSV_Handler(void)
  76. {
  77. }

  78. /**
  79.   * @brief  This function handles SysTick Handler.
  80.   * @param  None
  81.   * @retval : None
  82.   */
  83. void SysTick_Handler(void)
  84. {
  85. }

  86. void RTC_IRQHandler(void)
  87. {
  88.           if (RTC_GetITStatus(RTC_IT_SEC) != RESET)
  89.           {
  90.             /* Clear the RTC Second interrupt */
  91.             RTC_ClearITPendingBit(RTC_IT_SEC);
  92.        
  93.             /* Enable time update */
  94.             TimeDisplay = 1;
  95.        
  96.             /* Wait until last write operation on RTC registers has finished */
  97.             RTC_WaitForLastTask();

  98.             /* Reset RTC Counter when Time is 23:59:59 */
  99.             if (RTC_GetCounter() == 0x00015180)
  100.             {
  101.               RTC_SetCounter(0x0);
  102.               /* Wait until last write operation on RTC registers has finished */
  103.               RTC_WaitForLastTask();
  104.             }
  105.           }
  106. }

回复 支持 反对

使用道具 举报

发表于 2013-8-31 21:22:56 | 显示全部楼层
真棒!!非常感谢
回复 支持 反对

使用道具 举报

发表于 2013-11-26 11:22:19 | 显示全部楼层
真棒!!非常感谢
回复 支持 反对

使用道具 举报

发表于 2013-12-13 10:09:23 | 显示全部楼层
收藏了先!真棒!!非常感谢
回复 支持 反对

使用道具 举报

发表于 2014-3-25 15:35:08 | 显示全部楼层
哥们  山外历程是串口显示的   你的能在LCD上显示吗?  不用超级终端显示  怎么改啊强烈支持,非常感谢哥们
回复 支持 反对

使用道具 举报

发表于 2014-4-12 14:50:29 | 显示全部楼层
帅呆了,赞一个
回复 支持 反对

使用道具 举报

发表于 2014-5-9 20:48:57 | 显示全部楼层
yu940916 发表于 2014-3-25 15:35
哥们  山外历程是串口显示的   你的能在LCD上显示吗?  不用超级终端显示  怎么改啊强烈支持,非常感谢哥们 ...

今天刚做了一个,实在山外ISO开发板例程的基础上改的,支持串口和LCD显示,要的话留邮箱
回复 支持 反对

使用道具 举报

发表于 2014-5-9 21:18:05 | 显示全部楼层
很不错,学习了
回复 支持 反对

使用道具 举报

发表于 2014-5-10 09:32:15 | 显示全部楼层
yu940916 发表于 2014-3-25 15:35
哥们  山外历程是串口显示的   你的能在LCD上显示吗?  不用超级终端显示  怎么改啊强烈支持,非常感谢哥们 ...

调用LCD函数,应该不是很难的,移植一下
回复 支持 反对

使用道具 举报

发表于 2014-7-21 15:05:28 | 显示全部楼层
回复 支持 反对

使用道具 举报

发表于 2014-8-6 10:22:36 | 显示全部楼层
15637749583@163.com  希望能更详细一点  ,把你的实物也让我看看吧!
回复 支持 反对

使用道具 举报

发表于 2014-8-23 06:41:43 | 显示全部楼层
调用LCD函数强烈支持,非常感谢哥们强烈支持,非常感谢哥们
回复 支持 反对

使用道具 举报

发表于 2014-8-23 09:09:56 | 显示全部楼层
楼主  这不就是 RTC  实时时钟吗!   走过路过,不能错过
回复 支持 反对

使用道具 举报

发表于 2014-8-23 09:29:50 | 显示全部楼层
不错呦 帅呆了,赞一个
回复 支持 反对

使用道具 举报

发表于 2014-8-23 17:07:16 | 显示全部楼层
673261839@qq.com 能发给我一份么?谢了!
回复 支持 反对

使用道具 举报

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

本版积分规则

快速回复 返回列表 返回顶部