找回密码
 立即注册
查看: 1070|回复: 9

视频讲解:RTC 实时时钟,年月日时分秒,STC8H数据手册 RTC 内容

[复制链接]

该用户从未签到

550

主题

9316

回帖

1万

积分

管理员

积分
13894
发表于 2023-9-26 19:33:28 | 显示全部楼层 |阅读模式
视频教学RTC实时时钟,年/月/日/时/分/秒,1/128秒
截图202310040841262522.jpg
https://www.stcaimcu.com/forum.p ... 3184&extra=page%3D1

28      RTC,实时时钟,年/月/日/时/分/秒
  
产品线
  
RTC
STC8H1K08系列

STC8H1K28系列

STC8H3K64S4系列
STC8H3K64S2系列
STC8H8K64U系列A版本
STC8H8K64U系列B/C/D版本
STC8H4K64TL系列
STC8H4K64TLCD系列
STC8H1K08T系列
STC8H2K08U系列

STC8H系列部分单片机内部集成一个实时时钟控制电路,主要有如下特性:
n  低功耗:RTC模块工作电流低至2uA@VCC=3.3V、3uA@VCC=5.0V(典型值)
n  长时间跨度:支持2000年~2099年,并自动判断闰年
n  闹钟:支持一组闹钟设置
n  支持多个中断
Ø  一组闹钟中断(每天中断一次,中断的时间点为闹钟寄存器所设置的任意时/分/秒)
Ø  日中断(每天中断一次,中断的时间点为每天的0时0分0秒)
Ø  小时中断(每小时中断一次,中断的时间点为分/秒均为0,即整点时)
Ø  分钟中断(每分钟中断一次,中断的时间点为秒为0,即分钟寄存器发生变化时)
Ø  秒中断(每秒中断一次,中断的时间点为秒寄存器发生变化时)
Ø  1/2秒中断(每1/2秒中断一次)
Ø  1/8秒中断(每1/8秒中断一次)
Ø  1/32秒中断(每1/32秒中断一次)
n  支持掉电唤醒

28.1         RTC相关的寄存器
  
符号
  
描述
地址
位地址与符号
复位值
B7
B6
B5
B4
B3
B2
B1
B0
RTCCR
RTC控制寄存器
FE60H
-
-
-
-
-
-
-
RUNRTC
xxxx,xxx0
RTCCFG
RTC配置寄存器
FE61H
-
-
-
-
-
-
RTCCKS
SETRTC
xxxx,xx00
RTCIEN
RTC中断使能寄存器
FE62H
EALAI
EDAYI
EHOURI
EMINI
ESECI
ESEC2I
ESEC8I
ESEC32I
0000,0000
RTCIF
RTC中断请求寄存器
FE63H
ALAIF
DAYIF
HOURIF
MINIF
SECIF
SEC2IF
SEC8IF
SEC32IF
0000,0000
ALAHOUR
RTC闹钟的小时值
FE64H
-
-
-

xxx0,0000
ALAMIN
RTC闹钟的分钟值
FE65H
-
-

xx00,0000
ALASEC
RTC闹钟的秒值
FE66H
-
-

xx00,0000
ALASSEC
RTC闹钟的1/128秒值
FE67H
-

x000,0000
INIYEAR
RTC年初始化
FE68H
-

x000,0000
INIMONTH
RTC月初始化
FE69H
-
-
-
-

xxxx,0000
INIDAY
RTC日初始化
FE6AH
-
-
-

xxx0,0000
INIHOUR
RTC小时初始化
FE6BH
-
-
-

xxx0,0000
INIMIN
RTC分钟初始化
FE6CH
-
-

xx00,0000
INISEC
RTC秒初始化
FE6DH
-
-

xx00,0000
INISSEC
RTC1/128秒初始化
FE6EH
-

x000,0000
YEAR
RTC的年计数值
FE70H
-

x000,0000
MONTH
RTC的月计数值
FE71H
-
-
-
-

xxxx,0000
DAY
RTC的日计数值
FE72H
-
-
-

xxx0,0000
HOUR
RTC的小时计数值
FE73H
-
-
-

xxx0,0000
MIN
RTC的分钟计数值
FE74H
-
-

xx00,0000
SEC
RTC的秒计数值
FE75H
-
-

xx00,0000
SSEC
RTC1/128秒计数值
FE76H
-

x000,0000



