📄 新建 文本文档.txt
字号:
虽然是英文,但读起来还不是很难,我这板水平都应付了,相信您更没问题!
还是那句话写给菜鸟,大虾别见笑!
How can I use my crystal for high precision timebase ?
Introduction:
O.K. its easy to divide exact 12.000000MHz. But how using other crystals, or
correct the deviation ?
The way is always the same:
First on 8051 processors, the crystal was divided to give the timer clock. On
T0, T1 of 80C51 devices by 12, on the 80C52 for timer T2 by 2, also in the
Dallas DS80C320 at T0, T1 by 4.
Then you can use the timers to count 8 or 16 bit. The remaining divider stages
can be realized in software. On using only 8 of the 128 bytes of the 8051 you
can count up to 2 Giga years (the 8051 was dust, before this time was gone)
with a 40MHz crystal !
In most cases you get no exact divider values. But this is not important, you
must then calculate the error and can correct it, if needed. E.g. if the second
differ, nobody can detect it. But if the Error was accumulated over 1 month or
year, it can be seen. So correction can be done every second, minute, hour or
day. So the error was not accumulated and also not detected.
Lets Practice:
Following an example with assembler code:
Random choice of a crystal: 12345701 Hz (use every other crystal for your
calculation)
Crystal / 12 = 1028808.417
Using Timer T0: Crystal / 12 / 65536 = 15.69837062
So you need an additional Byte in RAM to divide down to 1 second. If this byte
divide by 256 you must not reload it.
Then the reload value of the T0: Crystal / 12 / 256 = 4018.782878 rounded to
4019.
The resulting error is: 1 - 4018.782878 / 4019 = 0.000054 = 5 sec / day = 140
sec / month.
This is to high for using as RTC. So every second we use a different T0 reload
value:
Crystal / 12 - 255 * 4019 = 3963.41667 rounded to 3963.
Then the resulting error is: 1 - 1028808.417 / (255 * 4019 + 3963) = 0.0000004
= 1 sec / month = 12 sec / year.
This is enough for most RTC applications. But additional correction every
minute can reduce it further.
For extreme high accuracy also deviation over temperature was important and
must be corrected.
Programming example:
The C example is easiest to use, since it can make all calculations for you.
You must only tell the real crystal frequency, thats all.
t0_int2.a51
t0_int2.c51
Correct deviation:
To correct the deviation you need a very high accurate and also very expensive
frequency meter to count the real crystal frequency with precision over more
than 10 digits.
The cheaper way was, let the RTC running over several months. Then the
deviation can be measured in seconds to calculate the true frequency.
Repeat the previous calculation with this real frequency and program the new
values into the micro.
E.g. you found an error of +12 seconds during 30 days. Then the true frequency
was:
12.345701 Hz * (1 + 12 / (30 * 24 * 60 * 60)) = 12345758Hz. Use this to repeat
the above described calculation and further the accuracy was very good.
;************************************************************************/
;*
*/
;* Software reload Example using Timer 0
*/
;* */
;* Author: Peter Dannegger */
;* danni@specs.de */
;* */
;************************************************************************/
org 0
jmp init
org $+5*8+3 ;reserved for interrupt vectors
init: mov tmod, #1 ;set Timer 0 mode 1
mov tl0, #0FFh
mov th0, #0FFh ;overflow on next cycle
setb tr0
clr f1sec
mov Divider_1s, #0
mov ie, #10000010b
main: jbc f1sec main1 ;test and clear
jmp main
main1: cpl p1.0 ;change every 1 second
jmp main
;Timebase 1 second at 12.345701 MHz:
; 12.3456701 MHz / 12 / (255 * 4019 + 3963) = 1 second
;Deviation: 12 seconds / year
T0_reload equ 4019
T0_sec_reload equ 3963
bseg at 0
F1sec: dbit 1
dseg at 30h
Divider_1s: ds 1
cseg
curr_adr equ $
org 000Bh
jmp Timer0_interrupt
org curr_adr
Timer0_interrupt:
push psw
djnz divider_1s, ?TI1
;done 1 time every second:
clr ea ;no additional delay by other
interrupts
clr tr0 ;no overflow during addition
xch a, tl0
add a, #low(8-T0_sec_reload) ;stop for 8 cycle
xch a, tl0
xch a, th0
addc a, #high(8-T0_sec_reload)
xch a, th0
setb ea ;other interrupts enabled after next
instr.
setb tr0
pop psw
setb F1sec ;say to main: 1 second was finished
;must be cleared my main
reti
;done 255 times every second:
?TI1: clr ea ;no additional delay by other
interrupts
clr tr0 ;no overflow during addition
xch a, tl0
add a, #low(8-T0_reload) ;stop for 8 cycle
xch a, tl0
xch a, th0
addc a, #high(8-T0_reload)
xch a, th0
setb ea ;other interrupts enabled after next
instr.
setb tr0
pop psw
reti
end
/************************************************************************/
/* */
/* High Precise Time Base
*/
/* */
/* Author: Peter Dannegger */
/* danni@specs.de */
/* */
/************************************************************************/
#pragma cd pl(30000)
#define uchar unsigned char
#define uint unsigned int
#include
/************************************************************************/
/*
*/
/* Insert your crystal frequency and you get exact 1 second */
/* without need understanding why :
*/
/*
*/
/**/ #define XTAL 12345701L
/**/
/*
*/
/************************************************************************/
#define T0_RELOAD ((uint) (XTAL / 12.0 / 256.0 + 0.5))
#define T0_RELOAD_1S ((uint) (XTAL / 12.0 - 255.0 * T0_RELOAD + 0.5))
#define T0_STOP_CYCLES 16 // calculated
with list file
bit F_1second = 0;
union bw{
int w;
struct{
char h;
char l;
}b;
};
void t0_int( void ) interrupt 1
{
static uchar prescaler = 0;
union bw i;
if( --prescaler == 0 ){
EA = 0;
TR0 = 0;
i.b.l = TL0;
i.b.h = TH0;
i.w += -T0_RELOAD_1S + T0_STOP_CYCLES; // 1 * every second
TL0 = i.b.l;
TH0 = i.b.h;
EA = 1;
TR0 = 1;
F_1second = 1;
}else{
EA = 0;
TR0 = 0;
i.b.l = TL0;
i.b.h = TH0;
i.w += -T0_RELOAD + T0_STOP_CYCLES; // 255 * every second
TL0 = i.b.l;
TH0 = i.b.h;
EA = 1;
TR0 = 1;
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -