{===============================================================}
{                                                               }
{ Program Uhr mit externem batteriegepufferten RTC und DCF;     }
{ LCD- und RTC-DCF-Funktionen                                   }
{                                                               }
{                                                               }
{ Bearbeitungsbeginn: 12.02.2007                                }
{ Bearbeitungsstand:  31.03.2008                                }
{ Hardware-Aenderung ab 01.04.2008  Version 2                   }
{ Bearbeitungsstand:  25.04.2008                                }
{ Bearbeiter: Stefan Taborek                                    }
{                                                               }
{ Dieses Modul kann jederzeit ueber TWI-Bus abgefragt werden    }
{ Wird das Kommandobyte 15 gesendet, so antwortet dieser Slave  }
{ mit der aktuellen Zeit und Datum.                             }
{ Der avrco-Compiler muss mit dem Optimizer gestartet werden!   }
{                                                               }
{===============================================================}


program RTC_DCF_Uhr;

{ $BOOTRST $00C00}         {Reset Jump to $00C00}
{$NOSHADOW}
{ $W+ Warnings}            {Warnings off}

Device = mega8, VCC=4.9;
(*
Define_Fuses   {fuer MEGA8 8MHZ mit internem Quarz}
  LockBits0 = [];
// FuseBits0 = [CKSEL0, CKSEL1, CKSEL3, SUT1];
// FuseBits1 = [SPIEN];
  ProgMode  = SPI;
                    *)
Import SysTick, TickTimer, SerPort , TWInet;

From System Import LongWord, {Float,} Pipes, Processes;

Define
  ProcClock      = 8000000;        {Hertz}
  SysTick        = 10;             {msec}
  Scheduler      = iData;
  StackSize      = $0064, iData;
  FrameSize      = $0080, iData;
  SerPort        = 9600, parnone, Stop2, Databit8;
  RxBuffer       = 8, iData;
  TxBuffer       = 8, iData;
  TWInetMode     = Slave;
  TWInode        = 07;
  TWIpresc       = TWI_BR100;      {Bitrate}
  TWIframe       = 36, iData;      {buffer/packet size}
  TWIframeBC     = 4;              {Broadcast Frame size}
  TickTimer      = Timer1;



Implementation

{$IDATA}


{--------------------------------------------------------------}
{ Type Declarations }

type

  TRTCDaten=array[0..7] of byte; //alle Datenregister  + Reserve
  //      Daten[0] :=  // Sekunde
  //      Daten[1] :=  // Minute
  //      Daten[2] :=  // Stunde
  //      Daten[3] :=  // Tag
  //      Daten[4] :=  // Monat
  //      Daten[5] :=  // Jahr
  //      Daten[6] :=  // Wochentag
  //      Daten[7] :=  //



  TTelefonNr = string[22];

  // Der folgende Daten-Rekord enthaelt alle Daten einer Weckzeit,
  TRAMDATENRec = Record
           cmd   : byte;
           state : byte;
           time  : TRTCDaten;   // {se}, mi, hr, dd, mm, jj, wd, rr
           str_  : TTelefonNr;
           snr   : byte;
           prs   : byte;
   end;


  TBCD = array[0..7] of byte;

  TPipeStr = TTelefonNr;

{--------------------------------------------------------------}
{ Const Declarations }

const
  MasterNode    : byte = $02;      // 2
  RTC_DCFNode   : byte = TWInode;  // $07;


  TxRxFrameSize  : byte = sizeOf(TRAMDATENRec);

  //Index 0 im folgenden Array ist fuer Telegramm-Fehler noetig:
  dwArr:array[0..7] of string[2]=( SO , MO , DI , MI , DO , FR , SA ,  00 );
 
{--------------------------------------------------------------}

{$EEPROM}
Structconst
  eInt : word = 1;
  ls1:string = #12+#1+#4;
  ls2:string =  -- Telefon-Wecker -- ; //!!!
  ls3:string = #2+#44 +  Stefan Taborek ;
  ls4:string = #2+#69 +  2008 ;
  eByte : byte = $AA;
  eCheck : word = CalcCheckSum (@ls1, @eByte);

{--------------------------------------------------------------}
{ Var Declarations }
{$IDATA}

