找回密码
 立即注册
查看: 4647|回复: 10

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

[复制链接]
  • 打卡等级:偶尔看看III
  • 打卡总天数:38
  • 最近打卡:2025-04-30 14:38:57

25

主题

977

回帖

3599

积分

超级版主

积分
3599
发表于 2023-2-1 12:27:55 | 显示全部楼层 |阅读模式
8H2K08U, 8H2K12U, 8H2K17U
8H2K32U
===以上这几个型号开始,CPU 复位, 不同步复位 RTC
=======================================
其他早期单片机的RTC模块,在单片机复位后RTC相关的特殊功能寄存器也会复位
本例程主要用于解决这些早期的MCU, 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, 下载次数: 343

回复

使用道具 举报 送花

  • 打卡等级:偶尔看看III
  • 打卡总天数:54
  • 最近打卡:2025-05-01 09:07:55

717

主题

1万

回帖

1万

积分

管理员

积分
15613
发表于 2024-5-4 09:45:33 | 显示全部楼层
回复 支持 反对

使用道具 举报 送花

1

主题

5

回帖

29

积分

新手上路

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

点评

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

使用道具 举报 送花

  • 打卡等级:偶尔看看III
  • 打卡总天数:38
  • 最近打卡:2025-04-30 14:38:57

25

主题

977

回帖

3599

积分

超级版主

积分
3599
发表于 2023-7-12 14:52:00 | 显示全部楼层
Jszq-*** 发表于 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 | 显示全部楼层
zh*** 发表于 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 | 显示全部楼层
zh*** 发表于 2023-7-12 14:52
0xfe00是CODE地址,0x0000是EEPROM地址

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

点评

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

使用道具 举报 送花

  • 打卡等级:偶尔看看III
  • 打卡总天数:38
  • 最近打卡:2025-04-30 14:38:57

25

主题

977

回帖

3599

积分

超级版主

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

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

使用道具 举报 送花

1

主题

5

回帖

29

积分

新手上路

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

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

使用道具 举报 送花

  • 打卡等级:以坛为家I
  • 打卡总天数:290
  • 最近打卡:2025-05-01 19:58:04

23

主题

65

回帖

1870

积分

金牌会员

积分
1870
发表于 2024-5-4 10:42:05 | 显示全部楼层
希望能在文档中的RTC章节提一下这个问题,避免踩坑,
我在这点上白白浪费了两天才研究出来不是代码写得不对,
是MCU复位引起时钟清零的,时间宝贵啊,
感觉时间越来越不够用了
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:偶尔看看III
  • 打卡总天数:54
  • 最近打卡:2025-05-01 09:07:55

717

主题

1万

回帖

1万

积分

管理员

积分
15613
发表于 2024-5-4 10:53:55 | 显示全部楼层
复位 CPU, 也复位 RTC, 是对的 !
复位 CPU, 不复位 RTC, 也是实际需求 !
现在新的设计开始转向将 CPU复位和 RTC复位分开
===数据手册会持续更新



STC8H2K08U, STC8H2K12U, STC8H2K17U
STC8H2K32U
===以上这几个型号开始,CPU 复位, 不同步复位 RTC




回复 支持 反对

使用道具 举报 送花

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

本版积分规则

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

GMT+8, 2025-5-2 06:30 , Processed in 0.168707 second(s), 119 queries .

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

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