STM32遥控修改RTC时钟带闹钟

您所在的位置:网站首页 小闹钟如何定闹钟时间 STM32遥控修改RTC时钟带闹钟

STM32遥控修改RTC时钟带闹钟

2024-07-16 19:57| 来源: 网络整理| 查看: 265

STM32遥控时钟带闹钟

设计目的

本次设计是基于STM32F103ZET6,正点原子战舰版制作的,采用正点原子的TFT-LCD 3.5寸屏幕和红外遥控等硬件,实现了实时日期和实时时间,以及闹钟和响铃,并且能用遥控器进行日期、时间、闹钟的更改。

设计原理

本设计运用STM32芯片内部RTC进行计时以及实时时钟和闹钟,采用定时器4来进行红外遥控的接收,LCD使用纯人工画点的方法通过FSMC驱动,RGB565显示当前日期、时间、闹铃。遥控器仅使用三个按键,UP(加)、DOWN(减)、ALIENTEK(切换)进行遥控设置。

TFT-LCD

ILI9341 液晶控制器自带显存,其显存总大小为 172800( 24032018/8),即 18 位模式( 26万色)下的显存量。在 16 位模式下, ILI9341 采用 RGB565 格式存储颜色数据,此时 ILI9341的 18 位数据线与 MCU 的 16 位数据线以及 LCD GRAM 的对应关系如图所示: RGB565

FSMC

在STM32中,使用FSMC需要先进行一些初始化设置,包括时钟频率、读写模式、地址宽度、数据宽度等。然后就可以通过FSMC控制器来读写存储器,包括读写数据、擦除数据、写入保护等操作。

例如,如果要使用FSMC控制器读取一块外部的SRAM存储器,可以按照以下步骤进行:

配置FSMC时钟和引脚配置FSMC控制器的寄存器,包括读写模式、地址宽度、数据宽度等配置SRAM存储器的地址范围和参数通过FSMC控制器进行读写操作,包括读取数据、写入数据、擦除数据等 RTC

RTC是STM32的实时时钟模块,可以提供高精度的时间和日期计数,可以被用于各种应用,例如日历、定时器、报警等。 RTC正常工作配置如下

使能电源时钟和备份区域时钟。取消备份区写保护。复位备份区域,开启外部低速振荡器。选择 RTC 时钟,并使能。设置 RTC 的分频,以及配置 RTC 时钟。更新配置,设置 RTC 中断分组。要开启闹钟相应,则要先启动中断线17编写中断服务函数。 NEC

NEC 遥控指令的数据格式为:同步码头、地址码、地址反码、控制码、控制反码。同步码由一个 9ms 的低电平和一个 4.5ms 的高电平组成,地址码、地址反码、控制码、控制反码均是8 位数据格式。按照低位在前,高位在后的顺序发送。采用反码是为了增加传输的可靠性(可用于校验), NEC 码规定的连发码(由 9ms 低电平+2.5m 高电平+0.56ms 低电平+97.94ms 高电平组成)。输入捕获来测量高电平的脉宽,解码红外遥控信号,利用输入捕获的这个功能来实现遥控解码。

硬件电路

REMOTE BEEP lcd

软件设计 rtc.c #include "sys.h" #include "delay.h" #include "usart.h" #include "rtc.h" #include "beep.h" _calendar_obj calendar;//时钟结构体 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; //RTC闹钟中断 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; //先占优先级1位,从优先级3位 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; //先占优先级0位,从优先级4位 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //使能该通道中断 NVIC_Init(&NVIC_InitStructure); //根据NVIC_InitStruct中指定的参数初始化外设NVIC寄存器 //若ALRF=1,如果在EXTI控制器中设置了EXTI线 17的中断模式,则允许产生RTC闹钟中断;如果在EXTI控制器中设置了EXTI线 17的事件模式,则这条线上会产生一个脉冲(不会产生RTC闹钟中断) EXTI_ClearITPendingBit(EXTI_Line17); //启动中断线17 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) != 0x5050) //从指定的后备寄存器中读出数据:读出了与写入的指定数据不相乎 { BKP_DeInit(); //复位备份区域 RCC_LSEConfig(RCC_LSE_ON); //设置外部低速晶振(LSE),使用外设低速晶振 while (RCC_GetFlagStatus(RCC_FLAG_LSERDY) == RESET&&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(2023,04,13,14,40,00); //设置时间 RTC_WaitForSynchro(); // RTC_Alarm_Set(); //设置闹钟 RTC_ExitConfigMode(); //退出配置模式 BKP_WriteBackupRegister(BKP_DR1, 0X5050); //向指定的后备寄存器中写入用户程序数据 } 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 u16 tcnt; extern int count; //秒钟中断 void RTC_IRQHandler(void) { if(RTC_GetITStatus(RTC_IT_SEC)!=RESET) { RTC_Get(); } RTC_ClearITPendingBit(RTC_IT_OW|RTC_IT_SEC); RTC_WaitForLastTask(); } //闹钟中断 void RTCAlarm_IRQHandler(void) { if(RTC_GetITStatus(RTC_IT_ALR) != RESET) //响铃 延时1000ms自动关闭 { BEEP = 1; delay_ms(1000); BEEP = 0; } EXTI_ClearITPendingBit(EXTI_Line17); RTC_WaitForLastTask(); RTC_ClearITPendingBit(RTC_IT_ALR); 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(syear2099)return 1; for(t=1970;t=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


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3