{**************************************************************}
program WS2300_Slave;
{ S.Taborek - Beginn: 28.02.2005}
{ Modul für die Verbindung zur Wetterstation WS2300}
{ Stand : 22.05.2005}
{ Stand : 03.06.2005}
{**************************************************************}


{$NOSHADOW}
Device = mega8, VCC=4.8;

(*
Define_Fuses
  LockBits0 = [];
  FuseBits0 = [CKSEL0, CKSEL1, CKSEL3, SUT0, BODEN];
  FuseBits1 = [];
  ProgMode  = SPI;    *)


Import SysTick, RTclock, SerPort, TWINet;

From System Import random, longword, Processes;

Define
  ProcClock      = 16000000;       {Hertz}
  SysTick        = 10;             {msec}
  StackSize      = $0096, iData;
  FrameSize      = $0064, iData;
  Scheduler      = iData;
  //
  SerPort        = 2400, Stop1;    {Baud, StopBits|Parity}
  RxBuffer       = 32, iData;
  TxBuffer       = 32, iData;
  //
  TWInetMode     = Slave;
  TWInode        = $03;             {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}
  RTCsource      = SysTick;
 
//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überwachg. 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;


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

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

type
  T4nibble = array[1..4] of byte;
//  TReply   = array[0..31]of Byte;
  TStr10   = String[10];
 
  TWS_Zug  = array[1..2] of word;
  TWS_REQ  = array[1..5] of byte;
 
  tWSRxRec = record
                Cmd     : byte;
                ww      : word;
                stM     : tStr10;
              end;


{--------------------------------------------------------------}
{ Const Declarations }
const
// TxFrameSize  : byte  = sizeOf(TWSTSlaveDS);

// TimeoutLimit :byte  = 160;  //für Timeoutüberwachung
pot10        : array[1..6]of longword = (1, 10, 100, 1000, 10000, 100000);


UHRZEIT         :TWS_Zug         = ($200,06);
DATUM           :TWS_Zug         = ($23B,11);

TEMPERATURE_INN :TWS_Zug         = ($346,3);

TEMPERATURE_OUT :TWS_Zug         = ($373,3);

DEWPOINT        :TWS_Zug         = ($3CE,7);

HUMIDITY_INN    :TWS_Zug         = ($3FB,2);

HUMIDITY_OUT    :TWS_Zug         = ($419,2);

RAIN_1H         :TWS_Zug         = ($4B4,6);

// RAIN_24H     :TWS_Zug         = ($497,6);

RAIN_TOTAL      :TWS_Zug         = ($4D2,8);

// SENSOREXT    : TWS_Zug        = ($54D,1);

WIND            :TWS_Zug         = ($527,6);

REL_DRUCK       :TWS_Zug         = ($5E2,5);

RainTotClear    :TWS_Zug         = ($4D1,7);
{--------------------------------------------------------------}
{ Var Declarations }
{$IDATA}
var
  NetRxRec[@TWIrxBuff]     : tWSRxRec;
  NetTxRec[@TWItxBuff]     : TWSTSlaveDS;

   TxDS           :TWSTSlaveDS;
  
   tick_min       :boolean;
   tick_std       :boolean;

   ret            :boolean;
   wsconnect      :boolean;
   nib            :T4nibble;
   bcnt           :byte;
   dd_cnt         :byte;
   WSReply        :TReply;
   wsContr        :byte;
  
   w              :word;
   iw             :integer;
   lw             :longint;
   c,i,j,h        :byte;
   RTC_Sync       :boolean;
   RTC_DCF        :boolean; // true nach der ersten Synchronisation

   st, mi, se     :byte;
   zeit1          :array[1..3] of byte;
   dd, mm, jj     :byte;
   date1          :array[1..3] of byte;

   WScon_cnt      :word;
   WScon_err      :word;
   WSqui_err      :word;
   WSprs_err      :word;
   WStio_err      :word;

   SLcon_cnt      :word;
   SLcon_err      :word;
   SLqui_err      :word;
   SLprs_err      :word;
   SLtio_err      :word;


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


{==============================================================}
procedure RTC_Lesen;
{==============================================================}
begin
  disableints;
   se := RTCGetSecond;
   mi := RTCGetMinute;
   st := RTCGetHour;
   dd := RTCGetDay;
   mm := RTCGetMonth;
   jj := RTCGetYear;
  enableints;
  // den Sendepuffer nur mit gesicherten Daten füllen:
  if RTC_DCF then    // erste Sync am Tag schon erfolgt?
    zeit1[1] := st;
    zeit1[2] := mi;
    zeit1[3] := se;
    date1[1] := dd;
    date1[2] := mm;
    date1[3] := jj;
  else
    for i := 1 to 3 do
      zeit1[i] := 90;
      date1[i] := 90;
    endfor;
  endif;
end;


{==============================================================}
Process RxMasterFrame(40, 80 : iData);
{==============================================================}
// cmd=1 bedeutet, dass der Slave die Wetterdaten senden soll
begin
  WaitSema(TWIrxSEMA);
  if NetRxRec.cmd = cmd_01 then
    RTC_Lesen;  // für Zeitstempel  füllt zeit1 und date1
      TxDS.Time := zeit1;
      TxDS.Date := date1;
      TxDS.cmd  := cmd_09;
      NetTxRec  := TxDS;    // Daten übergeben
      mdelay(100);
      TWItxFrame(02, TxFrameSize); // Senden
    TXDS.MW_Status := 0;   // Vorbereitung der neuen Sendung
  endif;

  TWIRXCLEAR;    //

end;


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


{==============================================================}
procedure RTCtickSecond;      // CallBack from RTCclock
begin
end;

procedure RTCtickMinute;      // CallBack from RTCclock
begin
  tick_min := true;
end;

procedure RTCtickHour;        // CallBack from RTCclock
begin
   tick_std := true;
end;




{==============================================================}
procedure RTC_Uhr_Stellen(std_, mi_, se_:byte);
{==============================================================}
begin
  disableints;
   RTCsetSecond(se_);
   RTCsetMinute(mi_);
   RTCsetHour(std_);
  enableints;
  RTC_DCF := true;     // wird täglich 1 mal zurückgesetzt
end;


{==============================================================}
procedure RTC_Datum_Stellen(dd_, mm_, jj_:byte);
{==============================================================}
begin
  disableints;
   RTCsetDay(dd_);
   RTCsetMonth(mm_);
   RTCsetYear(jj_);
  enableints;
end;


{==============================================================}
procedure InitPorts;
{==============================================================}
begin
//  DDRB:=  %00000010;
end InitPorts;


{--------------------------------------------------------------}
procedure SIOPufferLeeren;
{--------------------------------------------------------------}
begin
  while serstat do
    mdelay(10);
    c := serinp;    //Puffer leeren
  endwhile;
end;


{--------------------------------------------------------------}
function WS2300SendByte(sbf, ebf:byte; qb:boolean):boolean;
{--------------------------------------------------------------}
var cnt:byte;
// wenn qb=true, dann wird das Quittungsbyte geprüft
begin
  ret :=false;
  mdelay(13);
  serout(sbf);
  cnt := 0;
  repeat
    if cnt > 0 then
      mdelay(18);
    endif;
    inc(cnt);
  until (serstat)or(cnt = TimeoutLimit); // max 2sec
  if (cnt < TimeoutLimit) then
    c := serinp;                    // lesen der Schnittstelle
    if (c = ebf) or (not qb) then   // erwartete Quittung
      ret :=true;
    else
      //      inc(WSqui_err);
    endif;
  else
    //    inc(WStio_err);
  endif;
  Return(ret);
end;


{--------------------------------------------------------------}
procedure WS2300_Reset;
{--------------------------------------------------------------}
begin
  WS2300SendByte($06, $02, false);
  WS2300SendByte($06, $02, false); //Reset WS
end;


{--------------------------------------------------------------}
function WS2300Connected:boolean;
{--------------------------------------------------------------}
var i1:byte;
    v:boolean;
begin
  mdelay(200);
  i1 := 0;
  // es werden 3 Verbindungsversuche gemacht:
  repeat
    if i1 > 0 then
      mdelay(2500);  // warten vor dem nächsten Versuch
    //      inc(WScon_err);
    endif;
    SIOPufferLeeren;
    inc(i1);
    v := WS2300SendByte($06, $02, true);
  until v or(i1 = 3{max_v});
  if v then
    //    inc(WScon_cnt);
    TxDS.WSS_Slv_Status := TxDS.WSS_Slv_Status or 1;
    return(true);
  else
    WS2300_Reset;
    WScon_cnt := 0;  // ?
    TxDS.WSS_Slv_Status := TxDS.WSS_Slv_Status and %11111110;
    return(false);
  endif;
end;


{--------------------------------------------------------------}
procedure WordToNibbles(w:word);
{--------------------------------------------------------------}
begin
  nib[1] := hi(w) shr 4;
  nib[2] := hi(w) and $0F;
  nib[3] := lo(w) shr 4;
  nib[4] := lo(w) and $0F;
end;


{--------------------------------------------------------------}
function WS2300Lesen(z:TWS_Zug):TReply;
{--------------------------------------------------------------}
var bcnt,cnt1,i1,j1, sb, qb:byte;
    adr, sum :word;
// Abbruch der Funktion mit WSReply[0]=0  bedeutet, dass die Daten
// nicht oder nicht ungestört empfangen wurden
begin
  adr := z[1];
  bcnt:= byte(z[2]);
  WSReply[0] := 0;   // Anzahl der empfangenen Bytes
  // zuerst prüfen, ob WS2300 angeschlossen und bereit:
  if not wsconnect then
    if (not WS2300Connected) then
      wsconnect := false;
      return(WSReply);
    else
      wsconnect := true;
    endif;
  else
    SIOPufferLeeren;
  endif;
  //
  WordToNibbles(adr); //die Adr in Nibbles wandeln
  // 4 Adress-Nibble werden gesendet von hi nach lo
  for j1 := 1 to 4 do
    sb := $82 + (nib[j1] * 4);
    qb := ($10 *(j1 -1))+ nib[j1];
    if not WS2300SendByte(sb, qb, true) then
      wsconnect := false;
      return(WSReply); // Abbruch mit WSReply[0]=0
    endif;
  endfor;
  // nun folgt das Lesekommando:
  sb := bcnt * 4 + $C2; // Anfordern der gewünschten Zahl Bytes
  qb := $30 + bcnt;
  if not WS2300SendByte(sb, qb, true) then
    wsconnect := false;
    return(WSReply);  // Abbruch, mit WSReply[0]=0
  endif;
  //
  // nun Datenblock der Länge bcnt und ein Prüfbyte auslesen:
  i1 := 0;
  j1 := 0;
  repeat
    inc(i1);
    inc(j1);
    cnt1 := 0;
    repeat
      if cnt1 > 0 then
        mdelay(8);
      endif;
      inc(cnt1);
    until (serstat)or(cnt1 = TimeOutLimit);
    if (cnt1 < TimeOutLimit) then
      WSReply[j1] := serinp;   // Lesen von WS
      inc(j1);  // 2.Stelle freilassen für Nibble-Code
    else
      //Timeout
      inc(WStio_err);
      wsconnect := false;
      return(WSReply); // Abbruch, mit WSReply[0]=0
    endif;
  until (i1 = bcnt + 1)or(cnt1 > TimeOutLimit);
  //
  if (cnt1 > TimeOutLimit) then
    wsconnect := false;
    return(WSReply);   //Abbruch, mit WSReply[0]=0
  endif;
  // das letzte empfangene Byte ist das Summenbyte
  //........................
  // nun die Prüfsumme kontrollieren:
  sum := 0;
  j1 := 1;
  for i1 := 1 to bcnt do
    sum := sum + word(WSReply[j1]);
    inc(j1,2);
  endfor;
  sum := sum and $00FF; //relevant ist nur der lo-Teil
  if (sum <> word(WSReply[(2 * bcnt) + 1])) then  // Prüfsumme falsch
    inc(WSprs_err);
    return(WSReply);   //Abbruch, mit WSReply[0]=0
  else
  endif;
  // jedes Byte enthält im hi- und lo-Teil eine Dezimalziffer
  //
  // Daten in Nibbles wandeln:
  j := 1;
  for i1 := 1 to bcnt do
    h := WSReply[j];
    WSReply[j]   := h and $0F;
    WSReply[j+1] := h shr 4;
    j := j + 2;
  endfor;
  WSReply[0] := bcnt; // Anzahl der gelesenen Bytes
  return(WSReply);
end;


{--------------------------------------------------------------}
function DCFZeitLesen:boolean;
{--------------------------------------------------------------}
var ret:boolean;
begin
  ret := false;
   WSReply := WS2300Lesen(Uhrzeit);
  // in WSReply steht: SE,SZ,ME,MZ,HE,HZ
  if (WSReply[0] > 0) then
    se := (WSReply[1] + WSReply[2]*10);
    mi := (WSReply[3] + WSReply[4]*10);
    st := (WSReply[5] + WSReply[6]*10);
    //
    WSReply := WS2300Lesen(Datum);
    if (WSReply[0] > 0) then
      dd := (WSReply[6] + WSReply[7]*10);   //dd
      mm := (WSReply[8] + WSReply[9]*10);   //mm
      jj := (WSReply[10] + WSReply[11]*10); //jj
      ret := true;
    endif;
  endif;
  if ret then
      TxDS.WSS_Slv_Status := TxDS.WSS_Slv_Status or 2;
  else
      TxDS.WSS_Slv_Status := TxDS.WSS_Slv_Status and %11111101;
  endif;
  Return(ret);
