ccczzh 发表于 2025-8-6 14:08:47

RTC使用外部晶振的问题 | 已解决

求大佬帮助!在使用芯片STC8H1K08T作为主控的情况下,使用外部32.768K的晶振无法启动RTC,一直卡在while (!(X32KCR & 0x01) && timeout--) 的循环部分无法启动成功,选用的晶振匹配电容试过:20pf,15pf,12pf。三个均不行
程序功能是先初始化RTC,然后使用STCISP获取实时时间写入RTC中(目前启动RTC晶振出现问题所以后面的功能还未实现)下面是代码:


#include "STC8H.h"

#include "stdio.h"
#include "intrins.h"

typedef         unsigned char      u8;
typedef         unsigned int      u16;
typedef         unsigned long      u32;

#define MAIN_Fosc      22118400L   //定义主时钟(精确计算115200波特率)
//#define UART1_BUF_LENGTH    128
#defineP1_MODE_IO_PU(Pin)                              P1M1 &= ~(Pin), P1M0 &= ~(Pin);
#defineP3_MODE_IO_PU(Pin)                              P3M1 &= ~(Pin), P3M0 &= ~(Pin);
#defineP1_MODE_IN_HIZ(Pin)                        P1M1 |= (Pin), P1M0 &= ~(Pin);


/*************本地变量声明    **************/

u8TX1_Cnt;    //发送计数
u8RX1_Cnt;    //接收计数
bit B_TX1_Busy; //发送忙标志

//u8RX1_Buffer; //接收缓冲


char code *STCRTC= "@STCRTC#";    //= "@STCRTC#";命令头   
char indexrtc=0;                  //当前的命令头索引
char length =0;                     //长度
char rtctime ;               //rtc时间数据
bitRec_OK = 0;                  //rtc时间获取完成标志

bit B_1S;
bit B_Alarm;

/****************RTC初始化函数 *****************/
void RTC_config(void)
{
u16 timeout = 10000;

X32KCR = 0xc0; // 启动外部32K晶振

while (!(X32KCR & 0x01) && timeout--)
    _nop_();

if(!(X32KCR & 0x01)) {
    printf("X32K Fail! Status: %02x\n", X32KCR);
}

RTCCFG &= ~0x02; // 选择外部32K时钟源
INIYEAR = 24;    // 初始化时间
INIMONTH = 12;
INIDAY = 31;
INIHOUR = 23;
INIMIN = 59;
INISEC = 50;
INISSEC = 0;

RTCCFG |= 0x01;// 触发初始化
timeout = 10000;
while((RTCCFG & 0x01) && timeout--)
    _nop_();

if(RTCCFG & 0x01) {
    printf("RTC Init Timeout!\n");
}

RTCIF = 0;       // 清中断标志
RTCIEN = 0x08;   // 使能秒中断
RTCCR = 0x01;    // 使能RTC

printf("RTC Init Done. Status: %02x\n", RTCCR);
}

char putchar(char dat)
{
      B_TX1_Busy = 1;                        //标志发送忙
      SBUF = dat;                                        //发一个字节
      while(B_TX1_Busy);      //等待发送完成
    return dat;
}

void Uart1_Init(void)      //115200bps@24.000MHz
{
      SCON = 0x50;                //8位数据,可变波特率
      AUXR |= 0x01;                //串口1选择定时器2为波特率发生器
      AUXR |= 0x04;                //定时器时钟1T模式
      T2L = 0xCC;                        //设置定时初始值
      T2H = 0xFF;                        //设置定时初始值
      AUXR |= 0x10;                //定时器2开始计时
      ES = 1;                              //使能串口1中断
}


