不停电下载保持RTC参数利用用户接口实现--STC32G系列
本帖最后由 zhp 于 2023-4-28 13:07 编辑现有单片机系列的RTC模块,在单片机复位后RTC相关的特殊功能寄存器也会复位本例程主要用于解决ISP下载后用户的RTC参数丢失的问题解决思路:ISP下载前,先将RTC相关参数通过ISP下载软件的用户接口上传到PC保存,等待ISP下载完成后,下载软件再将保存的相关参数写入到FLASH的指定地址(范例中指定的地址为FE0000H)。ISP下载完成后会立即运行用户代码,用户程序在初始化RTC寄存器时,可从FLASH的指定地址中读取之前上传的RTC相关参数对RTC寄存器进行初始化,即可实现不停电下载保持RTC参数的目的。测试代如下:下载完整的项目程序包#include "stc32g.h"
#include "intrins.h"
#define FOSC 11059200UL
#define BAUD (65536 - FOSC/4/115200)
typedef bit BOOL;
typedef unsigned char BYTE;
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 ecode InitBlock _at_ 0xfe0000;
void SysInit();
void UartInit();
void RTCInit();
void SendUart(BYTE dat);
void UnpackCmd(BYTE dat);
void IapProgram(int addr, char dat);
BOOL fUartBusy;
BOOL fFetchRtc;
BOOL fReset2Isp;
BYTE bUartStage;
BYTE bDump;
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 = YEAR; //快速将当前的RTC值缓存,以缩短RTC暂停的时间,减小误差
bDump = MONTH;
bDump = DAY;
bDump = HOUR;
bDump = MIN;
bDump = SEC;
bDump = SSEC;
RTCCR = 1;
SendUart(0x5a); //上传12字节RTC参数
SendUart(bDump);
SendUart(bDump);
SendUart(bDump);
SendUart(bDump);
SendUart(bDump);
SendUart(bDump);
SendUart(bDump);
SendUart(ALAHOUR);
SendUart(ALAMIN);
SendUart(ALASEC);
SendUart(ALASSEC);
}
if (fReset2Isp) //重启请求
{
fReset2Isp = 0;
IAP_CONTR = 0x60; //软件触发复位到系统ISP区
}
}
}
void uart_isr() interrupt UART1_VECTOR
{
BYTE dat;
if (TI)
{
TI = 0;
fUartBusy = 0;
}
if (RI)
{
RI = 0;
dat = SBUF;
switch (bUartStage++) //解析串口命令
{
default:
case 0:
L_Check1st:
if (dat == '@') bUartStage = 1;
else bUartStage = 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') goto L_Check1st;
break;
case 4:
if (dat != 'C') goto L_Check1st;
break;
case 5:
if (dat != 'H') goto L_Check1st;
break;
case 6:
if (dat != '#') goto L_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') goto L_Check1st;
break;
case 11:
if (dat != 'T') goto L_Check1st;
break;
case 12:
if (dat != '#') goto L_Check1st;
bUartStage = 0;
fReset2Isp = 1; //当前命令序列为重启命令:"@REBOOT#"
break;
}
}
}
void rtc_isr() interrupt RTC_VECTOR //RTC中断复位程序
{
RTCIF = 0x00; //清RTC中断标志
P20 = !P20; //P2.0口每秒闪烁一次,测试用
}
void SysInit()
{
WTST = 0;
CKCON = 0;
EAXFR = 1;
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; //选择内部32K为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(int addr, char dat) //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下载软件中“用户接口”的设置如下:(注意,首次下载不能使能用户接口)
版主好,我的RTC读取、显示程序正常,就是每次停电或下载程序,RTC的值又被复位了(初始值)。看到这个帖子知道是解决这个问题的,但是程序下载能够顺利运行,P20指示灯也能正常闪烁。但我不知道怎么用到自己程序里,在下载或停电时保持当前时间。我的操作步骤是这样的:
第一,把STC32G系列-RTC-高级应用程序下载到单片机中。
第二,按上图设置用户接口。
第三,下载我自己的RTC程序到单片机。结果显示在“与用户接口通讯”界面,很快就弹出“通讯连接超时”
知道自己没有理解程序的操作步骤,该如何使用,还请版主赐教!另外,它和“RTC对时”(程序下载正常运行了,并能打印输出,但不知道如何对时{:4_167:})功能有什么区别?
页:
[1]