完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>
/*******************************************************
/******************************************************* RTC.H /******************************************************** /******************************************************** #ifndef __RTC_H #define __RTC_H #include "sys.h" //Mini STM32开发板 //RTC实时时钟 驱动代码 //正点原子@ALIENTEK //2010/6/6 //时间结构体 typedef struct { vu8 hour; vu8 min; vu8 sec; //公历日月年周 vu16 w_year; vu8 w_month; vu8 w_date; vu8 week; } _calendar_obj; typedef struct { vu8 year; vu8 month; vu8 day; vu8 hour; vu8 min; vu8 sec; } _alr_obj; extern _calendar_obj calendar; //日历结构体 extern u8 const mon_table[12]; //月份日期数据表 void Disp_Time(u8 x, u8 y, u8 size); //在制定位置开始显示时间 void Disp_Week(u8 x, u8 y, u8 size, u8 lang); //在指定位置显示星期 u8 RTC_Init(void); //初始化RTC,返回0,失败;1,成功; u8 Is_Leap_Year(u16 year);//平年,闰年判断 //u8 RTC_Alarm_Set(u16 syear,u8 smon,u8 sday,u8 hour,u8 min,u8 sec); u8 RTC_Get(void); //更新时间 u8 RTC_Get_Week(u16 year, u8 month, u8 day); u8 RTC_Set(u16 syear, u8 smon, u8 sday, u8 hour, u8 min, u8 sec); //设置时间 u8 ALR_Set(u16 year, u8 month, u8 day, u8 hour, u8 min, u8 sec); #endif /********************************************************** /********************************************************** RTC.C文件 /********************************************************** /********************************************************** #include "rtc.h" #include "sys.h" #include "delay.h" #include "usart.h" #include "led.h" #include "beep.h" //Mini STM32开发板 //RTC实时时钟 驱动代码 //正点原子@ALIENTEK //2010/6/6 _calendar_obj calendar;//时钟结构体 _alr_obj ALR; //static void RTC_NVIC_Config(void) //{ // NVIC_InitTypeDef NVIC_InitStructure; // NVIC_InitStructure.NVIC_IRQChannel = RTC_IRQn; //RTC全局中断 // NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; //先占优先级1位,从优先级3位 // NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; //先占优先级0位,从优先级4位 // NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //使能该通道中断 // NVIC_Init(&NVIC_InitStructure); //根据NVIC_InitStruct中指定的参数初始化外设NVIC寄存器 //} static void RTC_NVIC_Config(void) { NVIC_InitTypeDef NVIC_InitStructure; EXTI_InitTypeDef EXTI_InitStructure; NVIC_InitStructure.NVIC_IRQChannel = RTC_IRQn; //RTC全局中断 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2; //先占优先级1位,从优先级3位 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2; //先占优先级0位,从优先级4位 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //使能该通道中断 NVIC_Init(&NVIC_InitStructure); //根据NVIC_InitStruct中指定的参数初始化外设NVIC寄存器 NVIC_InitStructure.NVIC_IRQChannel = RTCAlarm_IRQn; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; NVIC_Init(&NVIC_InitStructure); EXTI_ClearITPendingBit(EXTI_Line17); EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; EXTI_InitStructure.EXTI_Line = EXTI_Line17; EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising; EXTI_InitStructure.EXTI_LineCmd = ENABLE; EXTI_Init(&EXTI_InitStructure); } //实时时钟配置 //初始化RTC时钟,同时检测时钟是否工作正常 //BKP->DR1用于保存是否第一次配置的设置 //返回0:正常 //其他:错误代码 u8 RTC_Init(void) { //检查是不是第一次配置时钟 u8 temp = 0; RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE); //使能PWR和BKP外设时钟 PWR_BackupAccessCmd(ENABLE); //使能后备寄存器访问 if (BKP_ReadBackupRegister(BKP_DR1) != 0x5051) //从指定的后备寄存器中读出数据:读出了与写入的指定数据不相乎 { BKP_DeInit(); //复位备份区域 RCC_LSEConfig(RCC_LSE_ON); //设置外部低速晶振(LSE),使用外设低速晶振 while (RCC_GetFlagStatus(RCC_FLAG_LSERDY) == RESET && temp < 250) //检查指定的RCC标志位设置与否,等待低速晶振就绪 { temp++; delay_ms(10); } if(temp >= 250)return 1; //初始化时钟失败,晶振有问题 RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE); //设置RTC时钟(RTCCLK),选择LSE作为RTC时钟 RCC_RTCCLKCmd(ENABLE); //使能RTC时钟 RTC_WaitForLastTask(); //等待最近一次对RTC寄存器的写操作完成 RTC_WaitForSynchro(); //等待RTC寄存器同步 RTC_ITConfig(RTC_IT_SEC | RTC_IT_ALR, ENABLE); //使能RTC秒中断 RTC_WaitForLastTask(); //等待最近一次对RTC寄存器的写操作完成 RTC_EnterConfigMode();/// 允许配置 RTC_SetPrescaler(32767); //设置RTC预分频的值 RTC_WaitForLastTask(); //等待最近一次对RTC寄存器的写操作完成 RTC_Set(2018, 4, 8, 21, 34, 50); //设置时间 RTC_WaitForLastTask(); RTC_WaitForSynchro(); ALR_Set(2018, 4, 8, 21, 35, 0); RTC_ExitConfigMode(); //退出配置模式 BKP_WriteBackupRegister(BKP_DR1, 0X5051); //向指定的后备寄存器中写入用户程序数据 } else//系统继续计时 { RTC_WaitForSynchro(); //等待最近一次对RTC寄存器的写操作完成 RTC_ITConfig(RTC_IT_SEC, ENABLE); //使能RTC秒中断 RTC_WaitForLastTask(); //等待最近一次对RTC寄存器的写操作完成 } RTC_NVIC_Config();//RCT中断分组设置 RTC_Get();//更新时间 return 0; //ok } //RTC时钟中断 //每秒触发一次 extern int count; void RTC_IRQHandler(void) { if(RTC_GetITStatus(RTC_IT_SEC) != RESET) { RTC_Get(); count++; } RTC_ClearITPendingBit(RTC_IT_OW | RTC_IT_SEC); RTC_WaitForLastTask(); } //闹钟中断 void RTCAlarm_IRQHandler(void) { if(RTC_GetITStatus(RTC_IT_ALR) != RESET) { BEEP = 1; } EXTI_ClearITPendingBit(EXTI_Line17); RTC_WaitForLastTask(); RTC_ClearITPendingBit(RTC_IT_ALR); RTC_WaitForLastTask(); } //RTC时钟中断 //每秒触发一次 //extern u16 tcnt; //void RTC_IRQHandler(void) //{ // if (RTC_GetITStatus(RTC_IT_SEC) != RESET)//秒钟中断 // { // RTC_Get();//更新时间 // } // if(RTC_GetITStatus(RTC_IT_ALR)!= RESET)//闹钟中断 // { // RTC_ClearITPendingBit(RTC_IT_ALR); //清闹钟中断 // RTC_Get(); //更新时间 // printf("Alarm Time:%d-%d-%d %d:%d:%dn",calendar.w_year,calendar.w_month,calendar.w_date,calendar.hour,calendar.min,calendar.sec);//输出闹铃时间 // // } // RTC_ClearITPendingBit(RTC_IT_SEC|RTC_IT_OW); //清闹钟中断 // RTC_WaitForLastTask(); //} //判断是否是闰年函数 //月份 1 2 3 4 5 6 7 8 9 10 11 12 //闰年 31 29 31 30 31 30 31 31 30 31 30 31 //非闰年 31 28 31 30 31 30 31 31 30 31 30 31 //输入:年份 //输出:该年份是不是闰年.1,是.0,不是 u8 Is_Leap_Year(u16 year) { if(year % 4 == 0) //必须能被4整除 { if(year % 100 == 0) { if(year % 400 == 0)return 1; //如果以00结尾,还要能被400整除 else return 0; } else return 1; } else return 0; } //设置时钟 //把输入的时钟转换为秒钟 //以1970年1月1日为基准 //1970~2099年为合法年份 //返回值:0,成功;其他:错误代码. //月份数据表 u8 const table_week[12] = {0, 3, 3, 6, 1, 4, 6, 2, 5, 0, 3, 5}; //月修正数据表 //平年的月份日期表 const u8 mon_table[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; u8 RTC_Set(u16 syear, u8 smon, u8 sday, u8 hour, u8 min, u8 sec) { u16 t; u32 seccount = 0; if(syear < 1970 || syear > 2099)return 1; for(t = 1970; t < syear; t++) //把所有年份的秒钟相加 { if(Is_Leap_Year(t))seccount += 31622400; //闰年的秒钟数 else seccount += 31536000; //平年的秒钟数 } smon -= 1; for(t = 0; t < smon; t++) //把前面月份的秒钟数相加 { seccount += (u32)mon_table[t] * 86400; //月份秒钟数相加 if(Is_Leap_Year(syear) && t == 1)seccount += 86400; //闰年2月份增加一天的秒钟数 } seccount += (u32)(sday - 1) * 86400; //把前面日期的秒钟数相加 seccount += (u32)hour * 3600; //小时秒钟数 seccount += (u32)min * 60; //分钟秒钟数 seccount += sec; //最后的秒钟加上去 RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE); //使能PWR和BKP外设时钟 PWR_BackupAccessCmd(ENABLE); //使能RTC和后备寄存器访问 RTC_SetCounter(seccount); //设置RTC计数器的值 RTC_WaitForLastTask(); //等待最近一次对RTC寄存器的写操作完成 return 0; } |
|
|
|
//初始化闹钟
//以1970年1月1日为基准 //1970~2099年为合法年份 //syear,smon,sday,hour,min,sec:闹钟的年月日时分秒 //返回值:0,成功;其他:错误代码. //u8 RTC_Alarm_Set(u16 syear,u8 smon,u8 sday,u8 hour,u8 min,u8 sec) //{ // u16 t; // u32 seccount=0; // if(syear<1970||syear>2099)return 1; // for(t=1970;t // if(Is_Leap_Year(t))seccount+=31622400;//闰年的秒钟数 // else seccount+=31536000; //平年的秒钟数 // } // smon-=1; // for(t=0;t // seccount+=(u32)mon_table[t]*86400;//月份秒钟数相加 // if(Is_Leap_Year(syear)&&t==1)seccount+=86400;//闰年2月份增加一天的秒钟数 // } // seccount+=(u32)(sday-1)*86400;//把前面日期的秒钟数相加 // seccount+=(u32)hour*3600;//小时秒钟数 // seccount+=(u32)min*60; //分钟秒钟数 // seccount+=sec;//最后的秒钟加上去 // //设置时钟 // RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE); //使能PWR和BKP外设时钟 // PWR_BackupAccessCmd(ENABLE); //使能后备寄存器访问 // //上面三步是必须的! // // RTC_SetAlarm(seccount); // // RTC_WaitForLastTask(); //等待最近一次对RTC寄存器的写操作完成 // // return 0; //} u8 ALR_Set(u16 year, u8 month, u8 day, u8 hour, u8 min, u8 sec) { u16 t; u32 seccount = 0; if(year < 1970 || year > 2099) return 1; for(t = 1970; t < year; t++) { if(Is_Leap_Year(t)) seccount += 31622400; else seccount += 31536000; } month -= 1; for(t = 0; t < month; t++) { seccount += (u32)mon_table[t] * 86400; if(Is_Leap_Year(year) && t == 1) seccount += 86400; } seccount += (u32)(day - 1) * 86400; seccount += (u32)hour * 3600; seccount += (u32)min * 60; seccount += sec; RCC_APB1PeriphClockCmd(RCC_APB1Periph_BKP | RCC_APB1Periph_PWR, ENABLE); PWR_BackupAccessCmd(ENABLE); RTC_EnterConfigMode(); RTC_SetAlarm(seccount); RTC_WaitForLastTask(); return 0; } //得到当前的时间 //返回值:0,成功;其他:错误代码. u8 RTC_Get(void) { static u16 daycnt = 0; u32 timecount = 0; u32 temp = 0; u16 temp1 = 0; timecount = RTC_GetCounter(); temp = timecount / 86400; //得到天数(秒钟数对应的) if(daycnt != temp) //超过一天了 { daycnt = temp; temp1 = 1970; //从1970年开始 while(temp >= 365) { if(Is_Leap_Year(temp1))//是闰年 { if(temp >= 366)temp -= 366; //闰年的秒钟数 else { temp1++; break; } } else temp -= 365; //平年 temp1++; } calendar.w_year = temp1; //得到年份 temp1 = 0; while(temp >= 28) //超过了一个月 { if(Is_Leap_Year(calendar.w_year) && temp1 == 1) //当年是不是闰年/2月份 { if(temp >= 29)temp -= 29; //闰年的秒钟数 else break; } else { if(temp >= mon_table[temp1])temp -= mon_table[temp1]; //平年 else break; } temp1++; } calendar.w_month = temp1 + 1; //得到月份 calendar.w_date = temp + 1; //得到日期 } temp = timecount % 86400; //得到秒钟数 calendar.hour = temp / 3600; //小时 calendar.min = (temp % 3600) / 60; //分钟 calendar.sec = (temp % 3600) % 60; //秒钟 calendar.week = RTC_Get_Week(calendar.w_year, calendar.w_month, calendar.w_date); //获取星期 return 0; } //获得现在是星期几 //功能描述:输入公历日期得到星期(只允许1901-2099年) //输入参数:公历年月日 //返回值:星期号 u8 RTC_Get_Week(u16 year, u8 month, u8 day) { u16 temp2; u8 yearH, yearL; yearH = year / 100; yearL = year % 100; // 如果为21世纪,年份数加100 if (yearH > 19)yearL += 100; // 所过闰年数只算1900年之后的 temp2 = yearL + yearL / 4; temp2 = temp2 % 7; temp2 = temp2 + day + table_week[month - 1]; if (yearL % 4 == 0 && month < 3)temp2--; return(temp2 % 7); } 1.注意RTC时钟采用了RTC秒中断和闹钟中断,这是两个不同的中断服务函数 2.中断服务管理函数优先级要注意看 /************************************************************** /************************************************************** main.c /************************************************************** /************************************************************** volatile int count = 0 ; 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初始化 BEEP_Init(); //初始化蜂鸣器端口 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); if(KEY0==0) { BEEP = 0; } if(count>20) //只会亮10s,跟时钟是同步走的 { BEEP = 0; count = 0 ; } }; } ***实验现象采用LCD屏幕显示RTC时间,闹钟到时蜂鸣器发出声音***硬件采用正点原子战舰 |
|
|
|
只有小组成员才能发言,加入小组>>
调试STM32H750的FMC总线读写PSRAM遇到的问题求解?
1117 浏览1 评论
X-NUCLEO-IHM08M1板文档中输出电流为15Arms,15Arms是怎么得出来的呢?
1143 浏览1 评论
575 浏览2 评论
STM32F030F4 HSI时钟温度测试过不去是怎么回事?
430 浏览2 评论
ST25R3916能否对ISO15693的标签芯片进行分区域写密码?
1032 浏览2 评论
1621浏览9评论
STM32仿真器是选择ST-LINK还是选择J-LINK?各有什么优势啊?
284浏览4评论
STM32F0_TIM2输出pwm2后OLED变暗或者系统重启是怎么回事?
294浏览3评论
279浏览3评论
stm32cubemx生成mdk-arm v4项目文件无法打开是什么原因导致的?
257浏览3评论
小黑屋|手机版|Archiver|德赢Vwin官网(湘ICP备2023018690号)
GMT+8, 2024-8-21 13:09, Processed in 0.946552 second(s), Total 78, Slave 62 queries .
Powered by德赢Vwin官网 网
© 2015bbs.elecfans.com
关注我们的微信
下载发烧友APP
德赢Vwin官网 观察
版权所有 © 湖南华秋数字科技有限公司
德赢Vwin官网 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号