ARM 【RTC时钟实验】

//main.c
#include "led.h"
#include "delay.h"
#include "key.h"
#include "sys.h"
#include "lcd.h"
#include "usart.h"    
#include "usmart.h"     
#include "rtc.h" 

/************************************************
 ALIENTEK 战舰STM32F103开发板实验15
 RTC实时时钟实验  
 技术支持:www.openedv.com
 淘宝店铺:http://eboard.taobao.com 
 关注微信公众平台微信号:"正点原子",免费获取STM32资料。
 广州市星翼电子科技有限公司  
 作者:正点原子 @ALIENTEK
************************************************/

 int main(void)
 {     
     u8 t=0;    
    delay_init();             //延时函数初始化      
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置中断优先级分组为组2:2位抢占优先级,2位响应优先级
    uart_init(115200);         //串口初始化为115200
     LED_Init();                 //LED端口初始化
    LCD_Init();                 
    usmart_dev.init(SystemCoreClock/1000000);    //初始化USMART    
    RTC_Init();                  //RTC初始化
    POINT_COLOR=RED;//设置字体为红色 
    LCD_ShowString(60,50,200,16,16,"WarShip STM32");    
    LCD_ShowString(60,70,200,16,16,"RTC TEST");    
    LCD_ShowString(60,90,200,16,16,"ATOM@ALIENTEK");
    LCD_ShowString(60,110,200,16,16,"2015/1/14");        
    //显示时间
    POINT_COLOR=BLUE;//设置字体为蓝色
    LCD_ShowString(60,130,200,16,16,"    -  -  ");       
    LCD_ShowString(60,162,200,16,16,"  :  :  ");            
    while(1)
    {                                    
        if(t!=calendar.sec)
        {
            t=calendar.sec;
            LCD_ShowNum(60,130,calendar.w_year,4,16);                                      
            LCD_ShowNum(100,130,calendar.w_month,2,16);                                      
            LCD_ShowNum(124,130,calendar.w_date,2,16);     
            switch(calendar.week)
            {
                case 0:
                    LCD_ShowString(60,148,200,16,16,"Sunday   ");
                    break;
                case 1:
                    LCD_ShowString(60,148,200,16,16,"Monday   ");
                    break;
                case 2:
                    LCD_ShowString(60,148,200,16,16,"Tuesday  ");
                    break;
                case 3:
                    LCD_ShowString(60,148,200,16,16,"Wednesday");
                    break;
                case 4:
                    LCD_ShowString(60,148,200,16,16,"Thursday ");
                    break;
                case 5:
                    LCD_ShowString(60,148,200,16,16,"Friday   ");
                    break;
                case 6:
                    LCD_ShowString(60,148,200,16,16,"Saturday ");
                    break;  
            }
            LCD_ShowNum(60,162,calendar.hour,2,16);                                      
            LCD_ShowNum(84,162,calendar.min,2,16);                                      
            LCD_ShowNum(108,162,calendar.sec,2,16);
            LED0=!LED0;
        }    
        delay_ms(10);                                  
    };  
 }
