Projekt Datenlogger für Wetterstation WS2300

Quelltext: LCD-Anzeige und Datenaufbereitung
{**************************************************************}
program WS2300_LCD;
{S.Taborek Beginn 04.04.2005}
{Stand: 30.05.2005}
{Programm für alle Anzeigen am Datenlogger ab Version 1.2}
{**************************************************************}



{$NOSHADOW}
{ $LCDNOINIT}               {LCD unbedingt später initialisiern}

Device = mega8, VCC=4.9;

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

From System Import  longword, Processes;

Define
  ProcClock      = 8000000;        {Hertz}
  SysTick        = 10, Timer2;     {msec}
  StackSize      = $0064, iData;
  FrameSize      = $0064, iData;
  TWInetMode     = Slave;
  TWInode        = 05;             {default address in slave mode}
  TWIpresc       = TWI_BR100;      {Bitrate}
  TWIframe       = 54, iData;      {buffer/packet size}
  TWIframeBC     = 4;              {Broadcast Frame size}
  LCDport        = PortD;
  LCDtype        = 44780;
  LCDrows        = 4, 2;           {rows, enables}
  LCDcolumns     = 40;             {columns per line}
  RTClock        = iData, DateTime;{Time, DateTime}
  RTCsource      = SysTick;
  Scheduler      = iData;

//uses Unit_Types;

Implementation

{$IDATA}


//_________UNIT_________________________

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


{$IDATA}
{--------------------------------------------------------------}
{ Type Declarations }
type
{$IDATA}
//common:

  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 Teil II }

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;


//________________________________________


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

type
  TNetTxRec  = Record
                 cmd:byte;
                 ww      : word;
                 stM:string[28];
               end;


  TMasterRxDS = Record
                  cmd            : byte;
                  qui            : byte;
                end;
              

{--------------------------------------------------------------}
{ Const Declarations }
const
  LCD_Cols    : byte  = 27;
  TxFrameSize : byte  = sizeOf(tNetTxRec);
 
  // Zeilen/Spalten für die Anzeige der Daten:
  zpos        : array[1..8]of byte = (2, 2, 3, 3, 4, 4, 4, 4) ;
  spos        : array[1..8]of byte = (1, 16, 1, 16, 1, 8, 16, 23) ;

{$EEPROM}
Structconst
  ls1:string =  -- WDatenLogger 1.3 -- ; // !!!
  ls2:string =  Wetterdaten von WS2300 ;
  ls3:string =  S.Taborek 2005 ;


{--------------------------------------------------------------}
{ Var Declarations }
{$IDATA}
var
  NetRxRec[@TWIrxBuff]     : TWSTSlaveDS;
  NetTxRec[@TWItxBuff]     : tNetTxRec;
 
  Ma_RxRec[@TWIrxBuff]     : TMasterRxDS;
 
  WstDaten                 : TWSTSlaveDS;

  MaRxDaten                : TMasterRxDS;

  h                        : byte;
  i,j                      : byte;
  cmd, anz                 : byte;
  s1                       : string[27];
  t                        : array[1..8] of string[14];
  w                        : word;
  lw                       : longword;
  se, mi, st               : byte;
  dd, mm, jj               : byte;
  sec_cnt                  : byte;
  rg                       : boolean;
  dcf_time                 : boolean;
  sectick                  : boolean;
  mintick                  : boolean;
  stdTick                  : boolean;
  TimeShow                 : boolean;

  Timer1                   : SysTimer;  // für die explizite Uhr


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

procedure RTCtickSecond;      // CallBack from RTCclock
begin
  SecTick := true;
end;

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

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


{--------------------------------------------------------------}
procedure Init_Var;
{--------------------------------------------------------------}
begin
//  TimeShow := false;
  minTick  := false;
  sec_cnt  := 0;
  se := 0;
  mi := 0;
//  st := 0;
  dd := 1;
  mm := 1;
  jj := 5;
  SetSysTimer(Timer1, 100); //ca. 100 * SysTick = 1 Sec
end;


{--------------------------------------------------------------}
procedure LCD_Clear;
{--------------------------------------------------------------}
begin
  LCDUpper;
  LCDClr;
  LCDLower;
  LCDClr;
