• 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
    
  • 相关阅读:
    PAT1007
    PAT1005
    PAT1002
    PAT1003
    PAT1016
    PAT 1018
    PAT1009
    pat 1037
    解决Git合并分支发生的冲突
    站和队列的基本使用
  • 原文地址:https://www.cnblogs.com/milton/p/15541298.html
Copyright © 2020-2023  润新知