从STC15开始, 宏晶就在内置RC震荡源(内置时脉, 宏晶称之为IRC)这条路上越走越远. STC15这一代仅仅是"有", 精度和漂移差强人意. 从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: 0x1FE9
VER1 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: 04A9 MCUID: F7 A4 C4 0D 11 E0 EE
Current VRTRIM:20, IRTRIM:A3, LIRTRIM:03

STC8H 时钟

STC8H要区分两个不同的系列

STC8H1K

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

ADDR: 0x1FE9
VER1 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: 04AA MCUID: 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: 0x7FE7
VER1 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: 04A3 MCUID: F7 4A C5 26 03 11 22
Current IRCBAND:03, VRTRIM:19, IRTRIM:2D, LIRTRIM:00

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

STC8A8K64D4 时钟

STC8A8K64D4上的内置时脉增加到了4个频段: 6M, 10M, 27M, 44M, 这个型号似乎更像是 STC8H3K 的增强版. 对应的标定也增加了这些频段

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

总结

记录一下避免其他人踩坑, 因为这个在网上基本上查不到深入点的资料, 并且同系列(STC8H1K和STC8H3K, STC8A8K64S4和STC8A8K64D4)之间差异那么大, 不搞清楚会误事.

对于在Linux下开发的, 建议还是要在Windows下通过STC-ISP烧录一次, 得到芯片的预设标定值, 这样以后可以直接在代码里赋值设置频率.

读取各预设值的代码

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");
}
}

最新文章

  1. mybatis 加载配置文件的两种方式
  2. VS2015中快捷注释代码块
  3. bzoj4025
  4. jquery datatable隐藏字段获取
  5. HDFS入门详解
  6. 关于开源框架GPUImage 的简单说明
  7. 10.7 noip模拟试题
  8. 解决UITableView中Cell重用机制导致内容出错的方法总结
  9. Qt的目录依赖问题----怎样生成一个绿色的Qt软件包
  10. js-学习方法之3
  11. 关于js模拟c#的Delegate(委托)实现
  12. 让C++控制台程序停下来,实现暂停功能
  13. [HOJ2634] How to earn more 最大权闭合子图
  14. C# 与Sql server 获取数据和执行命令
  15. 【Spring】23、ApplicationContext ,ApplicationContextAware,Listener,Event 的关系解读
  16. Visual Studio快速调出异常设置
  17. windows server r2 安装vs2017 更新补丁Windows8.1-KB2919355-x6
  18. .37-浅析webpack源码之事件流make(4)
  19. 自己写的一个jQuery分页插件
  20. 下拉刷新对象RefreshObject

热门文章

  1. C#数据库连接方式【简版】
  2. 在idea的java开发中字符串length()方法获取长度与赋值不符的问题
  3. day11 四层负载均衡和http协议
  4. Java SSLSocket
  5. innodb和myisam对比及索引原理区别
  6. What happens when more restrictive access is given to a derived class method in C++?
  7. 如何用shell脚本分析网站日志统计PV、404、500等数据
  8. 为什么企业全面云化需要IT战略支撑和驱动?
  9. Netty 编解码奥秘
  10. 一种基于Java Swing/HTML/MySQL的汽车租赁系统