{**************************************************************}
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.