zhp 发表于 2023-2-1 12:51:31

不停电下载保持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下载软件中“用户接口”的设置如下:(注意,首次下载不能使能用户接口)

Tuier 发表于 2025-2-22 12:01:52

版主好,我的RTC读取、显示程序正常,就是每次停电或下载程序,RTC的值又被复位了(初始值)。看到这个帖子知道是解决这个问题的,但是程序下载能够顺利运行,P20指示灯也能正常闪烁。但我不知道怎么用到自己程序里,在下载或停电时保持当前时间。我的操作步骤是这样的:
第一,把STC32G系列-RTC-高级应用程序下载到单片机中。
第二,按上图设置用户接口。
第三,下载我自己的RTC程序到单片机。结果显示在“与用户接口通讯”界面,很快就弹出“通讯连接超时”
知道自己没有理解程序的操作步骤,该如何使用,还请版主赐教!另外,它和“RTC对时”(程序下载正常运行了,并能打印输出,但不知道如何对时{:4_167:})功能有什么区别?
页: [1]
查看完整版本: 不停电下载保持RTC参数利用用户接口实现--STC32G系列