STC8A8K64S4A12内部时钟的IRTRIM和LIRTRIM简单标定
STC8A8K64S4A12因为没有固化的频率调节值, 要么在STC-ISP烧录时设置写入, 要么通过idata高地址读取, 这对于Linux下的SDCC用户就非常不方便, 既不能用STC-ISP, 写入SDCC编译后的程序也无法在idata区读取对应的值.
那么对于Linux下的SDCC用户, 如何去确定这个频率调节值? 一个办法是通过逻辑分析仪去标定, 但是如果没有逻辑分析仪呢? 如果对频率要求不严格的话, 可以直接通过代码输出串口数据去标定.
因为串口波特率与系统时钟是关联的, 假定当前系统时钟频率固定, 那么对应一个给定的波特率例如9600, 对应的寄存器值是固定的, 如果芯片按这个值运行, 只有当系统时钟频率与预设的值接近(误差5%内), 上位机才能解码出正确的输出, 其它情况看到的都是乱码. 根据这个特性, 如果在代码中不断调节频率, 同时输出当时的IRTRIM和LIRTRIM值, 根据乱码和正常接收的情况, 就能判断出对应此频率的IRTRIM和LIRTRIM值.
编译这个程序后写入STC8A8K64S4A12, 使用USB2TTL连接串口1, 波特率9600, 观察输出的字符串.
当实际频率接近预设的频率时, 能观察到正常的输出. 取非乱码区间的中间点对应的值, 就可以作为此频率对应的IRTRIM和LIRTRIM值.
代码已经添加了对应的宏处理, 兼容SDCC和Keil C51编译
/*****************************************************************************/
/**
* \file itrim_detect.c
* \brief 使用固定波特率串口输出标定STC8A8K64S4A12各频率的ITRIM
* \version v0.1
******************************************************************************/
/*****************************************************************************/
/**
* \brief 自适应SDCC和Keil C51的宏处理
******************************************************************************/
/** SDCC - Small Device C Compiler
* http://sdcc.sf.net
*/
#if defined (SDCC) || defined (__SDCC)
# define SBIT(name, addr, bit) __sbit __at(addr+bit) name
# define SFR(name, addr) __sfr __at(addr) name
# define SFRX(name, addr) __xdata volatile unsigned char __at(addr) name
#define NOP() __asm NOP __endasm
/** Keil C51
* http://www.keil.com
*/
#elif defined __CX51__
# define SBIT(name, addr, bit) sbit name = addr^bit
# define SFR(name, addr) sfr name = addr
# define SFRX(name, addr) volatile unsigned char xdata name _at_ addr
extern void _nop_ (void);
#define NOP() _nop_()
/** default
* unrecognized compiler
*/
#else
# warning unrecognized compiler
# define SBIT(name, addr, bit) volatile bool name
# define SFR(name, addr) volatile unsigned char name
# define SFRX(name, addr) volatile unsigned char name
#endif
/*****************************************************************************/
/**
* \brief 代码中涉及的寄存器
******************************************************************************/
SBIT(TI, 0x98, 1);
SFR(PCON, 0x87);
SFR(AUXR, 0x8E);
SFR(SCON, 0x98);
SFR(SBUF, 0x99);
SFR(LIRTRIM, 0x9E);
SFR(IRTRIM, 0x9F);
SFR(P_SW2, 0xBA);
SFR(T2H, 0xD6);
SFR(T2L, 0xD7);
SFRX(CLKDIV, 0xfe01);
SFRX(IRC24MCR, 0xfe02);
static const char hexTable[16] = { '0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
/*****************************************************************************/
/**
* \brief 时钟和串口1初始化
******************************************************************************/
void clock_init()
{
// [ BAH,0,0x00]: 外设端口切换控制寄存器2,串口2/3/4,I2C,比较器
P_SW2 = 0x80;
// [FE01H,1,0x00]: 时钟分频寄存器,ISP可能写入预设值
CLKDIV = 0x00;
// [ 9EH,0,0x00]: IRC频率微调寄存器, ISP可能写入预设值
LIRTRIM = 0x00;
// [ BAH,0,0x00]: 外设端口切换控制寄存器2,串口2/3/4,I2C,比较器
P_SW2 = 0x00;
// [ 87H,0,0x30]: 电源控制寄存器
PCON = 0xB0;
// [ 98H,0,0x00]: 串口1控制寄存器
SCON = 0x50;
// [ 8EH,0,0x01]: 辅助寄存器
AUXR = 0x15;
}
/*****************************************************************************/
/**
* \brief 不同频率对应的串口初始化程序
******************************************************************************/
void uart_init_18m_9600()
{
// [ D6H,0,0x00]: 定时器2高字节
T2H = 0xFE;
// [ D7H,0,0x00]: 定时器2低字节
T2L = 0x2B;
}
void uart_init_22m1184_9600()
{
// [ D6H,0,0x00]: 定时器2高字节
T2H = 0xFD;
// [ D7H,0,0x00]: 定时器2低字节
T2L = 0xC0;
}
void uart_init_24m_9600()
{
// [ D6H,0,0x00]: 定时器2高字节
T2H = 0xFD;
// [ D7H,0,0x00]: 定时器2低字节
T2L = 0x8F;
}
void uart_init_28m_9600()
{
// [ D6H,0,0x00]: 定时器2高字节
T2H = 0xFD;
// [ D7H,0,0x00]: 定时器2低字节
T2L = 0x26;
}
void uart_init_32m_9600()
{
// [ D6H,0,0x00]: 定时器2高字节
T2H = 0xFC;
// [ D7H,0,0x00]: 定时器2低字节
T2L = 0xBE;
}
void uart_init_33m1776_9600()
{
// [ D6H,0,0x00]: 定时器2高字节
T2H = 0xFC;
// [ D7H,0,0x00]: 定时器2低字节
T2L = 0xA0;
}
/*****************************************************************************/
/**
* \brief 通过修改IRTRIM和LIRTRIM调节内部时钟频率
******************************************************************************/
void trim_freq(unsigned char trim, unsigned char litrim)
{
IRTRIM = trim;
LIRTRIM = litrim;
while(!(IRC24MCR & 0x01));
}
void PrintChar(unsigned char dat)
{
SBUF = dat;
while(!TI);
TI = 0;
}
void PrintHex(unsigned char hex)
{
PrintChar(hexTable[hex >> 4]);
PrintChar(hexTable[hex & 0xF]);
}
void PrintString(unsigned char *str)
{
while (*str != '\0')
{
SBUF = *str;
while(!TI);
TI = 0; /* clear */
str++;
}
}
void Delay100ms()
{
unsigned char j, k;
j = 100;
k = 228;
do
{
while (--k);
} while (--j);
}
void DetectItrim(unsigned char *str)
{
unsigned char i, j;
do
{
j = 3;
do
{
trim_freq(i, j);
PrintHex(IRTRIM);
PrintChar(0x20);
PrintHex(LIRTRIM);
PrintChar(0x20);
PrintString(str);
Delay100ms();
} while (--j);
} while(--i);
}
void main()
{
clock_init();
while(1)
{
uart_init_18m_9600();
DetectItrim(" 18MHz 9600\r\n");
uart_init_22m1184_9600();
DetectItrim(" 22.1184MHz 9600\r\n");
uart_init_24m_9600();
DetectItrim(" 24MHz 9600\r\n");
uart_init_28m_9600();
DetectItrim(" 28MHz 9600\r\n");
uart_init_32m_9600();
DetectItrim(" 32MHz 9600\r\n");
uart_init_33m1776_9600();
DetectItrim(" 33.1776MHz 9600\r\n");
}
}
我手里的这块STC8A8K64S4实测结果是这样的
IRTRIM LIRTRIM FOSC BAUD
0E 02 18MHz
53 03 22.1184MHz
74 03 24MHz
F3 02 32MHz
FC 01 33.1776MHz
STC8A8K64S4A12内部时钟的IRTRIM和LIRTRIM简单标定的更多相关文章
- stm32 时钟配置——外部时钟倍频、内部时钟倍频 【worldsing笔记】
stm32可选的时钟源 在STM32中,可以用内部时钟,也可以用外部时钟,在要求进度高的应用场合最好用外部晶体震荡器,内部时钟存在一定的精度误差. 准确的来说有4个时钟源可以选分别是HSI.LSI.H ...
- STM32内部时钟设置-寄存器版
STM32寄存器版本——内部时钟设置 同时要记得把延时初始化函数设置好 //系统时钟初始化函数 //pll:选择的倍频数,从2开始,最大值为16 //pll:选择的倍频数,这里使用内部时钟,PLL为4 ...
- Oracle恢复ORA-00600: 内部错误代码, 参数: [kcratr_scan_lastbwr] 问题的简单解决
Oracle恢复ORA-00600: 内部错误代码, 参数: [kcratr_scan_lastbwr] 1. 简单处理 sqlplus / as sysdba startup mount recov ...
- 转:Linux内部的时钟处理机制全面剖析
Linux内部的时钟处理机制全面剖析 在 Linux 操作系统中,很多活动都和时间有关,例如:进程调度和网络处理等等.所以说,了解 Linux 操作系统中的时钟处理机制有助于更好地了解 Linux 操 ...
- 史上最简单的js+css3实现时钟效果
今天我看到百度搜索的时间那个效果不错,于是就产生了模仿一下的效果,不过为了节省时间,就随便布了下局,废话不多说,先看看效果吧,顺便把百度的效果也拿过来. 对比样子差了好多啊,但是基本功能都是实现了的, ...
- STM32F030 启用内部晶振并配置系统时钟为48M
在文件 system_stm32f0xx.c 里的函数 static void SetSysClock(void) { if (HSEStatus == (uint32_t)0x01) // 存在外部 ...
- STC8A,STC8G,STC8H系列的IRC内部振荡源频率调节
从STC15开始, 宏晶就在内置RC震荡源(内置时脉, 宏晶称之为IRC)这条路上越走越远. STC15这一代仅仅是"有", 精度和漂移差强人意. 从STC8开始对IRC的调节就越 ...
- C# ADO.NET编写简单的图书馆管理软件
使用软件: Microsoft SQL Server 2012 Microsoft Visual Studio 2012 本文地址: http://www.cnblogs.com/go2bed/ 参考 ...
- Cotex-M3内核STM32F10XX系列时钟及其配置方法
一.背景 最近做个项目,需要使用STM32,还是以前一样的观点,时钟就是MCU心脏,供血即时钟频率输出,想要弄明白一个MCU,时钟是一个非常好的切入点.言归正传,网上已经有太多大神详述过STM32的详 ...
- Linux驱动设计—— 中断与时钟
中断和时钟技术可以提升驱动程序的效率 中断 中断在Linux中的实现 通常情况下,一个驱动程序只需要申请中断,并添加中断处理函数就可以了,中断的到达和中断函数的调用都是内核实现框架完成的.所以程序员只 ...
随机推荐
- 0xGame 2023【WEEK1】Crypto全解
What's CBC? 题目信息 from Crypto.Util.number import * from secret import flag,key def bytes_xor(a,b): a, ...
- Shell-case-in-分支
- bcc的简单学习
bcc的简单学习 安装 # 安装部分依赖项目 yum install cmake llvm -y dnf install -y bison cmake ethtool flex git iperf3 ...
- [转帖]ESXi主机RAID卡_HBA卡_网卡 型号_固件_驱动查询
https://www.cnblogs.com/vincenshen/p/12332142.html 一.RAID卡/HBA卡 型号_固件_驱动查询 1. 查询所有SCSI设备列表 # esxcfg- ...
- [转帖]7.5 TiKV 磁盘空间占用与回收常见问题
https://book.tidb.io/session4/chapter7/compact.html TiKV 作为 TiDB 的存储节点,用户通过 SQL 导入或更改的所有数据都存储在 TiKV. ...
- [转帖]s3fs - 使用S3FS存储桶目录允许其他用户使用权限
https://www.coder.work/article/6661505 我在使用S3FS时遇到问题.我正在使用 ubuntu@ip-x-x-x-x:~$ /usr/bin/s3fs --ve ...
- Jmeter学习之八_测试kafka
Jmeter学习之八_测试kafka 背景 最近在持续学习. 昨天学习了grafana展示Jmeter测试数据库的结果 今天想着能够测试一下kafka验证一下kafka的吞吐量等信息 说干就干的. 遇 ...
- DBeaver连接国产信创数据库的步骤
DBeaver连接国产信创数据库的步骤 本次连接使用的数据库类型 1.达梦 2.神通 3.人大金仓 4.瀚高 安装DBeaver 通过官网或者是其他网站下载最新的数据库介质 之后的操作为: 这次不感谢 ...
- 手写promise完成异常处理和状态只能够修改一次
8.处理 Promise 抛出的异常 <script src="./Promise.js"></script> <script type=" ...
- RIPEMD加密技术探究:优势、劣势与实战应用
摘要:RIPEMD加密算法作为一种哈希算法,自1989年诞生以来,因其高效.安全的特性在网络安全领域得到了广泛的应用.本文将对RIPEMD算法的优缺点进行详细分析,并给出一个Java完整的示例代码.同 ...