void main(void)
{
      EAXSFR();
      EA = 1;
      P1_MODE_IO_PU(0x80 | 0x40);//P16、P17用于外部晶振
      P3_MODE_IO_PU(0x00 | 0x01);//P30、P31用于串口
      Uart1_Init();
      RTC_config();
//      EA = 1;
      
      while(1)
      {
                if(B_1S)
                {
                              B_1S = 0;
                              printf("Year=20%bd ", YEAR);
                              printf("Month=%bd ", MONTH);
                              printf("Day=%bd ", DAY);
                              printf("Hour=%bd ", HOUR);
                              printf("Minute=%bd ", MIN);
                              printf("Second=%bd ", SEC);
                              printf("\r\n");
                }
      }
      
}


void UART1_int (void) interrupt 4
{
    u8 dat;
    if(RI)
    {
      RI = 0;
      dat = SBUF;
//      RX1_Buffer = SBUF;
//      if(++RX1_Cnt >= UART1_BUF_LENGTH)   RX1_Cnt = 0;
//-------------------------------串口RTC对时 -------------------------------   
      if( length>0 )
      {   
            rtctime=dat;
            length++;
            if( length>=12 )
            {
                length = 0;
                Rec_OK = 1;
                indexrtc=0;
            }
      }      
      if (dat == STCRTC[ indexrtc])
      {
            indexrtc++;
            if(STCRTC == '\0')
            {
                length = 1;   //开启接收
                indexrtc=0;
            }
      }
      else
      {
            indexrtc = 0;
            if (dat ==STCRTC[ indexrtc])
                indexrtc++;
      }         
    }

    if(TI)
    {
      TI = 0;
      B_TX1_Busy = 0;
    }
}


void RTC_ISR_Handler (void) interrupt 13//RTC_VECTOR
{
      // TODO: 在此处添加用户代码
      if(RTCIF & 0x80)    //闹钟中断
      {
                P01 = !P01;
                RTCIF &= ~0x80;
                B_Alarm = 1;
      }

      if(RTCIF & 0x08)    //秒中断
      {
                P00 = !P00;
                RTCIF &= ~0x08;
                B_1S = 1;
      }
}










ccczzh 发表于 2025-8-6 14:10:35

求大佬解答{:baoquan:}

乘风飞扬 发表于 2025-8-6 14:41:16

直接烧录8H实验箱例程包例子到芯片里试试:50-内部RTC时钟程序
下载时, 选择时钟 24MHz,串口大于RTC时钟信息。
实验箱例程包下载地址:https://www.stcai.com/syx

如果还是不起振的话,先排查板子有没有虚焊或者短路,没有的话换个晶振试试。

ccczzh 发表于 2025-8-6 15:03:25

乘风飞扬 发表于 2025-8-6 14:41
直接烧录8H实验箱例程包例子到芯片里试试:50-内部RTC时钟程序
下载时, 选择时钟 24MHz,串口大于RTC时钟信 ...

我直接使用的试验箱的程序,还是不起振,打算换个晶振再试一试。{:xiaoku:}

DebugLab 发表于 2025-8-6 15:11:26

晶振IO设置为高阻

ccczzh 发表于 2025-8-6 15:29:23

DebugLab 发表于 2025-8-6 15:11
晶振IO设置为高阻

还是不行,无法起振。目前程序:#include "STC8H.h"

#include "stdio.h"
#include "intrins.h"

typedef         unsigned char        u8;
typedef         unsigned int        u16;
typedef         unsigned long        u32;

#define MAIN_Fosc      22118400L   //定义主时钟(精确计算115200波特率)
//#define UART1_BUF_LENGTH    128
#defineP1_MODE_IO_PU(Pin)                                P1M1 &= ~(Pin), P1M0 &= ~(Pin);
#defineP3_MODE_IO_PU(Pin)                                P3M1 &= ~(Pin), P3M0 &= ~(Pin);
#defineP1_MODE_IN_HIZ(Pin)                        P1M1 |= (Pin), P1M0 &= ~(Pin);


/*************本地变量声明    **************/

