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;
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)
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) {//频率自动校准完成 } }}
其实
1,直接用内部高速IRC-24MHz 给 CPU 跑;
2,IRC-24MHz / 2 = 12MHz 给 PLL时钟输入;
3,12MHz 的 PLL时钟输入 * 12 = 144MHz 时钟输出给 PWM;
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) { //频率自动校准完成 } }}
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:12 编辑
神农鼎 发表于 2023-10-2 14:18
1, 你节后申请 [免费+包邮送]的 STC8H1K08T-33I-TSSOP20
2, 你外部挂 32768晶振, 2个外挂电容 15pF
===用 ...
敬业啊,今天竟然还有人上班回复问题
您的意思是我用beta版可能有问题?
另外,我需要输出高精度的PWM频率信号,您说的校准的方式可能精度达不到我的要求,我不太想用。我还是想要外挂12M晶振的模式
等我试完正式版的 STC8H1K08T-33I,有什么结果再跟您反馈下
您的意思是我用beta版可能有问题?
===你用外部时钟,无问题
另外,我需要输出高精度的PWM频率信号,
您说的校准的方式可能精度达不到我的要求,我不太想用。我还是想要外挂12M晶振的模式
===无问题,12M * 8 = 96MHz 给 PWM做时钟输入
96MHz/4 = 24MHz 给CPU
外部 12MHz * 12 = 144MHz 给 PWM做时钟输入
144MHz/4 = 36MHz 给 CPU,
但 STC8H1K08T-33I-TSSOP20 是最高频率不要超过33.1776MHz 本帖最后由 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