从STC10/STC11系列开始出现内置RC震荡源(内置时脉, 宏晶称之为IRC). 最初的三代STC10/STC11/STC12, 在手册上的介绍都是"由于使用内部时钟源误差较大, … 有串行通信的情况下不建议使用内部R/C时钟源". 到STC15这一代之后, 精度提升明显, 开始出现了默认不使用外置晶振的MCU型号. 从STC8开始对IRC进行了更多的改进, 从STC8A/8F的一个频段, 到STC8G/STC8H的两个频段, 到STC8A8K64D4的4个频段, 从CODE预置, 到XDATA只读预置, 可用性也在不断提升.

这里说一下STC8系列的IRC设置.

STC8A/STC8F的内部时钟机制

只有一个IRC频段, 频率范围在16-27MHz, 通过两个寄存器调节内部时脉RTRIM, LIRTIM, 通过 CLKDIV 分频后作为系统时钟SYSCLK

细节

  • STC-ISP写入时对时钟校准, 除了会改IRTRIM的预设值, 还可能会修改CLKDIV(时钟分频系数)的预设值
  • STC-ISP中预设的频率, 18MHz-27MHz是不进行分频的(CLKDIV为0), 再往下更小的频率就会开始改CLKDIV了
  • 代码中使用预设值对IRTRIM赋值, 加上设置CLKDIV=0, 可以将时钟切换到这两个频率
    • 因为环境和老化等因素, 出厂时标定的值产生的频率会产生漂移, 如果重新标定可能会在这个值的±2附近, 预设值用作于UART之类的通信是足够了
  • 芯片上内置出厂时标定的22.1184MHz和24MHz频率对应的IRTRIM值, 可以从FLASH和RAM中读取, 但是这仅限于使用STC-ISP烧录并且勾选了对应选项的情况
  • FLASH部分的预设值: 22.1184MHz和24MHz地址分别是0xFDF4和0xFDF3, 这些地址位于code, 通过*(char code *)0xfdf3这样的形式访问
    • 在STC-ISP每次写入时(注意, 是每次), 必须勾选"在程序区结束处添加重要测试参数"才会往这部分地址写入, 否则这部分地址的值全为0xFF
  • RAM部分的预设值: 22.1184MHz和24MHz地址分别是0xFA和0xFB, 这些地址位于idata, 通过*(unsigned char idata *)0xFB这样的形式访问
    • 这两个值与其它因素无关, 上电即可读取, 相对于FLASH这个预设值更加可靠, 但是仅限于通过STC-ISP刷写的程序, 通过stcgal写入的程序, 这两个地址的数值为0

Linux环境下对IRTRIM, LIRTIM的标定

如果在Linux下开发, 不能使用STC-ISP, 则上述的方式都无效, 要通过辅助手段标定

  • 方式一: 通过程序给ITRIM和L遍历整个[0,255]区间确定中心点得到粗略的IRTRIM值
  • 方式二: 上设备, 示波器或者逻辑分析仪都行

实现思路

  • 预设系统时钟为22.1184MHz, UART波特率为115200
  • 代码中根据上面的条件, 初始化串口和定时器
  • 按IRTRIM从[0, 255], LIRTIM从[0,3]循环, UART输出一个固定的字符串
  • 当系统实际时钟接近 22.1184MHz时, 接收端才能看到正确的字符, 其它时候看到的都是乱码
    • 取接收正常的部分的中心点, 用作22.1184MHz的IRTRIM和LIRTRIM值
  • 如果用示波器或者逻辑分析仪, 可以做时钟10分频或20分频的输出, 在过程中观察波形宽度, 记下输出最接近的宽度时的IRTRIM和LIRTRIM.

STC8G 时钟

STC8G的内置振荡源频段有两个: 20MHz和33MHz, 可以从20MHz覆盖到36.864MHz,

因为存在多个频段, 多了两个寄存器用于频段的切换

  • IRCBAND: 用于选择频段
  • VRTRIM: 用于设置对应频段的电压

在设置频率时, 会涉及到这4个寄存器 IRCBAND, VRTRIM, IRTRIM, LIRTRIM, 都会对频率有影响, 调节程度从左到右递减

一个例子

ADDR: 0x1FE9VER1     VER2
VRTRIM 35M      40M:      20
VRTRIM 20M      24M:      1F
ITRIM  ---      48M:      FF
ITRIM  ---      44.2368M: D0
ITRIM 36.864M   40M:      A3
ITRIM 35M       36.864M:  88
ITRIM 33.1776M  35M:      6F
ITRIM 30M       33.1776M: 43
ITRIM 27M       30M:      1A
ITRIM 20M       27M:      63
ITRIM 24M       24M:      BA
ITRIM 22.1184M  22.1184M: 90
32kHz PD FreQ:            8DCC
1.19Vref:                 04A9MCUID: F7 A4 C4 0D 11 E0 EE
Current VRTRIM:20, IRTRIM:A3, LIRTRIM:03

