Projekt Datenlogger für Wetterstation WS2300

Quelltext: Datenaufbereitung und Speicherung
{**************************************************************}
program WS2300_RAM;
//S.Taborek
//Modul-RAMSlave für Datenlogger
//Stand: 20.05.2005
//Stand: 02.06.2005 Datenstrukturänderung
//Stand: 11.06.2005 MW_Status eingeführt
{**************************************************************}


{$NOSHADOW}

Device = mega8, VCC=4.8;

Define_Fuses  //negative Logik beachten
  override_fuses;
  LockBits0 = [];
  FuseBits0 = [CKSEL0, CKSEL1, CKSEL3, SUT1, BODEN]; //8MHz int. Osz
  FuseBits1 = [];
  ProgMode  = SPI;

Import SysTick, {RTclock,} TWInet;

From System Import LongWord, Processes;

Define
  ProcClock      = 8000000;        {Hertz}
  SysTick        = 10;             {msec}
  StackSize      = $0064, iData;
  FrameSize      = $0064, iData;
  TWInetMode     = Slave;
  TWInode        = 04;             {default address in slave mode}
  TWIpresc       = TWI_BR100;      {Bitrate}
  TWIframe       = 54, iData;      {buffer/packet size}
  TWIframeBC     = 4;              {Broadcast Frame size}
//  RTClock        = iData, DateTime;{Time, DateTime}
  Scheduler      = iData;

//uses Unit_Types;

Implementation

{$IDATA}

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

type

  TReply         = array[0..31]of Byte;

  TRAMDATENRec      = Record
                      Rec_jj        : byte;     //1
                      Rec_mm        : byte;     //2
                      Rec_dd        : byte;     //3
                      Rec_hh        : byte;     //4
                      Rec_mi        : byte;     //5
                      //..........................
                      TempInn       : Integer;  //6..7        1
                      TempOut       : Integer;  //8..9        2
                      HumidityOut   : Word;     //10..11      3
                      WindSpeed     : word;     //12..13      4
                      WindDir       : Word;     //14..15      5
                      AirPressRel   : Word;     //16..17      6
                      DewPoint      : Word;     //18..19      7
                      RainTotal     : Word;     //20..21      8
                      OkBits        : Byte;     //22  für Werte 1..8
                      //...........................
                      CRS           : Byte;     //23
                    end;

  // folgener Record muss in Größe gleich dem TRAMSaveRec sein!
  TRAMContrRec    = Record
                      RecStart_jj   : byte;     //1
                      RecStart_mm   : byte;     //2
                      RecStart_dd   : byte;     //3
                      RecStart_st   : byte;     //4
                      RecStart_mi   : byte;     //5
                      RecSize       : byte;     //6
                      MAX_DevNr     : byte;     //7
                      SaveZyk       : byte;     //8
                      Akt_WrSnr     : word;     //9..10
                      Last_RdPC     : word;     //11..12 letzter DS an PC
                      Last_AnzPC    : word;     //13..14
                      IdentCode     : word;     //15..16
                      voll          : boolean;  //17
                      d             : byte;     //18
                      MasterStatus  : byte;     //19
                      WSS_SlvStatus : byte;     //20
                      RAM_SlvStatus : byte;     //21
                      LCD_Slvstatus : byte;     //22
                      CRS           : byte;     //23
                    end;

  TRAM_DS         = array[1..sizeOf(TRAMDATENRec)] of byte;
  // da RAM-Wetterdaten und Ctrl-Daten gleich groß sind,
  // wird TRAM_DS auch als TRAM_CDS verwendet

  TTime1          = array[1..3{4}] of byte;


