STC32G内部RTC时钟低功耗,定时休眠唤醒,内部比较器监测外部电源
===RTC定时唤醒-比较器检测外部电压,正常恢复正常工作
===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 "STC32G.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) { WTST= 0; CKCON= 0; EAXFR= 1; 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; //启动内部32K晶振. // while (!(IRC32KCR &1)); //等待时钟稳定 // RTCCFG = 0x03; //选择内部32K时钟源,触发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; //中断方式读取比较器比较结果 }