main.c

 

 

  1 #include "sys.h"
  2 #include "delay.h"
  3 #include "usart.h"
  4 #include "rtc.h"             
  5 //Mini STM32开发板
  6 //RTC实时时钟 驱动代码             
  7 //正点原子@ALIENTEK
  8 //2010/6/6
  9        
 10 _calendar_obj calendar;//时钟结构体 
 11  
 12 static void RTC_NVIC_Config(void)
 13 {    
 14   NVIC_InitTypeDef NVIC_InitStructure;
 15     NVIC_InitStructure.NVIC_IRQChannel = RTC_IRQn;        //RTC全局中断
 16     NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;    //先占优先级1位,从优先级3位
 17     NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;    //先占优先级0位,从优先级4位
 18     NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;        //使能该通道中断
 19     NVIC_Init(&NVIC_InitStructure);        //根据NVIC_InitStruct中指定的参数初始化外设NVIC寄存器
 20 }
 21 
 22 //实时时钟配置
 23 //初始化RTC时钟,同时检测时钟是否工作正常
 24 //BKP->DR1用于保存是否第一次配置的设置
 25 //返回0:正常
 26 //其他:错误代码
 27 
 28 u8 RTC_Init(void)
 29 {
 30     //检查是不是第一次配置时钟
 31     u8 temp=0;
 32     RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE);    //使能PWR和BKP外设时钟   
 33     PWR_BackupAccessCmd(ENABLE);    //使能后备寄存器访问  
 34     if (BKP_ReadBackupRegister(BKP_DR1) != 0x5050)        //从指定的后备寄存器中读出数据:读出了与写入的指定数据不相乎
 35         {                 
 36         BKP_DeInit();    //复位备份区域     
 37         RCC_LSEConfig(RCC_LSE_ON);    //设置外部低速晶振(LSE),使用外设低速晶振
 38         while (RCC_GetFlagStatus(RCC_FLAG_LSERDY) == RESET&&temp<250)    //检查指定的RCC标志位设置与否,等待低速晶振就绪
 39             {
 40             temp++;
 41             delay_ms(10);
 42             }
 43         if(temp>=250)return 1;//初始化时钟失败,晶振有问题        
 44         RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE);        //设置RTC时钟(RTCCLK),选择LSE作为RTC时钟    
 45         RCC_RTCCLKCmd(ENABLE);    //使能RTC时钟  
 46         RTC_WaitForLastTask();    //等待最近一次对RTC寄存器的写操作完成
 47         RTC_WaitForSynchro();        //等待RTC寄存器同步  
 48         RTC_ITConfig(RTC_IT_SEC, ENABLE);        //使能RTC秒中断
 49         RTC_WaitForLastTask();    //等待最近一次对RTC寄存器的写操作完成
 50         RTC_EnterConfigMode();/// 允许配置    
 51         RTC_SetPrescaler(32767); //设置RTC预分频的值
 52         RTC_WaitForLastTask();    //等待最近一次对RTC寄存器的写操作完成
 53         RTC_Set(2015,1,14,17,42,55);  //设置时间    
 54         RTC_ExitConfigMode(); //退出配置模式  
 55         BKP_WriteBackupRegister(BKP_DR1, 0X5050);    //向指定的后备寄存器中写入用户程序数据
 56         }
 57     else//系统继续计时
 58         {
 59 
 60         RTC_WaitForSynchro();    //等待最近一次对RTC寄存器的写操作完成
 61         RTC_ITConfig(RTC_IT_SEC, ENABLE);    //使能RTC秒中断
 62         RTC_WaitForLastTask();    //等待最近一次对RTC寄存器的写操作完成
 63         }
 64     RTC_NVIC_Config();//RCT中断分组设置                                 
 65     RTC_Get();//更新时间    
 66     return 0; //ok
 67 
 68 }                             
 69 //RTC时钟中断
 70 //每秒触发一次  
 71 //extern u16 tcnt; 
 72 void RTC_IRQHandler(void)
 73 {         
 74     if (RTC_GetITStatus(RTC_IT_SEC) != RESET)//秒钟中断
 75     {                            
 76         RTC_Get();//更新时间   
 77      }
 78     if(RTC_GetITStatus(RTC_IT_ALR)!= RESET)//闹钟中断
 79     {
 80         RTC_ClearITPendingBit(RTC_IT_ALR);        //清闹钟中断          
 81       RTC_Get();                //更新时间   
 82       printf("Alarm Time:%d-%d-%d %d:%d:%d\n",calendar.w_year,calendar.w_month,calendar.w_date,calendar.hour,calendar.min,calendar.sec);//输出闹铃时间    
 83         
 84       }                                                    
 85     RTC_ClearITPendingBit(RTC_IT_SEC|RTC_IT_OW);        //清闹钟中断
 86     RTC_WaitForLastTask();                                                   
 87 }
 88 //判断是否是闰年函数
 89 //月份   1  2  3  4  5  6  7  8  9  10 11 12
 90 //闰年   31 29 31 30 31 30 31 31 30 31 30 31
 91 //非闰年 31 28 31 30 31 30 31 31 30 31 30 31
 92 //输入:年份
 93 //输出:该年份是不是闰年.1,是.0,不是
 94 u8 Is_Leap_Year(u16 year)
 95 {              
 96     if(year%4==0) //必须能被4整除
 97     { 
 98         if(year%100==0) 
 99         { 
100             if(year%400==0)return 1;//如果以00结尾,还要能被400整除        
101             else return 0;   
102         }else return 1;   
103     }else return 0;    
104 }                    
105 //设置时钟
106 //把输入的时钟转换为秒钟
107 //以1970年1月1日为基准
108 //1970~2099年为合法年份
109 //返回值:0,成功;其他:错误代码.
110 //月份数据表                                             
111 u8 const table_week[12]={0,3,3,6,1,4,6,2,5,0,3,5}; //月修正数据表      
112 //平年的月份日期表
113 const u8 mon_table[12]={31,28,31,30,31,30,31,31,30,31,30,31};
114 u8 RTC_Set(u16 syear,u8 smon,u8 sday,u8 hour,u8 min,u8 sec)
115 {
116     u16 t;
117     u32 seccount=0;
118     if(syear<1970||syear>2099)return 1;       
119     for(t=1970;t<syear;t++)    //把所有年份的秒钟相加
120     {
121         if(Is_Leap_Year(t))seccount+=31622400;//闰年的秒钟数
122         else seccount+=31536000;              //平年的秒钟数
123     }
124     smon-=1;
125     for(t=0;t<smon;t++)       //把前面月份的秒钟数相加
126     {
127         seccount+=(u32)mon_table[t]*86400;//月份秒钟数相加
128         if(Is_Leap_Year(syear)&&t==1)seccount+=86400;//闰年2月份增加一天的秒钟数       
129     }
130     seccount+=(u32)(sday-1)*86400;//把前面日期的秒钟数相加 
131     seccount+=(u32)hour*3600;//小时秒钟数
132     seccount+=(u32)min*60;     //分钟秒钟数
133     seccount+=sec;//最后的秒钟加上去
134 
135     RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE);    //使能PWR和BKP外设时钟  
136     PWR_BackupAccessCmd(ENABLE);    //使能RTC和后备寄存器访问 
137     RTC_SetCounter(seccount);    //设置RTC计数器的值
138 
139     RTC_WaitForLastTask();    //等待最近一次对RTC寄存器的写操作完成      
140     return 0;        
141 }
142 
143 //初始化闹钟          
144 //以1970年1月1日为基准
145 //1970~2099年为合法年份
146 //syear,smon,sday,hour,min,sec:闹钟的年月日时分秒   
147 //返回值:0,成功;其他:错误代码.
148 u8 RTC_Alarm_Set(u16 syear,u8 smon,u8 sday,u8 hour,u8 min,u8 sec)
149 {
150     u16 t;
151     u32 seccount=0;
152     if(syear<1970||syear>2099)return 1;       
153     for(t=1970;t<syear;t++)    //把所有年份的秒钟相加
154     {
155         if(Is_Leap_Year(t))seccount+=31622400;//闰年的秒钟数
156         else seccount+=31536000;              //平年的秒钟数
157     }
158     smon-=1;
159     for(t=0;t<smon;t++)       //把前面月份的秒钟数相加
160     {
161         seccount+=(u32)mon_table[t]*86400;//月份秒钟数相加
162         if(Is_Leap_Year(syear)&&t==1)seccount+=86400;//闰年2月份增加一天的秒钟数       
163     }
164     seccount+=(u32)(sday-1)*86400;//把前面日期的秒钟数相加 
165     seccount+=(u32)hour*3600;//小时秒钟数
166     seccount+=(u32)min*60;     //分钟秒钟数
167     seccount+=sec;//最后的秒钟加上去                 
168     //设置时钟
169     RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE);    //使能PWR和BKP外设时钟   
170     PWR_BackupAccessCmd(ENABLE);    //使能后备寄存器访问  
171     //上面三步是必须的!
172     
173     RTC_SetAlarm(seccount);
174  
175     RTC_WaitForLastTask();    //等待最近一次对RTC寄存器的写操作完成      
176     
177     return 0;        
178 }
179 
180 
181 //得到当前的时间
182 //返回值:0,成功;其他:错误代码.
183 u8 RTC_Get(void)
184 {
185     static u16 daycnt=0;
186     u32 timecount=0; 
187     u32 temp=0;
188     u16 temp1=0;      
189     timecount=RTC_GetCounter();     
190      temp=timecount/86400;   //得到天数(秒钟数对应的)
191     if(daycnt!=temp)//超过一天了
192     {      
193         daycnt=temp;
194         temp1=1970;    //从1970年开始
195         while(temp>=365)
196         {                 
197             if(Is_Leap_Year(temp1))//是闰年
198             {
199                 if(temp>=366)temp-=366;//闰年的秒钟数
200                 else {temp1++;break;}  
201             }
202             else temp-=365;      //平年 
203             temp1++;  
204         }   
205         calendar.w_year=temp1;//得到年份
206         temp1=0;
207         while(temp>=28)//超过了一个月
208         {
209             if(Is_Leap_Year(calendar.w_year)&&temp1==1)//当年是不是闰年/2月份
210             {
211                 if(temp>=29)temp-=29;//闰年的秒钟数
212                 else break; 
213             }
214             else 
215             {
216                 if(temp>=mon_table[temp1])temp-=mon_table[temp1];//平年
217                 else break;
218             }
219             temp1++;  
220         }
221         calendar.w_month=temp1+1;    //得到月份
222         calendar.w_date=temp+1;      //得到日期 
223     }
224     temp=timecount%86400;             //得到秒钟数          
225     calendar.hour=temp/3600;         //小时
226     calendar.min=(temp%3600)/60;     //分钟    
227     calendar.sec=(temp%3600)%60;     //秒钟
228     calendar.week=RTC_Get_Week(calendar.w_year,calendar.w_month,calendar.w_date);//获取星期   
229     return 0;
230 }     
231 //获得现在是星期几
232 //功能描述:输入公历日期得到星期(只允许1901-2099年)
233 //输入参数:公历年月日 
234 //返回值:星期号                                                                                         
235 u8 RTC_Get_Week(u16 year,u8 month,u8 day)
236 {    
237     u16 temp2;
238     u8 yearH,yearL;
239     
240     yearH=year/100;    yearL=year%100; 
241     // 如果为21世纪,年份数加100  
242     if (yearH>19)yearL+=100;
243     // 所过闰年数只算1900年之后的  
244     temp2=yearL+yearL/4;
245     temp2=temp2%7; 
246     temp2=temp2+day+table_week[month-1];
247     if (yearL%4==0&&month<3)temp2--;
248     return(temp2%7);
249 }              
rtc.c
 1 #ifndef __RTC_H
 2 #define __RTC_H        
 3 //Mini STM32开发板
 4 //RTC实时时钟 驱动代码             
 5 //正点原子@ALIENTEK
 6 //2010/6/6
 7 
 8 //时间结构体
 9 typedef struct 