var

    NetTimeOut               : SysTimer8;
    Timer1                   : SysTimer8, UpCount;   //8Bit fuer Pulsmessung
    S_RTC                    : Semaphore;
    Int_DCF_lo               : boolean;
    Zeit_Anzeigen            : boolean;
    min_voll                 : boolean;

    RTC_Sec                  : byte;
    RTC_Int_Sec              : boolean;

    RTC_Contr_CS1[@PortD,5]  : bit;
    RTC_DataOutPort[@PortC]  : byte;
    RTC_DataInPort[@PinC]    : byte;
    RTC_AdrPort[@PortB]      : byte;
    LED_A[@PortD,7]          : bit;

    RTC_Daten                : TRTCDaten;     // array[0..7] of byte


{--------------------------------------------------------------}

    NetTxRec[@TWITXBUFF]     : TRAMDATENRec;
    NetRxRec[@TWIRXBUFF]     : TRAMDATENRec;

    lb, hb, arr_ptr          : byte;

    DCF_Inp[@PinD,2]         : bit;


    LCD_Pipe                 : Pipe[4] of TPipeStr;
    Sec_Str                  : String[4];
    L_Str                    : String[24];
    LCD_Str_Info             : string[14];
    LCD_Str_Sig              : string[14];
    Zeit_Str                 : TPipeStr;


{--------------------------------------------------------------}

    tel                      : array[0..60]of byte;
    DCF_Daten                : TRTCDaten;
    DCF_true                 : boolean;
    part8                    : TBCD;

    anz_bit_sec              : byte;
    anz_bitfehler            : byte;
    anz_telflanken           : byte;
    anz_telflanken_alt       : byte;
    err_pr                   : byte;
    Tbit_Ptr                 : byte;
    wLo,wLoHi                : integer;
    PeSumme                  : integer;
    qlo                      : integer;
    qHi                      : integer;
    qcnt                     : integer;
    wcnt                     : word;
  

{--------------------------------------------------------------}
{ Interrupt-Routinen }

{ $NoSave}
{--------------------------I-----------------------------------}
Interrupt Int0;    //Ausgeloest von DCF ueber PinD2 H->L or L->H
{--------------------------------------------------------------}
begin
  //------------------ Telegramm-Empfang -------------------
  if (DCF_Inp= false)then       // Achtung hier Logikwechsel!!!!
    wLo := Integer(GetSysTimer(Timer1)); // Dauer der Low-Periode
    //    LED1 := true;
  else
    wLoHi := Integer(GetSysTimer(Timer1)); // Dauer der Lo + Hi-Periode
    ResetSysTimer(Timer1);                 //
    Int_DCF_lo := true;                    // Start des Process
    //    LED1 := false;
  endif;
end;


{$NoSave}
{--------------------------I-----------------------------------}
Interrupt Int1;    //Ausgeloest vom ext. RTC ueer PinD3
{--------------------------------------------------------------}
begin
  IncSema(S_RTC);
end;



{-------------------functions procedures-----------------------}


{--------------------------------------------------------------}
procedure InitPorts;
{--------------------------------------------------------------}
begin
  LED_A       := false;
  //------------- Port B -------------
  DDRB        := %00111111;   // Adress-Port (2Bit + 4Bit) Ausgabe
  RTC_AdrPort := %00110000;   // PortB: Bit4, Bit5 auf High setzen !!!!
  //
  //------------- Port C -------------
  DDRC        :=  %00001111;  //Daten-Port  (4Bit) zuerst Ausgabe
  //
  //------------ Port D --------------
  PortD       := %00001100;   // fuer PIN2 und PIN3 PullUp-Resistor aktivieren
  DDRD        := %11000000;   // Bit0
  //                          // Bit1
                              // Bit2  < Int0  DCF interrupt
                              // Bit3  < Int1  RTC Sekundeninterrupt
                              // Bit4
                              // Bit5
                              // Bit6  > CS1 am RTC
                              // Bit7  > LED
  //---Externer Interrupt Int0 (D2) und Int1 (D3):
  GICR  :=  GICR or %11000000;   // Int0 und Int1 sind erlaubt
  MCUCR := MCUCR or %00001001;   // Int0 bei jeder Flanke
                              // Int1 loest bei fall. Flanke aus
                              // Int0 kommt von DCF-In
                              // Int1 kommt von RTC
end InitPorts;


