firefly2k 发表于 2023-10-2 13:39:08

STC8H1K08T外部晶振和PLL144M问题

本帖最后由 firefly2k 于 2023-10-2 13:46 编辑

我使用的芯片是STC8H1K08T-Beta ( 固件版本号: 7.2.1U),使用外部晶振和PLL 144M有问题

使用内部IRC 24M(STC8H1K08T-Beta内部IRC不可调好像只能是24M),可以正常运行(uart和PWM时钟源都是用的内部24M)。我外接12M晶振,测量晶振已经起振,我下面代码想要实现主时钟24M,PLL 144M给PWM用。下面代码初始化后,uart波特率只有之前的1/6,PWM输出也只是之前的1/6(与144M的预期差的更远)。

我不知道是STC8H1K08T-Beta不支持还是我的软件初始化有问题,请指正
晶振初始化代码如下:

      P_SW2 = 0x80;
      XOSCCR = 0xC0;                //启动外部晶振
      while (!(XOSCCR & 1));      //等待时钟稳定
      CLKDIV = 3;                     //PLL/2/3=24M MCLK/3
      CLKSEL = 0xC5;                  //外部高速时钟,144M,PLL/2 CKMS=1;HSIOCK=1 MCK2SE=01 PLL/2;MCKSEL=01 外部晶振
      PLLCR      = 0x80;             //ENCKM=1 PLL;PCKI=00 12M
      HSCLKDIV = 0;



神农鼎 发表于 2023-10-2 14:18:21

1, 你节后申请 [免费+包邮送]的 STC8H1K08T-33I-TSSOP20
2, 你外部挂 32768晶振, 2个外挂电容 15pF
===用外部 32768 自动校准内部时钟到
      【11.0592MHz, 12MHz】
      【22.1184MHz, 24MHz】
      【30MHz, 33.1776MHz】



http://www.stcmcudata.com/STC8F-DATASHEET/STC8H.pdf




利用外部 32768 RTC 晶振时钟,自动校准内部高速IRC时钟,STC8H数据手册 内容 - 触摸按键/80mA大电流LED数码管自动刷新显示/段码LCD/RTC实时时钟/低功耗 - 国芯论坛-STC全球32位8051爱好者互助交流社区 - STC全球32位8051爱好者互助交流社区 (stcaimcu.com)


神农鼎 发表于 2023-10-2 14:24:39

7.2                  范例程序1.2.1                     自动校准内部高速IRC(HIRC)
例如:校准的目标频率为22.1184MHz,校准误差范围为±0.5%
则需要将CREHF设置为0,CRECNT设置为(16*22118400)/32768=10800(2A30H),
即将CRECNTH设置为2AH,CRECNTL设置为30H,CRERES设置为10800 * 0.5%=54(36H)

//测试工作频率为11.0592MHz#include "stc8h.h"//头文件见下载软件#define       CNT22M             (16 * 22118400L) / 32768)                     //校准目标频率为22.1184M#define       RES22M             (CNT22M *5 / 1000)                              //设置校准误差为0.5%void main(){         P_SW2 |= 0x80;//使能访问XFR         P0M0 = 0x00;         P0M1 = 0x00;         P1M0 = 0x00;         P1M1 = 0x00;         P2M0 = 0x00;         P2M1 = 0x00;         P3M0 = 0x00;         P3M1 = 0x00;         P4M0 = 0x00;         P4M1 = 0x00;         P5M0 = 0x00;         P5M1 = 0x00;X32KCR = 0xc0;                                                                           //启动外部32K晶振while (!(X32KCR & 1));                                                               //等待时钟稳定         IRCBAND &= ~0x03;         IRCBAND |= 0x02;                                                                      //选择27M频段         CLKSEL = 0x00;                                                                        //选择内部高速HIRC为系统时钟         CRECNTH = CNT22M >>8;                                                      //设置目标校准值         CRECNTL = CNT22M;         CRERES = RES22M;                                                                  //设置校准误差         CRECR = 0x90;                                                                            //使能CRE功能,并设置校准周期为4ms         while (1)         {                   if (CRECR& 0x01)                   {//频率自动校准完成                   }         }}

神农鼎 发表于 2023-10-2 14:29:15



其实
1,直接用内部高速IRC-24MHz 给 CPU 跑;
2,IRC-24MHz / 2 = 12MHz 给 PLL时钟输入;
3,12MHz 的 PLL时钟输入 * 12 = 144MHz 时钟输出给 PWM;


神农鼎 发表于 2023-10-2 14:35:13