28.1.1                 RTC控制寄存器(RTCCR
  
符号
  
地址
B7
B6
B5
B4
B3
B2
B1
B0
RTCCR
FE60H
-
-
-
-
-
-
-
RUNRTC
RUNRTC:RTC模块控制位
0:关闭RTC,RTC停止计数
1:使能RTC,并开始RTC计数

28.1.2                 RTC配置寄存器(RTCCFG
  
符号
  
地址
B7
B6
B5
B4
B3
B2
B1
B0
RTCCFG
FE61H
-
-
-
-
-
-
RTCCKS
SETRTC
RTCCKS:RTC时钟源选择
0:选择外部32.768KHz时钟源(需先软件启动外部32K晶振)
1:选择内部32K时钟源(需先软件启动内部32K振荡器)
SETRTC:设置RTC初始值
0:无意义
1:触发RTC寄存器初始化。当SETRTC设置为1时,硬件会自动将寄存器INIYEAR、INIMONTH、INIDAY、INIHOUR、INIMIN、INISEC、INISSEC中的值复制到寄存器YEAR、MONTH、DAY、HOUR、MIN、SEC、SSEC中。初始完成后,硬件会自动将SETRTC位清0。

28.1.3                 RTC中断使能寄存器(RTCIEN
  
符号
  
地址
B7
B6
B5
B4
B3
B2
B1
B0
RTCIEN
FE62H
EALAI
EDAYI
EHOURI
EMINI
ESECI
ESEC2I
ESEC8I
ESEC32I
EALAI:闹钟中断使能位
0:关闭闹钟中断
1:使能闹钟中断
EDAYI:一日(24小时)中断使能位
0:关闭一日中断
1:使能一日中断
EHOURI:一小时(60分钟)中断使能位
0:关闭小时中断
1:使能小时中断
EMINI:一分钟(60秒)中断使能位
0:关闭分钟中断
1:使能分钟中断
ESECI:一秒中断使能位
0:关闭秒中断
1:使能秒中断
ESEC2I:1/2秒中断使能位
0:关闭1/2秒中断
1:使能1/2秒中断
ESEC8I:1/8秒中断使能位
0:关闭1/8秒中断
1:使能1/8秒中断
ESEC32I:1/32秒中断使能位
0:关闭1/32秒中断
1:使能1/32秒中断

28.1.4                 RTC中断请求寄存器(RTCIF
  
符号
  
地址
B7
B6
B5
B4
B3
B2
B1
B0
RTCIF
FE63H
ALAIF
DAYIF
HOURIF
MINIF
SECIF
SEC2IF
SEC8IF
SEC32IF
ALAIF:闹钟中断请求位。需软件清0,软件写1无效。
DAYIF:一日(24小时)中断请求位。需软件清0,软件写1无效。
HOURIF:一小时(60分钟)中断请求位。需软件清0,软件写1无效。
MINIF:一分钟(60秒)中断请求位。需软件清0,软件写1无效。
SECIF:一秒中断请求位。需软件清0,软件写1无效。
SEC2IF:1/2秒中断请求位。需软件清0,软件写1无效。
SEC8IF:1/8秒中断请求位。需软件清0,软件写1无效。
SEC32IF:1/32秒中断请求位。需软件清0,软件写1无效。

28.1.5                 RTC闹钟设置寄存器
  
符号
  
地址
B7
B6
B5
B4
B3
B2
B1
B0
ALAHOUR
FE64H
-
-
-

ALAMIN
FE65H
-
-

ALASEC
FE66H
-
-

ALASSEC
FE67H
-

ALAHOUR:设置每天闹钟的小时值。
注意:设置的值不是BCD码,而是HEX码,比如需要设置小时值20ALAHOUR,则需使用如下代码进行设置
MOV             DPTR,#ALAHOUR
MOV             A,#14H
MOVX          @DPTR,A
ALAMIN:设置每天闹钟的分钟值。数字编码与ALAHOUR相同。
ALASEC:设置每天闹钟的秒值。数字编码与ALAHOUR相同。
ALASSEC:设置每天闹钟的1/128秒值。数字编码与ALAHOUR相同。

28.1.6                 RTC实时时钟初始值设置寄存器
  
符号
  
地址
B7
B6
B5
B4
B3
B2
B1
B0
INIYEAR
FE68H
-

INIMONTH
FE69H





INIDAY
FE6AH




INIHOUR
FE6BH
-
-
-

INIMIN
FE6CH
-
-

INISEC
FE6DH
-
-

INISSEC
FE6EH
-

INIYEAR:设置当前实时时间的年值。有效值范围00~99。对应2000年~2099年
注意:设置的值不是BCD码,而是HEX码,比如需要设置20INIYEAR,则需使用如下代码进行设置
MOV             DPTR,#INIYEAR
MOV             A,#14H
MOVX          @DPTR,A
INIMONTH:设置当前实时时间的月值。有效值范围1~12。数字编码与INIYEAR相同。
INIDAY:设置当前实时时间的日值。有效值范围1~31。数字编码与INIYEAR相同。
INIHOUR:设置当前实时时间的小时值。有效值范围00~23。数字编码与INIYEAR相同。
INIMIN:设置当前实时时间的分钟值。有效值范围00~59。数字编码与INIYEAR相同。
INISEC:设置当前实时时间的秒值。有效值范围00~59。数字编码与INIYEAR相同。
INISSEC:设置当前实时时间的1/128秒值。有效值范围00~127。数字编码与INIYEAR相同。
当用户设置完成上面的初始值寄存器后,用户还需要向SETRTC位(RTCCFG.0)写1来触发硬件将初始值装载到RTC实时计数器中
另需注意:硬件不会对初始化数据的有效性进行检查,需要用户在设置初始值时,必须保证数据的有效性,不能超出其有效范围。

28.1.7                 RTC实时时钟计数寄存器
  
符号
  
地址
B7
B6
B5
B4
B3
B2
B1
B0
YEAR
FE70H
-

MONTH
FE71H





DAY
FE72H




HOUR
FE73H
-
-
-

MIN
FE74H
-
-

SEC
FE75H
-
-

SSEC
FE76H
-

YEAR:当前实时时间的年值。注意:寄存器的值不是BCD码,而是HEX
MONTH:当前实时时间的月值。数字编码与YEAR相同。
DAY:当前实时时间的日值。数字编码与YEAR相同。
HOUR:当前实时时间的小时值。数字编码与YEAR相同。
MIN:当前实时时间的分钟值。数字编码与YEAR相同。
SEC:当前实时时间的秒值。数字编码与YEAR相同。
SSEC:当前实时时间的1/128秒值。数字编码与YEAR相同。
注意:YEARMONTHDAYHOURMINSECSSEC均为只读寄存器,若需要对这些寄存器执行写操作,必须通过寄存器INIYEARINIMONTlHINIDATINIHOUINIMININISECINISSECSETRTC来实现。

28.2          RTC实战线路图
file:///C:/Users/HP/AppData/Local/Temp/msohtmlclip1/01/clip_image002.gif 截图202309261938098904.jpg


28.3     范例程序1.3.1          串口打印RTC时钟范例
C语言代码

//测试工作频率为22.1184MHz,需要将C语言代码文件与下面的汇编代码文件加载到同一个项目里使用
#include "stc8h.h"
#include "intrins.h"
#include "stdio.h"
#define       MAIN_Fosc                22118400L
#define       Baudrate                      115200L
#define       TM                               (65536-(MAIN_Fosc/Baudrate+2)/4)
//2操作是为了让Keil编译器
                                                                                                                //自动实现四舍五入运算

bit               B1S_Flag;
void RTC_config(void);

void UartInit(void)
{
         SCON= (SCON & 0x3f) | 0x40;
         T2L  = TM;
         T2H  = TM>>8;
         AUXR|= 0x15;
}
void UartPutc(unsigned char dat)
{
         SBUF= dat;
         while(TI==0);
         TI= 0;
}
char putchar(char c)
{
         UartPutc(c);
         returnc;
}
void RTC_Isr() interrupt 13
{
         if(RTCIF& 0x08)                //判断是否秒中断
         {
                   RTCIF&= ~0x08;                                                              //清中断标志
                   B1S_Flag= 1;
         }
}
void main(void)
{
         P_SW2|= 0x80;                    //使能XFR访问
         P0M1= 0;   P0M0 = 0;   //设置为准双向口
         P1M1= 0;   P1M0 = 0;   //设置为准双向口
         P2M1= 0;   P2M0 = 0;   //设置为准双向口
         P3M1= 0;   P3M0 = 0;   //设置为准双向口
         P4M1= 0;   P4M0 = 0;   //设置为准双向口
         P5M1= 0;   P5M0 = 0;   //设置为准双向口
         UartInit();
         RTC_config();
         EA= 1;
         printf("RTCTest Programme!\r\n");                                         //UART发送一个字符串
         while(1)
         {
                   if(B1S_Flag)
                   {
                            B1S_Flag= 0;
                            printf("Year=20%bd  ", YEAR);
                            printf("Month=%bd  ", MONTH);
                            printf("Day=%bd  ", DAY);
                            printf("Hour=%bd  ", HOUR);
                            printf("Minute=%bd  ", MIN);
                            printf("Second=%bd  ", SEC);
                            printf("\r\n");
                   }
         }
}
void RTC_config(void)
{
//       //选择内部低速IRC
//       IRC32KCR = 0x80;                                                                      //启动内部低速振荡器
//       while (!(IRC32KCR & 0x01));                                                     //等待时钟稳定
//       RTCCFG |= 0x02;                                                                        //选择内部低速IRC作为RTC时钟源
         //选择外部32K
         X32KCR= 0xc0;                                                                           //启动外部32K晶振
         while(!(X32KCR & 0x01));                                                         //等待时钟稳定
         RTCCFG&= ~0x02;                                                                    //选择外部32K作为RTC时钟源
         INIYEAR= 21;                                                                            //Y:2021
         INIMONTH= 12;                                                                        //M:12
         INIDAY= 31;                                                                               //D:31
         INIHOUR= 23;                                                                           //H:23
         INIMIN= 59;                                                                               //M:59
         INISEC= 50;                                                                               //S:50
         INISSEC= 0;                                                                               //S/128:0
         RTCCFG|= 0x01;                                                                        //触发RTC寄存器初始化
         RTCIF= 0;                                                                                   //清中断标志
         RTCIEN= 0x08;                                                                          //使能RTC秒中断
         RTCCR= 0x01;                                                                            // RTC使能}
}

汇编代码

;将以下代码保存为ASM格式文件,一起加载到项目里,例如:isr.asm
                            CSEG    AT 0123H
                            JMP                    006BH
                            END

28.3.2          利用ISP软件的用户接口实现不停电下载保持RTC参数
C语言代码

//测试工作频率为11.0592MHz
/*************  功能说明 *********************************************************************
现有单片机系列的RTC模块,在单片机复位后RTC相关的特殊功能寄存器也会复位
本例程主要用于解决ISP下载后用户的RTC参数丢失的问题
解决思路:ISP下载前,先将RTC相关参数通过ISP下载软件的用户接口上传到PC保存,等待ISP下载完成后,下载软件再将保存的相关参数写入到FLASH的指定地址(范例中指定的地址为FE00H)。ISP下载完成后会立即运行用户代码,用户程序在初始化RTC寄存器时,可从FLASH的指定地址中读取之前上传的RTC相关参数对RTC寄存器进行初始化,即可实现不停电下载保持RTC参数的目的。
下载时, 选择时钟 11.0592MHZ
************************************************************************************************/
#include "stc8h.h"
#include "intrins.h"
#include "stdio.h"
#include "stc8h.h"
#include "intrins.h"
#define       FOSC                          11059200UL
#define       BAUD                         (65536- FOSC/4/115200)
typedef       bit                                 BOOL;
typedef       unsigned char              BYTE;
typedef       unsigned int                 WORD;
struct RTC_INIT
{
         BYTE bValidTag;                                                                      //数据有效标志(0x5a)
         BYTE bIniYear;                                                                        //(RTC初始化值)
         BYTE bIniMonth;                                                                    //
         BYTE bIniDay;                                                                         //
         BYTE bIniHour;                                                                       //
         BYTE bIniMinute;                                                                    //
         BYTE bIniSecond;                                                                    //
         BYTE bIniSSecond;                                                                  //次秒
         BYTE bAlaHour;                                                                      //(RTC闹钟设置值)
         BYTE bAlaMinute;                                                                   //
         BYTE bAlaSecond;                                                                   //
         BYTE bAlaSSecond;                                                                 //次秒
};
struct RTC_INIT code InitBlock_at_ 0xfe00;
void SysInit();
void UartInit();
void RTCInit();
void SendUart(BYTE dat);
void UnpackCmd(BYTE dat);
void IapProgram(WORD addr, BYTEdat);
BOOL fUartBusy;
BOOL fFetchRtc;
BOOL fReset2Isp;
BYTE bUartStage;
BYTE bDump[7];
void main()
{
         SysInit();                                                                                       //系统初始化
         UartInit();
         RTCInit();
         EA= 1;
         fUartBusy= 0;
         fFetchRtc= 0;
         fReset2Isp= 0;
         bUartStage= 0;
         while(1)
         {
                  if (fFetchRtc)                                                                       //获取RTC数据请求
                  {
                            fFetchRtc = 0;
                            RTCCR = 0;                                                               //上传当前的RTC值时,必须临时停止RTC
//以免发生进位错误
                            bDump[0] = YEAR;                                                   //快速将当前的RTC值缓存,
//以缩短RTC暂停的时间,减小误差
                            bDump[1] = MONTH;
                            bDump[2] = DAY;
                            bDump[3] = HOUR;
                            bDump[4]= MIN;
                            bDump[5]= SEC;
                            bDump[6]= SSEC;
                            RTCCR= 1;
                            SendUart(0x5a);                                                         //上传12字节RTC参数
                            SendUart(bDump[0]);
                            SendUart(bDump[1]);
                            SendUart(bDump[2]);
                            SendUart(bDump[3]);
                            SendUart(bDump[4]);
                            SendUart(bDump[5]);
                            SendUart(bDump[6]);
                            SendUart(ALAHOUR);
                            SendUart(ALAMIN);
                            SendUart(ALASEC);
                            SendUart(ALASSEC);
                  }
                  if (fReset2Isp)                                                                      //重启请求
                  {
                            fReset2Isp = 0;
                            IAP_CONTR = 0x60;                                                //软件触发复位到系统ISP
                  }
         }
}
void uart_isr() interruptUART1_VECTOR
{
         BYTEdat;
         if(TI)
         {
                  TI = 0;
                  fUartBusy =        0;
         }
         if(RI)
         {
                  RI = 0;
                  dat = SBUF;
                  switch (bUartStage++)                                                                 //解析串口命令
                  {
                  default:
                  case 0:
L_Check1st:
                            if (dat == '@') bUartStage = 1;
                           elsebUartStage = 0;
                            break;
                  case 1:
                            if (dat == 'F') bUartStage = 2;
                            else if (dat == 'R') bUartStage = 7;
                            else goto L_Check1st;
                            break;
                  case 2:
                            if (dat != 'E') goto L_Check1st;
                            break;
                  case 3:
                            if (dat != 'T') gotoL_Check1st;
                           break;
                  case 4:
                            if (dat != 'C') gotoL_Check1st;
                            break;
                  case 5:
                            if (dat != 'H') gotoL_Check1st;
                            break;
                  case 6:
                            if (dat != '#') gotoL_Check1st;
                            bUartStage = 0;
                            fFetchRtc = 1;                                                            //当前命令序列为获取RTC数据命令:"@FETCH#"
                            break;
                  case 7:
                            if (dat != 'E') goto L_Check1st;
                            break;
                  case 8:
                            if (dat != 'B') goto L_Check1st;
                            break;
                  case 9:
                  case 10:
                            if (dat != 'O') gotoL_Check1st;
                            break;
                  case 11:
                            if (dat != 'T') gotoL_Check1st;
                            break;
                  case 12:
                            if (dat != '#') goto L_Check1st;
                            bUartStage = 0;
                            fReset2Isp = 1;                                                           //当前命令序列为重启命令:"@REBOOT#"
                            break;
                  }
         }
}
void rtc_isr() interruptRTC_VECTOR                                                //RTC中断复位程序
{
         RTCIF= 0x00;                                                                             //RTC中断标志
         P20= !P20;                                                                                   //P2.0口每秒闪烁一次,测试用
}
void SysInit()
{
         P_SW2|= 0x80;
         P0M0= 0x00; P0M1 = 0x00;
         P1M0= 0x00; P1M1 = 0x00;
         P2M0= 0x00; P2M1 = 0x00;
         P3M0= 0x00; P3M1 = 0x00;
         P4M0= 0x00; P4M1 = 0x00;
         P5M0= 0x00; P5M1 = 0x00;
         P6M0= 0x00; P6M1 = 0x00;
         P7M0= 0x00; P7M1 = 0x00;
}
void UartInit()                                                                                        //串口初始化函数
{
         SCON= 0x50;
         AUXR= 0x40;
         TMOD= 0x00;
         TL1= BAUD;
         TH1= BAUD >> 8;
         TR1= 1;
         ES= 1;
}
void RTCInit()                                                                                        //RTC初始化函数
{
//       IRC32KCR = 0x80;
//       while (!(IRC32KCR & 0x01));
//       RTCCFG |= 0x02;                                                                        //选择内部低速IRCRTC时钟源
         X32KCR= 0xc0;
         while(!(X32KCR & 0x01));
         RTCCFG&= ~0x02;                                                                    //选择外部部32KRTC时钟源
         if(InitBlock.bValidTag == 0x5a)
         {
                   INIYEAR= InitBlock.bIniYear;                                         //如果初始化数据块有效,则使用数据块初始化RTC
                   INIMONTH= InitBlock.bIniMonth;
                   INIDAY= InitBlock.bIniDay;
                   INIHOUR= InitBlock.bIniHour;
                   INIMIN= InitBlock.bIniMinute;
                   INISEC= InitBlock.bIniSecond;
                   INISSEC= InitBlock.bIniSSecond;
                   ALAHOUR= InitBlock.bAlaHour;
                   ALAMIN= InitBlock.bAlaMinute;
                   ALASEC= InitBlock.bAlaSecond;
                   ALASSEC= InitBlock.bAlaSSecond;
                   IapProgram(0x0000,0x00);                                               //销毁初始化数据块,以免重复初始化
         }
         else
         {
                  INIYEAR = 23;                                                                   //否则初始化RTC为默认值
                  INIMONTH = 1;
                  INIDAY = 29;
                   INIHOUR= 12;
                   INIMIN= 0;
                   INISEC= 0;
                   INISSEC= 0;
                   ALAHOUR= 0;
                   ALAMIN= 0;
                   ALASEC= 0;
                   ALASSEC= 0;
         }
         RTCCFG|= 0x01;                                                                        //写入RTC初始值
         RTCCR= 0x01;                                                                            //RTC开始运行
         while(RTCCFG & 0x01);                                                            //等待RTC初始化完成
         RTCIF= 0x00;
         RTCIEN= 0x08;                                                                          //使能RTC秒中断
}
void SendUart(BYTE dat)                                                                     //串口发送函数
{
         while(fUartBusy);
         SBUF= dat;
         fUartBusy= 1;
}
void IapProgram(WORD addr, BYTEdat)                                           //EEPROM编程函数
{
         IAP_CONTR= 0x80;
         IAP_TPS= 12;
         IAP_CMD= 2;
         IAP_ADDRL= addr;
         IAP_ADDRH= addr >> 8;
         IAP_DATA= dat;
         IAP_TRIG= 0x5a;
         IAP_TRIG= 0xa5;
         _nop_();
         _nop_();
         _nop_();
         _nop_();}
}


ISP下载软件中“用户接口”的设置如下:(注意,首次下载不能使能用户接口)


28.3.3          内部RTC时钟低功耗休眠唤醒-比较器检测电压程序
/************* 本程序功能说明 **************
本例程基于STC8H8K64U为主控芯片的实验箱9进行编写测试,STC8H系列带RTC模块的芯片可通用参考.
读写芯片内部集成的RTC模块.
电路连接参考规格书RTC章节-RTC实战线路图.
RTC定时唤醒MCU,如1秒唤醒1次,唤醒后用比较器判断外部电压:1,正常,正常工作;2,如电压偏低,继续休眠,主时钟停止震荡,RTC继续工作.
比较器正极通过电阻分压后输入到P3.7口,比较器负极使用内部1.19V参考电压.
该分压电路的地用I/O(P3.5)控制,I/O设置为开漏,不比较时,对外设置为1I/O口浮空,省电;比较时,对外输出0,就是地!
下载时,     选择时钟 24MHZ (用户可自行修改频率).
******************************************/
#include "STC8H.h"
#include "stdio.h"
#include "intrins.h"
typedef                 unsigned char    u8;
typedef                 unsigned int        u16;
typedef                 unsigned long     u32;
/****************************** 用户定义宏***********************************/
#define       MAIN_Fosc       24000000L                                               //定义主时钟
#define       PrintUart            2                                                               //1:printf 使用 UART1; 2:printf 使用 UART2
#define       Baudrate            115200L
#define       TM                      (65536 -(MAIN_Fosc/Baudrate/4))
/*****************************************************************************/
/************* 本地常量声明   **************/
u8 code      ledNum[]={0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80};
/************* 本地变量声明   **************/
bit     B_1s;
bit     B_Alarm;                                                                                       //闹钟标志
u8     ledIndex;
/************* 本地函数声明   **************/
void RTC_config(void);
void CMP_config(void);
void Ext_Vcc_Det(void);
/******************** 串口打印函数 ********************/
void UartInit(void)
{
#if(PrintUart == 1)
         SCON= (SCON & 0x3f) | 0x40;
         AUXR|= 0x40;                                                                             //定时器时钟1T模式
         AUXR&= 0xFE;                                                                          //串口1选择定时器1为波特率发生器
         TL1= TM;
         TH1= TM>>8;
         TR1= 1;                                                                                        //定时器1开始计时
//       SCON = (SCON & 0x3f) | 0x40;
//       T2L = TM;
//       T2H = TM>>8;
//       AUXR |= 0x15;                                                                             //串口1选择定时器2为波特率发生器
#else
         P_SW2|= 1;                                                                                 //UART2    switch to: 0: P1.0 P1.1, 1: P4.6 P4.7
         S2CON&= ~(1<<7);                                                                    //8位数据, 1位起始位, 1位停止位, 无校验
         T2L= TM;
         T2H= TM>>8;
         AUXR|= 0x14;                                                                             //定时器2时钟1T模式,开始计时
#endif
}
void UartPutc(unsigned char dat)
{
#if(PrintUart == 1)
         SBUF= dat;      
         while(TI== 0);
         TI= 0;
#else
         S2BUF= dat;
         while((S2CON& 2) == 0);
         S2CON&= ~2;                                                                             //Clear Tx flag
#endif
}
char putchar(char c)
{
         UartPutc(c);
         returnc;
}
/**********************************************/
void main(void)
{
         P_SW2|= 0x80;                                                                            //扩展寄存器(XFR)访问使能
         P0M1= 0x00;   P0M0 = 0x00;                                                 //设置为准双向口
         P1M1= 0x00;   P1M0 = 0x00;                                                 //设置为准双向口
         P2M1= 0x00;   P2M0 = 0x00;                                                 //设置为准双向口
         P3M1= 0xa0;   P3M0 = 0x20;                                                 //设置为准双向口
// P3.5设置开漏输出, P3.7设置高阻输入
         P4M1= 0x00;   P4M0 = 0x00;                                                 //设置为准双向口
         P5M1= 0x00;   P5M0 = 0x00;                                                 //设置为准双向口
         P6M1= 0x00;   P6M0 = 0x00;                                                 //设置为准双向口
         P7M1= 0x00;   P7M0 = 0x00;                                                 //设置为准双向口
         UartInit();
         CMP_config();
         RTC_config();
         EA= 1;                                                                                          //打开总中断
         while(1)
         {
                   if(B_1s)
                   {
                            B_1s= 0;
                            printf("Year=20%bd,Month=%bd,Day=%bd,Hour=%bd,Minute=%bd,Second=%bd\r\n",
                                     YEAR,MONTH,DAY,HOUR,MIN,SEC);
                            Ext_Vcc_Det();                                                           //每秒钟检测一次外部电源,
//如果外部电源连接则工作,
外部电源断开则进入休眠模式
                   }
                   if(B_Alarm)
                   {
                            B_Alarm    = 0;
                            printf("RTC       Alarm!\r\n");
                   }
         }
}
//========================================================================
// 函数: void Ext_Vcc_Det(void)
// 描述: 外部电源检测函数。
// 参数: .
// 返回: .
// 版本: V1.0, 2022-10-10
//========================================================================
void Ext_Vcc_Det(void)
{
         P35= 0;                                                                                         //比较时,对外输出0,做比较电路的地线
         CMPCR1|= 0x80;                                                                        //使能比较器模块
         _nop_();
         _nop_();
         _nop_();
         if(CMPCR1& 0x01)                                                                    //判断是否CMP+电平高于CMP-,外部电源连接
         {
                   P40= 0;                                                                               //LED Power  On
                   P6= ~ledNum[ledIndex];                                                   //输出低驱动
                   ledIndex++;
                   if(ledIndex > 7)
                   {
                            ledIndex= 0;
                   }
         }
         else
         {
                   CMPCR1&= ~0x80;                                                          //关闭比较器模块
                   P35= 1;                                                                                //不比较时,对外设置为1I/O口浮空,省电
                   P40= 1;                                                                               //LED Power Off
                   _nop_();
                   _nop_();
                   PCON= 0x02;                                                                     //STC8H8K64U B版本芯片使用内部32K时钟,
休眠无法唤醒
                   _nop_();
                   _nop_();
                   _nop_();
                   _nop_();
                   _nop_();
                   _nop_();
         }
}
//========================================================================
// 函数: void CMP_config(void)
// 描述: 比较器初始化函数。
// 参数: .
// 返回: .
// 版本: V1.0, 2022-10-10
//========================================================================
void CMP_config(void)
{
         CMPEXCFG= 0x00;
//       CMPEXCFG |= 0x40;                                                                  //比较器DC迟滞输入选择,0:0mV;
//0x40:10mV; 0x80:20mV; 0xc0:30mV
//       CMPEXCFG &=         ~0x04;                                                      //P3.6CMP-输入脚
         CMPEXCFG|= 0x04;                                                                           //内部1.19V参考电压为CMP-输入脚
         CMPEXCFG&=         ~0x03;                                                      //P3.7CMP+输入脚
//       CMPEXCFG |= 0x01;                                                                           //P5.0CMP+输入脚
//       CMPEXCFG |= 0x02;                                                                           //P5.1CMP+输入脚
//       CMPEXCFG |= 0x03;                                                                           //ADC输入脚为CMP+输入脚
         CMPCR2= 0x00;
         CMPCR2&= ~0x80;                                                                    //比较器正向输出
//       CMPCR2 |= 0x80;                                                                        //比较器反向输出
         CMPCR2&= ~0x40;                                                                    //使能0.1us滤波
//       CMPCR2 |= 0x40;                                                                        //禁止0.1us滤波
         CMPCR2&= ~0x3f;                                                                    //比较器结果直接输出
//       CMPCR2 |= 0x10;                                                                        //比较器结果经过16个去抖时钟后输出
         CMPCR1= 0x00;
//       CMPCR1 |= 0x30;                                                                        //使能比较器边沿中断
//       CMPCR1 &= ~0x20;                                                                    //禁止比较器上升沿中断
//       CMPCR1 |= 0x20;                                                                        //使能比较器上升沿中断
//       CMPCR1 &= ~0x10;                                                                    //禁止比较器下降沿中断
//       CMPCR1 |= 0x10;                                                                        //使能比较器下降沿中断
         CMPCR1&= ~0x02;                                                                    //禁止比较器输出
//       CMPCR1 |= 0x02;                                                                        //使能比较器输出
         P_SW2&= ~0x08;                                                                       //选择P3.4作为比较器输出脚
//       P_SW2 |= 0x08;                                                                            //选择P4.1作为比较器输出脚
         CMPCR1|= 0x80;                                                                        //使能比较器模块
}
//========================================================================
// 函数: void RTC_config(void)
// 描述: RTC初始化函数。
// 参数: .
// 返回: .
// 版本: V1.0, 2022-10-10
//========================================================================
void RTC_config(void)
{
         INIYEAR  = 21;                                                                            //Y:2021
         INIMONTH= 12;                                                                        //M:12
         INIDAY= 31;                                                                                //D:31
         INIHOUR= 23;                                                                            //H:23
         INIMIN= 59;                                                                               //M:59
         INISEC= 50;                                                                                //S:50
         INISSEC= 0;                                                                                //S/128:0
         ALAHOUR= 0;                                                                            //闹钟小时
         ALAMIN= 0;                                                                                //闹钟分钟
         ALASEC= 0;                                                                                //闹钟秒
         ALASSEC= 0;                                                                             //闹钟1/128
//STC8H8K64U B版本芯片使用内部32K时钟,休眠无法唤醒
//       IRC32KCR = 0x80;                                                                      //启动内部低速IRC.
//       while (!(IRC32KCR &1));                                                           //等待时钟稳定
//       RTCCFG = 0x03;                                                                         //选择内部低速IRC时钟源,触发RTC寄存器初始化
         X32KCR= 0x80 + 0x40;                                                              //启动外部32K晶振, 低增益+0x00,   高增益+0x40.
         while(!(X32KCR & 1));                                                               //等待时钟稳定
         RTCCFG= 0x01;                                                                         //选择外部32K时钟源,触发RTC寄存器初始化
         RTCIF= 0x00;                                                                             //清中断标志
         RTCIEN= 0x88;                                                                          //中断使能, 0x80:闹钟中断, 0x40:日中断, 0x20:小时中断,
//0x10:分钟中断, 0x08:秒中断, 0x04:1/2秒中断,
//0x02:1/8秒中断, 0x01:1/32秒中断
         RTCCR= 0x01;                                                                            //RTC使能
         while(RTCCFG& 0x01);                                                             //等待初始化完成,需要在 "RTC使能" 之后判断.
//设置RTC时间需要32768Hz1个周期时间,
//大约30.5us./由于同步, 所以实际等待时间是0~30.5us.
//如果不等待设置完成就睡眠,RTC会由于设置没完成,
//停止计数, 唤醒后才继续完成设置并继续计数.
}
/******************** RTC中断函数 *********************/
void RTC_Isr() interrupt 13
{
         if(RTCIF& 0x80)                                                                        //闹钟中断
         {
//                 P01 = !P01;
                   RTCIF&= ~0x80;
                   B_Alarm= 1;
         }
         if(RTCIF& 0x08)                                                                        //秒中断
         {
//                 P00 = !P00;
                   RTCIF&= ~0x08;
                   B_1s= 1;
         }
}
/*****************************************************************************/
//如果开启了比较器中断就需要编写对应的中断函数
void CMP_Isr() interrupt 21
{
         CMPCR1&= ~0x40;                                                                             //清中断标志
//       P10 = CMPCR1 & 0x01;                                                                       //中断方式读取比较器比较结果
}




回复 送花

使用道具 举报

该用户从未签到

550

主题

9316

回帖

1万

积分

管理员

积分
13894
 楼主| 发表于 2023-9-27 12:56:36 | 显示全部楼层
视频讲解: RTC实时时钟年月日时分秒@STC32G
截图202310111100202489.jpg
https://www.stcaimcu.com/forum.p ... d=463&extra=&page=1
回复 支持 反对 送花

使用道具 举报

该用户从未签到

550

主题

9316

回帖

1万

积分

管理员

积分
13894
 楼主| 发表于 2023-10-11 11:01:06 | 显示全部楼层

RTC的精度跟MCU无关:
只跟外部 RTC-32768晶振 有关,具体要 正规晶振厂家提供样品测试,
分析他的【32768-晶振数据手册】说明的误差如:【精度+温漂】
回复 支持 反对 送花

使用道具 举报

该用户从未签到

550

主题

9316

回帖

1万

积分

管理员

积分
13894
 楼主| 发表于 2023-10-11 11:01:14 | 显示全部楼层
先占个高层楼层,好补充内容
回复 支持 反对 送花

使用道具 举报

该用户从未签到

550

主题

9316

回帖

1万

积分

管理员

积分
13894
 楼主| 发表于 2023-10-11 11:01:23 | 显示全部楼层
先占个高层楼层,好补充内容
回复 支持 反对 送花

使用道具 举报

  • TA的每日心情
    开心
    2024-4-19 08:18
  • 签到天数: 95 天

    [LV.6]常住居民II

    34

    主题

    85

    回帖

    670

    积分

    高级会员

    积分
    670
    发表于 2023-12-22 22:38:27 | 显示全部楼层
    是否有公历和农历相互转换功能?
    回复 支持 反对 送花

    使用道具 举报

  • TA的每日心情

    前天 22:38
  • 签到天数: 71 天

    [LV.6]常住居民II

    3

    主题

    38

    回帖

    81

    积分

    注册会员

    积分
    81
    发表于 2024-2-18 09:16:06 | 显示全部楼层
    超级有用😁
    回复 支持 反对 送花

    使用道具 举报

  • TA的每日心情
    开心
    2024-1-24 09:04
  • 签到天数: 6 天

    [LV.2]偶尔看看I

    0

    主题

    4

    回帖

    120

    积分

    注册会员

    积分
    120
    发表于 2024-2-22 10:50:14 | 显示全部楼层
    我用DS3231模块的32k引脚的信号进入P1.7脚,一个是STC8H的芯片,另一个是STC32G12K128的芯片,在STC8H的芯片上的RTC计时完全与DS3231的计时同步,没有误差。但在STC32G12K128的芯片上第30分钟误差5秒,不知是什么原因,请老师指导一下,谢谢!
    回复 支持 反对 送花

    使用道具 举报

  • TA的每日心情
    开心
    2024-1-24 09:04
  • 签到天数: 6 天

    [LV.2]偶尔看看I

    0

    主题

    4

    回帖

    120

    积分

    注册会员

    积分
    120
    发表于 2024-2-22 10:50:45 | 显示全部楼层
    神农鼎 发表于 2023-10-11 11:01
    RTC的精度跟MCU无关:
    只跟外部 RTC-32768晶振 有关,具体要 正规晶振厂家提供样品测试,
    分析他的【32768 ...

    我用DS3231模块的32k引脚的信号进入P1.7脚,一个是STC8H的芯片,另一个是STC32G12K128的芯片,在STC8H的芯片上的RTC计时完全与DS3231的计时同步,没有误差。但在STC32G12K128的芯片上第30分钟误差5秒,不知是什么原因,请老师指导一下,谢谢!
    回复 支持 反对 送花

    使用道具 举报

  • TA的每日心情
    奋斗
    6 天前
  • 签到天数: 51 天

    [LV.5]常住居民I

    2

    主题

    148

    回帖

    191

    积分

    注册会员

    积分
    191
    发表于 2024-4-17 21:40:29 | 显示全部楼层
    要是RTC有单独的供电就更好了
    回复 支持 反对 送花

    使用道具 举报

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

    本版积分规则

    QQ|手机版|深圳国芯人工智能有限公司 ( 粤ICP备2022108929号-2 )

    GMT+8, 2024-5-5 08:53 , Processed in 0.158511 second(s), 68 queries .

    Powered by Discuz! X3.5

    © 2001-2024 Discuz! Team.

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