u8TX1_Cnt;    //发送计数
u8RX1_Cnt;    //接收计数
bit B_TX1_Busy; //发送忙标志

//u8RX1_Buffer; //接收缓冲


char code *STCRTC= "@STCRTC#";    //= "@STCRTC#";命令头   
char indexrtc=0;                  //当前的命令头索引
char length =0;                     //长度
char rtctime ;               //rtc时间数据
bitRec_OK = 0;                  //rtc时间获取完成标志

bit B_1S;
bit B_Alarm;

///****************RTC初始化函数 *****************/
//void RTC_config(void)
//{
//u16 timeout = 10000;
//
////X32KCR = 0xc0; // 启动外部32K晶振
////
////while (!(X32KCR & 0x01) && timeout--)
////    _nop_();
////
////if(!(X32KCR & 0x01)) {
////    printf("X32K Fail! Status: %02x\n", X32KCR);
////}
//        INIYEAR = 24;    // 初始化时间
//INIMONTH = 12;
//INIDAY = 31;
//INIHOUR = 23;
//INIMIN = 59;
//INISEC = 50;
//INISSEC = 0;
//       
//        IRC32KCR = 0x80;   //启动内部32K晶振.
//        while (!(IRC32KCR & 1) && timeout--)//等待时钟稳定
//               _nop_();

//if(!(IRC32KCR & 0x01)) {
//    printf("IRC32K Fail! Status: %02x\n", IRC32KCR);
//}
//RTCCFG = 0x03;    //选择内部32K时钟源,触发RTC寄存器初始化
//       
//        RTCIF = 0;       // 清中断标志
//       
//RTCCR = 0x01;    // 使能RTC
//       
//timeout = 10000;
//while((RTCCFG & 0x01) && timeout--)
//    _nop_();
//
//if(RTCCFG & 0x01) {
//    printf("RTC Init Timeout!\n");
//}
//       
//printf("RTC Init Done. Status: %02x\n", RTCCR);
//       
//RTCIEN = 0x08;   // 使能秒中断
//}

/****************RTC初始化函数 *****************/
void RTC_config(void)
{
u16 timeout = 10000;

X32KCR = 0xc0; // 启动外部32K晶振

while (!(X32KCR & 0x01) && timeout--)
    _nop_();

if(!(X32KCR & 0x01)) {
    printf("X32K Fail! Status: %02x\n", X32KCR);
}

RTCCFG &= ~0x02; // 选择外部32K时钟源
INIYEAR = 24;    // 初始化时间
INIMONTH = 12;
INIDAY = 31;
INIHOUR = 23;
INIMIN = 59;
INISEC = 50;
INISSEC = 0;

RTCCFG |= 0x01;// 触发初始化
timeout = 10000;
while((RTCCFG & 0x01) && timeout--)
    _nop_();

if(RTCCFG & 0x01) {
    printf("RTC Init Timeout!\n");
}

RTCIF = 0;       // 清中断标志
RTCIEN = 0x08;   // 使能秒中断
RTCCR = 0x01;    // 使能RTC

printf("RTC Init Done. Status: %02x\n", RTCCR);
}

char putchar(char dat)
{
        B_TX1_Busy = 1;                        //标志发送忙
        SBUF = dat;                                        //发一个字节
        while(B_TX1_Busy);        //等待发送完成
    return dat;
}

void Uart1_Init(void)        //115200bps@24.000MHz
{
        SCON = 0x50;                //8位数据,可变波特率
        AUXR |= 0x01;                //串口1选择定时器2为波特率发生器
        AUXR |= 0x04;                //定时器时钟1T模式
        T2L = 0xCC;                        //设置定时初始值
        T2H = 0xFF;                        //设置定时初始值
        AUXR |= 0x10;                //定时器2开始计时
        ES = 1;                                //使能串口1中断
}