{--------------------------------------------------------------}
procedure InitVar;
{--------------------------------------------------------------}
begin
  anz_bitfehler  := 0;
  anz_telflanken := 0; // Zaehler fuer ungueltige Bits
  DCF_true       := false;
  PeSumme        := 0;
  qcnt           := 0;
  wcnt           := 0; // sperrt den evtl. fruehzeitigen RTC-Int
end;


{--------------------------------------------------------------}
procedure InitLCD;
{--------------------------------------------------------------}
begin
  Write(SerOut, #12+#1+#4);         // Clear; Cursor Home, Hide
  L_Str := ls2;
  Write(SerOut, L_Str);
  Write(SerOut, ls3);
  Write(SerOut, ls4);
  mdelay(3900);
  Write(SerOut, #12+#1+#4);         // Clear; Cursor Home
end;


{--------------------------------------------------------------}
function RTC_Read(adr:byte):byte;
{--------------------------------------------------------------}
var dat1 : byte;
// Bit4 :   RD   Lo-aktiv
// Bit5 :   WR   Lo-aktiv
// Achtung Reihenfolge der Befehle nicht veraendern!
// Achtung nichts veraendern!
// CS1 wird hier eingesetzt, weil damit auch der Standby-Modus
// des RTC gesteuert wird, dh. CS1 ist bei Netzausfall immer Lo
begin
  RTC_Contr_CS1 := true;         // CS1 auf Hi setzen
  adr := adr or %00110000;       // Bit4, Bit5 auf High setzen
  RTC_AdrPort := adr;            // PortB: adr out unbed. noetig!
  excl(adr, 4);                  // PortB Bit4 (RD) auf Low setzen
  RTC_AdrPort := adr;            // PortB gibt RD (+ Adresse) aus
  DDRC:=  %0000;                 // Daten-Port  (4Bit) Lesen
  dat1 := RTC_DataInPort and $0F;
  RTC_Contr_CS1 := false;        // CS1 auf Lo setzen  -> Holdbit=0
  return(dat1);
end;

{--------------------------------------------------------------}
procedure RTC_Write(adr, daten:byte);
{--------------------------------------------------------------}
// Bit4 :   RD   Lo-aktiv
// Bit5 :   WR   Lo-aktiv
// Achtung Reihenfolge der Befehle nicht veraendern!
// Achtung nichts veraendern!
// CS1 wird hier eingesetzt, weil damit auch der Standby-Modus
// des RTC gesteuert wird, dh. CS1 ist bei Netzausfall immer Lo
begin
  RTC_Contr_CS1 := true;            // CS1 auf Hi setzen
  adr := adr or %00110000;          // Bit4, Bit5 auf High setzen
  RTC_AdrPort := adr;               // PortB: adr out unbed noetig
  excl(adr, 5);                     // PortB Bit5 (WR) auf Low setzen
  DDRC:=  %1111;                    // Daten-Port  (4Bit) Schreiben
  RTC_DataOutPort := daten and $0F; // PortC
  RTC_AdrPort   := adr;             // PortB gibt WR (+ Adresse) aus
  RTC_Contr_CS1 := false;           // CS1 auf Lo setzen  -> Holdbit=0
end;


{--------------------------------------------------------------}
function RTC_BusyBit:boolean;
{--------------------------------------------------------------}
var busybit   : boolean;
    regD, cnt1: byte;
begin
  busybit := true;
  cnt1 := 5;
  Repeat
    RTC_Write($0D, %00000001);       // Reg_D  Hold-Bit setzen (Bit0)
    regD := RTC_Read($0D);           // Reg_D zuruecklesen
    if not bit(regD, 1) then         // Busy-Bit = 0 ?         (Bit1)
      busybit := false;
    else
      RTC_Write($0D, %00000000);     // Reg_D schr Hold-Bit=0
      mdelay(1);                     // wait laut Datenblatt = 0,19ms
    endif;
    dec(cnt1);
  until (not busybit) or (cnt1 =0);
  RTC_Write($0D, %00000000);         // Reg_D schr  Hold-Bit = 0
  return(busybit);
end;


{--------------------------------------------------------------}
procedure Set_RTC_Time;
{--------------------------------------------------------------}
var b,i8 : byte;
begin
  arr_ptr := 0;
  //
  if RTC_BusyBit=false then        // Busy-Bit=1 entspricht readonly
    for i8 := 0 to 11  by 2 do     //
      b :=  RTC_Daten[arr_ptr];
      lb := (b mod 10);
      hb := (b div 10);
      inc(arr_ptr);
      //
      RTC_Write(i8, lb);
      if i8=4 then hb := hb or %100; endif; // Bit2 fuer 24h-Betr.
      RTC_Write(i8+1, hb);
    endfor;
    RTC_Write(12, RTC_Daten[6]);   // Wochentag
  endif;
  //
  RTC_Write($0F, %00000101);       // Reg_F schreiben  Reset-Bit = 1
  RTC_Write($0F, %00000100);       // Reg_F schreiben  Reset-Bit = 0
  RTC_Write($0D, %00000000);       // Reg_D schreiben  Hold-Bit = 0
  RTC_Write($0D, %00000000);       // Reg_D schreiben  Hold-Bit = 0
end;

{--------------------------------------------------------------}
procedure Get_RTC_Time;
{--------------------------------------------------------------}
var h,i9 : byte;
begin
  // das RTC_Daten-Array in der selben Reihenfolge
  arr_ptr := 0;
  //
  if RTC_BusyBit=false then
    for i9 := 0 to 11 by 2 do     // ohne WD !!!!
      lb := RTC_Read(i9);
      hb := RTC_Read(i9+1);
      if (i9 = 4) then hb := hb and %0011; endif; //24h
      h := hb*10 + lb;
      //
      RTC_Daten[arr_ptr] := h;
      inc(arr_ptr);
    endfor;
    RTC_Daten[6] := RTC_Read(12) and %0111;  //WD 12
  else
  endif;
  RTC_Sec := RTC_Daten[0];        // Anfangssekunde einstellen !
  //
  RTC_Write($0D, %00000000);      // Reg_D schreiben  Hold-Bit = 0  2 mal
  RTC_Write($0D, %00000000);      // Reg_D schreiben  Hold-Bit = 0  !!!!
end;



{--------------------------------------------------------------}
procedure RTC_ZeitStellen(dcfsync : boolean);
{--------------------------------------------------------------}
var i0: byte;
begin
  // nur aufrufen, wenn DCF-Daten gerade eingetroffen sind!!
  // dh. Net_Puffer.dat ist aktuell !
  // oder mit Parameter false
  if RTC_BusyBit=false then  // Busy-Bit=1 entspricht readonly
      if dcfsync then
        RTC_Daten := DCF_Daten;
      else{----------------------}
        // Testwerte einsetzen bei Erstinitialisierung
        for i0 := 7 downto 1 do
          RTC_Daten[i0-1] := (7-i0)*i0-(11 mod i0) ;    //
        endfor;
        // Sekunde    0
        // Minute     5
        // Stunde     8
        // Tag        9
        // Monat     11
        // Jahr      10
        // Wochentag  2  Dienstag
      endif;
      //
      Set_RTC_Time;            // alle 12 Register von 0 bis C
  endif;
  mdelay(2);
  RTC_Write($0D, %00000000);  // Reg_D schreiben Hold-Bit = 0    !!
end;



{--------------------------------------------------------------}
procedure WriteTimeToLCD(zle : byte);
{--------------------------------------------------------------}
var
    i : byte;
begin
  // zle bezieht sich auf das Display 4x20;
  // zle=1  entspricht Zeile 1
  // Das Ausgabeformat benoetigt genau 20 Zeichen:
  //         hr:mi:se WD dd.mm.jj
  //
  dec(zle);
  zle := (zle * 20) + 1; //fortlaufende Cursorposition
  //
  Zeit_Str := #2+char(zle);
  for i := 2 downto 0 do
    Zeit_Str := Zeit_Str + ByteToStr(RTC_Daten[i]:2: 0 );
    case i of
      1..2: Zeit_Str := Zeit_Str +  : ;   |
         0: Zeit_Str := Zeit_Str +     + dwArr[RTC_Daten[6]] +    ;   |
    endCase;
  endfor;
  for i := 3 to  5 do
    Zeit_Str := Zeit_Str + ByteToStr(RTC_Daten[i]:2: 0 );
    if i < 5 then Zeit_Str := Zeit_Str +  . ; endif;
  endfor;
  PipeSend(LCD_Pipe, Zeit_Str);
end;


{--------------------------------------------------------------}
procedure RTC_Initialisieren;
{--------------------------------------------------------------}
var RTCRegD, RTCRegE : byte;
begin
  // nur bei Prozessor-Reset oder Neustart:
  RTCRegE      := RTC_Read($0E);     // Reg_E    !!!!!!!!!!!!!!
  RTCRegE      := RTC_Read($0E);     // Reg_E   2mal
  RTCRegD      := RTC_Read($0D);     // Reg_D
  if (not bit(RTCRegD, 0)) and       // HoldBit Bit= 0 ?
         (RTCRegE = %00000110) then  // E-Register ok?  xxxx
      Get_RTC_Time;                  // alle Zeit-Daten
  else
      // da der RTC nicht korrekt initialisiert ist:
      RTC_Write($0F, (%00000100 or %00000011));   //Reg_F
      mdelay(3);
      RTC_Write($0E, %00000110);     // Reg_E  sec-Periode Interrupt
      RTC_Write($0D, %00000001);     // Reg_D  Hold setzen
      RTC_Write($0F, %00000100);     // Reg_F
      //
      RTC_ZeitStellen(false);        // Parameter false --> nur Testwerte
  endif;
  RTC_Write($0D, %00000000);         // Reg_D schreiben Hold-Bit = 0    !!
end;


//*************************DCF***********************************


{--------------------------------------------------------------}
procedure Part8_clear;
{--------------------------------------------------------------}
var i4 : byte;
begin
  for i4 := 0 to 7 do
    part8[i4] :=0;
  endfor;
end;

{--------------------------------------------------------------}
function ParityTest(t_a, t_e:byte): byte;
{--------------------------------------------------------------}
var h5, i5 :byte;
begin
  // das Paritaetsbit ergaenzt immer auf eine gerade Anzahl Bits
  h5 := 0;
  for i5 := t_a to t_e do
    if tel[i5] = 1 then
      inc(h5);
    endif;
  endfor;
  return((h5) mod 2);
end;

{--------------------------------------------------------------}
function DCF_Wert_decodieren(bcdw:TBCD ):byte;
{--------------------------------------------------------------}
// to decimal
var h2, i2, w2 : byte;
begin
  // die Codierung der DCF-Werte erfolgt nicht im ueblichen
  // Nibble-Code
  w2 := 0;
  h2 := 1;
  for i2 := 0 to 7 do
    if (i2 = 4) then h2 := 10; endif;  // 10er-Werte beginnen
    if bcdw[i2] = 1 then w2 := w2 + h2; endif;
    h2 := h2 * 2;
  endfor;
  //
  return(w2);
end;

{--------------------------------------------------------------}
function DCF_Telegramm_decodieren : boolean;
{--------------------------------------------------------------}
var b, h7, i7 : byte;
begin
  // Hier wird das Telegramm erst geprueft und ausgewertet,
  // nachdem das Bit 58 gesendet wurde.
  err_pr := 0;                         // fuer Pruefbitfehler
  // als Pruefbitfehler werden auch Fehler an Bit0 und
  // Bit20 gezaehlt
  // die maximale Pruefbitfehlerzahl ist demnach 5
  for i7 := 0 to 59 do
     b := byte(tel[i7]);
     case i7 of
            0 : if (b > 0) then  //dieses Bit ist immer 0
                  inc(err_pr);
                endif;
                |
           20 : if (b <> 1) then // Startbit immer 1
                  inc(err_pr);
                endif;
                Part8_clear;
                h7:= 0;                  // Vorbereitung fuer Min
                |
       21..27 : Part8[h7] := byte(b);
                inc(h7);
                |
           28 : h7 := DCF_Wert_decodieren(part8); // Minute
                if h7 > 59 then
                   inc(err_pr);
                   h7 := 0;
                endif;
                DCF_Daten[1] := h7;
                err_pr := err_pr + ParityTest(21, 28);
                Part8_clear;             // Vorbereitung fuer Std
                h7 := 0;
                |
       29..34 : Part8[h7] := b;
                inc(h7);
                |
           35 : h7 := DCF_Wert_decodieren(part8); // Stunde
                if h7 > 23 then
                  inc(err_pr);
                  h7 := 1;
                endif;
                DCF_Daten[2] := h7;
                err_pr := err_pr + ParityTest(29, 35);
                Part8_clear;
                h7 := 0;                  // Vorbereitung fuer Tag
                |
       36..41 : part8[h7] := b;
                inc(h7);
                |
           42 : h7 :=  DCF_Wert_decodieren(part8); // Tag
                if not (h7 in [1..31]) then
                  inc(err_pr);
                  h7 := 1;
                endif;
                DCF_Daten[3] := h7;
                Part8_clear;
                part8[0] := b;            // 1.Bit fuer Wochentag
                h7 := 1;
                |
       43..44 : part8[h7]:= b;
                inc(h7);
                |
           45 : h7 :=  DCF_Wert_decodieren(part8); // Wochentag  1..7
                if not (h7 in [1..7]) then
                  inc(err_pr);
                  h7 := 1;
                endif;
                if h7 = 7 then h7 := 0; endif; // Anpassg an RTC
                DCF_Daten[6] := h7;
                Part8_clear;
                part8[0] := b;                // 1.Bit fuer Monat
                h7 := 1;
                |
       46..49 : part8[h7] := byte(tel[i7]);
                inc(h7);
                |
           50 : h7 := DCF_Wert_decodieren(part8); // Monat
                if not (h7 in [1..12]) then
                  inc(err_pr);
                  h7 := 1;
                endif;
                DCF_Daten[4] := h7;
                Part8_clear;
                part8[0] := b;                 // 1.Bit fuer Jahr
                h7 := 1;
                |
       51..57 : Part8[h7]:= b;
                inc(h7);
                |
           58 : h7 := DCF_Wert_decodieren(part8); // Jahr
                if not (h7 in [8..25]) then
                  inc(err_pr);
                  h7 := 0;
                endif;
                DCF_Daten[5] := h7;
                err_pr := err_pr + ParityTest(36, 58);
                |
     endcase;
  endfor;
  //
  return((Tbit_Ptr > 57)and(err_pr = 0));
end;



//=========================Prozesse======================

{--------------------------------------------------------------}
process WriteLCD(40, 32: iData, 3);
{--------------------------------------------------------------}
{ Frame- and Stack-Size habe ich ausgemessen }
begin
  WaitPipe(LCD_Pipe);
    PipeRecv(LCD_Pipe, L_Str);
    Write(SerOut, L_Str);
    mdelay(15);
end;


{==============================================================}
Process RxMasterFrame(40, 40 : iData, 4);
{==============================================================}
begin
  // Telegramm von Master eingetroffen:
  WaitSema(TWIrxSEMA);
  NetTxRec.cmd:= 254;
  if NetRxRec.cmd = 15 then
    if NetRxRec.str_ <>    then
      PipeSend(LCD_Pipe, NetRxRec.str_);
    endif;
    NetTxRec.time := RTC_Daten;   // Daten in Byteformat
    NetTxRec.str_ := Zeit_Str;
    NetTxRec.cmd  := 115;         // Quittungsbyte
  endif;
  mdelay(5);
  TWItxFrame(MasterNode, TxRxFrameSize); // an Master senden
  TWIRXCLEAR;                     // This is mandatory !!!
end;



{==============================================================}
process RTC_Sekunde(28,34 : iData, 3);
{==============================================================}
{ Frame- and Stack-Size habe ich ausgemessen }
begin

  waitSema(S_RTC);
    repeat until wcnt = 1; // Start des Main_Proc
    //
    //------------------------
    // Interruptbit des RTC muss hier noch quittiert werden:
    RTC_Write($0D, %00000000);  // Reg_D schreiben Int-Bit = 0
    //------------------------
    //
    inc(RTC_Sec);
    if (RTC_Sec > 59)or(min_voll) then
      min_voll := false;
      Get_RTC_Time;   // auch RTC_Sec := 0;
      Zeit_Anzeigen := true;
    else
      // Ausgabe der Sekunde auf dem LCD:
      Sec_Str := #2+#7 + ByteToStr(RTC_Sec:2: 0 );
      PipeSend(LCD_Pipe, Sec_Str);
      //
    endif;
    //
    //=============
    LED_A := true;
    mdelay(65);         // Blinkdauer
    LED_A := false;
    //=============
    //
    // ------ DCF-Signalueberwachung --------
    //----Signalqualitaet  berechnen:
       …..........
    //
    LCD_Str_Sig := #2+#61 +  Sig: +ByteToStr(Byte(qhi):3:   )+ % ;
      if (anz_bitfehler) > 0 then
        LCD_Str_Sig := #2+#61 +  Sig ??    ;
      endif;
      //
      if anz_telflanken_alt < anz_telflanken then
         anz_telflanken_alt := anz_telflanken;
         anz_bit_sec := 0;
      else
        inc(anz_bit_sec);
        if (anz_bit_sec > 3) then
          LCD_Str_Sig := #2+#61 +  Sig: aus  ;
          if  DCF_true then
            DCF_true := false;
            Int_DCF_lo := true;  // Anzeige aktualisieren
          endif;
        endif;
      endif;
     
      PipeSend(LCD_Pipe, LCD_Str_Sig);
    // --------------------------------------
end;



{--------------------------------------------------------------}
{ Main Program }
{$IDATA}
{--------------------------------------------------------------}

begin
  InitPorts;
  InitVar;
  //--------------------------------------
  EnableInts;
  //--------------------------------------
  mdelay(600); // vor InitLCD muessen ca 600ms Stabilisierungszeit liegen!!
  InitLCD;     // nicht vor EnableInts;
  //
  Start_Processes;
  TWIrxClear;               //erst nach Start_Processes !
  //
  //--------------------------------------
  RTC_Initialisieren;         //
  RTC_Sec := RTC_Daten[0];    // Anfangssekunde einstellen !
  WriteTimeToLCD(1);          // zeile  1
  //--------------------------------------

  wcnt := 1;                 // !!! Siehe RTC-Prozess (fuer Fehlstart)

  //============================================================
  loop
    repeat
      if Zeit_Anzeigen then
        Zeit_Anzeigen := false;
        WriteTimeToLCD(1);   // kompletten Zeitstring ausgeben
      endif;
    until (Int_DCF_lo);     // siehe Interrupt Int0;
    //
    Int_DCF_lo := false;

    (*-----------------------------------------------------------
     Start nur bei Flankenwechsel nach Low
     es folgt die Auswertung der vohergehenden Sekunde
     Messung erfolgte in der ISR
     -     -----------------------       ---------------------
      |    |                      |      |                    |
      |    |                      |      |                    |
      ------                      --------                    ----

        0                          1
      |<-----------1sec---------->|<-----------1sec---------->|
      | Lo |                      |  Lo  |        Hi          |
       100ms                        200ms
      ^                           ^                           ^
     --neue Sekunde beginnt:  alte Sek auswerten   wird
     gespeichert *)
    //
    if wLo in [09..12] then
      tel[Tbit_Ptr] := 0;
    endif;
    if wLo in [19..22] then
      tel[Tbit_Ptr] := 1;
    endif;
    //
    LCD_Str_Info := #2+#70+ DCF  ;
    if (wLoHi > 190) and (wLoHi < 215) then // Minutenwechsel
      if DCF_Telegramm_decodieren = true then         //
        RTC_ZeitStellen(true);
        Zeit_Anzeigen := true;
        LCD_Str_Info  := LCD_Str_Info +  Zt: OK  ;
        DCF_true      := true;    // ein mal nach Signalausfall
      else
        LCD_Str_Info  := LCD_Str_Info +  Zt: Err ;
      endif;
      //------------------
      Tbit_Ptr           := 0;       // hier erfolgt exakter Reset
//        RTC_Sec  := 0;
      anz_bitfehler      := 0;
      anz_telflanken_alt := 0;
      anz_telflanken     := 1;
      mdelay(10);                 // um nicht zu zeitig zu sein!
      min_voll           := true;
      //
    else //------------------------------
      if ((wLoHi > 90) and (wLoHi < 115)) then  // vorige Sek
      else
        tel[Tbit_Ptr] := 255; //unbestimmt
        if  (anz_bitfehler  < 255) then
          inc(anz_bitfehler);
        endif;
      endif;
      //------------------
      inc(Tbit_Ptr);                    // Bit-Pointer
      if (Tbit_Ptr > 59) then           // Sicherheit fuer array
        Tbit_Ptr  := 0;
      endif;
      //------------------
      //
      if (DCF_true)and(Tbit_Ptr > 4) then
        LCD_Str_Info := LCD_Str_Info +  Empf OK ;
      else
        LCD_Str_Info := LCD_Str_Info +  Empf ?? ;
      endif;
      //
    endif;
    PipeSend (LCD_Pipe, LCD_Str_Info);
    //-----------------------------------------
    inc(anz_telflanken);         //jede Lo-Telegrammflanke zaehlen
  endloop;

end RTC_DCF_Uhr.






















Quelltext des Programms
Blockschaltbild
Details