Why not a DCF 77 Lib ?
DCF77 is in Europe the same as WWV. Transmitting Time/Date via VLF (77.7 kc).
A Driver for DCF77 ist a good Idea
DCF77 Driver
-
- Posts: 6
- Joined: 27 Sep 2010 14:04
Re: DCF77 Driver
DCF77 decode example pascal code AVR
Code: Select all
Version:0.9 StartHTML:0000000105 EndHTML:0000140107 StartFragment:0000001460 EndFragment:0000140091
program timen;
{atemga 128
dcf77 conrad print aangesloten op interupt ingang E4 en E5 brug one pull-up needed
port C LED ON
C_0 = time pul 1sec by atmega 128 16bit clock
C_1 = alarm bit = compare time
C_2 = DCF77 puls, short= 0 long = 1
}
{ Declarations section }
type tijd = record
dag,
uur,
minuut,
seconde: byte;
txt: array[20] of char;
end;
// wekker
type wekker = record
status: byte;
alarm :tijd;
huidige:tijd;
{ on_off : sbit at status.B0;
aktief (teller loopt) b1.;
alarm : sbit at status.B2;
stil/setup : sbit at status.B3;
wijziging in sec .b4
wijziging in min = b5
wijz. uur =b6
zijz. dag =b7
}
end;
var
time : wekker ;
tel,seconde,minuut,uur,dag,knop : byte;
pulsduur:word;
intercept, error:byte;
dcf77dataold: array[0..59] of boolean;
dcf77data: array[0..59] of boolean;
dcf77tijd:tijd;
newdata:byte;
bitnummer: byte;
// Led lampjes, external connections
var on_led : sbit at PORTC0_bit;
var pieper : sbit at PORTC1_bit;
var on_led_clk : sbit at PORTC2_bit;
procedure setup_16_bit_timer();
const
Fio : dword = 1; //counter sec=01ec : freq=1/T=1/1= 1hertz
// mimimaal is 1hz
var
prescaler: word; //1=2^0, 8=2^3, 32=2^5, 64=2^6, 128, 256, or 1024 afhankelijk uP
deler:dword;
clk,deler_ber :dword;
clk_io :dword;
begin
//bereken prescaler HZ
clk := (1000*Clock_kHz()); //haal clock freq op uit microproccessor
deler_ber := clk div Fio; // deel uP clock door gewente IO Frequentie = deler waarde
deler:= (deler_ber div 65535)+1; //in HZ 65535 $FFFF =grootste vermenigvuldiger OCR1A (H+L)
if deler<=1024 then prescaler:= 1024;
if deler<=256 then prescaler:= 256;
if deler<=64 then prescaler:= 64;
if deler<=8 then prescaler:= 8;
if deler<=1 then prescaler:= 1;
// set prescaler automatisch
case prescaler of
1:begin
TCCR1B.cs10:= 1;
TCCR1B.CS11:= 0;
TCCR1B.CS12:= 0;
end;
8:begin
TCCR1B.cs10:= 0;
TCCR1B.CS11:= 1;
TCCR1B.CS12:= 0;
end;
64:begin
TCCR1B.cs10:= 1;
TCCR1B.CS11:= 1;
TCCR1B.CS12:= 0;
end;
256:begin
TCCR1B.cs10:= 0;
TCCR1B.CS11:= 0;
TCCR1B.CS12:= 1;
end;
1024:begin
TCCR1B.cs10:= 1;
TCCR1B.CS11:= 0;
TCCR1B.CS12:= 1;
end;
end; //case prescaler
//Timer/Counter Control Register – TCCR1
TCCR1A.wgm10 :=0;
TCCR1A.wgm11 :=0;
TCCR1B.wgm12 :=1; // (normal mode) mode 4 CTC compare ocr1a
TCCR1B.WGM13 :=0;
// restand uit teller topv TCNT2 mag niet groter zijn dan 65535 $FFFF
//set OCR compare waarde
clk_io := deler_ber div prescaler;
if (clk_io>0) then clk_io:=clk_io-1;
OCR1AH:= HI(clk_io);
OCR1AL:= LO(clk_io);
//set outpout CTC
TCCR1A.COM1A1:= 1; // OC1A/OC1B on compare match
TCCR1A.COM1A0:=0;
TCCR1A.COM1B1:= 1;
TCCR1A.COM1B0:=0;
//set interupt
TIMSK.OCIE1A:=1; // Timer/Counter1, Output Compare A Match Interrupt Enable
end; // timer 16 bit setup
procedure Timer1comparematch(); org $0018 ; //atmega 128 $0018, atmega8 $0006 TIMER1 COMPA Timer/Counter1 Compare Match A
var tel :byte;
begin
// if time.status and %00000010 = %00000010 then
// begin //wekker aan
// if time.status and %00010000 = %00010000 then portA0_bit:= not portA0_bit;// update display
if time.huidige.seconde<59 then begin
inc(time.huidige.seconde);
time.status :=time.status or %00010000; // zet wijzigings b4=sec op 1
end else begin
time.huidige.seconde:=0;
if time.huidige.minuut<59 then begin
inc(time.huidige.minuut);
time.status :=time.status or %00100000; // zet wijzigings b5=min op 1
end else begin
time.huidige.minuut:=0;
time.huidige.seconde:=0;
if time.huidige.uur<24 then begin
inc(time.huidige.uur);
time.status :=time.status or %01100000; // zet wijzigings b6=uur en b5=min op 1
end else begin
time.huidige.uur:=0;
end;
end; //minuut
end;
if (time.huidige.seconde = time.alarm.seconde) and
(time.huidige.minuut = time.alarm.minuut) and
(time.huidige.uur = time.alarm.uur)
then time.status := time.status or %11100100; // set alarm b2
// end; //wekker aan
end; // einde comp interupt
procedure setuppulsduurmeting();
// timer 0
//De pulsen zijn ofwel 100 ms ofwel 200 ms in lengte, waarbij de lange pulsen een binaire één voorstellen, en de korte een nul.
// 10msec =1/10=0,1kH=100hz
const
Fio : dword = 100; //counter sec=01ec : freq=1/T=1/1= 1hertz
var
prescaler: word; //1=2^0, 8=2^3, 32=2^5, 64=2^6, 128, 256, or 1024 afhankelijk uP
deler:dword;
clk,deler_ber :dword;
clk_io :dword;
begin
//bereken prescaler HZ
clk := (1000*Clock_kHz()); //haal clock freq op uit microproccessor
deler_ber := clk div Fio; // deel uP clock door gewente IO Frequentie = deler waarde
deler:= (deler_ber div 255)+1; //in HZ 255 $FF =grootste vermenigvuldiger OCR0
if deler<=1024 then prescaler:= 1024;
if deler<=256 then prescaler:= 256;
if deler<=64 then prescaler:= 64;
if deler<=8 then prescaler:= 8;
if deler<=1 then prescaler:= 1;
// set prescaler automatisch
case prescaler of
1:begin
TCCR0.cs00:= 1;
TCCR0.CS01:= 0;
TCCR0.CS02:= 0;
end;
8:begin
TCCR0.cs00:= 0;
TCCR0.CS01:= 1;
TCCR0.CS02:= 0;
end;
64:begin
TCCR0.cs00:= 1;
TCCR0.CS01:= 1;
TCCR0.CS02:= 0;
end;
256:begin
TCCR0.cs00:= 0;
TCCR0.CS01:= 0;
TCCR0.CS02:= 1;
end;
1024:begin
TCCR0.cs00:= 1;
TCCR0.CS01:= 0;
TCCR0.CS02:= 1;
end;
end; //case prescaler
// atmega 128
TCCR0.WGM00:=0;
TCCR0.WGM01:=0;
// interupt op 8mzh/(1024*255)=7812hz => 0,0327 sec => 32ms
TIMSK.TOIE0:=1; // set interupt overflow bit
end; // timer 0, 8 bit setup
procedure telpulsduur(); org $0020 ; //atmega128 $0020, atmeg 8 0x009 TIMER0 OVF Timer/Counter0 Overflow
begin
inc(pulsduur);
end;
procedure setupintercept_puls();
begin
//atmega 128
// pin PE4
//Interrupt 4 Sense Control heeft togle
EICRB.ISC40 :=0 ;// Any logical change on INT1 generates an interrupt request.
EICRB.ISC41 := 1; //10 The falling edge between two samples of INTn generates an interrupt
// EIMSK :=%00010000;
//pin pE5
EICRB.ISC50 :=1 ; // 1 1 The rising edge of INTn generates asynchronously an interrupt request
EICRB.ISC51 :=1 ;
// set interupt bit03 en bit04
EIMSK :=%00110000;
end;
procedure interceptpuls(); org $000A; //atmega128 $000A INT4 External Interrupt Request 4 , atmega8 0x001 INT0 External Interrupt Request 0
var pulslengte:word;
begin
on_led_clk := 0;
pulslengte:= pulsduur; // duur/32ms
pulsduur:=0;
//De pulsen zijn ofwel 100 ms ofwel 200 ms in lengte, waarbij de lange pulsen een binaire één voorstellen, en de korte een nul.
if (pulslengte>10) and (pulslengte <40 ) // puls <120ms
then begin
intercept:=0 ;
dcf77data[bitnummer]:=0;
inc( bitnummer);
// UART1_Write_Text('L');
end;
if pulslengte >40 //and pulslengte<8 // puls >120ms <240ms
then begin
intercept:=1 ;
dcf77data[bitnummer]:=1;
inc( bitnummer);
// UART1_Write_Text('H');
end;
// UART1_Write(pulslengte);
{if pulslengte >8 and pulslengte<17 // puls >240ms <544ms
then intercept=1 ;}
if bitnummer>60 then bitnummer:=0;
end;
procedure interceptrisingedge(); org $000C; //atmega128 $$000C INT5 External Interrupt Request 4 , atmega8 0x001 INT1 External Interrupt Request
var pulslengte:word;
begin
on_led_clk := 1;
pulslengte:=pulsduur;
// UART1_Write_Text('L');
// UART1_Write(pulslengte);
if pulslengte>230 then begin
// nieuwe reeks
dcf77dataold:= dcf77data;
newdata:=1;
bitnummer:=0;
UART1_Write_Text('nieuw');
UART1_Write($0D);
end;
pulsduur:=0; // start met tellen
end;
procedure decodedcf77();
var crc,teller:byte;
txt: string[4];
var getal, dagvdweek,maand,jaar:byte;
begin
error:=0;
dcf77tijd.seconde:=0;
{ 0= M Minuutmarkering
1-14 gereserveerd
15 R 1 als reserve-zendantenne in gebruik is
16 A1 aankondiging omschakeling zomer/wintertijd
17-18 Z1, Z2 01 tijdens wintertijd, 10 tijdens zomertijd
19 A2 aankondiging schrikkelseconde
20 S Start van tijdsbericht, altijd 1
21-24 eenheden minuten
25-27 tientallen minuten
28 P1 controlesom van bit 21-27
29-32 eenheden uren
33-34 tientallen uren
35 P2 controlesom bit 29-34
36-39 eenheden datum
40-41 tientallen datum
42-44 dag van de week
45-48 eenheden maand
49 tiental maand
50-53 eenheden jaartal (00..99)
54-57 tientallen jaartal (00..99)
58 P3 controlesom bit 36-57
(59) - ontbrekende impuls; markeert einde van een minuut}
if dcf77dataold[15]=1 then begin
UART1_Write_Text('reserve zender');
UART1_Write($0D);
end;
if dcf77dataold[16]=1 then begin
UART1_Write_Text('aankondiging omschakeling zomer/wintertijd');
UART1_Write($0D);
end;
if (dcf77dataold[17]=1) and (dcf77dataold[18]=0) then begin
UART1_Write_Text('Zomertijd');
UART1_Write($0D);
end;
if (dcf77dataold[17]=0) and (dcf77dataold[18]=1) then begin
UART1_Write_Text('wintertijd');
UART1_Write($0D);
end;
if dcf77dataold[19]=1 then begin
UART1_Write_Text('aankondiging schrikkelseconde');
UART1_Write($0D);
end;
if dcf77dataold[20]=1 then begin
UART1_Write_Text('de tijd is:');
UART1_Write($0D);
end else error:=1;
getal:=0;
getal:= dcf77dataold[24] ;
getal:= getal shl 1;
getal:=getal+dcf77dataold[23] ;
getal:= getal shl 1;
getal:=getal+dcf77dataold[22] ;
getal:= getal shl 1;
getal:=getal+dcf77dataold[21];
if dcf77dataold[25] then getal := getal +10 ;
if dcf77dataold[26] then getal := getal +20 ;
if dcf77dataold[27] then getal := getal +40 ;
crc:=0;
for teller:=21 to 27 do crc:=crc+ dcf77dataold[teller];
crc:=crc and %00000001;
if crc<>dcf77dataold[28] then begin
error:=error+2; // set 2e error bit;
dcf77tijd.minuut:=0;
end else dcf77tijd.minuut:= getal;
UART1_Write_Text('minuut:') ;
ByteToStr(getal,txt);
UART1_Write_Text(txt) ;
UART1_Write($0D);
getal:=0;
getal:=0;
getal:= dcf77dataold[32] ;
getal:= getal shl 1;
getal:=getal+dcf77dataold[31] ;
getal:= getal shl 1;
getal:=getal+dcf77dataold[30] ;
getal:= getal shl 1;
getal:=getal+dcf77dataold[29];
if dcf77dataold[33] then getal := getal +10 ;
if dcf77dataold[34] then getal := getal +20 ;
crc:=0;
for teller:=29 to 34 do crc:=crc+ dcf77dataold[teller];
crc:=crc and %00000001;
if crc<>dcf77dataold[35] then begin
error:=error+4 ;// set 2e error bit;
dcf77tijd.uur:=0;
end else dcf77tijd.uur:= getal;
UART1_Write_Text('uur:') ;
ByteToStr(getal,txt);
UART1_Write_Text(txt);
UART1_Write($0D);
///dag
getal:=0;
getal:= dcf77dataold[39] ;
getal:= getal shl 1;
getal:=getal+dcf77dataold[38] ;
getal:= getal shl 1;
getal:=getal+dcf77dataold[37] ;
getal:= getal shl 1;
getal:=getal+dcf77dataold[36];
if dcf77dataold[40] then getal := getal +10 ;
if dcf77dataold[41] then getal := getal +20 ;
dcf77tijd.dag:= getal;
UART1_Write_Text('dag:') ;
ByteToStr(getal,txt);
UART1_Write_Text(txt) ;
UART1_Write($0D);
// dagvdweek
getal:=0;
getal:=getal+dcf77dataold[44] ;
getal:= getal shl 1;
getal:=getal+dcf77dataold[43] ;
getal:= getal shl 1;
getal:=getal+dcf77dataold[42];
dagvdweek:=getal;
case dagvdweek of
1: UART1_Write_Text(' maandag') ;
2: UART1_Write_Text(' dinsdag') ;
3: UART1_Write_Text(' woensdag') ;
4: UART1_Write_Text(' donderdag') ;
5: UART1_Write_Text(' vrijdag') ;
6: UART1_Write_Text(' zaterdag') ;
7: UART1_Write_Text(' zondag') ;
end;
UART1_Write($0D);
//maand
getal:=0;
getal:= dcf77dataold[48] ;
getal:= getal shl 1;
getal:=getal+dcf77dataold[47] ;
getal:= getal shl 1;
getal:=getal+dcf77dataold[46] ;
getal:= getal shl 1;
getal:=getal+dcf77dataold[45];
if dcf77dataold[49] then getal := getal +10 ;
maand:= getal;
UART1_Write_Text('maand:') ;
ByteToStr(getal,txt);
UART1_Write_Text(txt) ;
UART1_Write($0D);
// jaar
getal:=0;
getal:= dcf77dataold[53] ;
getal:= getal shl 1;
getal:=getal+dcf77dataold[52] ;
getal:= getal shl 1;
getal:=getal+dcf77dataold[51] ;
getal:= getal shl 1;
getal:=getal+dcf77dataold[50];
if dcf77dataold[54] then getal := getal +10 ;
if dcf77dataold[55] then getal := getal +20 ;
if dcf77dataold[56] then getal := getal +40 ;
if dcf77dataold[57] then getal := getal +80 ;
crc:=0;
for teller:=36 to 57 do crc:=crc+ dcf77dataold[teller];
crc:=crc and %00000001;
if crc<>dcf77dataold[58] then begin
error:=error+8; // set 4e error bit;
jaar:=0;
end else jaar:= getal;
UART1_Write_Text('jaar:') ;
ByteToStr(getal,txt);
UART1_Write_Text(txt) ;
UART1_Write($0D);
UART1_Write_Text('error') ;
ByteToStr(error,txt);
UART1_Write_Text(txt) ;
UART1_Write($0D);
end;// decode
procedure uart_tijd();
var error, receive, teller, teken : byte;
var output : array[3] of char ;
begin
// UART
UART1_Write_Text('tijd:');
ByteToStr( time.huidige.uur,output );
UART1_Write_Text(output);
UART1_Write(58);
ByteToStr( time.huidige.minuut,output );
UART1_Write_Text(output);
UART1_Write(58);
ByteToStr( time.huidige.seconde,output );
UART1_Write_Text(output);
UART1_Write(58);
end;
begin
// Initialize Software UART communication on pins Rx, Tx, at 9600 bps
UART1_Init(9600);
delay_ms(100); // Wait for UART module to stabilize
UART1_Write_Text('setup');
UART1_Write($0D);
DDRC.B3 :=0; // uart aan
DDRC.b0 :=1; //set register C bit0 als uitgangen
DDRC.b1 :=1; //set register C bit 1 als uitgangen
DDRC.b2 :=1; //set register C bit 2 als uitgangen
//atmega 128
DDRE.B4 := 0; // input dcf77 puls uit conrad print
DDRE.B5:= 0; // input dcf77 puls uit conrad print
pulsduur:=0;
bitnummer:=0;
setup_16_bit_timer(); { Main program }
UART1_Write_Text('setup timer done');
UART1_Write($0D);
setuppulsduurmeting();
UART1_Write_Text('setup pulsduur done');
UART1_Write($0D);
setupintercept_puls();
UART1_Write_Text('setup puls ingang done');
UART1_Write($0D);
UART1_Write_Text('set interupt aan');
UART1_Write($0D);
SREG_I_bit := 1; // Interrupt enable
UART1_Write_Text('start');
UART1_Write($0D);
dcf77tijd.minuut:=00;
dcf77tijd.uur :=10;
dcf77tijd.dag := 1;
// wait mim 2 minuten
error:=1;
repeat
if newdata then begin // dcf77dataold ont leden
decodedcf77();
newdata:=0;
end; //if newdata
until (error=0);
time.huidige.seconde :=0;
time.huidige.minuut :=dcf77tijd.minuut;
time.huidige.uur :=dcf77tijd.uur;
time.huidige.dag :=dcf77tijd.dag;
UART1_Write_Text('tijd opgehaald');
uart_tijd();
while true do begin
if time.status and %00010000 = %00010000 then on_led:= not on_led ;// update display
// if time.status and %00010000 = %00010000 then portA:= not portA;// update display
if time.status and %00000100= %00000100 then begin
// alarm
pieper:=1;
end else pieper:=0; // alarm
time.status := time.status and %00001111;
// UART1_Write(pulsduur);
if newdata then begin // dcf77dataold ont leden
decodedcf77();
uart_tijd();
newdata:=0;
end; //if newdata
end;
end.
- slavisa.zlatanovic
- mikroElektronika team
- Posts: 1321
- Joined: 07 Apr 2009 09:39
Re: DCF77 Driver
Hi!
Thanks for sharing your code!
P.S.
There is the User Projects section at this forum.
Please, send your project to this address: marko@mikroe.com and we'll put it in the User Projects page.
Thanks for sharing your code!
P.S.
There is the User Projects section at this forum.
Please, send your project to this address: marko@mikroe.com and we'll put it in the User Projects page.
Best regards
Slavisa
Slavisa