5. Mikrokontroller Software

Letztes Update: 08.12.2002


5.2 Software

5.2.1 Übersicht

Repeat
  Wenn interner Messzyklus erreicht Dann Scanne alle Sensoren
  Wenn Hauptmesszyklus erreicht     Dann Speicher alle Datensätze
  Wenn Befehl vom PC vorhanden      Dann Bearbeite Befehl
  Wenn Aktiver Sensor sich meldet   Dann Speicher Datensatz
  Wenn Datenübertragung aktiv       Dann Sende Datensatz
Until forever

5.2.2 Datenspeicherung

Jeder Kanal wird in einem definierten Zeitinterval gemessen = SubTime

Jeder Kanal wird in einem definierten Zeitinterval aufgezeichnet = MeasTime

Es gilt: MeasTime >= SubTime, wobei die MeasTime immer ein ganzes vielfaches der SubTime ist.

Die SubTime kann z.B. bei 10 Sekunden und die MeasTime bei 5 Minuten liegen, d.h. ein Meßwert besteht dann aus einem Mittelwert von 30 Messungen. Über das Meßinterval wird der größte und der kleinste Wert festgehalten. Es sollte immer bedacht werden, das sich die meisten Wettergrößen innerhalb kurzer Zeit nicht stark ändern. Die Änderungen erfolgen in der Regel in Stunden und nicht in Sekunden. Sollte also bei der Temperatur oder beim Luftdruck der Min- oder Maxwert stark vom Mittelwert abweichen, dann kann ein defekter Sensor oder eine defekte Elektronik vermutet werden. Durch die Mittelwertbildung mit der Min/Max Speicherung kann also eine geringe Aussage über die Qualität des Meßwertes gemacht werden kann.

Jeder Meßwert (im PC) besteht also aus vier Meßgrößen = DataSet

Für den Datenspeicher ist eine Kapazität von 16 MB in Form einer MultiMediaCard geplant. .

Geplant sind für die Wetterstation 64 Kanäle, die sich aus realen und berechneten Werten zusammensetzen.

Aufbau eines DataSets

Byte-Pos Bytes Inhalt Bemerkung
$0000..$0005

6

Zeit MeasTime: Aktuelle Zeit im BCD Format (YYMMDDhhmmss)
$0006

1

Kanal Kanalnummer
$0007

2

n Anzahl der Messungen im Intervall MeasTime
$0009..$000B

3

Integer Summer aller Meßwerte im Intervall MeasTime
$000C..$000D

2

Integer Kleinster Wert im Intervall MeasTime
$000E..$000F

2

Integer Größter Wert im Intervall MeasTime

Type TDataSet = Record
       Time: Array [0..5] of Char;
       Chn: Byte;
       Cnt: Word;
       RawVal: Integer;
       MinVal: Word;
       MaxVal: Word;
     End;

Damit bei RawVal kein Überlauf auftritt, muß gelten: MeasTime / SubTime < 4096.

Der minimale Aufzeichnungszeitraum berechnet sich aus folgenden Angaben:

Wird alle 5 Minuten ein DataSet gespeichert kann ein Zeitraum von 16384 * 5 min = 81920 min aufgezeichnet werden:

Das sind 56 Tage 21 Stunden 20 Minuten

Wird alle 10 Minuten ein DataSet gespeichert kann ein Zeitraum von 16384 * 10 min = 163840 min aufgezeichnet werden:

Das sind ungefähr 113 Tage 18 Stunden 40 Minuten

Der Aufzeichnungszeitraum verkürzt sich, wenn Kanäle einen höheren Meßzyklus haben und er erhöht sich, wenn Kanäle einen kleineren Meßzyklus und/oder weniger Kanäle gemessen werden. Wird 1 Kanal alle 10 Minuten gemessen, kann also fast 20 Jahre aufgezeichnet werden.

Speicherorganisation

Der gesamte Speicher ist als Ringspeicher organisiert, d.h. der Speicher wird von Anfang bis Ende beschrieben. Wenn der Speicher voll ist, dann wird der DataSet, der zuerst gespeichert wurde durch den Letzten ersetzt. Verwaltet wird das ganze durch zwei Pointer:

