⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 osc_rtc_cal1.c

📁 C8051F系列C源码方便对此类单片机有兴趣的同志学习之用
💻 C
📖 第 1 页 / 共 2 页
字号:
                                          // overflow interrupt is enabled

   // init Timer0
   TCON &= ~0x30;                         // Stop timer; clear TF0
   TMOD &= ~0x0f;                         // Timer0 in 16-bit counter mode
   TMOD |=  0x01;
   CKCON |= 0x08;                         // Timer0 counts SYSCLKs

   tolerance_count = 1000;                // wait for 1000 cycles in a row
                                          // to lie within 20 clocks of each
                                          // other
   current = 0;
   do {
      PCA0CN = 0x00;
      PCA0L = 0xFF;                       // set PCA time base to '-1'
      PCA0H = 0xFF;
      TCON &= ~0x30;
      TH0 = 0x00;                         // init T0 time base
      TL0 = 0x00;

      // start PCA0
      CR = 1;
      while (CF == 0);                    // wait for edge
      TR0 = 1;                            // Start Timer0
      CF = 0;                             // clear PCA overflow
      PCA0L = -8;                         // set PCA to overflow in 8 cycles
      PCA0H = (-8) >> 8;
      while (CF == 0);
      TR0 = 0;
      last = current;
      current = (TH0 << 8) | TL0;
      if (abs (current - last) > 20) {
         tolerance_count = 1000;          // falls outside bounds; reset
                                          // counter
      } else {
         tolerance_count--;               // in-bounds; update counter
      }
   } while (tolerance_count != 0);
}

//-----------------------------------------------------------------------------
// PORT_Init
//-----------------------------------------------------------------------------
//
// Configure the Crossbar and GPIO ports
//
void PORT_Init (void)
{
   XBR0    |= 0x04;                    // Enable UART0
   XBR2    |= 0x40;                    // Enable crossbar and weak pull-ups
   P0MDOUT |= 0x01;                    // enable TX0 as a push-pull output
   P1MDOUT |= 0x40;                    // enable LED as push-pull output
}

//-----------------------------------------------------------------------------
// UART0_Init
//-----------------------------------------------------------------------------
//
// Configure the UART0 using Timer1, for <baudrate> and 8-N-1.
//
void UART0_Init (void)
{
   SCON0  = 0x50;                      // SCON0: mode 1, 8-bit UART, enable RX
   TMOD   = 0x20;                      // TMOD: timer 1, mode 2, 8-bit reload
   TH1    = -(SYSCLK/BAUDRATE/16);     // set Timer1 reload value for baudrate
   TR1    = 1;                         // start Timer1
   CKCON |= 0x10;                      // Timer1 uses SYSCLK as time base
   PCON  |= 0x80;                      // SMOD00 = 1
   ES0    = 0;                         // disable UART0 interrupts
   TI0    = 1;                         // indicate ready for TX
}

//-----------------------------------------------------------------------------
// Timer3_Init
//-----------------------------------------------------------------------------
//
// Configure Timer3 for 16-bit auto-reload mode using EXTCLK / 8 as its time
// base and to reload every 4096 counts.  This will generate one interrupt
// every second.
//
void Timer3_Init (void)
{
   TMR3CN = 0x01;                      // Stop Timer3; Clear TF3; Timer3
                                       // counts SYSCLK / 8
   TMR3RL = -4096;                     // reload every 4096 counts
   TMR3 = TMR3RL;                      // init T3
   EIE2 |= 0x01;                       // Enable Timer3 interrupts
   TMR3CN |= 0x04;                     // Start Timer3
}

//-----------------------------------------------------------------------------
// SYSCLK_Measure
//-----------------------------------------------------------------------------
//
// This routine uses the external oscillator to measure the frequency of the
// internal oscillator.  Assumes that the external oscillator has been
// started and settled.  Also assumes that the internal oscillator operating
// at its highest frequency is selected as the system clock source.
//
// The measurement algorithm is as follows:
// 1. PCA set to '-1'; Timer0 set to 0x0000; PCA stopped; Timer0 stopped
// 2. PCA started (CR = 1)
// 3. On CF, Timer0 is started (TR0 = 1); CF is cleared, PCA remains running
// 4. PCA set to '-4096' (note, we have about 4000 system clocks to
//    perform this operation before actually missing a count)
// 5. On CF, Timer0 is stopped (TR0 = 0);
// 6. Timer0 contains the number of 16 MHz SYSCLKs in 4096 periods of EXTCLK/8
//
// Upon completion, the global variable SYSCLK contains the internal 
// oscillator frequency in Hz.
//
// I believe the worst-case measurement error is around 20 system clocks.
// 20 / 16e6 = 1.3 ppm (far less than typical crystal ppm's of 20)
//
void SYSCLK_Measure (void)
{
   unsigned int T0_high;                  // keeps track of Timer0 overflows
   ULong temp;                            // byte-addressable Long

   // init PCA0
   PCA0CN = 0x00;                         // Stop counter; clear all flags
   PCA0MD = 0x0b;                         // PCA counts in IDLE mode;
                                          // EXTCLK / 8 is time base;
                                          // overflow interrupt is enabled
   PCA0L = 0xFF;                          // set time base to '-1'
   PCA0H = 0xFF;

   // init Timer0
   T0_high = 0;                           // clear overflow counter
   CKCON |= 0x08;                         // Timer0 counts SYSCLKs
   TCON &= ~0x30;                         // Stop timer; clear TF0
   TMOD &= ~0x0f;                         // Timer0 in 16-bit counter mode
   TMOD |=  0x01;
   TH0 = 0x00;                            // init time base
   TL0 = 0x00;

   // start PCA0
   CR = 1;
   while (CF == 0);                       // wait for edge
   TR0 = 1;                               // Start Timer0
   CF = 0;                                // clear PCA overflow
   PCA0L = -4096;                         // set PCA to overflow in 4096 
                                          // cycles (1 second)
   PCA0H = (-4096) >> 8;

   while (CF == 0) {                      // wait for 1 second
      if (TF0) {                          // handle T0 overflow
         T0_high++;
         TF0 = 0;
      }
   }
   TR0 = 0;                               // Stop Timer0

   // read Timer0 value

   //SYSCLK = (T0_high << 16) | (TH0 << 8) | TL0; // 0xa0 clock cycles
   // = 0x1a clock cycles using the optimization below
   temp.UInt[0] = T0_high;
   temp.Char[2] = TH0;
   temp.Char[3] = TL0;

   SYSCLK = temp.Long;
}

//-----------------------------------------------------------------------------
// Timer3_ISR
//-----------------------------------------------------------------------------
//
// This ISR is called on overflow of Timer3, which occurs once every second.
// Here we update a set of global RTC counters for seconds, minutes, hours,
// and days.
//
void Timer3_ISR (void) interrupt 14 using 3
{
   TMR3CN &= ~0x80;                       // clear Timer 3 overflow flag

   SECONDS++;
   if (SECONDS == 60) {
      SECONDS = 0;
      MINUTES++;
      if (MINUTES == 60) {
         MINUTES = 0;
         HOURS++;
         if (HOURS == 24) {
            HOURS = 0;
            DAYS++;
         }
      }
   }
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -