视频教学,RTC实时时钟,年/月/日/时/分/秒,1/128秒
https://www.stcaimcu.com/forum.p ... 3184&extra=page%3D1
28 RTC,实时时钟,年/月/日/时/分/秒
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相关的寄存器
28.1.1 RTC控制寄存器(RTCCR)RUNRTC:RTC模块控制位 0:关闭RTC,RTC停止计数 1:使能RTC,并开始RTC计数
28.1.2 RTC配置寄存器(RTCCFG)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)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)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闹钟设置寄存器ALAHOUR:设置每天闹钟的小时值。
注意:设置的值不是BCD码,而是HEX码,比如需要设置小时值20到ALAHOUR,则需使用如下代码进行设置
MOV DPTR,#ALAHOUR
MOV A,#14H
MOVX @DPTR,A ALAMIN:设置每天闹钟的分钟值。数字编码与ALAHOUR相同。 ALASEC:设置每天闹钟的秒值。数字编码与ALAHOUR相同。 ALASSEC:设置每天闹钟的1/128秒值。数字编码与ALAHOUR相同。
28.1.6 RTC实时时钟初始值设置寄存器INIYEAR:设置当前实时时间的年值。有效值范围00~99。对应2000年~2099年
注意:设置的值不是BCD码,而是HEX码,比如需要设置20到INIYEAR,则需使用如下代码进行设置
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实时时钟计数寄存器YEAR:当前实时时间的年值。注意:寄存器的值不是BCD码,而是HEX码 MONTH:当前实时时间的月值。数字编码与YEAR相同。 DAY:当前实时时间的日值。数字编码与YEAR相同。 HOUR:当前实时时间的小时值。数字编码与YEAR相同。 MIN:当前实时时间的分钟值。数字编码与YEAR相同。 SEC:当前实时时间的秒值。数字编码与YEAR相同。 SSEC:当前实时时间的1/128秒值。数字编码与YEAR相同。 注意:YEAR、MONTH、DAY、HOUR、MIN、SEC和SSEC均为只读寄存器,若需要对这些寄存器执行写操作,必须通过寄存器INIYEAR、INIMONTlH、INIDAT、INIHOU、INIMIN、INISEC、INISSEC和SETRTC来实现。
28.2 RTC实战线路图
file:///C:/Users/HP/AppData/Local/Temp/msohtmlclip1/01/clip_image002.gif
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; //选择内部低速IRC为RTC时钟源 X32KCR= 0xc0; while(!(X32KCR & 0x01)); RTCCFG&= ~0x02; //选择外部部32K为RTC时钟源 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设置为开漏,不比较时,对外设置为1,I/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; //不比较时,对外设置为1,I/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.6为CMP-输入脚 CMPEXCFG|= 0x04; //内部1.19V参考电压为CMP-输入脚 CMPEXCFG&= ~0x03; //P3.7为CMP+输入脚 // CMPEXCFG |= 0x01; //P5.0为CMP+输入脚 // CMPEXCFG |= 0x02; //P5.1为CMP+输入脚 // 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时间需要32768Hz的1个周期时间, //大约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; //中断方式读取比较器比较结果 }
|