7.2.1                     自动校准内部高速IRC(HIRC) 例如:校准的目标频率为22.1184MHz,校准误差范围为±0.5%
则需要将CREHF设置为0,CRECNT设置为(16*22118400)/32768=10800(2A30H),
即将CRECNTH设置为2AH,CRECNTL设置为30H,CRERES设置为10800 * 0.5%=54(36H)
//测试工作频率为11.0592MHz #include "stc8h.h"                                                                              //头文件见下载软件 #define       CNT22M             (16 * 22118400L) / 32768)                     //校准目标频率为22.1184M#define       RES22M             (CNT22M *5 / 1000)                              //设置校准误差为0.5% void main(){         P_SW2 |= 0x80;                                                                        //使能访问XFR          P0M0 = 0x00;         P0M1 = 0x00;         P1M0 = 0x00;         P1M1 = 0x00;         P2M0 = 0x00;         P2M1 = 0x00;         P3M0 = 0x00;         P3M1 = 0x00;         P4M0 = 0x00;         P4M1 = 0x00;         P5M0 = 0x00;         P5M1 = 0x00;          X32KCR = 0xc0;                                                                           //启动外部32K晶振         while (!(X32KCR & 1));                                                               //等待时钟稳定          IRCBAND &= ~0x03;         IRCBAND |= 0x02;                                                                      //选择27M频段         CLKSEL = 0x00;                                                                        //选择内部高速HIRC为系统时钟          CRECNTH = CNT22M >>8;                                                      //设置目标校准值         CRECNTL = CNT22M;         CRERES = RES22M;                                                                  //设置校准误差         CRECR = 0x90;                                                                            //使能CRE功能,并设置校准周期为4ms          while (1)         {                   if (CRECR& 0x01)                   {                                                                                                                //频率自动校准完成                   }         }}

神农鼎 发表于 2023-10-2 14:38:09

24.2.1                     使能高级PWM的高速模式(异步模式)
//测试工作频率为24MHz #include "stc8h.h"#include "intrins.h" #define       FOSC                           24000000UL #define       HSCK_MCLK             0#define       HSCK_PLL               1#define       HSCK_SEL               HSCK_PLL #define       PLL_96M                     0#define       PLL_144M                  1#define       PLL_SEL                     PLL_144M #define       CKMS                        0x80#define       HSIOCK                      0x40#define       MCK2SEL_MSK      0x0c#define       MCK2SEL_SEL1      0x00#define       MCK2SEL_PLLD2   0x04#define       MCK2SEL_PLLD4   0x08#define       MCKSEL_MSK          0x03#define       MCKSEL_HIRC         0x00#define       MCKSEL_XOSC      0x01#define       MCKSEL_X32K          0x02#define       MCKSEL_IRC32K   0x03 #define       ENCKM                      0x80#define       PCKI_MSK               0x60#define       PCKI_D1                     0x00#define       PCKI_D2                     0x20#define       PCKI_D3                     0x40#define       PCKI_D4                     0x60 void delay(){         int   i;                  for    (i=0; i<100; i++);} char ReadPWMA(char addr){         chardat;                  while(HSPWMA_ADR & 0x80);                                                //等待前一个异步读写完成         HSPWMA_ADR= addr | 0x80;                                                   //设置间接访问地址,只需要设置原XFR地址的低7位                                                                                                                //HSPWMA_ADR寄存器的最高位写1,表示读数据         while(HSPWMA_ADR & 0x80);                                                //等待当前异步读取完成         dat    = HSPWMA_DAT;                                                            //读取异步数据                  returndat;} void WritePWMA(char addr, chardat){         while(HSPWMA_ADR & 0x80);                                                //等待前一个异步读写完成         HSPWMA_DAT= dat;                                                               //准备需要写入的数据         HSPWMA_ADR= addr & 0x7f;                                                 //设置间接访问地址,只需要设置原XFR地址的低7位                                                                                                                //HSPWMA_ADR寄存器的最高位写0,表示写数据} void main(){         P_SW2|= 0x80;                                                                            //使能访问XFR                  //选择PLL输出时钟#if   (PLL_SEL == PLL_96M)         CLKSEL&= ~CKMS;                                                                  //选择PLL的96M作为PLL的输出时钟#elif (PLL_SEL == PLL_144M)         CLKSEL|= CKMS;                                                                      //选择PLL的144M作为PLL的输出时钟#else         CLKSEL&= ~CKMS;                                                                  //默认选择PLL的96M作为PLL的输出时钟#endif                  //选择PLL输入时钟分频,保证输入时钟为12M         PLLCR&= ~PCKI_MSK;#if   (FOSC == 12000000UL)         PLLCR|= PCKI_D1;                                                                   //PLL输入时钟1分频#elif (FOSC == 24000000UL)         PLLCR|= PCKI_D2;                                                                   //PLL输入时钟2分频#elif (FOSC == 36000000UL)         PLLCR|= PCKI_D3;                                                                   //PLL输入时钟3分频#elif (FOSC == 48000000UL)         PLLCR|= PCKI_D4;                                                                   //PLL输入时钟4分频#else         PLLCR|= PCKI_D1;                                                                   //默认PLL输入时钟1分频#endif          //启动PLL         PLLCR|= ENCKM;                                                                  //使能PLL倍频                  delay();                                                                                          //等待PLL锁频          //选择HSPWM/HSSPI时钟#if   (HSCK_SEL == HSCK_MCLK)         CLKSEL&= ~HSIOCK;                                                             //HSPWM/HSSPI选择主时钟为时钟源#elif (HSCK_SEL == HSCK_PLL)         CLKSEL|= HSIOCK;                                                                  //HSPWM/HSSPI选择PLL输出时钟为时钟源#else         CLKSEL&= ~HSIOCK;                                                             //默认HSPWM/HSSPI选择主时钟为时钟源#endif          HSCLKDIV= 0;                                                                            //HSPWM/HSSPI时钟源不分频                  HSPWMA_CFG= 0x03;                                                             //使能PWMA相关寄存器异步访问功能                  //通过异步方式设置PWMA的相关寄存器         WritePWMA((char)&PWMA_CCER1,0x00);         WritePWMA((char)&PWMA_CCMR1,0x00);                           //CC1为输出模式         WritePWMA((char)&PWMA_CCMR1,0x60);                           //OC1REF输出PWM1(CNT<CCR时输出有效电平1)         WritePWMA((char)&PWMA_CCER1,0x05);                           //使能CC1/CC1N上的输出功能         WritePWMA((char)&PWMA_ENO,0x03);                              //使能PWM信号输出到端口         WritePWMA((char)&PWMA_BKR,0x80);                              //使能主输出         WritePWMA((char)&PWMA_CCR1H,200 >> 8);                  //设置输出PWM的占空比         WritePWMA((char)&PWMA_CCR1L,200);         WritePWMA((char)&PWMA_ARRH,1000 >> 8);                  //设置输出PWM的周期         WritePWMA((char)&PWMA_ARRL,1000);         WritePWMA((char)&PWMA_DTR,10);                                    //设置互补对称输出PWM的死区         WritePWMA((char)&PWMA_CR1,0x01);                                 //开始PWM计数                  P2M0= 0;         P2M1= 0;         P3M0= 0;         P3M1= 0;                  P2= ReadPWMA((char)&PWMA_ARRH);                               //异步方式读取寄存器         P3= ReadPWMA((char)&PWMA_ARRL);                  while(1);}


firefly2k 发表于 2023-10-2 15:06:51

本帖最后由 firefly2k 于 2023-10-2 15:12 编辑

神农鼎 发表于 2023-10-2 14:18
1, 你节后申请 [免费+包邮送]的 STC8H1K08T-33I-TSSOP20
2, 你外部挂 32768晶振, 2个外挂电容 15pF
===用 ...
敬业啊,今天竟然还有人上班回复问题
您的意思是我用beta版可能有问题?
另外,我需要输出高精度的PWM频率信号,您说的校准的方式可能精度达不到我的要求,我不太想用。我还是想要外挂12M晶振的模式
等我试完正式版的 STC8H1K08T-33I,有什么结果再跟您反馈下

神农鼎 发表于 2023-10-2 15:25:44

您的意思是我用beta版可能有问题?
===你用外部时钟,无问题
另外,我需要输出高精度的PWM频率信号,
您说的校准的方式可能精度达不到我的要求,我不太想用。我还是想要外挂12M晶振的模式
===无问题,12M * 8 = 96MHz 给 PWM做时钟输入


96MHz/4 = 24MHz 给CPU


神农鼎 发表于 2023-10-2 15:29:06

外部 12MHz * 12 = 144MHz 给 PWM做时钟输入
144MHz/4 = 36MHz 给 CPU,
但 STC8H1K08T-33I-TSSOP20 是最高频率不要超过33.1776MHz

firefly2k 发表于 2023-10-2 15:31:36

本帖最后由 firefly2k 于 2023-10-2 15:33 编辑

神农鼎 发表于 2023-10-2 15:29
外部 12MHz * 12 = 144MHz 给 PWM做时钟输入
144MHz/4 = 36MHz 给 CPU,
但 STC8H1K08T-33I-TSSOP20 是最 ...
谢谢,我刚刚换上正式版的了,但还是一样的问题,原115200波特率,现在只有19200。可能还是寄存器配置问题,我再按您提供的例程仔细查查
页: [1] 2
查看完整版本: STC8H1K08T外部晶振和PLL144M问题