void main(void)
{
        EAXSFR();
        EA = 1;
        P1_MODE_IN_HIZ(0x80 | 0x40);//P16、P17用于外部晶振
        P3_MODE_IO_PU(0x00 | 0x01);//P30、P31用于串口
        Uart1_Init();
        RTC_config();
//        EA = 1;
       
        while(1)
        {
                if(B_1S)
                {
                                B_1S = 0;
                                printf("Year=20%bd ", YEAR);
                                printf("Month=%bd ", MONTH);
                                printf("Day=%bd ", DAY);
                                printf("Hour=%bd ", HOUR);
                                printf("Minute=%bd ", MIN);
                                printf("Second=%bd ", SEC);
                                printf("\r\n");
                }
               
                if(Rec_OK == 1)
                {
//                                // 禁用RTC以安全更新参数
//                                RTCCR = 0x00;   //RTC关闭
//                                YEAR = rtctime;   //Y:2021            //单片机内部rtc时钟初始化的办法
//                                MONTH = rtctime;    //M:12
//                                DAY = rtctime;      //D:31
//                                HOUR = rtctime;   //H:23
//                                MIN =rtctime;      //M:59
//                                SEC = rtctime;      //S:50
//                                SSEC = rtctime;      //S/128:0
//                                RTCCR = 0x01;   //RTC使能
                               
                                Rec_OK = 0;
                                printf("%02d%02dyear %dmon %dday\t",(int)rtctime,(int)rtctime,(int)rtctime,(int)rtctime);
                                printf("%d:%d:%d.%d\t",(int)rtctime,(int)rtctime,(int)rtctime,(int)((u16)(rtctime*256)|(u8)rtctime));
                                printf("%d\r\n",(int)rtctime);
                }
        }
       
}


void UART1_int (void) interrupt 4
{
    u8 dat;
    if(RI)
    {
      RI = 0;
      dat = SBUF;
//      RX1_Buffer = SBUF;
//      if(++RX1_Cnt >= UART1_BUF_LENGTH)   RX1_Cnt = 0;
//-------------------------------串口RTC对时 -------------------------------   
      if( length>0 )
      {   
            rtctime=dat;
            length++;
            if( length>=12 )
            {
                length = 0;
                Rec_OK = 1;
                indexrtc=0;
            }
      }      
      if (dat == STCRTC[ indexrtc])
      {
            indexrtc++;
            if(STCRTC == '\0')
            {
                length = 1;   //开启接收
                indexrtc=0;
            }
      }
      else
      {
            indexrtc = 0;
            if (dat ==STCRTC[ indexrtc])
                indexrtc++;
      }         
    }

    if(TI)
    {
      TI = 0;
      B_TX1_Busy = 0;
    }
}


void RTC_ISR_Handler (void) interrupt 13//RTC_VECTOR
{
        // TODO: 在此处添加用户代码
        if(RTCIF & 0x80)    //闹钟中断
        {
                P01 = !P01;
                RTCIF &= ~0x80;
                B_Alarm = 1;
        }

        if(RTCIF & 0x08)    //秒中断
        {
                P00 = !P00;
                RTCIF &= ~0x08;
                B_1S = 1;
        }
}


ccczzh 发表于 2025-8-6 15:30:38

目前使用的晶振为晶振链接

DebugLab 发表于 2025-8-6 16:27:09

ccczzh 发表于 2025-8-6 15:29
还是不行,无法起振。目前程序:
测试正常的程序:
基于以下串口程序:
https://www.stcaimcu.com/thread-16321-1-1.html
串口对时,命令头01 0B

#include <AI8H.H>
#include <intrins.h>
#include <absacc.h>
#include <string.h>
#include <stdarg.h>
#include <stdio.h>
#include <math.h>

#define                FOSC                        24000000UL                                        //主时钟
#define                BAUD                        9600UL                                                //波特率
#define                TMRF                        200UL                                                //定时器频率
#define                BRT                              (0x10000-(FOSC/BAUD+2)/4)      //波特率发生器值
#define                TMR                              (0x10000-FOSC/TMRF/12)                //定时器值
#define                T_Buf_Len                64                                                      //Uart1发送缓存长度
#define                R_Buf_Len                64                                                      //Uart1接收缓存长度

unsigned char                RP;                                        //Uart1接收指针
unsigned char                TP;                                        //Uart1发送指针
unsigned char                Uart_R_Len;                        //Uart1接收长度
unsigned char                Uart_T_Len;                        //Uart1发送长度
unsigned char xdata      R_Buf;      //Uart1接收缓存
unsigned char xdata      T_Buf;      //Uart1发送缓存

bit RTC_1s_Flag;

void Delay_ms(unsigned char ms)
{
      unsigned int i;
      do
      {
                i=FOSC/10000;
                while(--i);      //10T per loop
      }
      while(--ms);
}

void UART_Send(unsigned int x)
{
      while(Uart_T_Len);
      TP=0;
      Uart_T_Len=x;
      TI=1;
}

void Uart_Printf(unsigned char *v,...)
{
      va_list ap;
      va_start(ap,v);
      while(Uart_T_Len);
      UART_Send(vsprintf(T_Buf,v,ap));
      va_end(ap);
}
void Init(void)
{
      P_SW2|=EAXFR;
      
      P0M1=0x00;      P0M0=0x00;      //设置IO模式
      P1M1=0xC0;      P1M0=0x00;      //设置IO模式
      P2M1=0x00;      P2M0=0x00;      //设置IO模式
      P3M1=0x00;      P3M0=0x00;      //设置IO模式
      P4M1=0x00;      P4M0=0x00;      //设置IO模式
      P5M1=0x00;      P5M0=0x00;      //设置IO模式
      P6M1=0x00;      P6M0=0x00;      //设置IO模式
      P7M1=0x00;      P7M0=0x00;      //设置IO模式
      
      X32KCR=0x80;                        //启动外部32.768KHz晶振
      while(!(X32KCR&0x01));      //等待外部32.768KHz晶振稳定
      RTCCFG=0x00;                        //RTC选择外部32.768KHz时钟源
      
      AUXR=0x05;                //设置定时器0时钟为12T模式,设置定时器2为1T模式,设置定时器2为波特率发生器
      TMOD=0x01;                //设置定时器0为16位不自动重装载模式
      TH0=TMR>>8;                //设置定时器0初始值
      TL0=TMR;                //设置定时器0初始值
      TF0=0;                        //清除TF0中断标志位
      ET0=1;                        //启用定时器0中断
      
      SCON=0x50;                //设置UART1模式为8位数据可变波特率
      T2H=BRT>>8;                //设置UART1波特率
      T2L=BRT;                //设置UART1波特率
      AUXR|=T2R;                //打开定时器2
      ES=1;                        //启用UART1中断
      
      INIYEAR                =25;      //初始化年
      INIMONTH      =1;                //初始化月
      INIDAY                =1;                //初始化日
      INIHOUR                =0;                //初始化时
      INIMIN                =0;                //初始化分
      INISEC                =0;                //初始化秒
      INISSEC                =0;                //初始化1/128秒
      INIWEEK                =3;                //初始化星期
      
      RTCCFG|=0x01;                //初始化RTC
      
      RTCIF=0x00;                //清除RTC中断标志
      RTCIEN=0x08;      //启用RTC秒中断
      RTCCR=0x01;                //打开RTC
      
      EA=1;                        //启用总中断
}

void main(void)
{
      Init();
      while(1)
      {
                if(RTC_1s_Flag)
                {
                        RTC_1s_Flag=0;
                        Uart_Printf("\r\n\r\n20%02bu/%02bu/%02bu 星期%bu %02bu:%02bu:%02bu\r\n",RTCYEAR,RTCMONTH,RTCDAY,RTCWEEK,RTCHOUR,RTCMIN,RTCSEC);
                }
               
                Delay_ms(250);
                Delay_ms(250);
      }
}

void Uart_Start(void)
{
      TH0=TMR>>8;
      TL0=TMR;
      TR0=1;
}

void Uart_Stop(void)
{
      TR0=0;
      TH0=TMR>>8;
      TL0=TMR;
      RP=0;
      memset(R_Buf,0x00,sizeof R_Buf);
}

void TMR0_Isr(void) interrupt TMR0_VECTOR
{
      Uart_Stop();
}

void UART1_Isr(void) interrupt UART1_VECTOR
{
      if(RI)
      {
                RI=0;
                Uart_Start();
                R_Buf=SBUF;
                if(RP==0)
                {
                        if(R_Buf==0x01)
                        {
                              
                        }
                        else
                        {
                              Uart_Stop();
                        }
                }
                else if(RP==1)
                {
                        if(R_Buf==0x0B)
                        {
                              Uart_R_Len=R_Buf+2;
                        }
                        else
                        {
                              Uart_Stop();
                        }
                }
                else if(RP==Uart_R_Len-1)
                {
                        INIYEAR=      R_Buf;      //初始化年
                        INIMONTH=      R_Buf;      //初始化月
                        INIDAY=                R_Buf;      //初始化日
                        INIHOUR=      R_Buf;      //初始化时
                        INIMIN=                R_Buf;      //初始化分
                        INISEC=                R_Buf;      //初始化秒
                        INISSEC=      0;                        //初始化1/128秒
                        INIWEEK=      R_Buf;      //初始化星期
                        RTCCFG|=0x01;                        //初始化RTC
                        Uart_Stop();
                }
                else if(RP==R_Buf_Len-1)
                {
                        Uart_Stop();
                }
                if(TR0)
                {
                        RP++;
                }
      }
      if(TI)
      {
                TI=0;
                if(TP==Uart_T_Len)
                {
                        TP=0;
                        Uart_T_Len=0;
                }
                if(Uart_T_Len!=0)
                {
                        SBUF=(T_Buf);
                        TP++;
                }
      }
}

void RTC_Isr(void) interrupt RTC_VECTOR
{
//      if(RTCIF&0x80)      //闹钟中断
//      {
//                RTCIF&=~0x80;
//      }
//      if(RTCIF&0x40)      //日中断
//      {
//                RTCIF&=~0x40;
//      }
//      if(RTCIF&0x20)      //时中断
//      {
//                RTCIF&=~0x20;
//      }
//      if(RTCIF&0x10)      //分中断
//      {
//                RTCIF&=~0x10;
//      }
      if(RTCIF&0x08)      //秒中断
      {
                RTCIF&=~0x08;
                RTC_1s_Flag=1;
      }
//      if(RTCIF&0x04)      //1/2秒中断
//      {
//                RTCIF&=~0x04;
//      }
//      if(RTCIF&0x02)      //1/8秒中断
//      {
//                RTCIF&=~0x02;
//      }
//      if(RTCIF&0x01)      //1/32秒中断
//      {
//                RTCIF&=~0x01;
//      }
}


ccczzh 发表于 2025-8-6 16:50:49

DebugLab 发表于 2025-8-6 16:27
测试正常的程序:
基于以下串口程序:
https://www.stcaimcu.com/thread-16321-1-1.html


我测试还是不行,应该是我硬件选型和设计的问题,晶振有推荐的吗?

DebugLab 发表于 2025-8-6 17:25:19

ccczzh 发表于 2025-8-6 16:50
我测试还是不行,应该是我硬件选型和设计的问题,晶振有推荐的吗?

2*6mm直插:X206032768KGB2SC
3215贴片:XKXGI-SUA-32.768K
1610贴片:X161032768KGD2SI
页: [1] 2
查看完整版本: RTC使用外部晶振的问题 | 已解决