end;


{--------------------------------------------------------------}
procedure SetCursor(spa_, zle_:byte);
{--------------------------------------------------------------}
begin
// diese Proz. erhält die Spalten- und Zeilennummerierung
// des steuernden Rechners. d.h. Home = 1,1  und nicht 0,0 als
// Parameter. Da die importierten Proceduren aber 0,0 benutzen,
// wird die Cursorpos. hier umgerechent.
    zle_ := zle_ - 1;       // -1 , weil Pos bei 0 beginnen
    spa_ := spa_ - 1;
    if zle_ < 2 then
      LCDUpper;
    else
      LCDLower;
    endif;
    LCDXY(spa_, zle_);
end;


{--------------------------------------------------------------}
procedure LCD_Out(zle, spa:byte; s:string[27]);
{--------------------------------------------------------------}
begin
  SetCursor(spa, zle);
  if length(s) > 0 then
    write(LCDOut, s);
  endif;
end;


{--------------------------------------------------------------}
procedure LCD_Start;
{--------------------------------------------------------------}
begin
//  LCD_Clear;
  SetCursor(3, 1);
  write(LCDOut ,ls1); // !!!
  SetCursor(3, 2);
  write(LCDOut,ls2);
  SetCursor(5, 4);
  write(LCDOut,ls3);
  mdelay(3300);
  LCD_Clear;
end;


{--------------------------------------------------------------}
procedure Sekunden_Anzeige;
{--------------------------------------------------------------}
begin
// die Position der Strings wurde definiert
    s1 := ByteToStr(se:2: 0 );
    LCD_Out(1, 11, s1);
end;


{--------------------------------------------------------------}
procedure Uhr_Datum_Anzeige;
{--------------------------------------------------------------}
begin
  if dcf_time then
    s1 :=  DCF ;
  else
    s1 :=  Int ;
  endif;
  s1 := s1 +    ;
  s1 := s1 + ByteToStr(st:2: 0 ) +  :  +
             ByteToStr(mi:2: 0 ) +  :  +
             ByteToStr(se:2: 0 ) +       +
             ByteToStr(dd:2: 0 ) +  .  +
             ByteToStr(mm:2: 0 ) +  .20  +
             ByteToStr(jj:2: 0 ) +    ;

  LCD_Out(1, 1, s1);
end;


{--------------------------------------------------------------}
Process RxMasterFrame(40, 80 : iData);
{--------------------------------------------------------------}
begin
  WaitSema(TWIrxSEMA);
  WstDaten := NetRxRec;
  if WstDaten.cmd = cmd_08 then
    WstDaten := NetRxRec;  // Datenübernahme  Wetterdaten + Zeit
    // Quittung:
    //NetTxRec.cmd:= 107;
  endif;
  if WstDaten.cmd = 15 then
    MaRxDaten := Ma_RxRec;  // Datenübernahme   Masterdaten
    //Quittung:
    //NetTxRec.cmd:= 115;
  endif;

  TWItxFrame(02, byte(sizeOf(tNetTxRec))); // senden
  TWIRXCLEAR;    //

end;


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


{--------------------------------------------------------------}
function    DateTimeLesen_Stellen:boolean;
{--------------------------------------------------------------}
begin
  if WstDaten.cmd = 7 then
    if (WstDaten.Time[1] < 24){and(WstDaten.Time[2] < 60) and
       (WstDaten.Time[3] < 60)and
       (WstDaten.Date[1] > 0) and (WstDaten.Date[1] < 32)}and
       (WstDaten.date[2] > 0) and (WstDaten.date[2] < 13) and
       (WstDaten.date[3] > 0)and(WstDaten.date[3] < 99)  then
      //--------Uhr stellen---------
      if WstDaten.Time[3] < 58 then
        WstDaten.Time[3] := WstDaten.Time[3] +2;  //Übertragungszeitversatz
      endif;
      st  := WstDaten.Time[1];
      mi  := WstDaten.Time[2];
      se  := WstDaten.Time[3];
      dd  := WstDaten.Date[1];
      mm  := WstDaten.Date[2];
      jj  := WstDaten.Date[3];
     return(true);
    endif;
  endif;
  return(false);