//.................................................

  // folgender Record darf die Größe von TWIframe nicht übersteigen!!
  // Der Record enthält alle Messwerte der Wetterstation - auch jene,
  // die nicht im RAM archiviert werden.

  TWSTSlaveDS    = Record
                     cmd            : byte;              //1
                     Time           : TTime1;            //2..4   4
                     Date           : TTime1;            //5..7
                     TempInnen      : Integer;           //8..9
                     TempAussen     : Integer;           //10..11
                     HumidityInn    : word;              //12..13
                     HumidityOut    : word;              //14..15
                     WindFlag       : byte;              //16
                     WindCode       : Byte;              //17
                     WindSpeed      : word;              //18..19
                     WindDir        : array[1..7]of byte;//20..26
                     AirPressRel    : Word;              //27..28
                     Rain1H         : word;              //29..30
                     RainTotal      : word;              //31..32
                     DewPoint       : word;              //33..34
                     Reserve        : byte;              //35
                     WSSensorExt    : byte;              //36
                     MW_Status      : word;              //37..38 für alle MW
                     WSConnErr      : word;              //39..40
                     Last_RdPC      : word;              //41..42
                     MasterStatus   : byte;              //43  >> LED s
                     WSS_Slv_Status : byte;              //44
                     RAM_Slv_Status : byte;              //45
                     LCD_Slv_status : byte;              //46
                     RAMCapacity    : longword;          //47..50
                     r1             : longword;
                   end;

  // folgender Record darf die Größe von TWIframe nicht übersteigen!!
  TRAMSlaveRec   = Record
                     cmd            : byte;            //1
                     qui            : byte;            //2
                     Akt_WrSnr      : word;            //3..4
                     CtrlDS         : TRAMContrRec;    //Controldaten  5..28
                     WetterDS       : TRAMDATENRec;    //Wetterdaten  29..51
                     r1             : longword;
                  end;

{--------------------------------------------------------------}
{ Const Declarations }
const
  BroadCNode    : byte = $00;
  MasterNode    : byte = $02;
  WSTSlvNode    : byte = $03;
  RAMSlvNode    : byte = $04;
  LCDSlvNode    : byte = $05;
  BatSlvNode    : byte = $06;

const

  FM24C_Adr       : byte = $50;  // Moduladr. im Datenblatt: 10100000b

  SlvTimeOut      : byte  = 20;  // 20x SysTick = 200msec

  TxFrameSize     : byte  = sizeOf(TWSTSlaveDS);
  TxLCDFrameSize  : byte  = SizeOf(TWSTSlaveDS);

  TimeoutLimit    : byte = 230;  // für Timeoutüberwachung der ser.Schnittst.

  CRAM_ZykTime    : byte = 10;   // Anzahl Minuten bis Speicherung

const
  RAMCtrlCode     : word = $abcd;
  RAM_MAX_DevNr   : byte = 3;        // 0..3  für Anzahl FM24C256
  RAMDevCapacit   : word = 32768;    // Bytes pro Device
  RAMRecSize      : byte = sizeOf(TRAMDATENRec);
  RAMDS_proDev    : word = RAMDevCapacit div word(RAMRecSize);
  RAM_MAX_Snr     : word = ((RAM_MAX_DevNr + 1)* RAMDS_proDev) -1; //
  RAMContrDSAdr   : word = 0;       // Datensatzadresse für Control-Daten

  //-----------------------------
  ClearBuffer     : byte = $01;     // broadcast for Slv to clear Rx state

  cmd_01          : byte = $01;
  cmd_02          : byte = $04;
  cmd_03          : byte = $15;
  cmd_04          : byte = $17;
  cmd_05          : byte = $19;
  cmd_06          : byte = $31;
  cmd_07          : byte = $43;
  cmd_08          : byte = $07;
  cmd_09          : byte = $13;

  qui_01          : byte = $A1;
  qui_02          : byte = $A4;
  qui_03          : byte = $A7;
  qui_04          : byte = $A9;

  kenng1          : byte = $37;
  kenng2          : byte = $32;
  kenng3          : byte = $31;
  kenng4          : byte = $33;
  kenng5          : byte = $35;
  kenng6          : byte = $36;
  kenng8          : byte = $38;
  kenng9          : byte = $A2;
  kenngA          : byte = $AA;
  kenngB          : byte = $BB;
  kenngC          : byte = $CC;

// es folgen Messwert-Kennzeichnungen:

  CTempInn        : word  = 1;
  CTempOut        : word  = 2;
  CHumyInn        : word  = 4;
  CHumyOut        : word  = 8;
  CWindFlag       : word  = 16;
  CWindCode       : word  = 32;
  CWindSpd        : word  = 64;
  CWindDir        : word  = 128;
  CAirPress       : word  = 256;
  CRain1H         : word  = 512;
  CRainTot        : word  = 1024;
  CDewPoint       : word  = 2048;
  CWSSensExt      : word  = 4096;


//--------end des Unit_Types---Ersatzes


type

  TMW             = array[1..4] of longint;
  //...............................................

  TMiWerteRec     = Record
                      TempInn       :TMW;   //1
                      TempOut       :TMW;   //2
                      HumidityOut   :TMW;   //3
                      WindSpeed     :TMW;   //4
                      WindDir       :TMW;   //5
                      AirPressRel   :TMW;   //6
                      DewPoint      :TMW;   //7
                      RainTotal     :TMW;   //8
                    end;

{--------------------------------------------------------------}
{ Const Declarations }
//const


{--------------------------------------------------------------}
{ Var Declarations }
{$IDATA}
var
  NetTxRec[@TWITXBUFF]     : TRAMSlaveRec;
  NetRxRec[@TWIRXBUFF]     : TWSTSlaveDS; //

  WstDaten                 : TWSTSlaveDS;
 
  //die folgende Struktur wird nur für die Übermittlung des
  //RAM_Ctrl-DS vom Master an den RAM_Slave benötigt:
  RAM_Dat_Rx[@TWIRXBUFF]   : TRAMSlaveRec; // Empfangsdaten wie Sendedaten
  //
  WDS_MiW                  : TMiWerteRec;  //für Mittelwerte

  RAM_WDS_A                : TRAM_DS;      // nur für Controlsum-Proc
  RAM_RecDS[@RAM_WDS_A]    : TRAMDATENRe c;
  DS_Saved                 : boolean;
  RAM_Wr_Snr               : word;         // Schreibadresse

  RAM_DS_sent              : boolean;
  DRec_erstellt            : boolean;
  RAMSlvStatus             : byte;
  MW_MittOkBits            : byte;
  MW_TempOkBits            : byte;

   h23_request             : boolean;
   tick_std                : boolean;
   sk                      : byte;
   ret                     : boolean;
   w                       : word;
   lw                      : longint;
   iw                      : integer;
   c1,c2,i,j,h             : byte;
   wadd                    : integer;
//   Ma_con_cnt              : word;
   Sl_prs_err              : word;



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



{--------------------------------------------------------------}
function GetSumCode(RAM_DS_:TRAM_DS):byte;
{--------------------------------------------------------------}
var ps:word;
begin
  ps := 0;
  for i := 1 to (RAMRecSize-1) do     // letztes Byte = prs
    ps := ps + word(RAM_DS_[i]);
  endfor;
  return(hi(ps) xor lo(ps));
end;


{--------------------------------------------------------------}
function TestSumCode(DS:TRAM_DS):boolean;
{--------------------------------------------------------------}
begin
  return(GetSumCode(DS) = DS[RAMRecSize]);
end;


{--------------------------------------------------------------}
function MesswertMitteln(mw:TMW):TMW;
{--------------------------------------------------------------}
// mw[4]  enthält den letzten aktuellen Wert
// mw[3]  enthält den letzten Mittelwert
// mw[2]  enthält die Summe der letzten Messwerte
// mw[1]  enthält die Anzahl der letzten Messwerte
begin
  if mw[1] > 0 then   // Divisor und Zähler
    if mw[3] <> 0 then
      inc(mw[1]);
      mw[2] := mw[2] + mw[3];
    endif;
    mw[3] := mw[2] div mw[1]; // neuer Mittelwert
  endif;
  mw[2]   := 0;  // Summenspeicher
  mw[1]   := 0;  // Divisor
  return(mw);
end;


{--------------------------------------------------------------}
function WindDirMittelWert(mw:TMW):longint;
{--------------------------------------------------------------}
begin
//Kat:
//Hier wird der letzte Mittelwert mit dem aktuellen Wert gemittelt
// mw[3]  enthält den letzten Mittelwert
// mw[2]  enthält den letzten Messwert
// mw[1]  wird als Hilfswert benötigt
  //
  if abs(mw[2] - mw[3]) > 180 then
    mw[1] := (mw[2] + mw[3] - 360) div 2;
    if mw[1] < 0 then
      mw[1] := mw[1] + 360;
    endif;
  else
    mw[1] := (mw[2] + mw[3]) div 2;
  endif;
  return(mw[1]);
end;


{--------------------------------------------------------------}
procedure DatenMittelwerteBerechnen;
{--------------------------------------------------------------}
begin
  with WDS_MiW do
    TempInn     := MesswertMitteln(TempInn);
    TempOut     := MesswertMitteln(TempOut);
    HumidityOut := MesswertMitteln(HumidityOut);
    WindSpeed   := MesswertMitteln(WindSpeed);
    //WindDir     separat
    WDS_MiW.WindDir[1] := 0;
    //Die Rücksetzung des Max-Wertes der Windgeschwindigkeit
    //erfolgt in der  procedure RAMDatenRecErstellen(mittelwerte:boolean);
    AirPressRel := MesswertMitteln(AirPressRel);
    DewPoint    := MesswertMitteln(DewPoint);
    RainTotal   := MesswertMitteln(RainTotal);
endwith;
end;


