📄 int_osc_measure1.c
字号:
//-----------------------------------------------------------------------------
// INT_OSC_Measure1.c
//-----------------------------------------------------------------------------
// Copyright 2002 Cygnal Integrated Products, Inc.
//
// AUTH: BW
// DATE: 02 APR 02
//
// This program shows an example of how the external oscillator
// can be used to measure the internal oscillator frequency.
//
// In this example, the internal oscillator is set to its highest setting.
// The external oscillator is configured to its desired mode (external
// 22.1184MHz crystal). The PCA counter is used as a generic 16-bit counter
// that uses EXTCLK / 8 as its time base.
//
// We configure Timer0 to count SYSCLKs, and count the number of INTCLKs
// in 1 second's worth of EXTCLK/8
//
// Target: C8051F02x
// Tool chain: KEIL C51 6.03 / KEIL EVAL C51
//
//-----------------------------------------------------------------------------
// Includes
//-----------------------------------------------------------------------------
#include <c8051f020.h> // SFR declarations
#include <stdio.h>
#include <math.h>
//-----------------------------------------------------------------------------
// 16-bit SFR Definitions for 'F02x
//-----------------------------------------------------------------------------
sfr16 DP = 0x82; // data pointer
sfr16 TMR3RL = 0x92; // Timer3 reload value
sfr16 TMR3 = 0x94; // Timer3 counter
sfr16 ADC0 = 0xbe; // ADC0 data
sfr16 ADC0GT = 0xc4; // ADC0 greater than window
sfr16 ADC0LT = 0xc6; // ADC0 less than window
sfr16 RCAP2 = 0xca; // Timer2 capture/reload
sfr16 T2 = 0xcc; // Timer2
sfr16 RCAP4 = 0xe4; // Timer4 capture/reload
sfr16 T4 = 0xf4; // Timer4
sfr16 DAC0 = 0xd2; // DAC0 data
sfr16 DAC1 = 0xd5; // DAC1 data
//-----------------------------------------------------------------------------
// Global CONSTANTS
//-----------------------------------------------------------------------------
#define EXTCLK 22118400 // EXTCLK frequency in Hz
#define BAUDRATE 9600 // Baud rate of UART in bps
sbit LED = P1^6; // LED = 1 means ON
//-----------------------------------------------------------------------------
// Structures, Unions, Enumerations, and Type definitions
//-----------------------------------------------------------------------------
typedef union ULong {
long Long;
unsigned int UInt[2];
unsigned char Char[4];
} ULong;
//-----------------------------------------------------------------------------
// Function PROTOTYPES
//-----------------------------------------------------------------------------
void SYSCLK_Init (void);
void PORT_Init (void);
void UART0_Init (void);
void INTCLK_Measure (void);
//-----------------------------------------------------------------------------
// Global VARIABLES
//-----------------------------------------------------------------------------
long INTCLK; // holds INTCLK frequency in Hz
long SYSCLK; // holds SYSCLK frequency in Hz
//-----------------------------------------------------------------------------
// MAIN Routine
//-----------------------------------------------------------------------------
void main (void) {
WDTCN = 0xde; // disable watchdog timer
WDTCN = 0xad;
SYSCLK_Init (); // initialize oscillator
PORT_Init (); // initialize crossbar and GPIO
EA = 1; // enable global interrupts
INTCLK_Measure (); // measure internal oscillator and
// update INTCLK variable
SYSCLK = INTCLK;
UART0_Init (); // initialize UART0
while (1) {
INTCLK_Measure (); // measure internal oscillator and
// update INTCLK variable
printf ("INTCLK = %ld Hz\n", INTCLK);
}
}
//-----------------------------------------------------------------------------
// Initialization Subroutines
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// SYSCLK_Init
//-----------------------------------------------------------------------------
//
// This routine initializes the system clocks
//
void SYSCLK_Init (void)
{
int i; // delay counter
OSCXCN = 0x67; // start external oscillator
for (i=0; i < 256; i++) ; // wait for osc to start up
while (!(OSCXCN & 0x80)) ; // Wait for crystal osc. to settle
OSCICN = 0x07; // configure internal oscillator at max
// frequency;
// set INTCLK as SYSCLK source
}
//-----------------------------------------------------------------------------
// 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
}
//-----------------------------------------------------------------------------
// INTCLK_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. PCA0 started (CR = 1)
// 3. On CF, Timer0 is started (TF0 = 1); CF is cleared, PCA0 remains running
// 4. When T0_high:Timer0 reach 0x00000000, stop PCA0
// 5. EXTCLK frequency = PCA0_high:PCA0
// Upon completion, the global variable EXTCLK 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 INTCLK_Measure (void)
{
unsigned int T0_high; // overflow bytes of Timer0
unsigned int PCA0_high; // overflow bytes of PCA0
ULong temp; // byte-addressable Long
// PCA0 counts up to EXTCLK/8; PCA0_high is the upper 2 bytes of this number
temp.Long = -(EXTCLK >> 3);
PCA0_high = temp.UInt[0];
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;
// Timer0 counts from zero to INTCLK
// init Timer0
CKCON |= 0x08; // Timer0 counts SYSCLKs
TCON &= ~0x30; // Stop timer; clear TF0
TMOD &= ~0x0f; // Timer0 in 16-bit counter mode
TMOD |= 0x01;
T0_high = 0x0000; // init Timer0
TL0 = 0x00;
TH0 = 0x00;
// start PCA0
CR = 1;
while (CF == 0); // wait for edge
TR0 = 1; // Start Timer0
CF = 0; // clear PCA overflow
PCA0L = temp.Char[3];
PCA0H = temp.Char[2];
while (1) { // wait for 1 second
if (CF) { // handle PCA0 overflow
PCA0_high++;
if (PCA0_high == 0x0000) { // check for completion
TR0 = 0; // Stop Timer0
break;
}
CF = 0;
}
if (TF0) { // handle T0 overflow
T0_high++;
TF0 = 0;
}
}
CR = 0; // Stop PCA0
// read 32-bit Timer0 value
temp.UInt[0] = T0_high;
temp.Char[2] = TH0;
temp.Char[3] = TL0;
INTCLK = temp.Long; // INTCLK = Timer0
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -