📄 osc_rtc_cal1.c
字号:
// 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 + -