In Bild 1 zeigt Grün den Startpointer und Rot den Endpointer aus Sicht des Programmes, welches Daten Lesen will. Wenn Start- und Endpointer identisch sind, ist der Ringspeicher Leer.

Wird ein DataSet ausgelesen, dann immer von der Position Startpointer. Danach wird der Pointer erhöht bis er mit dem Endpointer identisch ist.

Ein Datenset wird zuerst an der Position EndPointer+1 eingeschrieben, dann wird erst der Endpointer erhöht. Sollte der Endpointer jetzt identisch sein mit dem Startpointer, dann wird auch der Startpointer erhöht.

Wird der End-/Startpointer erhöht und es ist das Speicherende erreicht, dann wird der Pointer auf den Speicheranfang gesetzt (Ringspeicher).

Ein Datensatz ist dann vorhanden, wenn StartPointer und EndPointer verschieden sind. Sind sie identisch ist der Ringspeicher Leer. Der Ringspeicher ist voll, wenn der StartPointer um 1 größer ist als der EndPointer.

Bild 1

0. Leerer Ringspeicher

1. Fünf DataSets (1 bis 5) wurden in den Ringspeicher geschrieben.

2. DataSet 6 wurde eingeschrieben und 1 und 2 ausgelesen.

3. DataSet 7 und 8 wurden eingeschrieben. Da das Ende des Speicherbereiches erreicht wurde, ist DataSet 8 an den Anfang geschrieben worden.

4. DataSet 3 wurde gelesen und 9 und 10 eingeschrieben. Der Speicher ist jetzt voll.

5. DataSet 11 wurde eingeschrieben. Dazu wurden der Start- und Endpointer erhöht und der DataSet beim Endpointer eingeschrieben. Der letzte DataSet (Nummer 4), auf den der alte Startpointer zeigte geht verloren.

Folgendes ist zu beachten:

Wird ein DataSet gelesen, dann wird er in einen Zwischenspeicher kopiert und zum PC gesendet. Kommt vom PC eine positive Quittierung wird der nächste Datensatz in den Zwischenspeicher kopiert und übertragen. Kommt eine negative Quittierung wird noch einmal übertragen.

Wird ein DataSet eingeschrieben, dann wird erst der Endpointer erhöht und dann eingeschrieben. Wird der Endpointer erhöht, wird vor dem Einschreiben geprüft, ob er identisch mit dem Startpointer ist, wenn ja, dann wird auch der Startpointer erhöht. Der DataSet, auf den der Startpointer zeigte ist dann verloren.

5.2.3 Befehlssatz

Der Befehlssatz unterteilt sich in funf Gruppen:

T - Time Parameter

C - Channel Parameter

D - Datatransfer Parameter

F - Format Parameter

S - Sonstige Parameter

Hinweis: Am Ende einiger Kommandos oder Antworten steht ein cr. Dies ist die Abkürzung für ein Carriage Return Zeichen = 13 = $0D. Das Beispiel besteht immer aus den zwei Zeilen Eingabe und Ausgabe.

Alle Ein- und Ausgaben, bis auf die Zeit, erfolgen als Hexadezimale Zahl.

Befehl Datum und Uhrzeit setzen
Syntax T1 x1 cr
Parameter x1 = 12stellig im Format YYMMDDhhmmss
Antwort cr
Beispiel T1 021123123456cr
cr

Befehl Datum und Uhrzeit auslesen
Syntax T2 cr
Parameter -
Antwort 12stellig im Format YYMMDDhhmmss
Beispiel T2cr
021123123456cr

Befehl SubTime in Sekunden für alle Kanäle setzen
Syntax T3 x1 cr
Parameter x1 =  4stellige Zeit in Sekunden
Antwort cr
Beispiel T3 000Acr
cr

Befehl SubTime in Sekunden für alle Kanäle auslesen
Syntax T4cr
Parameter -
Antwort 4stellig
Beispiel T4cr
000Acr

Befehl Messwertinterrupt sperren oder freigeben
Syntax T5 x1cr
Parameter x1 = 0 = Messzyklus sperren
x1 = 1 = Messzyklus freigeben
Antwort cr
Beispiel T5 0cr
cr

Befehl Bitmaske für einen/alle Kanäle setzen
Syntax C1 x1 x2cr
Parameter x1 = 2stellige Kanalnummer
  01..40 = Kanalnummer
  00 = alle Kanäle
