请选择 进入手机版 | 继续访问电脑版

 找回密码
 立即注册
查看: 2816|回复: 6

不停电下载保持RTC参数利用用户接口实现---STC8H系列

[复制链接]
  • TA的每日心情
    开心
    2024-1-4 08:56
  • 签到天数: 14 天

    [LV.3]偶尔看看II

    16

    主题

    702

    回帖

    2460

    积分

    超级版主

    积分
    2460
    发表于 2023-2-1 12:27:55 | 显示全部楼层 |阅读模式
    本帖最后由 zhp 于 2023-4-28 13:04 编辑

    现有单片机系列的RTC模块,在单片机复位后RTC相关的特殊功能寄存器也会复位
    本例程主要用于解决ISP下载后用户的RTC参数丢失的问题
    解决思路:ISP下载前,先将RTC相关参数通过ISP下载软件的用户接口上传到PC保存,等待ISP下载完成后,下载软件再将保存的相关参数写入到FLASH的指定地址(范例中指定的地址为FE0000H)。ISP下载完成后会立即运行用户代码,用户程序在初始化RTC寄存器时,可从FLASH的指定地址中读取之前上传的RTC相关参数对RTC寄存器进行初始化,即可实现不停电下载保持RTC参数的目的。
    测试代如下:  下载完整的项目程序包
    1. #include "stc8h.h"
    2. #include "intrins.h"
    3. #define FOSC        11059200UL
    4. #define BAUD        (65536 - FOSC/4/115200)
    5. typedef bit BOOL;
    6. typedef unsigned char BYTE;
    7. struct RTC_INIT
    8. {
    9.     BYTE bValidTag;         //数据有效标志(0x5a)
    10.     BYTE bIniYear;          //年(RTC初始化值)
    11.     BYTE bIniMonth;         //月
    12.     BYTE bIniDay;           //日
    13.     BYTE bIniHour;          //时
    14.     BYTE bIniMinute;        //分
    15.     BYTE bIniSecond;        //秒
    16.     BYTE bIniSSecond;       //次秒
    17.     BYTE bAlaHour;          //时(RTC闹钟设置值)
    18.     BYTE bAlaMinute;        //分
    19.     BYTE bAlaSecond;        //秒
    20.     BYTE bAlaSSecond;       //次秒
    21. };
    22. struct RTC_INIT code InitBlock _at_ 0xfe00;
    23. void SysInit();
    24. void UartInit();
    25. void RTCInit();
    26. void SendUart(BYTE dat);
    27. void UnpackCmd(BYTE dat);
    28. void IapProgram(int addr, char dat);
    29. BOOL fUartBusy;
    30. BOOL fFetchRtc;
    31. BOOL fReset2Isp;
    32. BYTE bUartStage;
    33. BYTE bDump[7];
    34. void main()
    35. {
    36.     SysInit();                              //系统初始化
    37.     UartInit();
    38.     RTCInit();
    39.     EA = 1;
    40.     fUartBusy = 0;
    41.     fFetchRtc = 0;
    42.     fReset2Isp = 0;
    43.     bUartStage = 0;
    44.     while (1)
    45.     {
    46.         if (fFetchRtc)                      //获取RTC数据请求
    47.         {
    48.             fFetchRtc = 0;
    49.             RTCCR = 0;                      //上传当前的RTC值时,必须临时停止RTC,以免发生进位错误
    50.             bDump[0] = YEAR;                //快速将当前的RTC值缓存,以缩短RTC暂停的时间,减小误差
    51.             bDump[1] = MONTH;
    52.             bDump[2] = DAY;
    53.             bDump[3] = HOUR;
    54.             bDump[4] = MIN;
    55.             bDump[5] = SEC;
    56.             bDump[6] = SSEC;
    57.             RTCCR = 1;
    58.             
    59.             SendUart(0x5a);                 //上传12字节RTC参数
    60.             SendUart(bDump[0]);
    61.             SendUart(bDump[1]);
    62.             SendUart(bDump[2]);
    63.             SendUart(bDump[3]);
    64.             SendUart(bDump[4]);
    65.             SendUart(bDump[5]);
    66.             SendUart(bDump[6]);
    67.             SendUart(ALAHOUR);
    68.             SendUart(ALAMIN);
    69.             SendUart(ALASEC);
    70.             SendUart(ALASSEC);
    71.         }
    72.         if (fReset2Isp)                     //重启请求
    73.         {
    74.             fReset2Isp = 0;
    75.             IAP_CONTR = 0x60;               //软件触发复位到系统ISP区
    76.         }
    77.     }
    78. }
    79. void uart_isr() interrupt UART1_VECTOR
    80. {
    81.     BYTE dat;
    82.     if (TI)
    83.     {
    84.         TI = 0;
    85.         fUartBusy = 0;
    86.     }
    87.     if (RI)
    88.     {
    89.         RI = 0;
    90.         dat = SBUF;
    91.         switch (bUartStage++)               //解析串口命令
    92.         {
    93.         default:
    94.         case 0:
    95. L_Check1st:
    96.             if (dat == '@') bUartStage = 1;
    97.             else bUartStage = 0;
    98.             break;
    99.         case 1:
    100.             if (dat == 'F') bUartStage = 2;
    101.             else if (dat == 'R') bUartStage = 7;
    102.             else goto L_Check1st;
    103.             break;
    104.         case 2:
    105.             if (dat != 'E') goto L_Check1st;
    106.             break;
    107.         case 3:
    108.             if (dat != 'T') goto L_Check1st;
    109.             break;
    110.         case 4:
    111.             if (dat != 'C') goto L_Check1st;
    112.             break;
    113.         case 5:
    114.             if (dat != 'H') goto L_Check1st;
    115.             break;
    116.         case 6:
    117.             if (dat != '#') goto L_Check1st;
    118.             bUartStage = 0;
    119.             fFetchRtc = 1;                  //当前命令序列为获取RTC数据命令:"@FETCH#"
    120.             break;
    121.         case 7:
    122.             if (dat != 'E') goto L_Check1st;
    123.             break;
    124.         case 8:
    125.             if (dat != 'B') goto L_Check1st;
    126.             break;
    127.         case 9:
    128.         case 10:
    129.             if (dat != 'O') goto L_Check1st;
    130.             break;
    131.         case 11:
    132.             if (dat != 'T') goto L_Check1st;
    133.             break;
    134.         case 12:
    135.             if (dat != '#') goto L_Check1st;
    136.             bUartStage = 0;
    137.             fReset2Isp = 1;                 //当前命令序列为重启命令:"@REBOOT#"
    138.             break;
    139.         }
    140.     }
    141. }
    142. void rtc_isr() interrupt RTC_VECTOR         //RTC中断复位程序
    143. {
    144.     RTCIF = 0x00;                           //清RTC中断标志
    145.     P20 = !P20;                             //P2.0口每秒闪烁一次,测试用
    146. }
    147. void SysInit()
    148. {
    149.     P_SW2 |= 0x80;
    150.     P0M0 = 0x00; P0M1 = 0x00;
    151.     P1M0 = 0x00; P1M1 = 0x00;
    152.     P2M0 = 0x00; P2M1 = 0x00;
    153.     P3M0 = 0x00; P3M1 = 0x00;
    154.     P4M0 = 0x00; P4M1 = 0x00;
    155.     P5M0 = 0x00; P5M1 = 0x00;
    156.     P6M0 = 0x00; P6M1 = 0x00;
    157.     P7M0 = 0x00; P7M1 = 0x00;
    158. }
    159. void UartInit()                             //串口初始化函数
    160. {
    161.     SCON = 0x50;
    162.     AUXR = 0x40;
    163.     TMOD = 0x00;
    164.     TL1 = BAUD;
    165.     TH1 = BAUD >> 8;
    166.     TR1 = 1;
    167.     ES = 1;
    168. }
    169. void RTCInit()                              //RTC初始化函数
    170. {
    171. //  IRC32KCR = 0x80;
    172. //  while (!(IRC32KCR & 0x01));
    173. //  RTCCFG |= 0x02;                         //选择内部32K为RTC时钟源
    174.     X32KCR = 0xc0;
    175.     while (!(X32KCR & 0x01));
    176.     RTCCFG &= ~0x02;                        //选择外部部32K为RTC时钟源
    177.     if (InitBlock.bValidTag == 0x5a)
    178.     {
    179.         INIYEAR  = InitBlock.bIniYear;      //如果初始化数据块有效,则使用数据块初始化RTC
    180.         INIMONTH = InitBlock.bIniMonth;
    181.         INIDAY   = InitBlock.bIniDay;
    182.         INIHOUR  = InitBlock.bIniHour;
    183.         INIMIN   = InitBlock.bIniMinute;
    184.         INISEC   = InitBlock.bIniSecond;
    185.         INISSEC  = InitBlock.bIniSSecond;
    186.         ALAHOUR  = InitBlock.bAlaHour;
    187.         ALAMIN   = InitBlock.bAlaMinute;
    188.         ALASEC   = InitBlock.bAlaSecond;
    189.         ALASSEC  = InitBlock.bAlaSSecond;
    190.         IapProgram(0x0000, 0x00);           //销毁初始化数据块,以免重复初始化
    191.     }
    192.     else
    193.     {
    194.         INIYEAR  = 23;                      //否则初始化RTC为默认值
    195.         INIMONTH = 1;
    196.         INIDAY   = 29;
    197.         INIHOUR  = 12;
    198.         INIMIN   = 0;
    199.         INISEC   = 0;
    200.         INISSEC  = 0;
    201.         ALAHOUR  = 0;
    202.         ALAMIN   = 0;
    203.         ALASEC   = 0;
    204.         ALASSEC  = 0;
    205.     }
    206.     RTCCFG |= 0x01;                         //写入RTC初始值
    207.     RTCCR = 0x01;                           //RTC开始运行
    208.     while (RTCCFG & 0x01);                  //等待RTC初始化完成
    209.     RTCIF = 0x00;
    210.     RTCIEN = 0x08;                          //使能RTC秒中断
    211. }
    212. void SendUart(BYTE dat)                     //串口发送函数
    213. {
    214.     while (fUartBusy);
    215.     SBUF = dat;
    216.     fUartBusy = 1;
    217. }
    218. void IapProgram(int addr, char dat)         //EEPROM编程函数
    219. {
    220.     IAP_CONTR = 0x80;
    221.     IAP_TPS = 12;
    222.     IAP_CMD = 2;
    223.     IAP_ADDRL = addr;
    224.     IAP_ADDRH = addr >> 8;
    225.     IAP_DATA = dat;
    226.     IAP_TRIG = 0x5a;
    227.     IAP_TRIG = 0xa5;
    228.     _nop_();
    229.     _nop_();
    230.     _nop_();
    231.     _nop_();
    232. }
    复制代码

    ISP下载软件中“用户接口”的设置如下:(注意,首次下载不能使能用户接口)
    STC8H系列 —— 利用用户接口实现不停电下载保持RTC参数-2.png

    STC8H系列-RTC-高级应用.rar

    12.16 KB, 下载次数: 156

    回复 送花

    使用道具 举报

    该用户从未签到

    1

    主题

    5

    回帖

    29

    积分

    新手上路

    积分
    29
    发表于 2023-7-12 13:34:56 | 显示全部楼层
    为什么时钟保存在0XFE00地址,销毁的时候却是0x0000地址?

    点评

    zhp
    0xfe00是CODE地址,0x0000是EEPROM地址 EEPROM地址和代码地址的关系请参考数据手册中下面章节的描述  详情 回复 发表于 2023-7-12 14:52
    回复 支持 反对 送花

    使用道具 举报

  • TA的每日心情
    开心
    2024-1-4 08:56
  • 签到天数: 14 天

    [LV.3]偶尔看看II

    16

    主题

    702

    回帖

    2460

    积分

    超级版主

    积分
    2460
     楼主| 发表于 2023-7-12 14:52:00 | 显示全部楼层
    Jszq-tech 发表于 2023-7-12 13:34
    为什么时钟保存在0XFE00地址,销毁的时候却是0x0000地址?

    0xfe00是CODE地址,0x0000是EEPROM地址

    1.png



    EEPROM地址和代码地址的关系请参考数据手册中下面章节的描述
    2.png

    回复 支持 反对 送花

    使用道具 举报

    该用户从未签到

    1

    主题

    5

    回帖

    29

    积分

    新手上路

    积分
    29
    发表于 2023-7-12 17:29:16 | 显示全部楼层
    zhp 发表于 2023-7-12 14:52
    0xfe00是CODE地址,0x0000是EEPROM地址

    EEPROM大小设置为16K,我在用户接口页面下用户数据写入地址是0XD000,初始化RTC模块后写EEPROM地址0X1000地址为0X00,为什么我保存在EEPROM地址0X0000-0X0800的一些数据都没了?
    回复 支持 反对 送花

    使用道具 举报

    该用户从未签到

    1

    主题

    5

    回帖

    29

    积分

    新手上路

    积分
    29
    发表于 2023-7-12 17:29:32 | 显示全部楼层
    zhp 发表于 2023-7-12 14:52
    0xfe00是CODE地址,0x0000是EEPROM地址

    EEPROM大小设置为16K,我在用户接口页面下用户数据写入地址是0XD000,初始化RTC模块后写EEPROM地址0X1000地址为0X00,为什么我保存在EEPROM地址0X0000-0X0800的一些数据都没了?

    点评

    zhp
    按理是不会出现你这种情况的 但有一点需要注意,设置EEPROM大小的硬件选项需要下次重新上电才生效  详情 回复 发表于 2023-7-12 21:24
    回复 支持 反对 送花

    使用道具 举报

  • TA的每日心情
    开心
    2024-1-4 08:56
  • 签到天数: 14 天

    [LV.3]偶尔看看II

    16

    主题

    702

    回帖

    2460

    积分

    超级版主

    积分
    2460
     楼主| 发表于 2023-7-12 21:24:53 | 显示全部楼层
    Jszq-tech 发表于 2023-7-12 17:29
    EEPROM大小设置为16K,我在用户接口页面下用户数据写入地址是0XD000,初始化RTC模块后写EEPROM地址0X1000 ...

    按理是不会出现你这种情况的
    但有一点需要注意,设置EEPROM大小的硬件选项需要下次重新上电才生效
    回复 支持 反对 送花

    使用道具 举报

    该用户从未签到

    1

    主题

    5

    回帖

    29

    积分

    新手上路

    积分
    29
    发表于 2023-7-13 14:03:18 | 显示全部楼层
    zhp 发表于 2023-7-12 21:24
    按理是不会出现你这种情况的
    但有一点需要注意,设置EEPROM大小的硬件选项需要下次重新上电才生效 ...

    不是重新上电生效的问题,试验了多次都是这样的,但是把RTC模块初始化参数放在EEPROM的0X0000地址,其他参数放在后面的扇区中就不会有这种情况。
    回复 支持 反对 送花

    使用道具 举报

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    QQ|手机版|深圳国芯人工智能有限公司 ( 粤ICP备2022108929号-2 )

    GMT+8, 2024-3-29 22:56 , Processed in 0.069841 second(s), 56 queries .

    Powered by Discuz! X3.5

    © 2001-2024 Discuz! Team.

    快速回复 返回顶部 返回列表