手册信息齐备。STC32G12K128 有两条设置内部 24MHz 的正规途径,我会都说明清楚。
前提说明:内部 24MHz 从哪里来
手册有两个关键结论:
- "STC32G系列单片机内部……在用户使用ISP下载软件进行下载时,ISP下载软件会根据用户所选择/设置的频率自动进行调整",且"对于一般用户,内部IRC频率的调整可以不用关心,因为频率调整工作在进行ISP下载时已经自动完成了"。→ 最简单:下载时把 IRC 频率选 24MHz。
- 若要在程序里自行切到 24MHz,手册"如何在用户程序中设置程序运行时的工作频率"给出了标准算法,使用 CHIPID12(T24M_ADDR,即 24MHz 校准值)、VRTRIM = VRT27M_ADDR、IRCBAND 选 27MHz 频段(因为 24MHz 落在 27MHz 频段 ±27% 范围内)。
程序一即按手册原算法编写。
程序一:内部高速 IRC,24MHz(程序内自行设定)
/*------------------------------------------------------------------
STC32G12K128 —— 使用内部高速高精度 IRC,系统工作频率 24MHz
------------------------------------------------------------------
使用说明(必读):
1. 本程序在代码中主动把内部 IRC 设为 24MHz,使用手册
"如何在用户程序中设置程序运行时的工作频率"中的标准做法:
IRTRIM 取 CHIPID12(24MHz 校准值),VRTRIM 取 VRT27M_ADDR,
IRCBAND 选择 27MHz 频段(24MHz 位于该频段内)。
2. 若你只想用"下载时选的频率",可把下载时的 IRC 频率设为 24MHz,
然后删掉本程序中标有【频率设定】的两行,效果相同。两种方式不要混用。
3. 编译环境:Keil C251,头文件使用 stc32g.h。
4. 观察现象:P2.0 接 LED,约 1Hz 闪烁。
------------------------------------------------------------------*/
#include "stc32g.h"
#include "intrins.h"
#define T24M_ADDR CHIPID12 /* 24MHz 的 IRTRIM 校准值 */
#define VRT27M_ADDR CHIPID23 /* VRTRIM_27M 校准值 */
/* 软件延时:约 ms 毫秒,基于 24MHz 主频 */
void Delay_ms(unsigned int ms)
{
unsigned int i;
unsigned char j;
for (i = 0; i < ms; i++)
{
for (j = 0; j < 200; j++)
{
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
}
}
}
void main(void)
{
EAXFR = 1; /* 使能访问 XFR,没有冲突不用关闭 */
CKCON = 0x00; /* 设置外部数据总线速度为最快 */
WTST = 0x00; /* 设置程序代码等待参数,赋值为0可将CPU执行程序的速度设置为最快 */
P0M0 = 0x00; P0M1 = 0x00;
P1M0 = 0x00; P1M1 = 0x00;
P2M0 = 0x00; P2M1 = 0x00;
P3M0 = 0x00; P3M1 = 0x00;
P4M0 = 0x00; P4M1 = 0x00;
P5M0 = 0x00; P5M1 = 0x00;
/*----【频率设定】把内部 IRC 设为 24MHz ----*/
CLKDIV = 0x04; /* 改频前先分频,避免高频运行不稳 */
IRTRIM = T24M_ADDR; /* 24MHz 的 IRTRIM 校准值 */
VRTRIM = VRT27M_ADDR; /* 使用 27MHz 频段对应的 VRTRIM 校准值 */
IRCBAND &= ~0x03; /* IRCBAND[1:0] 先清零 */
IRCBAND |= 0x02; /* IRCBAND[1:0]=10:选择 27MHz 频段 */
CLKDIV = 0x00; /* 频率设定完成后取消分频 */
/*----使能内部高速 IRC 并等待稳定----*/
HIRCCR = 0x80; /* ENHIRC(B7)=1,启动内部高速IRC */
while (!(HIRCCR & 0x01));/* 等待 HIRCST(B0)=1,时钟稳定 */
CLKDIV = 0x00; /* 时钟不分频 */
CLKSEL = 0x00; /* MCK2SEL[1:0]=00 -> MCKSEL[1:0]=00:主时钟=内部高精度IRC */
while (1)
{
P20 = 0; /* LED 亮 */
Delay_ms(500);
P20 = 1; /* LED 灭 */
Delay_ms(500);
}
}
寄存器位对应(依据手册"系统时钟选择寄存器(CLKSEL)"、"内部高速高精度IRC控制寄存器(HIRCCR)"、"IRC频段选择寄存器(IRCBAND)"):
CLKSEL(7EFE00H):B3、B2 = MCK2SEL[1:0],B1、B0 = MCKSEL[1:0]。0x00 → MCK2SEL=00(选择 MCKSEL 指定的时钟源)、MCKSEL=00(内部高精度 IRC)。
HIRCCR(7EFE02H):B7 = ENHIRC,B0 = HIRCST(只读)。0x80 使能,& 0x01 查稳定。
IRCBAND:B1、B0 = SEL[1:0]。&= ~0x03 后 |= 0x02 → SEL[1:0]=10 → 27MHz 频段(24MHz 在该频段 ±27% 范围内)。
程序二:外部 24MHz 晶振
/*------------------------------------------------------------------
STC32G12K128 —— 使用外部 24MHz 晶振作为系统时钟
------------------------------------------------------------------
使用说明(必读):
1. 硬件:24MHz 晶体接在 XTALI(P1.7) 与 XTALO(P1.6) 之间,
两个引脚各对地接负载电容(典型 10~30pF,按晶振规格书);
2. XITYPE 必须为 1(外部时钟源为晶体振荡器,接 XTALI+XTALO);
3. STC32G12K128 的 XOSCCR 位序:
B7 ENXOSC, B6 XITYPE, B5 GAIN, B3~B2 XCFILTER[1:0], B0 XOSCST
24MHz 属于"24M 及以下",XCFILTER[1:0] 置 01,因此写 0xE4;
4. 必须先等 XOSCST=1 再切 CLKSEL,顺序不可颠倒;
5. 编译环境:Keil C251,头文件 stc32g.h;
6. 若晶振不起振,程序停在 while(!(XOSCCR & 0x01)) 处,便于定位硬件问题。
------------------------------------------------------------------*/
#include "stc32g.h"
#include "intrins.h"
/* 软件延时:约 ms 毫秒,基于 24MHz 主频 */
void Delay_ms(unsigned int ms)
{
unsigned int i;
unsigned char j;
for (i = 0; i < ms; i++)
{
for (j = 0; j < 200; j++)
{
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
}
}
}
void main(void)
{
EAXFR = 1; /* 使能访问 XFR,没有冲突不用关闭 */
CKCON = 0x00; /* 设置外部数据总线速度为最快 */
WTST = 0x00; /* 程序代码等待参数设为0,CPU执行最快 */
P0M0 = 0x00; P0M1 = 0x00;
P1M0 = 0x00; P1M1 = 0x00;
P2M0 = 0x00; P2M1 = 0x00;
P3M0 = 0x00; P3M1 = 0x00;
P4M0 = 0x00; P4M1 = 0x00;
P5M0 = 0x00; P5M1 = 0x00;
/* 启动外部晶振:ENXOSC=1, XITYPE=1(晶振), GAIN=1(高增益),
XCFILTER[1:0]=01(24M及以下) -> B7B6B5 B3B2 = 1110 0100b = 0xE4 */
XOSCCR = 0xE4;
while (!(XOSCCR & 0x01)); /* 等待 XOSCST(B0)=1,外部晶振频率稳定 */
CLKDIV = 0x00; /* 时钟不分频 */
CLKSEL = 0x01; /* MCK2SEL[1:0]=00, MCKSEL[1:0]=01:主时钟=外部高速晶振 */
while (1)
{
P20 = 0; /* LED 亮 */
Delay_ms(500);
P20 = 1; /* LED 灭 */
Delay_ms(500);
}
}
XOSCCR 位对应(依据手册"外部振荡器控制寄存器(XOSCCR),外部晶振抗干扰"):
| 位 |
B7 |
B6 |
B5 |
B4 |
B3 |
B2 |
B1 |
B0 |
| XOSCCR |
ENXOSC |
XITYPE |
GAIN |
- |
XCFILTER[1] |
XCFILTER[0] |
- |
XOSCST |
写 0xE4 = 1110 0100b:ENXOSC=1、XITYPE=1、GAIN=1、XCFILTER[1:0]=01、B1/B0 写 0;读回时 B0 由硬件置为 XOSCST。
关于手册范例中 XOSCCR = 0xc0 的说明
手册"选择外部高速晶振(XOSC)作为系统时钟源"范例写的是 XOSCCR = 0xc0,即 1100 0000b:ENXOSC=1、XITYPE=1、GAIN=0(低增益)、XCFILTER[1:0]=00。这组值对 24MHz **仍可工作**(XCFILTER=00 适用于 48M 及以下),只是抗干扰滤波档位偏宽、增量为低增益。我上面给的 0xE4 是在不改变"能起振"这一基本事实的前提下,加了"24M 及以下"滤波档与高增益。若你的板子已在用 0xC0 且稳定运行,**没有必要改成 0xE4**。
两种方案对比
| 项目 |
内部 IRC 24MHz |
外部 24MHz 晶振 |
| 主时钟 |
MCK2SEL[1:0]=00, MCKSEL[1:0]=00 |
MCK2SEL[1:0]=00, MCKSEL[1:0]=01 |
| 频率来源 |
CHIPID12 校准值 + IRCBAND=27M 频段 |
晶振本体 |
| 需等待稳定标志 |
HIRCST(HIRCCR.B0) |
XOSCST(XOSCCR.B0) |
| 硬件需求 |
无 |
晶体 + 2 个负载电容 |
| 精度 |
±0.3% 以内(下载校准后),温漂可达 -1.35%~1.30% |
取决于晶振规格 |
以上寄存器地址、位定义与配置顺序均依照《STC32G-20261023》第 7 章"时钟管理,芯片上电工作过程,外部晶振抗干扰"及第 10 章"第三方对STC32系列ISP下载程序范例及用户程序如何选择内部时钟频率"中的原文与范例程序给出。
如需把 Delay_ms 改为定时器精确定时,或需要在运行时用按键在内部 IRC 与外部晶振之间动态切换(切换时需重新设 CLKDIV),告诉我是否需要保留串口,我再给对应代码。
🔍 搜索 "STC32G12K128 内部高速IRC 24MHz 时钟配置 程序"
📌 相关论坛讨论
- 梁工,关于几个例子程序主时钟问题
- 请教大家keil 项目中的频率与STC-ISP中用户程序运行时的IRC频率的关系
- 关于32G12K128芯片外部晶振选择问题 | 串口通信,建议用STC高稳定的内部时钟
⏱️ 查找用时 7.3s | 总回答用时 20.4s