10 {
11     vu8 hour;
12     vu8 min;
13     vu8 sec;            
14     //公历日月年周
15     vu16 w_year;
16     vu8  w_month;
17     vu8  w_date;
18     vu8  week;         
19 }_calendar_obj;                     
20 extern _calendar_obj calendar;    //日历结构体
21 
22 extern u8 const mon_table[12];    //月份日期数据表
23 void Disp_Time(u8 x,u8 y,u8 size);//在制定位置开始显示时间
24 void Disp_Week(u8 x,u8 y,u8 size,u8 lang);//在指定位置显示星期
25 u8 RTC_Init(void);        //初始化RTC,返回0,失败;1,成功;
26 u8 Is_Leap_Year(u16 year);//平年,闰年判断
27 u8 RTC_Alarm_Set(u16 syear,u8 smon,u8 sday,u8 hour,u8 min,u8 sec);
28 u8 RTC_Get(void);         //更新时间   
29 u8 RTC_Get_Week(u16 year,u8 month,u8 day);
30 u8 RTC_Set(u16 syear,u8 smon,u8 sday,u8 hour,u8 min,u8 sec);//设置时间             
31 #endif
rtc.h

 

 

 1 #include "stm32f10x.h"
 2 #include "key.h"
 3 #include "sys.h" 
 4 #include "delay.h"
 5 //////////////////////////////////////////////////////////////////////////////////     
 6 //本程序只供学习使用,未经作者许可,不得用于其它任何用途
 7 //ALIENTEK战舰STM32开发板
 8 //按键驱动代码       
 9 //正点原子@ALIENTEK
