一、RTC实时时钟原理
1、RTC简介
STM32的 RTC 外设(Real Time Clock),实质是一个掉电后还继续运行的定时器。
掉电:
掉电是指主电源 VDD断开的情况,为了 RTC外设掉电继续运行,必须接
上锂电池给 STM32 的 RTC、备份发卡通过 VBAT引脚供电。当主电源 VDD有效时,由 VDD
给 RTC 外设供电;而当 VDD掉电后,由 VBAT给 RTC 外设供电。但无论由什么电源供电,
RTC 中的数据都保存在属于 RTC 的备份域中,若主电源 VDD 和 VBAT 都掉电,那么备份域
中保存的所有数据将丢失。备份域除了 RTC 模块的寄存器,还有 42 个 16 位的寄存器可以
在 VDD 掉电的情况下保存用户程序的数据,系统复位或电源复位时,这些数据也不会被复
位。
2、RTC架构图
二、读取STM32内部时钟到PC
2.1 任务要求
读取STM32F103C8T6 内部的时钟(年月日时分秒),日历(星期x),1秒周期,通过串口输出到PC上位机
2.2 程序设计要点
1、初始化 RTC 外设;
2、设置时间以及添加配置标志;
3、获取当前时间;
2.3 代码实现
1、定义时间结构体,包含 年月日/时分秒
//时间结构体
typedef struct
{
vu8 hour;
vu8 min;
vu8 sec;
//公历日月年周
vu16 w_year;
vu8 w_month;
vu8 w_date;
vu8 week;
}_calendar_obj;
extern _calendar_obj calendar; //日历结构体
2、对RTC进行初始化,配置实时时钟
设置初始时间为2023/11/27/16:48:00
初始时间在初始化函数那里更改
//实时时钟配置
//初始化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) //检查指定的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, ENABLE); //使能RTC秒中断
RTC_WaitForLastTask(); //等待最近一次对RTC寄存器的写操作完成
RTC_EnterConfigMode();/// 允许配置
RTC_SetPrescaler(32767); //设置RTC预分频的值
RTC_WaitForLastTask(); //等待最近一次对RTC寄存器的写操作完成
RTC_Set(2023,11,27,16,48,00); //设置时间 2023/11/27/16:48
RTC_ExitConfigMode(); //退出配置模式
BKP_WriteBackupRegister(BKP_DR1, 0X5050); //向指定的后备寄存器中写入用户程序数据
RTC_NVIC_Config();//RCT中断分组设置
RTC_Get();//更新时间
return 0; //ok
}
3、中断服务函数
//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:%d\n",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();
}
4、主函数main.c
#include "sys.h"
#include "usart.h"
#include "rtc.h"
#include "stm32f10x.h"
#include "delay.h"
#include "gui.h"
#include "bmp.h"
#include "oled.h"
int main(void) {
u8 t;
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); /* 设置NVIC中断分组2:2位抢占优先级,2位响应优先级 */
//delay_init(); /* 延时函数初始化 */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE); /* 关闭jtag,使能SWD,可以用SWD模式调试 */
Delay_ms(500); /* 等待稳定 */
uart_init(115200);//以115200的波特率初始化串口
//IIC_Init();
RTC_Init(); //RTC初始化
while (1) {
if (t != calendar.sec) {
t = calendar.sec;
printf("%d-%02d-%02d %02d:%02d:%02d\r\n", calendar.w_year, calendar.w_month, calendar.w_date,
calendar.hour, calendar.min, calendar.sec);
switch (calendar.week) {
case 0:
printf("Sunday \r\n");
break;
case 1:
printf("Monday \r\n");
break;
case 2:
printf("Tuesday \r\n");
break;
case 3:
printf("Wednesday\r\n");
break;
case 4:
printf("Thursday \r\n");
break;
case 5:
printf("Friday \r\n");
break;
case 6:
printf("Saturday \r\n");
break;
}
}
Delay_ms(10);
}
}
2.4 硬件实现
1、烧录
2、物理连接
3、实现效果
三、OLED显示年月份时分秒和实时温湿度
3.1 任务要求
读取AHT20的温度和湿度,通过OLED,把年月份时分秒、日历和实时温度、湿度显示出来,2秒周期。
3.2 代码实现
1、在oledfont.h文件中的cfont16[]
函数中添加需要用得到字模
const typFNT_GB16 cfont16[] =
{
/*-- 文字: 温 --*/
/*-- 宋体12; 此字体下对应的点阵为:宽x高=16x16 --*/
"温",0x00,0x00,0x23,0xF8,0x12,0x08,0x12,0x08,0x83,0xF8,0x42,0x08,0x42,0x08,0x13,0xF8,0x10,0x00,0x27,0xFC,0xE4,0xA4,0x24,0xA4,0x24,0xA4,0x24,0xA4,0x2F,0xFE,0x00,0x00,
/*-- 文字: 湿 --*/
/*-- 宋体12; 此字体下对应的点阵为:宽x高=16x16 --*/
"湿",0x00,0x00,0x27,0xF8,0x14,0x08,0x14,0x08,0x87,0xF8,0x44,0x08,0x44,0x08,0x17,0xF8,0x11,0x20,0x21,0x20,0xE9,0x24,0x25,0x28,0x23,0x30,0x21,0x20,0x2F,0xFE,0x00,0x00,
/*-- 文字: 度 --*/
/*-- 宋体12; 此字体下对应的点阵为:宽x高=16x16 --*/
"度",0x01,0x00,0x00,0x80,0x3F,0xFE,0x22,0x20,0x22,0x20,0x3F,0xFC,0x22,0x20,0x22,0x20,0x23,0xE0,0x20,0x00,0x2F,0xF0,0x24,0x10,0x42,0x20,0x41,0xC0,0x86,0x30,0x38,0x0E,
/*-- 文字: 显 --*/
/*-- 宋体12; 此字体下对应的点阵为:宽x高=16x16 --*/
"显",0x00,0x00,0x1F,0xF0,0x10,0x10,0x10,0x10,0x1F,0xF0,0x10,0x10,0x10,0x10,0x1F,0xF0,0x04,0x40,0x44,0x44,0x24,0x44,0x14,0x48,0x14,0x50,0x04,0x40,0xFF,0xFE,0x00,0x00,
/*-- 文字: 示 --*/
/*-- 宋体12; 此字体下对应的点阵为:宽x高=16x16 --*/
"示",0x00,0x00,0x3F,0xF8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFE,0x01,0x00,0x01,0x00,0x11,0x10,0x11,0x08,0x21,0x04,0x41,0x02,0x81,0x02,0x05,0x00,0x02,0x00,
/*-- 文字: 星 --*/
/*-- 宋体12; 此字体下对应的点阵为:宽x高=16x16 --*/
"星",0x00,0x00,0x1F,0xF0,0x10,0x10,0x1F,0xF0,0x10,0x10,0x1F,0xF0,0x01,0x00,0x11,0x00,0x1F,0xF8,0x21,0x00,0x41,0x00,0x1F,0xF0,0x01,0x00,0x01,0x00,0x7F,0xFC,0x00,0x00,
/*-- 文字: 期 --*/
/*-- 宋体12; 此字体下对应的点阵为:宽x高=16x16 --*/
"期",0x22,0x00,0x22,0x7C,0x7F,0x44,0x22,0x44,0x22,0x44,0x3E,0x7C,0x22,0x44,0x22,0x44,0x3E,0x44,0x22,0x7C,0x22,0x44,0xFF,0x44,0x04,0x84,0x22,0x84,0x41,0x14,0x82,0x08,
/*-- 文字: 时 --*/
/*-- 宋体12; 此字体下对应的点阵为:宽x高=16x16 --*/
"时",0x00,0x08,0x00,0x08,0x7C,0x08,0x44,0x08,0x45,0xFE,0x44,0x08,0x44,0x08,0x7C,0x08,0x44,0x88,0x44,0x48,0x44,0x48,0x44,0x08,0x7C,0x08,0x44,0x08,0x00,0x28,0x00,0x10,
/*-- 文字: 分 --*/
/*-- 宋体12; 此字体下对应的点阵为:宽x高=16x16 --*/
"分",0x00,0x40,0x04,0x40,0x04,0x20,0x08,0x20,0x10,0x10,0x20,0x08,0x40,0x04,0x9F,0xE2,0x04,0x20,0x04,0x20,0x04,0x20,0x08,0x20,0x08,0x20,0x10,0x20,0x21,0x40,0x40,0x80,
/*-- 文字: 秒 --*/
/*-- 宋体12; 此字体下对应的点阵为:宽x高=16x16 --*/
"秒",0x08,0x20,0x1C,0x20,0xF0,0x20,0x10,0xA8,0x10,0xA4,0xFC,0xA2,0x11,0x22,0x31,0x20,0x3A,0x24,0x54,0x24,0x54,0x28,0x90,0x08,0x10,0x10,0x10,0x20,0x10,0xC0,0x13,0x00,
//以及文字:一二三四五六年月日
};
2、修改main.c
#include "sys.h"
#include "usart.h"
#include "rtc.h"
#include "stm32f10x.h"
#include "delay.h"
#include "gui.h"
#include "bmp.h"
#include "oled.h"
int main(void) {
u8 t;
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); /* 设置NVIC中断分组2:2位抢占优先级,2位响应优先级 */
//delay_init(); /* 延时函数初始化 */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE); /* 关闭jtag,使能SWD,可以用SWD模式调试 */
Delay_ms(500); /* 等待稳定 */
uart_init(115200);
IIC_Init();
RTC_Init(); //RTC初始化
OLED_Init(); //初始化OLED
OLED_Clear(0); //清屏(全黑)
while (1) {
read_AHT20_once();
OLED_Clear(0);
if (t != calendar.sec) {
t = calendar.sec;
GUI_ShowNum(00,00,calendar.w_year,4,16,1);
GUI_ShowCHinese(32,00,16,"年",1);
GUI_ShowNum(48,00,calendar.w_month,2,16,1);
GUI_ShowCHinese(64,00,16,"月",1);
GUI_ShowNum(80,00,calendar.w_date,2,16,1);
GUI_ShowCHinese(96,00,16,"日",1);
GUI_ShowNum(00,20,calendar.hour,2,16,1);
GUI_ShowCHinese(16,20,16,"时",1);
GUI_ShowNum(32,20,calendar.min,2,16,1);
GUI_ShowCHinese(48,20,16,"分",1);
GUI_ShowNum(64,20,calendar.sec,2,16,1);
GUI_ShowCHinese(80,20,16,"秒",1);
switch (calendar.week) {
case 0:
GUI_ShowCHinese(00,40,16,"星期日",1);
//GUI_ShowString(0,100,"Sunday",16,1);
//printf("Sunday \r\n");
break;
case 1:
GUI_ShowCHinese(00,40,16,"星期一",1);
//GUI_ShowString(0,100,"Monday",16,1);
//printf("Monday \r\n");
break;
case 2:
GUI_ShowCHinese(00,40,16,"星期二",1);
//GUI_ShowString(0,100,"Tuesday",16,1);
//printf("Tuesday \r\n");
break;
case 3:
GUI_ShowCHinese(00,40,16,"星期三",1);
//GUI_ShowString(0,100,"Wednesday",16,1);
//printf("Wednesday\r\n");
break;
case 4:
GUI_ShowCHinese(00,40,16,"星期四",1);
//GUI_ShowString(0,100,"Thursday",16,1);
//printf("Thursday \r\n");
break;
case 5:
GUI_ShowCHinese(00,40,16,"星期五",1);
//GUI_ShowString(0,100,"Friday",16,1);
//printf("Friday \r\n");
break;
case 6:
GUI_ShowCHinese(00,40,16,"星期六",1);
//GUI_ShowString(0,100,"Saturday",16,1);
//printf("Saturday \r\n");
break;
}
}
Delay_ms(1500);
Delay_ms(1500);
OLED_Clear(0);
}
}
3.3 硬件实现
1、硬件连接
OLED屏连线说明(7脚)
1.GND 电源地
2.VCC 电源正(3~5.5V)
3.D0(SCL) SCK管脚
4.D1(SDA) MOSI管脚
5.RES(RST) 用来复位(低电平复位)
6.DC(D/C) 数据和命令控制管脚 1表示数据 0表示命令
7.CS(NSS) 片选管脚
文章来源:https://www.toymoban.com/news/detail-830131.html
AHT20
2、FlyMCU烧录
3、实验效果文章来源地址https://www.toymoban.com/news/detail-830131.html
到了这里,关于STM32日历读取与温湿度显示的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!