{--------------------------------------------------------------}
procedure DatenInMittelwertArrayEintragen;
{--------------------------------------------------------------}
//Die Mittelwerteintragung erfolgt mit jedem neuen Datensatz
//erst bei Anforderung des RAM-Datensatzes vom Master werden
//die Mittelwerte übernommen.
//  TMiWerteRec     = Record
//                      TempInnen     :Integer;   //1
//                      TempAussen    :Integer;   //2
//                      FeuchteOut    :Integer;   //3
//                      WindSpeed     :Integer;   //4
//                      WindDir       :Integer;   //5
//                      AirPressRel   :Integer;   //6
//                      Reserve       :Integer;   //7
//                      RainTotal     :Integer;   //8
//                    end;
//
//Bei der Übernahme eines ungstörten Wertes wird das Ok-bit
//gesetzt. Das gilt bis zur Übergabe an den Master,
//wonach alle Okbits wieder zurückgesetzt werden. Die Okbits
//werden vom low-bit gezählt, wobei Bit0 für den ersten Wert
//steht.
var MWStatus : word;
begin
  // setzt die OKBits
  // WstDaten ist vom Typ TWS2300SlaveDS
  //---Wert 1----------------------
  MWStatus := WStDaten.MW_Status;  // siehe WS_Slave
  iw := WStDaten.TempInnen;        // Wert ist mit 10 multipliziert
  if (iw < 450)and(iw > -120) then
    if (MWStatus and CTempInn) > 0 then //Wert wurde neu gemessen
      WDS_MiW.TempInn[2] := WDS_MiW.TempInn[2] + longint(iw);
      inc(WDS_MiW.TempInn[1]);     // Divisor
      MW_MittOkBits := MW_MittOkBits or 1;
    endif;
    WDS_MiW.TempInn[4] := longint(iw);
    MW_TempOkBits := MW_TempOkBits or 1;
  else
    MW_TempOKBits := MW_TempOKBits and %11111110;
  endif;
  //---Wert 2----------------------
  iw := WStDaten.Tempaussen; //Wert ist mit 10 multipliziert
  if (iw < 600)and(iw > -500) then
    if (MWStatus and CTempOut) > 0 then
      WDS_MiW.TempOut[2] := WDS_MiW.TempOut[2] + longint(iw);
      inc(WDS_MiW.TempOut[1]);
      MW_MittOkBits := MW_MittOkBits  or %00000010;
    endif;
    WDS_MiW.TempOut[4] := longint(iw);
    MW_TempOkBits := MW_TempOkBits  or %00000010;
  else
    MW_TempOKBits := MW_TempOKBits and %11111101;
  endif;
  //---Wert 3----------------------
  w := WStDaten.HumidityOut;  //Wert ist mit 10 multipliziert
  if (w < 1001)and(w > 0) then
    if (MWStatus and CHumyOut) > 0 then
      WDS_MiW.HumidityOut[2] := WDS_MiW.HumidityOut[2] + longint(w);
      inc(WDS_MiW.HumidityOut[1]);
      MW_MittOkBits := MW_MittOkBits  or %00000100;
    endif;
    WDS_MiW.HumidityOut[4] := longint(w);
    MW_TempOkBits := MW_TempOkBits  or %00000100;
  else
    MW_TempOKBits := MW_TempOKBits and %11111011;
  endif;
  //---Windgeschwindigkeit 4-----------------------
  //keine MIttelwertbildung unterstützen, sondern Maximum suchen
  if WStDaten.WindFlag = 0 then
    WDS_MiW.WindSpeed[4] := longint(WStDaten.WindSpeed);  //momentan
    if (MWStatus and CWindSpd) > 0 then
      if WDS_MiW.WindSpeed[2] < WDS_MiW.WindSpeed[4] then //max suchen
        WDS_MiW.WindSpeed[2] := WDS_MiW.WindSpeed[4];     //neuer max
      endif;
      WDS_MiW.WindSpeed[1] := 1;                          //div immer 1
      MW_MittOkBits := MW_MittOkBits  or %00001000;
    endif;
    MW_TempOkBits := MW_TempOkBits  or %00001000;
  else
    MW_TempOKBits := MW_TempOKBits and %11110111;
  endif;
  //---Windrichtung 5------------xx---------
  if WStDaten.WindFlag = 0 then
    // Windrichtungswertebereich: 0..15
    // muss mit 22.5 multipliziert werden.
    // Hier wird der aktuelle Wert mit dem jew. letzten Wert gemittelt,
    // da eine einfache Mittelwertbildung der Werte keinen Sinn hat.
    if ((sk mod 3) = 0) then
      wadd := wadd *(-1);   //leichter Spin
    endif;
    lw := ((longint(WStDaten.WindDir[1]) * 225) div 10) +longint(wadd);
    if lw < 0 then
      lw := lw + 360;
    endif;
    if (MWStatus and CWindDir) > 0 then
      WDS_MiW.WindDir[2] := lw;
      WDS_MiW.WindDir[3] := WindDirMittelWert(WDS_MiW.WindDir);
      inc(WDS_MiW.WindDir[1]);
      MW_MittOkBits := MW_MittOkBits  or %00010000;
    endif;
    WDS_MiW.WindDir[4] := lw;
    MW_TempOkBits := MW_TempOkBits  or %00010000;
  else
    MW_TempOKBits := MW_TempOKBits and %11101111;
  endif;
  //---Wert 6----------------------
  w := WStDaten.AirPressRel; //Wert ist mit 10 multipliziert
  if (w > 8500)and(w < 12000) then
    if (MWStatus and CAirPress) > 0 then
      WDS_MiW.AirPressRel[2] := WDS_MiW.AirPressRel[2] + longint(w);
      inc(WDS_MiW.AirPressRel[1]);
      MW_MittOkBits := MW_MittOkBits  or %00100000;
    endif;
    WDS_MiW.AirPressRel[4] := longint(w);
    MW_TempOkBits := MW_TempOkBits  or %00100000;
  else
    MW_TempOKBits := MW_TempOKBits and %11011111;
  endif;
  //---Wert 7----------------------
  iw := integer(WStDaten.DewPoint div 10); //
  if (iw > -10000)and(iw < 12000) then        //????
    if (MWStatus and CDewPoint) > 0 then
      WDS_MiW.DewPoint[2] := WDS_MiW.DewPoint[2] + longint(iw);
      inc(WDS_MiW.DewPoint[1]);
      MW_MittOkBits := MW_MittOkBits  or %01000000;
    endif;
    WDS_MiW.DewPoint[4] := longint(iw);
    MW_TempOkBits := MW_TempOkBits  or %01000000;
  else
    MW_TempOKBits := MW_TempOKBits and %10111111;
  endif;
  //---Wert 8----------------------
  if (WStDaten.RainTotal < 51000) then // Wert ist mit 100 multipliziert
    //keine Mittelwertbildung sinnvoll
    WDS_MiW.RainTotal[3] := longint(WStDaten.RainTotal);
    WDS_MiW.RainTotal[2] := longint(WStDaten.RainTotal); { stehen lassen}
    WDS_MiW.RainTotal[4] := longint(WStDaten.RainTotal); {}
    WDS_MiW.RainTotal[1] := 1;
    MW_MittOkBits := MW_MittOkBits  or %10000000;
    MW_TempOkBits := MW_TempOkBits  or %10000000;
  else
    MW_TempOKBits := MW_TempOKBits and %01111111;
  endif;
