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; //中断方式读取比较器比较结果
}





我要赚赏金