x2 = ASCII Zeichen mit 0 oder 1
  0 = Kanal wird nicht gemessen
  1 = Kanal wird gemessen
Antwort cr
Beispiel C1 05 1cr
cr

Befehl Bitmaske für einen/alle Kanäle auslesen
Syntax C2 x1cr
Parameter x1 = 2stellige Kanalnummer
  01..40 = Kanalnummer
  00 = alle Kanäle
Antwort Wenn x1 = 00 dann String aus 64 Zeichen mit 0 oder 1
Wenn x1 = 01..40 dann 0 oder 1
Beispiel C2 05cr
1cr

Befehl MeasTime in Sekunden für einen/alle Kanäle setzen
Syntax C3 x1 x2cr
Parameter x1 = 2stellige Kanalnummer
  01..40 = Kanalnummer
  00 = alle Kanäle
x2 = 4stellige Zykluszeit in Sekunden
Antwort cr
Beispiel C3 05 0258cr (= 600 Sekunden)
cr

Befehl MeasTime in Sekunden für einen Kanal auslesen
Syntax C4 x1cr
Parameter x1 = 2stellige Kanalnummer
  01..40 = Kanalnummer
Antwort String aus 4 Zeichen
Beispiel C4 05cr
0258cr

Befehl Rohwert eines Kanals auslesen
Syntax D1 x1cr
Parameter x1 = 2stellige Kanalnummer
  01..40 = Kanalnummer
  00 = alle Kanäle
Antwort Wenn x1 = 01..40 dann Kanalnummer und Meßwert aus 5 Zeichen
Wenn x1 = 00 dann 64 Zeilen mit Kanalnummer und Meßwert
Beispiel D1 05cr
05 03A5cr

Der ADC arbeitet mit 12Bit Auflösung und einer Referenzspannung von 4,096Volt. Das ergibt eine Auflösung von 1mV/Bit. Die Ausgabe 03A5 (=933) entspricht also einer Spannung von 0,933Volt.

Befehl Übertrage den Status des Datenspeichers
Syntax D2cr
Parameter -
Antwort Drei 4stellige Hexadezimale Zahlen
  Anzahl der Datensätze
  Schreibpointer
  Lesepointer
Beispiel D2cr
0091 012B 01BCcr

Es sind 145 Datensätze vorhanden. Im Ringspeicher liegt der älteste Datensatz an Position 299 und der neueste Datensatz an Position 444. Es ist zu beachten, das der Schreibpointer immer auf die nächste freie Position zeigt.

Befehl Übertrage den nächsten Datensatz aus dem Datenspeicher. Sollte kein Datensatz vorhanden sein, wird nur mit einem cr geantwortet.
Syntax D3cr
Parameter -
Antwort Siehe Daten-Protokoll-Format
Beispiel D3cr
021123123456 03 003C 014820 04D2 0654cr

1. Zahl: Datum = 23.11.02 12:34:56
2. Zahl: Kanalnummer = 3
3. Zahl: Anzahl der Messwerte im Mittelungsintervall = 60
4. Zahl: Summe aller Messwerte im Mittelungsintervall = 84000
5. Zahl: Kleinster Wert im Mittelungsintervall = 1234
6. Zahl: Größter Wert im Mittelungsintervall = 1620

Befehl Übertrage den gleichen Datensatz noch einmal.
Syntax D4cr
Parameter -
Antwort Siehe Daten-Protokoll-Format
Beispiel D4cr
021123123456 03 003C 014820 04D2 0654cr

1. Zahl: Datum = 23.11.02 12:34:56
2. Zahl: Kanalnummer = 3
3. Zahl: Anzahl der Messwerte im Mittelungsintervall = 60
4. Zahl: Summe aller Messwerte im Mittelungsintervall = 84000
5. Zahl: Kleinster Wert im Mittelungsintervall = 1234
6. Zahl: Größter Wert im Mittelungsintervall = 1620

Befehl Lösche den Datenspeicher
Syntax D5cr
Parameter -
Antwort cr
Beispiel D4cr
cr