end;


{--------------------------------------------------------------}
function WertHolen(z:TWS_Zug):boolean;
{--------------------------------------------------------------}
// ...das alles und mehr, weil der 8KB ROM nicht reicht
begin
  h := 0;
  repeat
    mdelay(400);
    WSReply := WS2300Lesen(z);
    inc(h);
  until (WSReply[0] > 0) or (h > 3);
  return(WSReply[0] > 0);
end;


{--------------------------------------------------------------}
function TemperaturLesen(z:TWS_Zug):integer;
{--------------------------------------------------------------}
begin
  if WertHolen(z) then
    // temperatur = ((nib4*10 + nib3), nib2) -30
    // der gelesene Wert wird mit 10 multipliziert zurückgegeben
    w := word(WSReply[4])* 100 + (word(WSReply[3])* 10) +
         word(WSReply[2]);
    return(integer(w) - 300);  // -30 Grad ist Grenzwert
  else
    return(-1000);
  endif;
end;


{--------------------------------------------------------------}
function BCDWert(WSR:TReply; anz:byte):longint;
{--------------------------------------------------------------}
var lw_:longint;
begin
  lw_ := 0;
  for i := 1 to anz do
    lw_ := lw_ + longint(WSR[i]) * longint(pot10[i]);
  endfor;
{lw_ := longint(WSR[6]) * 100000 + longint(WSR[5]) * 10000 +
       longint(WSR[4]) * 1000   + longint(WSR[3]) * 100 +
       longint(WSR[2]) * 10     + longint(WSR[1]); }
  return(lw_);
end;


{--------------------------------------------------------------}
procedure WS2300DatenPuffern(nr:byte);
{--------------------------------------------------------------}
(*          1         TempInnen      : Integer;
            2         TempAussen     : Integer;
            3         HumidityInn    : Word;
            4         HumidityOut    : Word;
            5         WindFlag       : byte;
            6         WindCode       : Byte;
            7         WindSpeed      : word;
            8         WindDir        : array[1..7]of byte;
            9         AirPressRel    : Word;
           10         Rain1H         : word;
           11         RainTotal      : word;
           12         DewPoint       : Word;
           13         Reserve        : byte;
           14         WSSensorExt    : byte;       *)
begin
  //
  //Das Byte MW_Status gibt dem RAM_Slave bekannt, welche Werte neu
  //gemessen wurden, damit nicht alte Messwerte wieder in die Mittel-
  //wertberechnung übernommen werden.
  //Das Byte wird zurückgesetzt unmittelbar nach dem die Werte an den
  //Master gesendet wurden.
  case nr of
  1: // Temperaturwerte sind mit 10 multipliziert
     TXDS.TempInnen  := TemperaturLesen(TEMPERATURE_INN);
     TXDS.MW_Status := CTempInn;
     TXDS.TempAussen := TemperaturLesen(TEMPERATURE_OUT);
     TXDS.MW_Status := TXDS.MW_Status or CTempOut;
     |
  2: if WertHolen(HUMIDITY_INN) then
       TXDS.HumidityInn := word(BCDWert(WSReply, 2) * 10);
       TXDS.MW_Status := TXDS.MW_Status or CHumyInn;
     else
       TXDS.HumidityInn := 254;
     endif;
     |
  3: if WertHolen(HUMIDITY_OUT) then
       TXDS.HumidityOut := word(BCDWert(WSReply, 2) * 10);
       TXDS.MW_Status := TXDS.MW_Status or CHumyOut;
     else
       TXDS.HumidityOut := 254;
     endif;
     |
  4: if WertHolen(REL_DRUCK) then
       //WS-Wert ist BCD-codiert:
       //Wert ist mit 10 multipliziert   hPa
       TXDS.AirPressRel := word(BCDWert(WSReply, 5));
       TXDS.MW_Status := TXDS.MW_Status or CAirPress;
     else
       TXDS.AirPressRel := 5;
     endif;
     |
  5: if WertHolen(Wind) then
       TXDS.WindFlag  := WSReply[1];
       TXDS.WindCode  := WSReply[2];
       //------Windgeschwindigkeit----------
       // WS_Wert ist binär-codiert:    !!!  (nicht BCD)
       //Wert ist mit 10 multipliziert  m/sec
       w := word(WSReply[5])* 256 + word(WSReply[4])* 16 + word(WSReply[3]);
       if w <> 510 then    //Fehler der WS2300
         TXDS.WindSpeed := w;
         TXDS.MW_Status := TXDS.MW_Status or CWindSpd;
       endif;
       //-------Windrichtungen: 1-6---------
       for i := 6 to 11 do
         TXDS.WindDir[i-5] := WSReply[i];    // aktuelle Richtungen
       endfor;
       TXDS.MW_Status := TXDS.MW_Status or CWindDir;
     else
       TXDS.WindFlag  := 7; //Störung
       TXDS.WindCode  := 7;
       TXDS.WindSpeed := 9999;
       TXDS.WindDir[1] := 254;
     endif;
     |
  6: if WertHolen(DEWPOINT) then
       //WS_Wert ist BCD-codiert:
       TXDS.DewPoint := word(BCDWert(WSReply, 6));  // ??????
       TXDS.MW_Status := TXDS.MW_Status or CDewPoint;   //12
     else
       TXDS.DewPoint := $E1F1;
     endif;
     |
  7: if WertHolen(RAIN_1H) then
       //WS_Wert ist BCD-codiert:
       //Wert ist ist 100 multipliziert
       TXDS.Rain1H := word(BCDWert(WSReply, 6));
       TXDS.MW_Status := TXDS.MW_Status or CRain1H;   // 10
     else
       TXDS.Rain1H := $9FF0;
     endif;
     |
     //
  8: if WertHolen(RAIN_Total) then
       //WS_Wert ist BCD-codiert:
       //Wert ist ist 100 multipliziert
       lw := (BCDWert(WSReply, 6)); // lw falls irgendwann Rain > word-bereich
       TXDS.RainTotal := word(lw);
       TXDS.MW_Status := TXDS.MW_Status or CRainTot;  //11
       //
       if lw >= 50000 then   //nie mehr als 500mm Regen messen, sonst reset
         WSReply := WS2300Lesen(RainTotClear); //Reset-Commando
         //es muss auf 4D8 bis 4E1 der Zeit-Datensatz geschrieben werden !!! fehlt