STC8H 时钟

STC8H要区分两个不同的系列

STC8H1K

内置振荡源频段有两个, 20MHz和35MHz, STC-ISP预设的数值, 右边一列是芯片实测数据

ADDR: 0x1FE9VER1     VER2
VRTRIM 35M      40M:      1F
VRTRIM 20M      24M:      1E
ITRIM  ---      48M:      FF
ITRIM  ---      44.2368M: E4
ITRIM 36.864M   40M:      B5
ITRIM 35M       36.864M:  9A
ITRIM 33.1776M  35M:      7E
ITRIM 30M       33.1776M: 51
ITRIM 27M       30M:      26
ITRIM 20M       27M:      73
ITRIM 24M       24M:      D0
ITRIM 22.1184M  22.1184M: A4
32kHz PD FreQ:            8A48
1.19Vref:                 04AAMCUID: F7 34 C5 68 00 11 22
Current VRTRIM:1F, IRTRIM:B7, LIRTRIM:03

STC8H3K

这里是和手册不一致的地方, 对于STC8H3K32S2, F/W version: 7.4.1U, 实际上有4个频段, 也就是IRCBAND取值从 0x00 - 0x03, 24MHz和40MHz这两个属于0x02和0x03, 预设的寄存器要提前两个字节, 从0x7FE7开始读, 这样才是正确的, 研究这个问题耽误了半天时间. 手册不一致, 真是坑爹.

ADDR: 0x7FE7VER1     VER2
VRTRIM          40M:      19
VRTRIM          24M:      1C
VRTRIM 35M      ??M:      20
VRTRIM 20M      ??M:      1E
ITRIM  ---      45M:      7C
ITRIM  ---      40M:      47
ITRIM 36.864M:            2D
ITRIM 35M:                12
ITRIM 33.1776M:           FF
ITRIM 30M:                D2
ITRIM 27M:                98
ITRIM 20M:                1A
ITRIM 24M:                64
ITRIM 22.1184M:           41
32kHz PD FreQ:            8D04
1.19Vref:                 04A3MCUID: F7 4A C5 26 03 11 22
Current IRCBAND:03, VRTRIM:19, IRTRIM:2D, LIRTRIM:00

在设置时, 如果选择了高频段(35MHz或40MHz), ITRIM不能设置得太高, 如果设置得太高(超过0xE0), 会导致芯片无法启动

STC8A8K64D4 时钟

内置RC振荡的频段增加到了4个: 6M, 10M, 27M, 44M,

STC8A8K64D4是个比较特殊的型号, 你可以看成和STC8H8K功能一样, 只是引脚布局做成了和STC8A8K兼容的布局. 可以看成是为了让之前使用STC8A8K的客户能不改PCB升级的一个STC8H版本.

使用方式和4个IRC频段的STC8H一致, 也是通过IRCBAND, VRTRIM, IRTRIM, LIRTRIM这4个寄存器调节频率.

总结

记录一下避免其他人踩坑

同系列之间可能是跨系列产品

  • STC8H1K和STC8H3K
  • STC8A8K64S4和STC8A8K64D4

获取各频段预设值

对于在Linux下开发的, 建议还是要在Windows下通过STC-ISP烧录一次, 这样是最方便快捷的方式得到芯片的预设标定值.

调节CLKDIV需要一个较长的稳定期

如果在程序开始时调节了 CLKDIV, 至少需要等待 0x2FFFF 个时钟周期后再进行其它操作, 否则极容易导致后续的UART和Timer设置出现莫名其妙的错误, 这是今天排查了一整天才填的坑.

设置的代码