Befehl Arbeitsmodus setzen
Syntax F1 x1cr
Parameter x1 = Übetragungsmodus
  0 = Die Messwerte werden intern im Massenspeicher abgelegt, bis sie mit dem Befehl D3 abgeholt werden.
  1 = Nach jedem Messzyklus werden die gemessenen Werte über die Schnittstelle gesendet. Im Format wie bei D3
  2 = Nach jeder Messung werden die Werte über die Schnittstelle gesendet. Im Format wie bei D1.
Antwort cr
Beispiel F1 1cr
cr

Befehl Arbeitsmodus auslesen
Syntax F2cr
Parameter -
Antwort 0 = Die Messwerte werden intern im Massenspeicher abgelegt.
1 = Nach jedem Messzyklus werden die gemessenen Werte über die Schnittstelle gesendet.
2 = Nach jeder Messung werden die Werte über die Schnittstelle gesendet.
Beispiel F2cr
1cr

Befehl Übertragungsformat für die Messwerte eines Datensatzes setzen
Syntax F3 x1cr
Parameter x1 = Folge von 8 Bits (immer alle 8 Bits angeben)

Bit

Bedeutung
xxxxxxx0
xxxxxxx1
Binär-Format
ASCII Format.
xxxxxx0x
xxxxxx1x
frei
frei
xxxxx0xx
xxxxx1xx
Übetrage den Datensatz
Übetrage nur den Mittelwert
xxxx0xxx
xxxx1xxx
Zeilenabschluss mit CR
Zeilenabschluss mit CR LF
xxx0xxxx
xxx1xxxx
Die Übetragung aller Daten wird nicht markiert
Starte Übetragung aller Daten mit STX und beende sie mit ETX
xx0xxxxx
xx1xxxxx
Übertrage Werte als Dezimalzahl
Übertrage Werte als Hexadezimalzahl
x0xxxxxx
x1xxxxxx
frei
frei
0xxxxxxx
1xxxxxxx
frei
frei
Antwort cr
Beispiel F3 00000001cr
cr

Befehl Übertragungsformat für die Messwerte eines Datensatzes auslesen
Syntax F4cr
Parameter -
Antwort Format = Folge von 8 Bits (immer alle 8 Bits angeben)

Bit

Bedeutung
xxxxxxx0
xxxxxxx1
Binär-Format
ASCII Format.
xxxxxx0x
xxxxxx1x
frei
frei
xxxxx0xx
xxxxx1xx
Übetrage den Datensatz
Übetrage nur den Mittelwert
xxxx0xxx
xxxx1xxx
Zeilenabschluss mit CR
Zeilenabschluss mit CR LF
xxx0xxxx
xxx1xxxx
Die Übetragung aller Daten wird nicht markiert
Starte Übetragung aller Daten mit STX und beende sie mit ETX
xx0xxxxx
xx1xxxxx
Übertrage Werte als Dezimalzahl
Übertrage Werte als Hexadezimalzahl
x0xxxxxx
x1xxxxxx
frei
frei
0xxxxxxx
1xxxxxxx
frei
frei
Beispiel F4cr
00000001cr

Befehl Alle Variablen neu initialisieren
Syntax S1cr
Parameter -
Antwort Versionsangaben cr
Beispiel S1cr
WUDU2 / V1.00 / 2002-11-24 22:00:00cr

Befehl Software neu Starten durch Software Reset
Syntax S2cr
Parameter -
Antwort Versionsangaben cr
Beispiel S2cr
WUDU2 / V1.00 / 2002-11-24 22:00:00cr

Befehl Versionsinformation auslesen
Syntax S3cr
Parameter -
Antwort Versionsangaben cr
Beispiel S3cr
WUDU2 / V1.00 / 2002-11-24 22:00:00cr

5.2.4 Daten-Protokoll-Format

5.2.4.1 ASCII Format

5.2.4.1.1 Protokollrahmen

[STX=$02] MeasTime Daten [ETX=$03] CR=$0D [LF=$0A]

5.2.4.1.2 Startbyte

Wenn im ASCII Modus alle Kanäle auf einmal übertragen werden, kann es bei einigen PC's passieren, das der komplette String nicht in einem Rutsch an den Eingangsbuffer der seriellen Schnittstelle übergeben wird, d.h. der Eingangsbuffer muß nach dem Stringanfang und -ende gescannt werden. Das STX und das ETX Zeichen sollen diesen Vorgang vereinfachen. Sollte der PC aber immer schnell genug sein, ist diese Kennung nicht notwendig und kann über eines der DF Flags ausgeschaltet werden.