end;


{--------------------------------------------------------------}
procedure RAMDatenRecErstellen(mittelwerte:boolean);
{--------------------------------------------------------------}
// Daten werden immer ab Snr 1 bis RAM_MAX_Snr gespeichert und dann
// wird RAM_voll gesetzt. Die Datensicherung läuft jedoch weiter
// und überschreibt nicht abgeholte Daten. Die Speichernazeige
// LCDbuf.RAMCapacity bleibt jedoch auf 100% stehen bis PC Daten
// übernimmt.
// da jeder DS seine Zeitstempel bekommt, kann PC archivieren
// ind = 4 liest die Momentanwerte aus
// ind = 3 liest die berechneten Mittelwerte aus
var ind :byte;
begin
  //
  if mittelwerte then
     DatenMittelwerteBerechnen;
     RAM_RecDS.OkBits := MW_MittOKBits;
     ind := 3; //3 liest die berechneten Mittelwerte aus
  else
     RAM_RecDS.OkBits := MW_TempOKBits;
     ind := 4; //4 liest die aktuellen Werte aus
  endif;
  //....................................
  //jetzt den Zeitstempel in den aktuellen DS eintragen:
  RAM_RecDS.Rec_jj    := WstDaten.Date[3];
  RAM_RecDS.Rec_mm    := WstDaten.Date[2];
  RAM_RecDS.Rec_dd    := WstDaten.Date[1];
  RAM_RecDS.Rec_hh    := WstDaten.Time[1];
  RAM_RecDS.Rec_mi    := WstDaten.Time[2];
  //....................................
  //
  RAM_RecDS.TempInn     := integer(WDS_MiW.TempInn[ind]);
  RAM_RecDS.TempOut     := integer(WDS_MiW.TempOut[ind]);
  RAM_RecDS.HumidityOut := word(WDS_MiW.HumidityOut[ind]);
  RAM_RecDS.AirPressRel := word(WDS_MiW.AirPressRel[ind]);
  RAM_RecDS.WindSpeed   := word(WDS_MiW.WindSpeed[ind]);
  RAM_RecDS.WindDir     := word(WDS_MiW.WindDir[ind]);
  RAM_RecDS.DewPoint    := Word(WDS_MiW.DewPoint[ind]);
  RAM_RecDS.RainTotal   := word(WDS_MiW.RainTotal[ind]); {ist kein Mittelwert!!}
  // RAM_RecDS.OKBits wurden in DatenMittelwerteBerechnen gesetzt
  RAM_RecDS.crs         := GetSumCode(RAM_WDS_A); //RAM_Rec overlays RAM_WDS
  //
  // Daten in den Sendepuffer eintragen:
  NetTxRec.WetterDS  := RAM_RecDS;
  //
  if ind = 3 then
    WDS_MiW.WindSpeed[3] := 0; // wegen neuer Maximumbildung
  endif;
  //
end;


