请教 RTC闹钟到点能触发中断 不能退出掉电休眠
本帖最后由 wjhhhhh 于 2024-9-8 09:59 编辑STC32G12K128 设置的闹钟,到点能触发RTC中断,不能退出掉电休眠,而外部中断0(按下连接P32按键接地)能退出掉电休眠,串口1接收到数据(RXT有低电平)也能退出掉电休眠 。 进入休眠的PCON=0x02或者DP=1 必须设置二次,否则不能休眠。 哪里没弄好?请各位指教。谢谢
#include "STC32G.h"
#include "stdio.h"
#include "intrins.h"
typedef unsigned char u8;
typedef unsigned int u16;
typedef unsigned long u32;
/****************************** 用户定义宏 ***********************************/
#define MAIN_Fosc 22118400L //定义主时钟
#define Baudrate 19200L
#define TM (65536 -(MAIN_Fosc/Baudrate/4))
/**********************************/
bit B_1s;
bit B_Alarm; //闹钟标志
bit busy; //串口忙,
bit huan_xing; //唤醒
bit q_t=1;
/*****Uart1Init********************************/
void Uart1Init(void) //19200bps@22.1184MHz
{ SCON = 0x50; //8位数据,可变波特率
AUXR |= 0x01; //串口1选择定时器2为波特率发生器
AUXR |= 0x04; //定时器时钟1T模式
T2L = 0xE0; //设置定时初始值
T2H = 0xFE; //设置定时初始值
AUXR |= 0x10; //定时器2开始计时
ES=1;
}
/*=======发字节 ===========*/
void Uart1Send(u8 dat)
{ while (busy);
busy = 1;
SBUF = dat;
}
/***RTC初始化***********/
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 = 58; //S:50
INISSEC = 0; //S/128:0
ALAHOUR = 0; //闹钟小时
ALAMIN= 0; //闹钟分钟
ALASEC= 15; //闹钟秒第15秒闹钟时间到
// 第15秒闹钟时间到
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使能
//RTCCFG |= 0x01; //触发RTC寄存器初始化---20240513PDF910/875页
while(RTCCFG & 0x01); //等待初始化完成,需要在 "RTC使能" 之后判断.
}
/*=======延时函数大约1mS===========*/
voiddelay_ms(u16 ms)
{ u16 i;
do
{i = MAIN_Fosc / 6000;
while(--i) ;
}while(--ms);
}
//掉电休眠前设置I/O口
voidS_sleep(void)
{ Uart1Send(0x8C);Uart1Send(0x8C);
delay_ms(10);
P0M1 = 0x00; P0M0 = 0x00;
P1M1 = 0x00; P1M0 = 0x00;
P2M1 = 0x00; P2M0 = 0x00;
P3M1 = 0x00; P3M0 = 0x00;
P4M1 = 0x00; P4M0 = 0x00;
P5M1 = 0x00; P5M0 = 0x00;
P6M1 = 0x00; P6M0 = 0x00;
P7M1 = 0x00; P7M0 = 0x00;
P0=0xFF;P1=0xFF;P2=0xFF;P3=0xFF;
P4=0xFF;P5=0xFF;P6=0xFF;P7=0xFF;
// 基本成功全部IO口双向 8.4 mA 掉电1.85uA
//2024.9.4 VCC=4V 全部IO口高阻 8.26mA 掉电34uA
//-----------------------
//P0=0x00;P1=0x00;P2=0x00;P3=0x00; //不能退出掉电?
//P4=0x00;P5=0x00;P6=0x00;P7=0x00;
// 全部IO口双向 8.4 mA 掉电2.0xuA
//2024.9.4 VCC=4V 全部IO口高阻 8.26mA 掉电37uA
P0IE = 0x00;//关闭所有I/0口的数字通道
P1IE = 0x00;
P2IE = 0x00;
//P3IE = 0x00;
P3IE |= 0x84;//P3数字通道需要唤醒脚P32(INT0调试用)?
P4IE = 0x00;
P5IE = 0x00;
P6IE = 0x00;
P7IE = 0x00;
//PD=1;//掉电休眠 PD=1或PCON=0x02都可以,都必须两次 !?
//PD=1;//2024.9.6w这里必须两次!?前后都加多个nop都不行
PCON=0x02;
PCON=0x02;
}
/***不能漏掉汇编那一段!!********************************/
void main(void)
{ WTST = 0;//设置程序指令延时参数,赋值为0可将CPU执行指令的速度设置为最快
EAXFR = 1; //扩展寄存器(XFR)访问使能
CKCON = 0; //提高访问XRAM速度
P0M1 = 0x00; P0M0 = 0x00;//设置为准双向口
P1M1 = 0x00; P1M0 = 0x00;
P2M1 = 0x00; P2M0 = 0x00;
P3M1 = 0x00; P3M0 = 0x00;
P4M1 = 0x00; P4M0 = 0x00;
P5M1 = 0x00; P5M0 = 0x00;
P6M1 = 0x00; P6M0 = 0x00;
P7M1 = 0x00; P7M0 = 0x00;
Uart1Init();
RTC_config();
IT0=1; //IT0下降沿中断
EX0=1; //使能IT0 中断
P27=0; // 标记
P21=0;
EA = 1; //打开总中断
Uart1Send(0x1A);Uart1Send(0x2A);Uart1Send(0x3A);Uart1Send(0x4A);
while(1)
{
if(huan_xing==1)
{P0M1 = 0x00; P0M0 = 0x00;
P1M1 = 0x00; P1M0 = 0x00;
P2M1 = 0x00; P2M0 = 0x00;
P3M1 = 0x00; P3M0 = 0x00;
P4M1 = 0x00; P4M0 = 0x00;
P5M1 = 0x00; P5M0 = 0x00;
P6M1 = 0x00; P6M0 = 0x00;
P7M1 = 0x00; P7M0 = 0x00;
P0IE = 0xFF;//使能所有I/0口的数字通道
P1IE = 0xFF;
P2IE = 0xFF;
P3IE = 0xFF;
P4IE = 0xFF;
P5IE = 0xFF;
P6IE = 0xFF;
P7IE = 0xFF;
}
if(B_1s)
{B_1s = 0;
Uart1Send(0xBB);Uart1Send(0xBB);
Uart1Send(YEAR);Uart1Send(MONTH);Uart1Send(DAY);
Uart1Send(HOUR);Uart1Send(MIN);Uart1Send(SEC);
if(q_t==1){P20=0;P27=1;}
else {P20=1;P27=0;}
if(SEC==8) //第八秒开始掉电休眠
{_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();
S_sleep();
_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();
}
}
if(B_Alarm)
{B_Alarm = 0;
Uart1Send(0xAA);Uart1Send(0xAA);Uart1Send(0xAA);Uart1Send(0xAA);
}
if(P35==0)//按下 P35键 进入掉电休眠
{huan_xing=0;
Uart1Send(0x1C);Uart1Send(0x1C);
delay_ms(10);
S_sleep();
}
}
}
/***P32 外部中断0 中断退出掉电 ****interrupt 0************************************ */
void EX_0_interr() interrupt 0
{huan_xing=1;
}
/******************** RTC中断函数 *********************/
void RTC_Isr() interrupt 13
{
if(RTCIF & 0x80) //闹钟中断 休眠开源 播放立体声音乐
{
RTCIF &= ~0x80;
B_Alarm = 1;
}
if(RTCIF & 0x08) //秒中断
{
RTCIF &= ~0x08;
B_1s = 1;
}
}
/*******interrupt 4*********************************** */
void Uart1Isr() interrupt 4
{if (TI)
{ TI = 0;
busy = 0;
}
if (RI)
{RI = 0;
huan_xing=1; //只要有中断发生就退出掉电?
}
}
首先休眠语句只需要写一次,写两句就是程序不对的根源
然后代码有两处小问题,这么写感觉也没错,但逻辑上感觉有点不对
第一处,X32KCR=0xc0是启动外部32K晶振,
等待外部晶振稳定后,让RTC选择外部晶振,需要RTCCFG 的B1位清零(RTCCFG &= ~0x02 ) 但这个时候不需要初始化RTC(不需要RTCCFG = 0x01),应该在 "RTC使能" 之后,再等待初始化完成
第二处,就是RTCCFG的B0位置1(RTCCFG = 0x01),初始化RTC,写入年月日等信息,在RTC使能语句后,再初始化感觉会更合理
代码整体没什么问题,可能你对程序效果有什么误解,下面分析下代码效果:
1、进入主函数后,各种初始化,串口打印:1A 2A 3A 4A,然后进入while(1)循环
2、每1秒RTC中断一次,串口打印 BB BB 年 月 日 时 分 秒
3、if(SEC == 8)的意思是:秒到了每分钟第8秒的时候,即每1分钟进一次if,不是每8秒
所以BB BB 年 月 日...串口会打印60次,第一次是8秒,后面是60秒休眠一次
4、if(B_Alarm)不是每15秒中断一次,是每天 00:00:15,即凌晨0点0分15秒,闹钟中断一次,
所以串口打印一天,只会看到一次AA AA AA AA
5、串口打印看到的8C 8C就是进入休眠时刻打印的数据,但RTC每1秒唤醒一次,感觉就完全没有进休眠
6、按P35进入休眠,休眠前打印1C 1C ,1秒后RTC唤醒,继续打印BB BB 年 月 日....
测试代码:
还是逻辑关系不清晰严谨造成的,我也跟着学习了一下{:4_245:} 这个不错,如果要精确还是要外部晶振。 本帖最后由 wjhhhhh 于 2024-9-9 17:27 编辑
感谢“布丁局长”耐心细致解答指教。
下载附件再试 还有不解:
1.PCON=0x02语句只写一次仍然不能进入休眠。
2.不启用RTC秒中断, 设置在00时00分08秒进入休眠设置闹钟00时00分15秒触发中断退出休眠,实际运行08秒能进入休眠15秒不能退出; 在到达15秒前、后按P32外部触发或串口触发都能退出休眠。
使用"屠龙刀"核心板, STC32G12K128芯片, 去掉P20~P26发光管; USB--CH340转TTL串口下载/通讯
还有哪里没弄对?请指教。谢谢
页:
[1]