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

posted on 2021-11-11 19:02  Milton  阅读(426)  评论(0编辑  收藏  举报

导航