/*** STC8H Clock: *  MCKSEL                     ||===> MCLKODIV ==> MCLKO_S => P1.6/P5.4*  00 Internal IRC    |       ||*  01 External OSC    |==> CLKDIV ==> SYSCLK*  10 External 32KHz  |*  11 Internal 32KHz  |
*/#define SYS_SetFOSC(__IRCBAND__, __VRTRIM__, __IRTRIM__, __LIRTRIM__)  do {      \IRCBAND = ((__IRCBAND__) & 0x03);           \VRTRIM = (__VRTRIM__);                      \IRTRIM = (__IRTRIM__);                      \LIRTRIM = ((__LIRTRIM__) & 0x03);           \} while(0)/*** Change system clock* - invoke this in the beginning of code* - don't invoke this if the target frequency is already set by STC-ISP
*/
void SYS_SetClock(void)
{uint16_t i = 0; uint8_t j = 5;P_SW2 = 0x80;if (CLKDIV != (__CONF_CLKDIV)){CLKDIV = (__CONF_CLKDIV);do { // Wait a while after clock changed, or it may block the main processwhile (--i);} while (--j);}P_SW2 = 0x00;clkdiv = (__CONF_CLKDIV == 0)? 1 : __CONF_CLKDIV;SYS_SetFOSC(__CONF_IRCBAND, __CONF_VRTRIM, __CONF_IRTRIM, __CONF_LIRTRIM);while (--i); // Wait
}

读取各预设值的代码

INTERRUPT(tm0isr, 1)
{uint8_t i, j;counter++;if (counter == 1000){i = 0;counter = 0;UTIL_PrintString("ADDR: 0x");UTIL_PrintHex(__CID_ADDR >> 8);UTIL_PrintHex(__CID_ADDR & 0xFF);UTIL_PrintString("\r\n");UTIL_PrintString("       VER1     VER2\r\n");UTIL_PrintString("VRTRIM          40M:      ");UTIL_PrintHex(readCode(i++));UTIL_PrintString("\r\n");UTIL_PrintString("VRTRIM          24M:      ");UTIL_PrintHex(readCode(i++));UTIL_PrintString("\r\n");UTIL_PrintString("VRTRIM 35M      ??M:      ");UTIL_PrintHex(readCode(i++));UTIL_PrintString("\r\n");UTIL_PrintString("VRTRIM 20M      ??M:      ");UTIL_PrintHex(readCode(i++));UTIL_PrintString("\r\n");UTIL_PrintString("ITRIM  ---      45M:      ");UTIL_PrintHex(readCode(i++));UTIL_PrintString("\r\n");UTIL_PrintString("ITRIM  ---      40M:      ");UTIL_PrintHex(readCode(i++));UTIL_PrintString("\r\n");UTIL_PrintString("ITRIM 36.864M:            ");UTIL_PrintHex(readCode(i++));UTIL_PrintString("\r\n");UTIL_PrintString("ITRIM 35M:                ");UTIL_PrintHex(readCode(i++));UTIL_PrintString("\r\n");UTIL_PrintString("ITRIM 33.1776M:           ");UTIL_PrintHex(readCode(i++));UTIL_PrintString("\r\n");UTIL_PrintString("ITRIM 30M:                ");UTIL_PrintHex(readCode(i++));UTIL_PrintString("\r\n");UTIL_PrintString("ITRIM 27M:                ");UTIL_PrintHex(readCode(i++));UTIL_PrintString("\r\n");UTIL_PrintString("ITRIM 20M:                ");UTIL_PrintHex(readCode(i++));UTIL_PrintString("\r\n");UTIL_PrintString("ITRIM 24M:                ");UTIL_PrintHex(readCode(i++));UTIL_PrintString("\r\n");UTIL_PrintString("ITRIM 22.1184M:           ");UTIL_PrintHex(readCode(i++));UTIL_PrintString("\r\n");UTIL_PrintString("32kHz PD FreQ:            ");UTIL_PrintHex(readCode(i++));UTIL_PrintHex(readCode(i++));UTIL_PrintString("\r\n");UTIL_PrintString("1.19Vref:                 ");UTIL_PrintHex(readCode(i++));UTIL_PrintHex(readCode(i++));UTIL_PrintString("\r\n");UTIL_PrintString("\r\n");UTIL_PrintString("MCUID: ");for (j = 0; j < 7; j++){UTIL_PrintHex(readCode(i+j));UTIL_PrintChar(' ');}UTIL_PrintString("\r\n");UTIL_PrintString("Current IRCBAND:");UTIL_PrintHex(IRCBAND);UTIL_PrintString(", VRTRIM:");UTIL_PrintHex(VRTRIM);UTIL_PrintString(", IRTRIM:");UTIL_PrintHex(IRTRIM);UTIL_PrintString(", LIRTRIM:");UTIL_PrintHex(LIRTRIM);UTIL_PrintString("\r\n\r\n");}
}

STC8A,STC8G,STC8H系列的IRC内部振荡源频率调节相关推荐

  1. Neural Turing Machines-NTM系列(三)ntm-lasagne源码分析

    Neural Turing Machines-NTM系列(三)ntm-lasagne源码分析 在NTM系列文章(二)中,我们已经成功运行了一个ntm工程的源代码.在这一章中,将对它的源码实现进行分析. ...

  2. Trends in Neurosciences:通过脑振荡的夹带调节人类记忆

    在人类大脑中,与记忆相关的神经过程中会出现振荡.这已经被大量有关记忆过程与特定振荡信号的研究所证明.最近的几项研究已经超越了这些相关的方法,并提供了证据,表明通过特定频率的夹带调制振荡可以改变记忆功能 ...

  3. CentOS 搭建内部Yum源同步阿里Yum源

    背景: 有这样的需求,测试环境网段不能上网,但是测试环境centos安装软件包每一台都配置本地yum源很麻烦,也缺少第三方yum源,特此在内网搭建一台yum源服务器满足这一需求,同时防火墙层面只允许此 ...

  4. arcgis开发 多版本之间如何兼容_arcgis api 4.x for js 结合 react 入门开发系列初探篇(附源码下载)...

    你还在使用 JQuery 或者 Dojo 框架开发 arcgis api 4.x for js 吗?想试试模块化开发吗?随着前端技术的发展,arcgis api 4.x for js 也有了结合 re ...

  5. 【Faster R-CNN论文精度系列】从Faster R-CNN源码中,我们“学习”到了什么?

    [Faster R-CNN论文精度系列] (如下为建议阅读顺序) 1[Faster R-CNN论文精度系列]从Faster R-CNN源码中,我们"学习"到了什么? 2[Faste ...

  6. APM32F103 RTC内部时钟源报警中断例程测试

    APM32F103 RTC内部时钟源报警中断例程测试 ✨相关篇推荐<[开源电路]STM32F103VCT6开发板>

  7. APM32F103 RTC内部时钟源秒中断例程测试

    APM32F103 RTC内部时钟源秒中断例程测试 ✨相关篇推荐<[开源电路]STM32F103VCT6开发板>

  8. perp系列之二:perp源码README

    perp系列之二:perp源码README 版本说明 版本 作者 日期 备注 0.1 ZY 2019.5.29 初稿 目录 文章目录 perp系列之二:perp源码README 版本说明 目录 per ...

  9. 松下伺服电机与驱动器A6系列的modbus控制SDK源码

    松下伺服电机与驱动器A6系列的modbus控制SDK源码前段时间,有个非标的项目用到了两台松下伺服电机电机,伺服驱动器为MINAS-A6/A6L系列 ,一台用于控制行走轴的前进.后退,一台用于控制旋转 ...

最新文章

  1. NASA投资有远景技术,有望改变未来人类和机器人的勘探任务
  2. 成功解决AttributeError: module 'cv2.cv2' has no attribute 'CV_CAP_PROP_FPS'和 'CV_CAP_PROP_FRAME_WIDTH'
  3. 人工智能,人脸识别门禁下的校园考勤
  4. SaaS 模式云数据仓库 MaxCompute 数据安全最佳实践
  5. 小甲鱼python视频第八讲(课后习题)
  6. python云变量_Python之变量的创建过程
  7. (三)nodejs循序渐进-值传递和引用传递,深拷贝和浅拷贝(基础篇)
  8. 过拟合问题——正则化方法
  9. 开发者论坛一周精粹(第十七期) :【漏洞预警】Windows再被爆SMB服务0day漏洞,阿里云提示您关注并修复...
  10. 用C#打开文件对话框的方法和简单使用的程序
  11. pytorch 存取模型(待补充)
  12. 川大计算机复试公平吗,看清华、川大这波操作,你还会担心网络复试会不公平吗?...
  13. case结构条件语句
  14. python设计模式之工厂模式概述
  15. 用超级鹰来识别B站图片验证
  16. 华为手机一直android,华为手机内存不够用?这5个文件夹常清理,可以腾出近10个G内存...
  17. BizTalk Server : 提高 BizTalk 编程能力的 8 点技巧和窍门
  18. 统一社会信用代码校验规则
  19. [Unity]摘录笔记UnityShader(解读shader代码构成)
  20. kasp技术原理_SNP检测Massarray法怎么样?中高通量大样本适用吗?

热门文章

  1. 小旋风蜘蛛池V9.02源码
  2. 小傻蛋的妹妹跟随小甲鱼学习Python的第十二节012
  3. PyCharm配置远程解释器
  4. 深度学习之图像分类(六)--Inception进化史
  5. 初识湍流,诗情画意(湍流模型1)
  6. 提高影响力:职权+威信
  7. 125啦读书导航新版上线啦
  8. kali上的一些密码破解工具
  9. 深圳软件测试培训:java中数组的操作
  10. 深圳软件测试培训:刚入行的软件测试工程师如何自学软件测试?