noch
        endif;
     else
       TXDS.RainTotal := $FFF0;   //65520
     endif;
     |
     (*  // ROM reichte nicht
  9: if WertHolen(SENSOREXT) then
       TXDS.WSSensorExt  := WSReply[1];
       TXDS.MW_Status := TXDS.MW_Status or CWSSensExt;
     else
       TXDS.WSSensorExt  := 254;
     endif;
     |    *)
  endcase;
  TxDS.WSconnerr := WScon_err;
//TxDS.WSQuitErr := WSqui_err;
end;


{--------------------------------------------------------------}
procedure InitVar;
{--------------------------------------------------------------}
begin
  tick_std  := true;
  tick_min  := true;
  WScon_cnt := 10;
  WSqui_err := 0;
  WSprs_err := 0;
  RTC_Sync  := false;
  dd_cnt    := 60;     // stehen lassen
  TXDS.MW_Status := 0;
end;


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

begin
  InitPorts;

  InitVar;
  EnableInts;
  //.......................
  TWIadrMask:= $FF;

  Priority(main_proc, 2);
  Start_Processes;
  TWIrxClear; // erst nach Start_Processes !
  TWItxClear;
  //
  WS2300_Reset;
  RTC_Sync := false;
  RTC_DCF  := false;
  repeat
    if DCFZeitLesen then // Uhrzeit und Datum aus WS2300
      RTC_DCF := true;
    else
      mdelay(1000);
    endif;
  until RTC_DCF; // wenn DCF-Zeit gelesen, dann RTC_Sync = true
 
  //================Hauptschleife=================
 
  loop
    inc(wsContr);
    if wsContr > 9 then   //max-case
      wsContr := 0;
    endif;
    WS2300DatenPuffern(wsContr);
   
    if tick_min then
      tick_min := false;
      if tick_std then
        tick_std := false;
        if (dd <> dd_cnt) and (RTC_sync) then
           dd_cnt  := dd;
           RTC_DCF := false;  // wird in RTC_Uhr_Stellen true
        endif;
        if DCFZeitLesen then
          RTC_Sync := true;
          RTC_Uhr_Stellen(st, mi, se);
          RTC_Datum_Stellen(dd, mm, jj);
        else
          RTC_Sync := false;
          tick_std := true;
        endif;
      endif;
    endif;
    mdelay(2005);

  endloop;
 
end WS2300_Slave.

Projekt Datenlogger für Wetterstation WS2300

Quelltext: Slave1-Modul