10 //技术论坛:www.openedv.com
11 //修改日期:2012/9/3
12 //版本:V1.0
13 //版权所有,盗版必究。
14 //Copyright(C) 广州市星翼电子科技有限公司 2009-2019
15 //All rights reserved                                      
16 //////////////////////////////////////////////////////////////////////////////////  
17                                     
18 //按键初始化函数
19 void KEY_Init(void) //IO初始化
20 { 
21      GPIO_InitTypeDef GPIO_InitStructure;
22  
23      RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOE,ENABLE);//使能PORTA,PORTE时钟
24 
25     GPIO_InitStructure.GPIO_Pin  = GPIO_Pin_2|GPIO_Pin_3|GPIO_Pin_4;//KEY0-KEY2
26     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; //设置成上拉输入
27      GPIO_Init(GPIOE, &GPIO_InitStructure);//初始化GPIOE2,3,4
28 
29     //初始化 WK_UP-->GPIOA.0      下拉输入
30     GPIO_InitStructure.GPIO_Pin  = GPIO_Pin_0;
31     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD; //PA0设置成输入,默认下拉      
32     GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA.0
33 
34 }
35 //按键处理函数
36 //返回按键值
37 //mode:0,不支持连续按;1,支持连续按;
38 //0,没有任何按键按下
39 //1,KEY0按下
40 //2,KEY1按下
41 //3,KEY2按下 
42 //4,KEY3按下 WK_UP
43 //注意此函数有响应优先级,KEY0>KEY1>KEY2>KEY3!!
44 u8 KEY_Scan(u8 mode)
45 {     
46     static u8 key_up=1;//按键按松开标志
47     if(mode)key_up=1;  //支持连按          
48     if(key_up&&(KEY0==0||KEY1==0||KEY2==0||WK_UP==1))
49     {
50         delay_ms(10);//去抖动 
51         key_up=0;
52         if(KEY0==0)return KEY0_PRES;
53         else if(KEY1==0)return KEY1_PRES;
54         else if(KEY2==0)return KEY2_PRES;
55         else if(WK_UP==1)return WKUP_PRES;
56     }else if(KEY0==1&&KEY1==1&&KEY2==1&&WK_UP==0)key_up=1;         
57      return 0;// 无按键按下
58 }
key.c

 

posted @ 2019-04-17 22:43  Crown-V  阅读(288)  评论(0)    收藏  举报