5.2.4.1.3 MeasTime

Die Uhrzeit im Standard Format: YYMMDDhhmmss

Mit einem Space als Separator.

5.2.4.1.4 Daten

Jede Zahl wird in seinem zugehörigen Format übertragen und durch ein Space getrennt.

1 Byte = 3stellig
2 Byte = 5stellig
3 Byte = 8stellig

Es werden nur die Kanäle übertragen, die auch gemessen werden, als DataSet oder nur der RawValue (abhängig von einem der F4 Flags).

5.2.4.1.5 Stopbyte

Wenn Daten übertragen werden, kann es bei einigen PC's passieren, das der komplette String nicht in einem Rutsch an den Eingangsbuffer der seriellen Schnittstelle übergeben wird, d.h. der Eingangsbuffer muß nach dem Stringanfang und -ende gescannt werden. Das STX und das ETX Zeichen sollen diesen Vorgang vereinfachen. Sollte der PC aber immer schnell genug sein, ist diese Kennung nicht notwendig und kann über eines der F4 Flags ausgeschaltet werden.

5.2.4.1.6 Zeilenende

Jede Zeile im ASCII Modus wird mit einem CR und LF abgeschlossen. Ist nur ein CR notwendig, kann das LF über eines der DF Flags ausgeschaltet werden.

5.2.4.1.7 Beispiel

Kanal 3 und 32 mit vollem DataSet und allen Optionen:

S = STX, E = ETX, C = CR, L = LF

S021123123456 03 003C 014820 04D2 0654ECL
S021123123456 04 003C 014820 04D2 0654ECL

Das sind 82 Bytes. Bei einer Übertragungsrate von 19200 Baud dauert das Senden 42,7ms.

5.2.4.2 Binärformat

5.2.4.2.1 Protokoll Rahmen

Die eigentlichen Daten werden in einer HDLC ähnlichen Struktur verpackt:
$7F Daten CRC-Checksumme $7E

Zeichen, die nicht auf der Schnittstelle auftauchen dürfen, werden durch ein Markierungsbyte gekennzeichnet und beim eigentlichen Zeichen wird das sechste Bit invertiert. Zu den Zeichen gehören:
Zeichen

wird zu

Bedeutung

$11

$7D $31 X-on, wird für das Software-Handshake auf der seriellen Schnittstelle gebraucht

$13

$7D $33 X-off, wird für das Software-Handshake auf der seriellen Schnittstelle gebraucht

$7D

$7D $5D Das Markierungsbyte selbst muß natürlich auch gekennzeichnet werden

$7E

$7D $5E Das Ende Zeichen darf auch nicht zu früh erkannt werden

$7F

$7D $5F Das gleiche gilt für das Startzeichen

5.2.4.2.2 Startbyte

Das Zeichen $7F kennzeichnet den Anfang des Datenprotokolls.

5.2.4.2.3 Daten

Es wird immer der komplette DataSet übertragen.

T1 K1 C1 F1 F2 F3

  Bytes Bemerkung
T1

1

Jahr = 0..99

1

Monat = 1..12

1

Tag = 1..31

1

Stunde = 0..23

1

Minute = 0..59

1

Sekunde = 0..59

K1

1

Kanalnummer
C1

2

Anzahl der Messung im Mittelungsintervall

F1

3

Summe der Messwerte im Hexadezimal Format

F2

2

Minimumwert im Hexadezimal Format

F3

2

Maximumwert im Hexadezimal Format

5.2.4.2.4 CRC Checksumme

Zur Generierung des 16 Bit CRC wird das Polynom nach CCITT Empfehlung verwendet:

CRC = x16 + x12 + x5 + 1

Hier die Pascal Kodierung:

Const Crc16Tab : Array[0..255] of Word = (
$0000, $1021, $2042, $3063, $4084, $50a5, $60c6, $70e7,
$8108, $9129, $a14a, $b16b, $c18c, $d1ad, $e1ce, $f1ef,
$1231, $0210, $3273, $2252, $52b5, $4294, $72f7, $62d6,
$9339, $8318, $b37b, $a35a, $d3bd, $c39c, $f3ff, $e3de,
$2462, $3443, $0420, $1401, $64e6, $74c7, $44a4, $5485,
$a56a, $b54b, $8528, $9509, $e5ee, $f5cf, $c5ac, $d58d,
$3653, $2672, $1611, $0630, $76d7, $66f6, $5695, $46b4,
$b75b, $a77a, $9719, $8738, $f7df, $e7fe, $d79d, $c7bc,
$48c4, $58e5, $6886, $78a7, $0840, $1861, $2802, $3823,
$c9cc, $d9ed, $e98e, $f9af, $8948, $9969, $a90a, $b92b,
$5af5, $4ad4, $7ab7, $6a96, $1a71, $0a50, $3a33, $2a12,
$dbfd, $cbdc, $fbbf, $eb9e, $9b79, $8b58, $bb3b, $ab1a,
$6ca6, $7c87, $4ce4, $5cc5, $2c22, $3c03, $0c60, $1c41,
$edae, $fd8f, $cdec, $ddcd, $ad2a, $bd0b, $8d68, $9d49,
$7e97, $6eb6, $5ed5, $4ef4, $3e13, $2e32, $1e51, $0e70,
$ff9f, $efbe, $dfdd, $cffc, $bf1b, $af3a, $9f59, $8f78,
$9188, $81a9, $b1ca, $a1eb, $d10c, $c12d, $f14e, $e16f,
$1080, $00a1, $30c2, $20e3, $5004, $4025, $7046, $6067,
$83b9, $9398, $a3fb, $b3da, $c33d, $d31c, $e37f, $f35e,
$02b1, $1290, $22f3, $32d2, $4235, $5214, $6277, $7256,
$b5ea, $a5cb, $95a8, $8589, $f56e, $e54f, $d52c, $c50d,
$34e2, $24c3, $14a0, $0481, $7466, $6447, $5424, $4405,
$a7db, $b7fa, $8799, $97b8, $e75f, $f77e, $c71d, $d73c,
$26d3, $36f2, $0691, $16b0, $6657, $7676, $4615, $5634,
$d94c, $c96d, $f90e, $e92f, $99c8, $89e9, $b98a, $a9ab,
$5844, $4865, $7806, $6827, $18c0, $08e1, $3882, $28a3,
$cb7d, $db5c, $eb3f, $fb1e, $8bf9, $9bd8, $abbb, $bb9a,
$4a75, $5a54, $6a37, $7a16, $0af1, $1ad0, $2ab3, $3a92,
$fd2e, $ed0f, $dd6c, $cd4d, $bdaa, $ad8b, $9de8, $8dc9,
$7c26, $6c07, $5c64, $4c45, $3ca2, $2c83, $1ce0, $0cc1,
$ef1f, $ff3e, $cf5d, $df7c, $af9b, $bfba, $8fd9, $9ff8,
$6e17, $7e36, $4e55, $5e74, $2e93, $3eb2, $0ed1, $1ef0
);

Function GenerateCRC16(Var s1:String):Word;
Var w1,w2,crc16:Word; i:Integer;
begin
  crc16 := 0;
  For i := 1 to Length(s1) do Begin
    w1 := Crc16 shr 8;
    w1 := w1 xor Ord(s1[i]);
    w1 := w1 and $00FF;
    w1 := Crc16Tab[w1];
    w2 := (Crc16 shl 8) and $FFFF;
    Crc16 := w1 xor w2;
  End;
  Result := crc16;
end;

5.2.4.2.5 Stopbyte

Beim HDLC Rahmen wird das Ende eines Protokollrahmens ebenfalls durch ein $7F gekennzeichnet. Es ist jedoch wesentlich einfacher ein anderes Zeichen als Ende zu erkennen. Deshalb wird hier ein $7E benutzt.

5.2.4.2.6 Beispiel

Benutzt werden die gleichen Werte wie im Beispiel zum ASCII Modus.

7F 02 7D 31 23 12 34 56 03 00 3C 01 48 20 04 D2 06 54 xx xx 7E

7F 02 7D 31 23 12 34 56 04 00 3C 01 48 20 04 D2 06 54 xx xx 7E

Das sind 42 Bytes. Bei einer Übertragungsrate von 19200 Baud dauert das Senden 21,9ms, also fast doppelt so schnell wie ASCI Übertragung.