{==============================================================}
Process RxMasterFrame(40, 80 : iData);
{==============================================================}
var err : byte;
begin
  WaitSema(TWIrxSEMA);
  case NetRxRec.cmd of         // 1.Byte wie in RAM_Dat_Rx
    cmd_01:
        WstDaten := NetRxRec;  // Datenübernahme Wetterdaten + Zeit
        if not RAM_DS_sent then
          DatenInMittelwertArrayEintragen; // Daten vom Master übernehmen
          if not DRec_erstellt then
            RAMDatenRecErstellen(true);
            //Rücksetzen aller OK-Bits nur an dieser Stelle
            RAM_RecDS.OkBits := 0; // jeder MW wird ok=1 oder ok=0 gesetzt
            //für die temporären Messwerte über cmd_02 gilt zusätzlich:
            MW_TempOKBits := $FF; // jeder MW wird ok=1 oder ok=0 gesetzt
            DRec_erstellt := true;
          endif;
        endif;
        mdelay(100);
        NetTxRec.cmd := cmd_07;  // Quittung für kompl RAM_DS
        if TWItxFrame(02, byte(sizeOf(TRAMSlaveRec))) then // Senden des RAM_DS
          RAM_DS_sent   := true;  // siehe unter cmd_01
          DRec_erstellt := false;
        endif;
        |
    cmd_02: //Datenübernahme Wetterdaten + Zeit wie bei cmd_01, mit
        // dem Unterschied, dass hier nur eine temporärer DS zurück-
        //gesendet wird, der für Anzeigezwecke verwendet werden kann.
        WstDaten    := NetRxRec;
        RAM_DS_sent := false;
        DatenInMittelwertArrayEintragen; //Daten vom Master übernehmen
        RAMDatenRecErstellen(false); //false= keine Mittelwerte bilden
        MW_TempOKBits := $FF; //jeder MW wird ok=1 oder ok=0 gesetzt
        //mdelay(5);
        NetTxRec.cmd:= cmd_01;  // Quittung für temp. RAM_DS
        TWItxFrame(02, byte(sizeOf(TRAMSlaveRec))); //Senden des RAM_DS
        |
  endcase;
  //
  mdelay(50);
  TWIRXCLEAR;    // !!!
end;


{==============================================================}
Process RxBroadcastFrame(40, 80 : iData);
{==============================================================}
begin
  WaitSema(TWIbroadcastSema);
  case TWIbroadcastCMD of
    ClearBuffer   : TWIrxClear;         // remove deadlocks
                    TWItxClear;
                  |
  endcase;
end;


{--------------------------------------------------------------}
procedure InitPorts;
{--------------------------------------------------------------}
begin
  DDRB:=  %00000110;
end InitPorts;


{--------------------------------------------------------------}
procedure InitVar;
{--------------------------------------------------------------}
begin
  h23_request   := false;
  tick_std      := true;
  //Ma_con_cnt  := 0;
  Sl_prs_err    := 0;
  DS_Saved      := false;
  RAM_DS_sent   := false;
  DRec_erstellt := false;
  RAMSlvStatus  := 0;
  MW_TempOKBits := $FF;
  wadd := -1;
end;


{==============================================================}
{ Main Program  WS2300-Datenlogger-Master}
{$IDATA}

begin
  InitPorts;
  InitVar;
  EnableInts;
  //---------------------------------
  TWIadrMask:= $FF;

  Priority(main_proc, 2);
  Start_Processes;
  TWIrxClear; //erst nach Start_Processes !
  TWItxClear;


 
  //==================Hauptschleife===================

  loop
    //
    mdelay(810);
    if sk > 59 then
      sk := 0;
    endif;
    inc(sk);
    //---------------
    DisableInts;
      if (WstDaten.Time[1] = 23) and (h23_request) then
          h23_request := false;
      endif;
      if WstDaten.Time[1] = 22 then // 22 Uhr
          h23_request := true;
      endif;
    EnableInts;

  endloop;
 
end WS2300_RAM.