end;


{--------------------------------------------------------------}
procedure DatenAnzeige;
{--------------------------------------------------------------}
var iw:integer;
begin
  with WstDaten do
    t[1] :=  RAM   + longtostr(WstDaten.RAMCapacity:7:3) +  % ;

    w := word(WStDaten.WindDir[1]) * 45 div 2; //
    if (w < 361) then
      t[2] :=  D:   + inttostr(w : 3) +   deg ;
    endif;

    w := WStDaten.AirPressRel; //Wert ist mit 10 multipliziert
    rg := not rg;
    if not rg then
      if ((w > 8400)and(w < 12000)) then
        t[3] :=  P:   + inttostr(w : 6 : 1) +  hPa  ;
      else
      endif;
    else
      w := WStDaten.RainTotal;
      if w < 50000 then //   <500mm
        t[3] :=  R:   + inttostr(w : 7 : 2) +  mm  ;  //Regen
      endif;
    endif;

    w := WStDaten.WindSpeed; //Wert ist mit 10 multipliziert
    if (w < 1000) then
      t[4] :=  V:   + inttostr(w : 4:1) +  m/s ;
    else
      t[4] :=  V: -- ;
    endif;

    h := Byte(WStDaten.HumidityInn div 10);  //Wert ist mit 10 multipliziert
    if (h < 101)and(h > 0) then
      t[5] :=  I:   + ByteTostr(h:2)+ %  ;
    else
      t[5] :=  I: -- ;
    endif;

    iw :=  WstDaten.Tempinnen; //Wert ist mit 10 multipliziert
    if (iw < 600)and(iw > -400) then
      t[6] := inttostr(iw:4:1) +  C ;
    else
      t[6] :=  --.- ;
    endif;

    h := Byte(WStDaten.HumidityOut div 10); //Wert ist mit 10 multipliziert
    if (h < 101)and(h > 0) then
      t[7] :=  A:   + ByteTostr(h:2)+ %  ;
    else
      t[7] :=  A: -- ;
    endif;

    iw := WStDaten.Tempaussen; //Wert ist mit 10 multipliziert
    if (iw < 600)and(iw > -400) then
      t[8] := inttostr(iw:4:1) +  C ;
    else
      t[8] :=  --.- ;
    endif;
  endwith;
  //
  for i := 1 to 8 do
    LCD_Out(zpos[i],spos[i], t[i]);
  endfor;
end;


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

begin
  Init_Var;
  EnableInts;
  mdelay(700);  //Zeit für Anschaltung des LCD-Processors
  LCD_Clear;    //erst jetzt initialisieren!  nach $LCDNOINIT

  LCD_Start;    //Basis-Ausschriften

  //  TWIadrMask:= $FF;

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

  TimeShow := true;
  dcf_time := false;
  //------------------------------
  Uhr_Datum_Anzeige;     //lokale Zeit 00:00
 
  //==============Hauptschleife================
  loop
 
    w := GetSysTimer(Timer1);
    if (w = 0) then  //nach einer sec
      inc(sec_cnt);
      if sec_cnt = 4 then
        sec_cnt := 0;
        DatenAnzeige;
        if not dcf_time then
          if DateTimeLesen_Stellen then
            dcf_time := true;
          endif;
        endif;
      endif;
      inc(se);
      if se > 59 then
        se := 0;
        mi := mi + 1;
        if (mi mod 6) = 0 then
          dcf_time := false; //stehen lassen !
        endif;
        if mi > 59 then
          mi := 0;
          st := st + 1;
          if st > 23 then st := 0; endif;
        endif;
        if TimeShow then
          Uhr_Datum_Anzeige;
        endif;
      endif;
      SetSysTimer(Timer1, 104);  // 104 ist der Eichfaktor
      if TimeShow then
        Sekunden_Anzeige;
      endif;
    endif{w = 0};

    mdelay(1); // nicht ändern, solange interner Oszillator !

  endloop;
 
end WS2300_LCD.