Projektbericht 796.8 KByte - Technikpreis
Projektbericht 796.8 KByte - Technikpreis
Projektbericht 796.8 KByte - Technikpreis
Sie wollen auch ein ePaper? Erhöhen Sie die Reichweite Ihrer Titel.
YUMPU macht aus Druck-PDFs automatisch weboptimierte ePaper, die Google liebt.
<strong>Technikpreis</strong> 2006 des VDE Rhein-Ruhr e. V.<br />
Projektdokumentation<br />
Bau und Entwicklung einer<br />
Wettermessstation<br />
mit Anbindung<br />
ins Packet Radio Netz<br />
Reinhold Bertram<br />
St. Antonius Gymnasium, Lüdinghausen<br />
Betreuer : Herr Dr. Ruttert<br />
Eingereicht am : 7. Juni 2006
Danksagung<br />
Ich danke besonders dem VDE Rhein-Ruhr e.V. für die finanzielle Unterstützung dieser<br />
Arbeit.<br />
Herrn Dipl. Ing. Thomas Aundrup gilt mein besonderer Dank für die engagierte Betreuung<br />
meines Projekts.<br />
Die schnellen Antworten und Hilfen haben mir sehr geholfen.<br />
Außerdem gilt mein Dank meinem Bruder Clemens, sowie dem DARC OV Lüdinghausen.<br />
Ohne ihre Hilfe wäre die Arbeit nicht so gut gelungen.
III<br />
Inhaltsverzeichnis<br />
Inhaltsverzeichnis<br />
Danksagung<br />
II<br />
1 ”Und nun das Wetter” 1<br />
2 Messwerterfassung 3<br />
2.1 Allgemeines über die serielle Schnittstelle . . . . . . . . . . . . . . . . . . 3<br />
2.2 Funktionsweise des TLC 549 . . . . . . . . . . . . . . . . . . . . . . . . . 3<br />
2.3 Multiplexer/Demultiplexer . . . . . . . . . . . . . . . . . . . . . . . . . . 5<br />
2.4 Achtstufiger Binärzähler als Seriell/Parallel-Wandler . . . . . . . . . . . 5<br />
3 Sensortechnik 6<br />
3.1 Temperatursensor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6<br />
3.2 Lichtsensor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9<br />
3.3 Feuchtesensor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10<br />
3.4 Drucksensor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12<br />
4 Software 13<br />
4.1 Steuerung des A/D-Wandler über serielle Schnittstelle . . . . . . . . . . . 13<br />
4.2 Steuerung des Analog-Multiplexer . . . . . . . . . . . . . . . . . . . . . . 14<br />
4.3 Umwandlung der Spannungswerte in Wetterdaten . . . . . . . . . . . . . 14<br />
4.4 Dokumentation der Messparameter . . . . . . . . . . . . . . . . . . . . . 15<br />
5 Übertragung 16<br />
5.1 Packet Radio . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16<br />
5.2 Packet Radio Station . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17<br />
5.3 Terminalprogramm Paxon . . . . . . . . . . . . . . . . . . . . . . . . . . 17<br />
5.4 Übertragung in eine Mailbox . . . . . . . . . . . . . . . . . . . . . . . . . 19<br />
6 Schlussbetrachtung 20<br />
7 Ausblick 22<br />
Literatur 23<br />
A Schaltpläne 25<br />
B Fotos 28
IV<br />
Inhaltsverzeichnis<br />
C Stückliste 32<br />
D Quellcode 34
1 1 ”Und nun das Wetter”<br />
1 ”Und nun das Wetter”<br />
Mit diesen Worten leiten Nachrichtensprecher zum vielleicht spannendsten Teil der Nachrichten,<br />
der Wettervorschau für die nächsten Tage, über. Menschliches Handeln und Tun<br />
ist massiv vom Wetter beeinflusst. Die Wahl der Kleidung, der Sportunterricht und die<br />
Organisation der Grillparty am nächsten Samstag sind genauso vom Wetter abhängig<br />
wie die Arbeit der Gärtner und Bauern. Die Bedeutung der Wettervorhersage für Sturm,<br />
Hagel und Hochwasser für unser aller Wohl liegt klar auf der Hand.<br />
Auslöser für die Entwicklung und den Bau einer lokalen Wetterstation ist ein Projekt<br />
der Biologischen Station Lüdinghausen zur Wiederansiedlung von Wanderfledermäusen<br />
in unserer Region. Eine Gruppe, die sich aus Ornithologen, Naturschützern, Biologen,<br />
Gärtnern und Schülern zusammensetzt, hat im Biologischen Zentrum Lüdinghausen einen<br />
Fledermausstollen gebaut, der den Tieren als Herberge und Nistbaustätte dienen soll.<br />
Für eine erfolgreiche Ansiedlung der Wanderfledermaus gehört sicherlich ein biologisches<br />
intaktes Umfeld, das sich in einer reichen Artenvielfalt an Pflanzen und Insekten widerspiegelt,<br />
und klimatisch passenden Bedingungen.<br />
In der Gruppe stellten wir uns deshalb die Frage, inwieweit das Verhalten der Tiere durch<br />
das Wetter beeinflusst wird. Bei welchen Lichtverhältnissen verlassen die Fledermäuse<br />
den Stollen? Fliegen sie bei jeder Temperatur aus oder verbleiben sie im Stollen, wenn<br />
es draußen zu kalt ist? Wie verhalten sich die empfindlichen Tiere bei Regenwetter? Aus<br />
dieser Fragestellung entstand die Idee, das Wetter in unmittelbarer Nähe zum Stollen<br />
zu messen und zeitgleich das Verlassen und Zurückkehren der bedrohten Tiere in ihre<br />
Behausung durch Lichtschranken zu registrieren.<br />
In dem vorliegenden Bericht möchte ich mich allein auf die Darstellung der Wetterstation<br />
beschränken. Hier werden die Arbeitsergebnisse der letzten vier Monate beschrieben. Bei<br />
der Planung habe ich von Beginn ab an beabsichtigt, leicht zugängliche elektronische<br />
Bauteile zu verwenden, damit auch andere Naturgruppen die Anlage einfach nachbauen<br />
können. Die Wetterdaten werden im Packet Radio Netz der Funkamateure übertragen<br />
und somit einer breiten Öffentlichkeit zugänglich gemacht. Somit ist es möglich, das
2 1 ”Und nun das Wetter”<br />
Verhalten der Tiere in Lüdinghausen mit denen in anderen Städten zu vergleichen, um<br />
so zu einem besseren Verständnis der Tiere und zum Artenschutz beizutragen.<br />
Vielleicht wird die Wetterstation, die ich hier beschreiben werde, auch nur von interessierten<br />
Schülerinnen und Schülern nachgebaut, weil sie wissen wollen, wie das Wetter<br />
an ihrer Schule gerade ist. Für die Weiterverarbeitung des von mir entwickelten Systems<br />
an interessierte Gruppen ist allerdings eine präzise Bauanleitung mit detaillierten<br />
Schaltplänen notwendig, um auch bei elektrotechnisch unerfahrenen Interessenten den<br />
erfolgreichen Nachbau zu ermöglichen. Der vorliegende Bericht dokumentiert zunächst<br />
einmal die grundlegenden technischen Ideen meines Projekts.<br />
Nach der Einleitung folgt im zweiten Kapitel des Berichts die Erläuterungen zu den zentralen<br />
elektronischen Bauteilen zur Messung der Wetterparameter Temperatur, Licht, relative<br />
Luftfeuchtigkeit und Druck. Dazu gehört die serielle Schnittstelle, der TLC 549, der<br />
Multiplexer/Demultiplexer und der achtstufige Binärzähler als Seriell/Parallel-Wandler.<br />
Im 3. Kapitel stelle ich die Sensoren kurz vor und beschreibe die Erzeugung von Spannungswerten<br />
aus den gemessenen Wetterparametern. Nach der Hardware wird im 4. Abschnitt<br />
die Software vorgestellt, die von mir selbst entwickelt wurde. Die Beschreibung<br />
der Übertragung der Daten wird im 5. Abschnitt behandelt. Der vorliegende Bericht<br />
schließt mit einem Ausblick auf die mögliche Weiterentwicklung der Messstation.
3 2 Messwerterfassung<br />
2 Messwerterfassung<br />
2.1 Allgemeines über die serielle Schnittstelle<br />
Ich habe mich für die Abfrage über die serielle Schnittstelle entschieden, weil sie relativ<br />
einfach zu programmieren ist und häufig in älteren PCs eingebaut ist. Die serielle Schnittstelle<br />
verfügt über neun Anschlüsse, von denen drei Sendeleitungen und fünf Empfangsleitungen<br />
sind. Der neunte Anschluss geht nach Masse. Da die Steuerung der seriellen<br />
Schnittstelle asynchron erfolgt (oder overlapped, wie es unter Windows heißt), können<br />
nur vier Empfangsleitungen genutzt werden. Für den A/D-Wandler TLC549 werden zwei<br />
Steuerleitungen und eine Empfangsleitung benötigt, weshalb eine Steuerleitung und drei<br />
Empfangsleitungen zunächst frei bleiben 1 .<br />
2.2 Funktionsweise des TLC 549<br />
Anhand der Darstellung (Abbildung 2.1) erkennt man, dass bei Anschluss 1 und 3 die<br />
obere und untere Referenzspannung anliegt, welche mit der von Pin 2 kommenden analogen<br />
Spannung im 8-Bit Analog-to-Digital Converter ins Output Data Register geschrieben<br />
wird. Über ChipSelect und I/O Clock wird mit Hilfe des Control Logic and Output<br />
Counter nacheinander bitweise die Spannung als digitaler Wert ausgegeben.<br />
Abbildung 2.2 zeigt den zeitlichen Verlauf zweier Abfragen: Mit der fallenden Flanke<br />
an ChipSelect (CS) liegt an DataOut (Pin6) das höchstwertige Bit des acht Bit langen<br />
digitalen Wertes an. Nach einer steigenden Flanke liegt das nächste Bit am Ausgang.<br />
Nach achtmal Schalten ist der komplette digitale Wert ausgegeben worden.<br />
Mit einem einzigen A/D-Wandler ist zunächst nur eine Messwerterfassung möglich, da<br />
ich aber bis zu 8 Sensoren benutzen möchte, benötige ich eine Schaltung die mehrere<br />
1 Vgl. H.-J. Berndt/B. Kainka, Messen, Steuern und Regeln mit Word und Excel, Poing, Francis-Verlag,<br />
2001 3 , 100ff.
4 2 Messwerterfassung<br />
Abbildung 2.1: Functional block diagram (Quelle: Datenblatt TLC549 )<br />
Abbildung 2.2: Operating sequence (Quelle: Datenblatt TLC549 )
5 2 Messwerterfassung<br />
Leitungen möglich macht. Man könnte mehrere A/D-Wandler benutzen, welche man<br />
über Digital-Multiplexer an die serielle Schnittstelle anschließt. Oder man nutzt einen<br />
Analog-Demultiplexer um acht Leitungen seriell, d.h. nacheinander abzufragen.<br />
2.3 Multiplexer/Demultiplexer<br />
Als Analog Multiplexer/Demultiplexer verwende ich den CD4051, der für acht Leitungen<br />
ausgelegt ist. Um die Leitungen durchzuschalten ist ein achtstufiger Binärzähler notwendig.<br />
2.4 Achtstufiger Binärzähler als<br />
Seriell/Parallel-Wandler<br />
Ein achtstufiger Binärzähler lässt sich aus drei jk-Master-Slave FlipFlops aufbauen, wie<br />
er in ”Einführung in die Elektronik 2 / Kontaktlose Signalverarbeitung” von K. Block,<br />
H.-J. Hölzel, L. Wölfing und P. Zachert auf Seite 206 beschrieben ist. Dazu schließt man<br />
den Ausgang des ersten FF als Clock-Signal an den zweiten FF und dessen Ausgang als<br />
Clock-Signal des dritten Ausgangs. Mit jedem Ausgang hat man dann insgesamt drei<br />
Leitungen die 2 3 = 8 unterschiedliche Zustände annehmen können. Diese kann man nun<br />
an den Multiplexer anschließen.<br />
Wenn man das Signal der seriellen Schnittstelle direkt als erstes Clock-Signal weitergibt,<br />
kann es dazu kommen, dass der achtstufige Binärzähler weiter zählt als zu erwarten<br />
ist. Es lässt sich vermuten, dass sich dahinter ein Kontaktprellen verbirgt, weshalb eine<br />
Vielzahl von Impulsen gezählt wird. Um dies zu verhindern könnte man wie auf S.<br />
207 des schon genannten Buches ”Einführung in die Elektronik 2” zwei NAND-Stufen<br />
benutzen. Ich habe mich allerdings für die Schaltung über zwei Transistoren, die die 5<br />
Volt-Versorgungsspannung schalten, entschieden, mit der das unerwünschte Weiterschalten<br />
auch vermieden wird.<br />
Mit der bis hierhin beschriebenen Schaltung ist es also möglich, acht Leitungen im Bereich<br />
von 0 bis 5 Volt mit einer Genauigkeit von 8-bit über die serielle Schnittstelle<br />
nacheinander abzufragen.
6 3 Sensortechnik<br />
3 Sensortechnik<br />
Da der TLC549 einen Spannungsbereich von 0 bis 5 Volt abdeckt, ist es notwendig alle<br />
zu ermittelnden Werte, wie Temperatur, Licht, Luftdruck usw. in veränderliche Spannungswerte<br />
umzuwandeln.<br />
3.1 Temperatursensor<br />
Der Temperatursensor ist ein PTC-Widerstand (Positive Temperature Coeffizient Widerstand<br />
- Kaltleiter). Dies bedeutet, dass er bei hohen Temperaturen einen größeren<br />
Widerstand besitzt als bei niedrigeren. Da es aber aufwendiger wäre den Widerstand<br />
des PTCs zu messen als eine Spannung ist es sinnvoll die Widerstandsänderung in eine<br />
Spannungsänderung umzusetzen. Dafür benutzt man eine Widerstandsbrückenschaltung.<br />
Sie besteht aus zwei in Reihe geschalteten Widerständen zwischen denen die Spannung<br />
abgegriffen wird.<br />
Die Spannungsänderung ergibt sich aus der Widerstandsänderung wie folgt:<br />
In einer Reihenschaltung fließt durch jedes Bauteil ein gleich großer Strom: I 1 = I 2 = I ges .<br />
Die Spannung teilt sich allerdings an jedem Bauteil und addiert sich zur Gesamtspannung<br />
U 1 + U 2 = U ges . Das Ohmsche Gesetz besagt I ges = U ges /R ges . Mit R ges = R 1 + R 2 folgt<br />
daraus für den Gesamtstrom I ges = U ges /(R 1 + R 2 ). Da in der Mitte zwischen beiden<br />
Widerständen die Spannung abgegriffen wird, gilt für sie U 1 = R 1 · I ges , also:<br />
U 1 = R 1 · U ges /(R 1 + R 2 )<br />
Für R 1 > R 2 ist U 1 > 1/2U ges ,<br />
für R 1 = R 2 ist U 1 = 1/2U ges und<br />
für R 1 < R 2 ist U 1 < 1/2U ges .<br />
Dies zeigt, wie sich eine Widerstandsänderung leicht in eine Spannungsänderung umwandeln<br />
lässt.
7 3 Sensortechnik<br />
Abbildung 3.1: Schaltplan für Temperatursensor
8 3 Sensortechnik<br />
Das Datenblatt des benutzten Sensors (KTY 81-210) gibt an, dass der Widerstandswert<br />
des Sensor bei 10 ◦ C 1772 Ohm beträgt. Wenn nun der 1. Widerstand ebenfalls auf diesen<br />
Wert eingestellt wird, ergibt sich somit eine Spannung von 2,5 V. Bei einer Veränderung<br />
der Temperatur ändert sich der Widerstand; die Spannung wird somit geändert. Bei dem<br />
benutzten Sensor spielt sich die Bandbreite der Widerstandswerte in einem Bereich von<br />
-20 ◦ C bis 40 ◦ C bei 1367 Ohm bis 2245 Ohm ab. Damit ergeben sich Spannungen im<br />
Bereich von:<br />
U 1 (−20 ◦ C) = 5V ·<br />
1367Ω<br />
1367Ω + 1772Ω<br />
= 2, 17V<br />
U 1 (40 ◦ C) = 5V ·<br />
2245Ω<br />
2245Ω + 1772Ω<br />
= 2, 79V<br />
Diese Spannungsbandbreite reicht für eine adäquate Messwertbestimmung jedoch nicht<br />
aus. Aus diesem Grund muss sie verstärkt werden. Dies geschieht mit einem Operationsverstärker<br />
als Differenzverstärker, der über R 4 und R 5 etwa eine Verstärkung v U um das<br />
etwa fünffache bewirkt (berechnet sich nach der Formel v U = 1 + R 5 /R 4 = 5, 6, siehe<br />
Fußnote 1 ).<br />
Daraus folgt:<br />
Differenz von 2,5 Volt ohne Verstärkung:<br />
∆U 1 (−20 ◦ C) = 2, 17 − 2, 5V = −0, 33V<br />
∆U 1 (40 ◦ C) = 2, 80 − 2, 5V = 0, 30V<br />
Mit Verstärkung von v U = 5, 6 :<br />
−0, 33V · 5, 6 = −1, 848V<br />
0, 30V · 5, 6 = 1, 680V<br />
Damit:<br />
U1(-20 ◦ C) = 2,5 - 1,848 V = 0,652 V<br />
U1(40 ◦ C) = 2,5 + 1,680 V = 4,18 V<br />
1 W.-D. Schmidt, Sensorschaltungstechnik, S.30
9 3 Sensortechnik<br />
Mit dieser Differenz von insgesamt 3,528 Volt auf 60 ◦ C ergibt sich:<br />
3,472 V / 60 ◦ C = 0,0588 V/ ◦ C bzw. 17,01 ◦ C/V<br />
Bei einer Genauigkeit des A/D-Wandlers von 8bit bedeutet dies:<br />
5V/2 8 bit = 0, 019V/bit<br />
17, 01 ◦ C/V · 0, 019V/bit = 0, 323 ◦ C/bit<br />
Die Messung findet also mit einer Genauigkeit von 0,323 ◦ C statt (ungefähr 1/3 ◦ C<br />
bzw. 3bit/ ◦ C).<br />
Diese Berechung gilt für die vom Datenblatt angegebenen typischen Widerstandswerte<br />
des Sensors. Das Datenblatt gibt allerdings auch maximale und minimale Werte für jede<br />
Temperatur an, zwischen denen der tatsächliche Widerstandswert liegt. Laut Datenblatt<br />
liegt der Fehler dabei im Bereich von ±2%.<br />
3.2 Lichtsensor<br />
Ähnlich wie der Temperatursensor besitzt der Lichtsensor (LDR 03) einen veränderlichen<br />
Widerstandswert, der im Bereich von 2 Megaohm bei Dunkelheit und unter 100 Ohm<br />
bei Sonnenlicht liegt. Im Schatten besitzt er immerhin noch ungefähr 2000 Ohm. Da in<br />
dieser Arbeit keine absolute Lichtstärkemessung vorgenommen werden soll, sondern nur<br />
eine relative Helligkeit festgestellt werden soll, besteht die Schaltung für den Lichtsensor<br />
nur aus einer Brückenschaltung mit einem Präzisionstrimmer, mit welchem man den<br />
gewünschten Schwellenwert für eine Messung von Hell/Dunkel einstellen kann. Aufgrund<br />
des stark veränderlichen Fotowiderstands ist es nicht notwendig, die Spannung weiter zu<br />
verstärken.<br />
Abbildung 3.2: Schaltplan für Lichtsensor
10 3 Sensortechnik<br />
3.3 Feuchtesensor<br />
Der Feuchtesensor besitzt eine veränderliche Kapazität, weshalb er mit den bisherigen<br />
Methoden nicht gemessen werden kann.<br />
Meine Idee dazu sieht folgendermaßen aus:<br />
Abbildung 3.3: Schaltplan für Feuchtesensor<br />
Der Feuchtesensor ist als Kondensator im RC-Glied, des Timer-Schaltkreises mit einem<br />
NE555 getaktet. Abhängig von der Kapazität entsteht eine variable Frequenz 2 . Da mit<br />
meiner restlichen Hardware keine Frequenzmessung möglich ist, soll die Frequenz mit<br />
einem Frequenz-Spannungs-Wandler umgewandelt werden und mit einem Operationsverstärker,<br />
wie er auch schon benutzt wurde, angepasst werden. Die Frequenz des astabilen<br />
Multivibrators berechnet sich mit f =<br />
1<br />
0,7(R 4 +2R 2 )C (siehe Fußnote3 ) . Mit den berechneten<br />
Werten für die Widerstände kommt man auf eine mittlere Frequenz von ungefähr 10<br />
kHz, die um ungefähr 3 kHz nach oben und unten schwankt. Die Ausgangsspannung des<br />
2 Vgl. Schmidt, Sensorschaltungstechnik, S.134ff.<br />
3 Schmidt, Sensorschaltungstechnik, S. 136 und Datenblatt NE555
11 3 Sensortechnik<br />
Frequenz-Spannungs-Wandlers LM2917 berechnet sich nach: 4<br />
V out = f in · V c · R 1 · C 1<br />
Weshalb R 1 · C 1 = 1 · 1 kHz sein soll.<br />
2 10<br />
Der NE555 liefert eine positive Rechteckspannung, weshalb die Schaltung so noch nicht<br />
funktioniert, da der LM2907 eine Frequenz erwartet, die zwischen positiven und negativen<br />
Spannungen pendelt. Dieses Problem lässt sich beheben, indem man an Pin 11 des<br />
LM2907 eine Spannung anlegt, die zwischen den Spitzen der Rechteckspannung liegt.<br />
Aus dem Diagramm des Datenblattes kann man für den Feuchtigkeitssensor folgende<br />
Werte entnehmen:<br />
Kapazität des Feuchtesensors bei 0% r.F. ungefähr 100pF<br />
Kapazität des Feuchtesensors bei 43% r.F. ungefähr 120pF<br />
Kapazität des Feuchtesensors bei 100% r.F. ungefähr 150pF<br />
Mit den benutzten Bauteilen errechnen sich folgende Werte für die Schaltung:<br />
Frequenz am Ausgang des NE555:<br />
für 0% r.F.:<br />
f =<br />
1<br />
0, 7(R4 + 2R2)C => f 0 =<br />
1<br />
0, 7(47kΩ + 2 · 530kΩ) · 100pF<br />
= 13, 0kHz<br />
für 43% r.F.:<br />
=> f 1 =<br />
1<br />
0, 7(47kΩ + 2 · 530kΩ) · 120pF<br />
= 10, 8kHz<br />
für 100% r.F.:<br />
=> f 2 =<br />
1<br />
0, 7(47kΩ + 2 · 530kΩ) · 150pF<br />
= 8, 7kHz<br />
Spannungswerte für die Frequenzen:<br />
V = f · 5V · 100kΩ · 470pF = f · 0, 000235V s<br />
V 0 = f 0 · 0, 000235V s = 3, 056V<br />
V 1 = f 1 · 0, 000235V s = 2, 54V<br />
V 2 = f 2 · 0, 000235V s = 2, 038V<br />
4 National Semiconductor,LM2907/LM2917 Frequency to Voltage Converter, DATA SHEET, 18 Seiten,<br />
1995
12 3 Sensortechnik<br />
Somit gibt es also eine Spannungsdifferenz von etwa 1V. Für die Messung muss sie also<br />
um das Fünffache verstärkt werden. Der Verstärkungsfaktor v U berechnet sich nach v U<br />
= 1 + R 11<br />
R 10<br />
= 5, siehe Fußnote 5<br />
mit R 11 = 10kΩ folgt:<br />
4 · R 10 = 10kΩ => R 10 = 2, 5kΩ<br />
3.4 Drucksensor<br />
Als Drucksensor kommt ein integrierter Sensor der Firma Motorola zum Einsatz, der im<br />
Bereich von 15 bis 115 kPa ein lineares Spannungssignal im Bereich von 0.2 bis 4.8 Volt<br />
ausgibt. Dieses wird nur noch durch die bereits beschriebene Operationsverstärkerschaltung<br />
an die Messstation angepasst.<br />
5 Schmidt,Sensorschaltungstechnik, S.30
13 4 Software<br />
4 Software<br />
Zur Programmierung der Software habe ich mich für die Programmiersprache Delphi<br />
entschieden, da sie sowohl einfachen Gebrauch von der Windows-API machen kann als<br />
auch eine leichte Programmierung der Benutzeroberfläche ermöglicht und zudem objektorientiert<br />
ist.<br />
4.1 Steuerung des A/D-Wandler über serielle<br />
Schnittstelle<br />
Zunächst muss die serielle Schnittstelle geöffnet werden. Die Funktion CreateFile öffnet<br />
diese und gibt ein Handle von ihr zurück. Dies wird in der Variablen PortHandle<br />
gespeichert, da es später für den Aufruf der übrigen Funktionen benötigt wird.<br />
Die einzelnen Sendeleitungen werden mittels EscapeCommFunction gesetzt und zurückgesetzt.<br />
Der Status der Empfangsleitungen wird mit GetCommModemStatus abgefragt. Um<br />
den A/D-Wandler TLC549 nun abzufragen, wird zunächst der Variablen BitWert der<br />
Wert 128 und b der Wert 0 zugewiesen. Durch einmaliges ein- und ausschalten von RTS<br />
liefert der A/D-Wandler das höchstwertige Bit an der CTS-Leitung. Diese Leitung wird<br />
in einer for-Schleife achtmal abgefragt, während I/O-Clock weitergeschaltet wird. Am<br />
Ende ist in der Variablen b der Wert des TLC549 gespeichert und wird von der Funktion<br />
zurückgegeben.<br />
function TSerialThread.ByteRead : Integer; stdcall;<br />
var BitWert, b, i : Integer;<br />
BitWert := 128;<br />
b := 0;<br />
//Chipselect ein und ausschalten<br />
SetzeRTS;<br />
ClearRTS;<br />
//Am Dataout liegt jetzt das 1. Bit<br />
for i := 0 to 7 do // 8 mal weiterschalten
14 4 Software<br />
begin<br />
if CTS = True then<br />
b := b + BitWert;<br />
//I/O-Clock weiterschalten<br />
SetzeDTR;<br />
ClearDTR;<br />
//nächstes Bit nur noch halbwertig<br />
BitWert := BitWert div 2;<br />
end;<br />
result := b;<br />
end;<br />
Vgl. Berndt/Kainka, Messen, Steuern und Regeln mit Word und Excel, S. 103, Listing<br />
6.7<br />
4.2 Steuerung des Analog-Multiplexer<br />
Wie schon in Abschnitt 2.4 beschrieben, reicht eine Sendeleitung für das Weiterschalten<br />
des Achtstufigen Binärzählers aus, welcher den Analog-Multiplexer steuert. Hierfür wird<br />
die TXD-Leitung genutzt, die insgesamt achtmal umgeschaltet wird, um anschließend<br />
den Rückgabewert des TLC549 zu ermitteln und mit einer Wertetabelle für den Sensor<br />
zu vergleichen. Zuletzt wird ein String mit allen Werten der Sensoren gefüllt, der in einer<br />
Datei gespeichert und in eine Mailbox des Packet Radio Netz geschickt werden kann.<br />
for SenNr := 0 to 7 do<br />
begin<br />
if mySerialThread.StatTXD = True then mySerialThread.ClearTXD<br />
else if mySerialThread.StatTXD = False then mySerialThread.SetzeTXD;<br />
Sensor[SenNr] := RoundTo(frmCalibSensor.CalibArray[SenNr,ByteWert],-2);<br />
str := str + IntToStr(SenNr)+ ’;’ + FloatToStr(Sensor[SenNr]) + ’;’;<br />
mySensorString := str;<br />
end;<br />
4.3 Umwandlung der Spannungswerte in Wetterdaten<br />
Um aus den ermittelten Spannungswerten die Wetterdaten zu gewinnen, kann man zwei<br />
verschiedene Wege gehen. Zum einen kann man den Spannungswert einfach in eine Funk-
15 4 Software<br />
tion einsetzen und den Funktionswert angeben. Eine andere Möglichkeit ist es, den Spannungswert<br />
mit einer Tabelle zu vergleichen, in der für alle 256 möglichen Spannungswerte<br />
ein entsprechender Wert eingetragen ist. Der erste Weg eignet sich besonders gut für lineare<br />
Sensoren und Systeme mit geringer Speicherkapazität und Rechenleistung. Für<br />
den zweiten Weg spricht, dass er die Kalibrierung auch nicht linearer Sensoren einfach<br />
ermöglicht, sowie gezielte Korrekturen der Messwerte vorgenommen werden können. Der<br />
Nachteil des etwas größeren Speicherbedarfs von 8 <strong>KByte</strong> spielt allerdings auf PCs, wie<br />
sie hier benutzt werden, keine Rolle. Anders sähe es bei einer Mikrocontroller gesteuerten<br />
Station aus.<br />
4.4 Dokumentation der Messparameter<br />
procedure WriteMyData(FileName: OpenString; Data : OpenString);<br />
var myFile : TextFile;<br />
begin<br />
AssignFile(myFile,FileName);<br />
try<br />
if FileExists(FileName) = True then Append(myFile) else Rewrite(myFile);<br />
writeln(myFile,Data);<br />
finally<br />
CloseFile(myFile);<br />
end;<br />
end;<br />
Zunächst wird überprüft, ob die Datei schon existiert, anschließend wird sie geöffnet<br />
oder erzeugt und die Daten werden in die Datei geschrieben. Zum Schluss wird die Datei<br />
wieder geschlossen.
16 5 Übertragung<br />
5 Übertragung<br />
Für die Übertragung ist es vorgesehen, dass eine automatische Übertragung in eine Packet<br />
Radio Mailbox stattfindet, die auch über das Internet erreichbar ist. So können die Daten<br />
z.B. auf http://www.db0res.de:8080/ angesehen werden.<br />
5.1 Packet Radio<br />
Packet Radio ist eine digitale Betriebsart des Amateurfunks. Sie dient dem Aufbau von<br />
Verbindungen zu anderen Funkamateuren und dem weltweiten Informationsaustausch.<br />
So genannte Digipeater, automatisch arbeitende Packet Radio Amateurfunkstationen an<br />
exponierten Standorten bilden das Gerüst des Packet Radio Netzes. Die Digipeater sind<br />
untereinander verlinkt. Sie tauschen untereinander ständig Routeninformationen aus, so<br />
dass sie wie das Internet die effektivste Verbindung zwischen zwei Usern herstellen. Vor<br />
Ort bieten sie den Nutzern einen lokalen User-Einstieg ins Netz.<br />
Der Nutzer kann, nachdem er einen Digipeater connectet hat, sich mit weiteren Stationen<br />
verbinden. Im Netz besteht die Möglichkeit, Nachrichten und Binärdateien in eine<br />
Mailbox zu senden oder herunter zu laden. So besteht zum Beispiel auch die Möglichkeit,<br />
sich Satellitenbilder anzusehen oder schnell Wetterdaten abzurufen.<br />
Die Übertragung findet im 23cm, 70cm und 2m Band statt. Üblich sind dabei Übertragungsraten<br />
von 1k2 bit/s und 9k6 bit/s bei Nutzereinstiegen und 19k8 bit/s bis zu<br />
mehreren Megabit/s bei Linkstrecken zwischen Digipeatern.<br />
Packet Radio wird durch Frequenzumtastung moduliert (FSK-Modulation). Moderne<br />
kommerzielle Datenfunkanwendungen wie GPRS und WLAN nutzen die gleiche, wenn<br />
auch weiterentwickeltere Modulation.
17 5 Übertragung<br />
5.2 Packet Radio Station<br />
Für die Datenübertragung benötigt man neben einem Computer und einem handelsüblichen<br />
Amateurfunk-Transceiver ein Modem. Das Modem stellt zusammen mit entsprechender<br />
Software (z.B. FlexNet) die Verbindung zum Packet Radio Netz her und<br />
bewerkstelligt den Datentransfer, indem es die Befehle und Nutzdaten in Pakete des<br />
AX.25 Protokoll einbettet. Das AX.25 Protokoll ist eine für den Amateurfunk modifizierte<br />
Variante des kommerziellen X.25 Übertragungsprotokolls. Es sorgt für eine sichere<br />
und fehlerfreie Datenübertragung Statt des Modems und der Software (FlexNet) kann<br />
auch ein TNC (Terminal Node Controller) eingesetzt werden.<br />
5.3 Terminalprogramm Paxon<br />
Dem Nutzer steht mit einem Terminalprogramm wie Paxon eine leicht zu bedienende<br />
Oberfläche für die Betriebsart Packet Radio auf modernen Windows PCs zur Verfügung.<br />
Paxon ist aber nicht - wie andere Terminalprogramm unter DOS (z.B. SP) - fähig<br />
andere Programme aufzurufen bzw. fernzusteuern. Um auf einem modernen Windows<br />
PC dennoch die ermittelten Wetterparameter zu übertragen, muss meine Software die<br />
Übertragung selbst übernehmen. Glücklicherweise bietet Paxon eine COM- Programmierschnittstelle,<br />
mit der man auf wichtige Funktionen des Programms zugreifen kann,<br />
ohne sich um die eigentlichen Funktionsweise des Verbindungsaufbaus kümmern zu müssen.<br />
Dafür wird zunächst die Component Object Model (COM) Library mit CoInitialize initialisiert<br />
und anschließend mit CreateOleObject eine Referenz auf die COM-Schnittstelle<br />
von Paxon zurückgegeben. Mit dieser ist es nun möglich, Funktionen von Paxon wie<br />
FindConnection, Connect, SendTextLine, WaitForText oder Disconnect aufzurufen.<br />
If CoInitialize(NIL) S_OK then<br />
begin<br />
CoUninitialize;<br />
exit;<br />
end;<br />
// Paxon finden<br />
if FindWindow(’tHauptfenster’, NIL) > 0 then<br />
begin<br />
myPaxon := CreateOLEObject(’Paxon.Application’) as iApplication;
18 5 Übertragung<br />
Zu erwähnen bleibt, dass die Übertragung in einem eigenen Thread ausgeführt wird, so<br />
dass die Messwerterfassung ungestört von den Vorgängen der Übertragung stattfindet.<br />
Dieses Multithreading findet mittels einer abgeleiteten Standard TThread-Klasse statt.
19 5 Übertragung<br />
5.4 Übertragung in eine Mailbox<br />
Um die Daten nun z.B. alle 30 Minuten zu übertragen, ist es nur noch notwendig eine<br />
Verbindung mit dem nächsten User-Einstieg aufzubauen, sich mit einer Mailbox zu<br />
connecten und die Mail zu senden. Anschließend kann die Verbindung beendet werden.<br />
Dies geschieht bei meiner Software durch folgenden Code:<br />
procedure TPaxonThread.Connect(Call : WideString);<br />
begin<br />
Connection := myPaxon.FindConnection(Call);<br />
PaxonStr := ’Connection gefunden’;<br />
Synchronize(UpdateLabel);<br />
If Connection = Nil Then<br />
begin<br />
Connection := myPaxon.Connect(Call);<br />
PaxonStr := ’Neu verbunden’;<br />
Synchronize(UpdateLabel);<br />
end;<br />
end;<br />
procedure TPaxonThread.SendToMailbox(Einstieg : WideString; Board :<br />
WideString; Betreff : WideString);<br />
begin<br />
Connect(Einstieg);<br />
Connection.SendTextLine(’ ’);<br />
Connection.WaitForText(’=>’);<br />
Connection.SendTextLine(’m’);<br />
Connection.WaitForText(’-->’);<br />
Connection.SendTextLine(’ ’);<br />
Connection.WaitForText(’-->’);<br />
Connection.SendTextLine(’s’ + ’ ’ + Board + ’ ’ + Betreff);<br />
Connection.WaitForText(’:’);<br />
Connection.SendTextLine(’Diese Mail wurde automatisch generiert’);<br />
Synchronize(SendSensorData);<br />
Connection.SendTextLine(myString);<br />
Connection.SendTextLine(’NNNN’);<br />
Connection.WaitForText(’-->’);<br />
Connection.SendTextLine(’ ’);<br />
Connection.WaitForText(’-->’);<br />
Connection.SendTextLine(’q’);<br />
SendMailNext := False;<br />
end;
20 6 Schlussbetrachtung<br />
6 Schlussbetrachtung<br />
Diese Arbeit bedeutete für mich eine sehr große Herausforderung. Da zahlreiche Probleme<br />
zu lösen waren:<br />
• Entwicklung von Wettersensoren<br />
• Entwicklung der Hardware zur Messwerterfassung<br />
• Entwicklung und Programmierung von Software<br />
• Programmierung der Übertragung ins Funknetz<br />
Um all diese Probleme zu lösen, ging ich zunächst auf die Suche nach geeigneter Literatur.<br />
Ich stieß auf den TLC 549 und dessen Ansteuerung mithilfe des PCs in ”Messen,<br />
Steuern und Regeln mit Word und Excel” von H.J. Berndt und B. Kainka. Im gleichen<br />
Buch fand sich die Schaltung eines Temperatursensors.<br />
Für den ersten Aufbau benutzte ich ein Steckbrett, so dass ich die Schaltungen einfach<br />
ausprobieren und erweitern konnte. Da von vornherein klar war, das nicht nur ein Sensor<br />
abgefragt werden sollte, suchte ich Möglichkeiten, die Schaltung um Sensoren zu erweitern.<br />
So kam ich zu der Idee, einen Analog-Multiplexer zu benutzen. Ich baute darauf<br />
die Schaltung für den A/D-Wandler, den Multiplexer und den achtstufigen Binärzähler<br />
auf der Steckplatine auf.<br />
Neben dem Aufbau programmierte ich die grundlegenden Funktionen der Software und<br />
zeichnete den Schaltplan. Nachdem auf dem Steckbrett weitere Sensoren funktionierten,<br />
begann ich mit dem Aufbau der Station auf einer Streifenrasterplatine. Trotz einiger<br />
zu bewältigende Programmierprobleme und Hardwareschwierigkeiten, gelang es mir,<br />
schließlich einen Prototypen fertig zu stellen. Da dieser recht gut lief, kontrollierte ich<br />
die Schaltung auf Fehler und ließ eine Platine dieser Schaltung ätzen.<br />
Das hier vorgestellte Projekt bietet aus meiner Sicht vielfältige Anbindungsmöglichkeiten<br />
an den projektorientierten Physik- und Technikunterricht in der Schule. Dies ist eine gute<br />
Möglichkeit, den Unterricht in diesen Fächern interessant, anspruchsvoll und innovativ
21 6 Schlussbetrachtung<br />
zu gestalten, um so das Interesse und die Begeisterung von Schülerinnen und Schülern<br />
an der Technik zu wecken und zu fördern.<br />
Der Leser kann sich von der Funktionsfähigkeit der Station überzeugen, indem er unter<br />
http://www.db0res.de:8080/ den Befehl l wetter -100 in der Befehlsbox unter der Beschriftung<br />
”Commands” eingibt. Dort findet man unter meinem Rufzeichen, DO2YRB,<br />
mit dem Betreff ”Wx LH” die Wetterdaten aus Lüdinghausen. Anschließend einfach auf<br />
das Rufzeichen klicken und die Mail wird angezeigt.
22 7 Ausblick<br />
7 Ausblick<br />
Eigenartig und dunkel erscheint schon seit der Antike das Verhalten von Fledermäusen:<br />
So beschreibt der römische Dichter Ovid (43 v. Chr. bis 17 n. Chr.) das Ende der drei<br />
Töchter des Königs von Böotien, Minyas: Zur Strafe wurden sie in Fledermäuse verwandelt,<br />
weil sie es vorgezogen hatten, am Webstuhl zu arbeiten und sich Geschichten zu<br />
erzählen, statt an den Festlichkeiten zu Ehren des Weingottes Bacchus teilzunehmen.<br />
Tectaque, non silvas celebrant lucemque perosae<br />
Nocte volant seroque tenent a vespere nomen.<br />
(Häuser, nicht Wälder bewohnen sie, hassen das Licht<br />
fliegen in der Nacht und vom späten Abend haben sie ihren Namen.)<br />
(Ovid, Metamorphosen IV 414f.)<br />
Ein wenig Licht in das Verhalten dieser immer schon in unserem Kulturkreis suspekten<br />
und mit dunklem Odem behafteten Tiere, die sich in der Nähe von Häusern aufhalten<br />
und ihren lateinischen Namen durch ihre Nachtaktivität erhalten haben, war und ist das<br />
Ziel dieser Arbeit.<br />
Dafür ist die Wetterstation zunächst einmal auf ihre Zuverlässigkeit bei Wind und Wetter<br />
zu prüfen. Hat sie sich bewährt, dann soll sie in unmittelbarer Nahe zum Fledermausstollen<br />
dauerhaft installiert werden. Dazu müssen Kabel vom Standort des nun<br />
anzuschaffenden PC zu den Sensoren verlegt werden. Darüber hinaus ist der Erwerb von<br />
Funkgeräten notwendig. Hier empfehle ich das Projekt einer weiteren Förderung durch<br />
den VDE Rhein Ruhr e.V.<br />
Denkbar für die Zukunft ist die Erweiterung der Wetterstation für IR-Lichtschranken und<br />
eines Sensors für die Messung der Windgeschwindigkeit. Bei der Planung des Systems<br />
wurde diese Erweiterungsmöglichkeit berücksichtigt. Eine prinzipielle Weiterentwicklung<br />
wäre der Einsatz von Microcontrollern.<br />
Hat sich die Station in der Praxis als zuverlässig erwiesen, wird sie bestimmt auch für<br />
einen breiteren Nutzerkreis interessant sein.
23 Literatur<br />
Literatur<br />
[1] A. Wendt, “Computergestützte Wetterstation”, Praxisheft 3 für Amateurfunk und<br />
Elektronik in Schule und Freizeit, Heft 3 , Seite 4-19, o.J..<br />
[2] A. Schweizer, “ASYNOP-meterologischer Schlüssel für das WxNET”, Praxisheft 9<br />
für Amateurfunk und Elektronik in Schule und Freizeit, Heft 9 , Seite 4-9, 1999.<br />
[3] A. Schweizer, “Die AATiS-Wetterstation: Hardware”, Praxisheft 9 für Amateurfunk<br />
und Elektronik in Schule und Freizeit, Heft 9 , Seite 10-14, 1999.<br />
[4] A. Schweizer, “Die AATis-Wetterstation: Software”, Praxisheft 9 für Amateurfunk<br />
und Elektronik in Schule und Freizeit, Heft 9 , Seite 15-17, 1999.<br />
[5] A. Schweizer, “Schritte ins WxNET”, Praxisheft 9 für Amateurfunk und Elektronik<br />
in Schule und Freizeit, Heft 9 , Seite 18-23, 1999.<br />
[6] H.J. Berndt/B. Kainka, Messen, Steuern und Regeln mit Word und Excel, Poing,<br />
Francis-Verlag, 2001 3 .<br />
[7] K. Block/H.-J. Hölzel/L. Wölfing/P. Zachert, Kontaktlose Signalverarbeitung, Köln-<br />
Porz, Verlag H. Stam GmbH, 1979 3 .<br />
[8] W.-D. Schmidt, Sensorschaltungstechnik, Würzburg, Vogel Verlag, 2002 2 .<br />
[9] DISCRETE SEMICONDUCTORS, KTY81-2 series. Silicon temperature sensors,<br />
DATA SHEET, 16 Seiten, 1996<br />
[10] STMicroelectronics, NE555 SA555 SE555. GENERAL PURPOSE SINGLE BIPO-<br />
LAR TIMERS, DATA SHEET, 10 Seiten, 1998<br />
[11] National Semiconductor, LM2907/LM2917 Frequency to Voltage Converter, DATA<br />
SHEET, 18 Seiten, 1995<br />
[12] Texas Instruments, CD4051B, CD4052B, CD4053B, DATA SHEET, 20 Seiten, 2003<br />
[13] Fairchild Semiconductor, CD4027BC Dual J-K Master/Slave Flip-Flop with Set and<br />
Reset, DATA SHEET,6 Seiten, 2002<br />
[14] Philips Components, Moisture control with Philips’humidity sensor, DATA SHEET,<br />
7 Seiten, 1997<br />
[15] Motorola, MPX4115A MPXA4115A SERIES, SEMICONDUCTOR TECHNICAL<br />
DATA, 9 Seiten, 2001
24 Literatur<br />
[16] Texas Instruments, TLC548C, TLC548I, TLC549C, TLC549I 8-BIT ANALOG-<br />
TO-DIGITAL CONVERTERS WITH SERIAL CONTROL DATA SHEET, 12 Seiten,<br />
1996<br />
[17] Texas Instruments, µA741, µA741Y GENERAL-PURPOSE OPERATIONAL AM-<br />
PLIFIERS, DATA SHEET, 11 Seiten, 2000<br />
[18] Michael Puff, Thread Programmierung unter Windows mit Delphi, Version 2.4,<br />
http://www.luckie-online.de, 2005
A Schaltpläne<br />
25 A Schaltpläne
26 A Schaltpläne<br />
Abbildung A.1: Schaltplan für Wettermessstation
27 A Schaltpläne<br />
Abbildung A.2: Schaltplan für Temperatursensoren, Lichtsensoren und Drucksensor
B Fotos<br />
28 B Fotos
29 B Fotos<br />
Abbildung B.1: Messschaltung auf Streifenrasterplatine, Schrägansicht<br />
Abbildung B.2: Messschaltung auf Streifenrasterplatine, Draufsicht
30 B Fotos<br />
Abbildung B.3: Sensoren auf Streifenrasterplatine<br />
Abbildung B.4: Geätzte Platine, Schrägansicht
31 B Fotos<br />
Abbildung B.5: Geätzte Platine, Draufsicht<br />
Abbildung B.6: Geätzte Sensorplatine für Luftfeuchigkeit
C Stückliste<br />
32 C Stückliste
33 C Stückliste<br />
Tabelle C.1: Stückliste für Messstation (Preise: Reichelt Elektronik, 07.06.06)<br />
Artikel Beschreibung Preis Anzahl<br />
(inkl. MWSt.)<br />
MOS 4051 CD4051BE Multiplexer 0.23 1<br />
MOS 4027 Dual-JK Master-Slave Flip-Flop 0.23 1<br />
TLC 549 CP A/D-Converter, DIP-8 1.95 1<br />
µA 7805 Spannungsregler 1A positiv, TO-220 0.17 1<br />
µA 7905 Spannungsregler 1A negativ, TO-220 0.17 1<br />
LED 5MM LED, 5mm 0.05 4<br />
1N 4001 DIODE 0.02 3<br />
BC 107A TRANSISTOR 0.23 2<br />
Schalter Kippschalter 1.15 2<br />
D-SUB BU 09 D-SUB-Buchse, 9-polig, Lötkelch 0.10 1<br />
BB 4 Bananenbuchse 4mm, vollisoliert 0.25 4<br />
µA 741 DIP Op-Amp, DIP-8 0.14 4<br />
64W-1,0K Präzisionspoti. 25 Gänge, stehend, 1,0 K-Ohm 0.64 2<br />
1,0K Metalloxidschicht-Widerstand 1,0 K-Ohm 0.09 22<br />
4,7K Metalloxidschicht-Widerstand 4,7 K-Ohm 0.09 1<br />
NE 555 DIP Timer, DIP-8 0.12 1<br />
LM 2907 DIL Converter, DIL-14 (LM 2907-8) 1.20 1<br />
1,0M Metalloxidschicht-Widerstand 1 M-Ohm 0.09 1<br />
560K Metalloxidschicht-Widerstand 560 K-Ohm 0.09 1<br />
47K Metalloxidschicht-Widerstand 47 K-Ohm 0.09 1<br />
KERKO 22N KERAMIK-KONDENSATOR 0.07 1<br />
KERKO 470P KERAMIK-KONDENSATOR 0.04 1<br />
100K Metalloxidschicht-Widerstand 100 K-Ohm 0.09 1<br />
10K Metalloxidschicht-Widerstand 10 K-Ohm 0.09 6<br />
2,2K Metalloxidschicht-Widerstand 2,2 K-Ohm 0.09 2<br />
64W-10K Präzisionspoti. 25 Gänge, stehend, 10 K-Ohm 0.64 7<br />
KERKO 100N KERAMIK-KONDENSATOR 0.07 15<br />
H25SR160 Streifenrasterplatine, Hartpapier, 160x100mm 1.30 2<br />
Warenwert: 21.42<br />
MPX 4115A Motorola-Drucksensor 24.30 1<br />
KTY 81-210 Temperatursensor, -55...+150 ◦ C 0.59 2<br />
LDR 03 Fotowiderstand 1.60 2<br />
FEUCHTES. Sensor für Feuchtigkeit 11.60 1<br />
Warenwert: Sensoren 40.28<br />
Warenwert: gesamt 61.70
34 D Quellcode<br />
D Quellcode<br />
program Wetherstation;<br />
uses<br />
Forms,<br />
Main in ’Main.pas’ {frmMain},<br />
Thread in ’Thread.pas’,<br />
Speichern in ’Speichern.pas’,<br />
Paxon in ’Paxon.pas’,<br />
CalibSensor in ’CalibSensor.pas’ {frmCalibSensor};<br />
{$R *.res}<br />
begin<br />
Application.Initialize;<br />
Application.CreateForm(TfrmMain, frmMain);<br />
Application.CreateForm(TfrmCalibSensor, frmCalibSensor);<br />
MySerialThread := TSerialThread.Create(True);<br />
MyPaxonThread := TPaxonThread.Create(@mySendMailNext, @mySensorString,frmMain.lblPaxon,True);<br />
Application.Run;<br />
end.<br />
unit Main;<br />
interface<br />
uses<br />
Windows, Messages, Variants, Classes, Graphics, Controls, Forms,<br />
Dialogs, StdCtrls, SysUtils, Thread, ExtCtrls, Speichern, Math, Paxon,<br />
CalibSensor,Paxon_TLB,ActiveX,ComObj;<br />
type<br />
TfrmMain = class(TForm)<br />
btnOpen: TButton;<br />
lblStatus: TLabel;<br />
btnCloseCom: TButton;<br />
Label1: TLabel;<br />
Label2: TLabel;<br />
Label3: TLabel;<br />
Label4: TLabel;<br />
Label5: TLabel;<br />
Label6: TLabel;<br />
Label7: TLabel;<br />
Label8: TLabel;<br />
Label9: TLabel;<br />
lblSensor1: TLabel;<br />
lblSensor2: TLabel;<br />
lblSensor3: TLabel;<br />
lblSensor4: TLabel;<br />
lblSensor5: TLabel;<br />
lblSensor6: TLabel;<br />
lblSensor7: TLabel;<br />
lblSensor8: TLabel;
35 D Quellcode<br />
tmrSensorabfrage: TTimer;<br />
chbSensoren: TCheckBox;<br />
chbSaveSensor: TCheckBox;<br />
lblUhr: TLabel;<br />
btnStartThread: TButton;<br />
lblPaxon: TLabel;<br />
btnStopThread: TButton;<br />
btnCalibSensor: TButton;<br />
chbSendMail: TCheckBox;<br />
tmrMail: TTimer;<br />
Label10: TLabel;<br />
txtSensorTime: TEdit;<br />
Label11: TLabel;<br />
Label12: TLabel;<br />
txtSendTime: TEdit;<br />
Label13: TLabel;<br />
txtEinstieg: TEdit;<br />
Label14: TLabel;<br />
lbl: TLabel;<br />
Label15: TLabel;<br />
txtBoard: TEdit;<br />
txtBetreff: TEdit;<br />
Label16: TLabel;<br />
btnSendEinstellungen: TButton;<br />
procedure btnOpenClick(Sender: TObject);<br />
procedure btnCloseComClick(Sender: TObject);<br />
procedure tmrSensorabfrageTimer(Sender: TObject);<br />
procedure btnStartThreadClick(Sender: TObject);<br />
procedure btnStopThreadClick(Sender: TObject);<br />
procedure btnCalibSensorClick(Sender: TObject);<br />
procedure tmrMailTimer(Sender: TObject);<br />
procedure txtSensorTimeChange(Sender: TObject);<br />
procedure txtSendTimeChange(Sender: TObject);<br />
procedure btnSendEinstellungenClick(Sender: TObject);<br />
private<br />
public<br />
end;<br />
var<br />
frmMain: TfrmMain;<br />
var mySerialThread: TSerialThread;<br />
var mySaveSensor: TSaveSensor;<br />
var myPaxonThread: TPaxonThread;<br />
myTimeString : String;<br />
mySensorString : WideString;<br />
mySendMailNext : Boolean;<br />
implementation<br />
{$R *.dfm}<br />
procedure TfrmMain.btnOpenClick(Sender: TObject);<br />
begin<br />
if mySerialThread.OpenCOM(1)= False then<br />
lblStatus.Caption := ’Fehler beim Öffnen’<br />
else<br />
lblStatus.Caption := ’Erfolgreich geöffnet’;<br />
end;<br />
procedure TfrmMain.btnCloseComClick(Sender: TObject);<br />
begin<br />
if mySerialThread.CloseCOM = true then lblStatus.Caption := ’COM geschlossen’;<br />
end;<br />
procedure TfrmMain.tmrSensorabfrageTimer(Sender: TObject);
36 D Quellcode<br />
var ByteWert, SenNr, i, ByteSumme : Integer;<br />
Sensor: array[0..7] of Extended;<br />
str, myTimeStr, appendstr: string;<br />
myTime : TDateTime;<br />
const Zahler = 1000;<br />
begin<br />
if chbSensoren.Checked = True then<br />
begin<br />
myTime := Date + Time;<br />
myTimeStr := DateToStr(Date) + ’;’ + TimeToStr(Time);<br />
str := myTimeStr + ’;’;<br />
mySensorString := ’PC Uhrzeit: ’ + myTimeStr + #13;<br />
for SenNr := 0 to 7 do<br />
begin<br />
if mySerialThread.StatTXD = True then mySerialThread.ClearTXD<br />
else if mySerialThread.StatTXD = False then mySerialThread.SetzeTXD;<br />
ByteWert:=0;<br />
ByteSumme:=0;<br />
for i := 0 to Zahler do<br />
begin<br />
ByteWert := mySerialThread.ByteRead;<br />
ByteSumme := ByteSumme + ByteWert;<br />
end;<br />
ByteWert := Round(ByteSumme / Zahler);<br />
Sensor[SenNr] := RoundTo(frmCalibSensor.CalibArray[SenNr,ByteWert],-2);<br />
appendstr := IntToStr(SenNr)+ ’;’ + FloatToStr(Sensor[SenNr]) +<br />
frmCalibSensor.EinheitArray[SenNr] + ’;’;<br />
str := str + appendstr;<br />
mySensorString := mySensorString + ’SensorNr ’ + IntToStr(SenNr) + ’: ’ +<br />
FloatToStr(Sensor[SenNr]) + frmCalibSensor.EinheitArray[SenNr]<br />
+ #13;<br />
end;<br />
str := str + #13;<br />
if chbSaveSensor.Checked = True then WriteMyData(’SensorData.txt’,str);<br />
lblSensor1.Caption := FloattoStr(Sensor[0]);<br />
lblSensor2.Caption := FloattoStr(Sensor[1]);<br />
lblSensor3.Caption := Floattostr(Sensor[2]);<br />
lblSensor4.Caption := FloattoStr(Sensor[3]);<br />
lblSensor5.Caption := FloattoStr(Sensor[4]);<br />
lblSensor6.Caption := Floattostr(Sensor[5]);<br />
lblSensor7.Caption := FloattoStr(Sensor[6]);<br />
lblSensor8.Caption := Floattostr(Sensor[7]);<br />
lblUhr.Caption := DateTimeToStr(myTime);<br />
end;<br />
mySaveSensor.Free;<br />
end;<br />
procedure TfrmMain.btnStartThreadClick(Sender: TObject);<br />
begin<br />
tmrMail.Interval := StrToInt(txtSendTime.Text) * 60000;<br />
myPaxonThread.Resume;<br />
end;<br />
procedure TfrmMain.btnStopThreadClick(Sender: TObject);<br />
begin<br />
myPaxonThread.Terminate;<br />
end;<br />
procedure TfrmMain.btnCalibSensorClick(Sender: TObject);<br />
begin<br />
frmCalibSensor.lblSensorNr.Caption := inttostr(frmCalibSensor.SensorNr);<br />
frmCalibSensor.Show;<br />
end;<br />
procedure TfrmMain.tmrMailTimer(Sender: TObject);
37 D Quellcode<br />
begin<br />
if chbSendMail.Checked = True Then myPaxonThread.SendMailNext := True<br />
else myPaxonThread.SendMailNext := False;<br />
end;<br />
procedure TfrmMain.txtSensorTimeChange(Sender: TObject);<br />
begin<br />
tmrSensorabfrage.Interval := StrToInt(txtSensorTime.Text) * 1000;<br />
end;<br />
procedure TfrmMain.txtSendTimeChange(Sender: TObject);<br />
begin<br />
tmrMail.Interval := StrToInt(txtSendTime.Text) * 60000;<br />
end;<br />
procedure TfrmMain.btnSendEinstellungenClick(Sender: TObject);<br />
var save : boolean;<br />
begin<br />
save := myPaxonThread.SendMailNext;<br />
myPaxonThread.SendMailNext := False;<br />
myPaxonThread.myEinstieg := txtEinstieg.Text;<br />
myPaxonThread.myBoard := txtBoard.Text;<br />
myPaxonThread.myBetreff := txtBetreff.Text;<br />
myPaxonThread.SendMailNext := save;<br />
end;<br />
end.<br />
unit Thread;<br />
interface<br />
uses<br />
Classes, Windows, SysUtils;<br />
type<br />
TSerialThread = class(TThread)<br />
private<br />
PortTimeout : _COMMTIMEOUTS;<br />
PortHandle : Integer;<br />
PortDCB : TDCB;<br />
PortNr : Integer;<br />
PortState : Cardinal;<br />
WriteOverlapped,ReadOverlapped,StatusOs: TOverlapped; { Private-Deklarationen }<br />
protected<br />
fComEvent: cardinal;<br />
fStatCTS: boolean;<br />
fStatDCD: boolean;<br />
fStatDSR : Boolean;<br />
fStatRing : Boolean;<br />
procedure Execute; override;<br />
public<br />
StatDTR : boolean;<br />
StatRTS : boolean;<br />
StatTXD : boolean;<br />
constructor Create(CreateSuspended: Boolean);<br />
property ComEvent: cardinal read fComEvent;<br />
property StatCTS: boolean read fStatCTS;<br />
property StatDCD: boolean read fStatDCD;<br />
property StatDSR: boolean read fStatDSR;<br />
property StatRing: boolean read fStatRing;<br />
function ClearDTR : boolean; stdcall;<br />
function ClearRTS : boolean; stdcall;<br />
function ClearTXD : boolean; stdcall;<br />
function SetzeDTR : boolean; stdcall;
38 D Quellcode<br />
function SetzeRTS : boolean; stdcall;<br />
function SetzeTXD : boolean; stdcall;<br />
function ComAvailable(ComNr: byte): boolean; stdcall;<br />
function CTS : boolean; stdcall;<br />
function DCD : boolean; stdcall;<br />
function DSR : boolean; stdcall;<br />
function RING : boolean; stdcall;<br />
function ByteRead : Integer; stdcall;<br />
function OpenCOM(Port: byte): boolean; stdcall;<br />
function CloseCOM : boolean; stdcall;<br />
procedure InitOverlapped(var Overlapped : TOverlapped);<br />
procedure ReleaseEvent(Event : Cardinal);<br />
function SetBaudRate(baud: cardinal): boolean; stdcall;<br />
end;<br />
implementation<br />
constructor TSerialThread.Create(CreateSuspended: Boolean);<br />
begin<br />
FreeOnTerminate:= True;<br />
inherited Create(CreateSuspended);<br />
Priority := tpNormal;<br />
end;<br />
procedure TSerialThread.ReleaseEvent(Event : Cardinal);<br />
begin<br />
fStatCTS := CTS;<br />
fStatDSR := DSR;<br />
fStatDCD := DCD;<br />
fStatRING := RING;<br />
end;<br />
procedure TSerialThread.Execute;<br />
var<br />
SerialEvent, WaitResult, BytesRead: Cardinal;<br />
begin<br />
SetCommMask(PortHandle,EV_CTS or EV_DSR or<br />
EV_RING or EV_RLSD);<br />
if not WaitCommEvent(PortHandle,SerialEvent,@StatusOs) then<br />
begin<br />
if (GetLastError = ERROR_IO_PENDING) then<br />
begin<br />
WaitResult := WaitForSingleObject(StatusOs.hEvent,INFINITE);<br />
case WaitResult of<br />
WAIT_OBJECT_0:<br />
begin<br />
if GetOverlappedResult(PortHandle,StatusOs,BytesRead,false) then<br />
ReleaseEvent(SerialEvent);<br />
end;<br />
end;<br />
end;<br />
end else ReleaseEvent(SerialEvent);<br />
end;<br />
procedure TSerialThread.InitOverlapped(var Overlapped : TOverlapped);<br />
begin<br />
Overlapped.Offset := 0;<br />
Overlapped.OffsetHigh := 0;<br />
Overlapped.Internal := 0;<br />
Overlapped.InternalHigh := 0;<br />
Overlapped.hEvent := CreateEvent(nil,True,False,’’);<br />
end;
39 D Quellcode<br />
function TSerialThread.OpenCOM(Port: byte): boolean; stdcall;<br />
begin<br />
PortHandle :=<br />
CreateFile(PChar(’\\.\COM’+IntToStr(Port)),GENERIC_READ or GENERIC_WRITE,0,<br />
nil,OPEN_EXISTING,FILE_FLAG_OVERLAPPED,LongInt(0));<br />
if PortHandle > 0 then<br />
begin<br />
Result := true;<br />
InitOverlapped(WriteOverlapped);<br />
InitOverlapped(ReadOverlapped);<br />
InitOverlapped(StatusOs);<br />
end else Result := false;<br />
end;<br />
function TSerialThread.CloseCOM : boolean; stdcall;<br />
begin<br />
PurgeComm(PortHandle, PURGE_RXABORT or PURGE_RXCLEAR or PURGE_TXABORT or PURGE_TXCLEAR);<br />
SetCommMask(PortHandle,0); //unterbricht WaitCommEvent im Polling thread<br />
result:= CloseHandle(PortHandle);<br />
PortHandle := 0;<br />
end;<br />
function TSerialThread.ComAvailable(ComNr: byte): boolean; stdcall;<br />
var<br />
TestHandle : integer;<br />
begin<br />
TestHandle :=<br />
CreateFile(PChar(’\\.\COM’+IntToStr(ComNr)),GENERIC_READ or GENERIC_WRITE,0,<br />
nil,OPEN_EXISTING,FILE_FLAG_OVERLAPPED,LongInt(0));<br />
if (TestHandle
40 D Quellcode<br />
begin<br />
if (PortHandle 0) then Result := EscapeCommFunction(PortHandle,CLRDTR);<br />
StatDTR := False;<br />
end;<br />
function TSerialThread.ClearRTS : boolean; stdcall;<br />
begin<br />
if (PortHandle 0) then Result := EscapeCommFunction(PortHandle,CLRRTS);<br />
StatRTS := False;<br />
end;<br />
function TSerialThread.ClearTXD : boolean; stdcall;<br />
begin<br />
if (PortHandle 0) then Result := EscapeCommFunction(PortHandle,CLRBREAK);<br />
StatTXD := False;<br />
end;<br />
function TSerialThread.DSR : boolean; stdcall;<br />
begin<br />
GetCommModemStatus(PortHandle,PortState);<br />
if ((Portstate and MS_DSR_ON) 0) then Result := true<br />
else Result := false;<br />
end;<br />
function TSerialThread.CTS : boolean; stdcall;<br />
begin<br />
GetCommModemStatus(PortHandle,PortState);<br />
if ((Portstate and MS_CTS_ON) 0) then Result := true<br />
else Result := false;<br />
end;<br />
function TSerialThread.DCD : boolean; stdcall;<br />
begin<br />
GetCommModemStatus(PortHandle,PortState);<br />
if ((Portstate and MS_RLSD_ON) 0) then Result := true<br />
else Result := false;<br />
end;<br />
function TSerialThread.RING : boolean; stdcall;<br />
begin<br />
GetCommModemStatus(PortHandle,PortState);<br />
if ((Portstate and MS_RING_ON) 0) then Result := true<br />
else Result := false;<br />
end;<br />
function TSerialThread.ByteRead : Integer; stdcall;<br />
var BitWert, b, i : Integer;<br />
begin<br />
BitWert := 128;<br />
b := 0;<br />
//Chipselect ein und ausschalten<br />
SetzeRTS;<br />
ClearRTS;<br />
//Am Dataout liegt jetzt das 1. Bit<br />
for i := 0 to 7 do // 8 mal weiterschalten<br />
begin<br />
if CTS = True then<br />
b := b + BitWert;<br />
//I/O-Clock weiterschalten<br />
SetzeDTR;<br />
ClearDTR;<br />
//nächstes Bit nur noch halbwertig<br />
BitWert := BitWert div 2;<br />
end;<br />
result := b;<br />
end;<br />
end.
41 D Quellcode<br />
unit Speichern;<br />
interface<br />
uses<br />
Classes, Windows, SysUtils;<br />
procedure WriteMyData(FileName: OpenString; Data : OpenString);<br />
type<br />
TSaveSensor = class(TFileStream)<br />
private<br />
protected<br />
public<br />
end;<br />
const<br />
fmCreate = $FFFF;<br />
fmOpenRead = $0000;<br />
fmOpenWrite = $0001;<br />
fmOpenReadWrite = $0002;<br />
fmShareCompat = $0000 platform;<br />
fmShareExclusive = $0010;<br />
fmShareDenyWrite = $0020;<br />
fmShareDenyRead = $0030 platform;<br />
fmShareDenyNone = $0040;<br />
implementation<br />
procedure WriteMyData(FileName: OpenString; Data : OpenString);<br />
var myFile : TextFile;<br />
begin<br />
AssignFile(myFile,FileName);<br />
try<br />
if FileExists(FileName) = True then Append(myFile) else Rewrite(myFile);<br />
writeln(myFile,Data);<br />
finally<br />
CloseFile(myFile);<br />
end;<br />
end;<br />
end.<br />
unit Paxon;<br />
interface<br />
uses Windows, Paxon_TLB, ComObj, ActiveX, Dialogs, Classes, StdCtrls;<br />
type PBoolean = ^Boolean;<br />
type<br />
TPaxonThread = class(TThread)<br />
private<br />
lblCaption : TLabel;<br />
myStringPointer :PWideString;<br />
myString : WideString;<br />
SendMailNextPointer : PBoolean;<br />
procedure Connect(Call : WideString);<br />
procedure SendSensorData();<br />
protected<br />
PaxonStr : string;<br />
procedure Execute; override;<br />
procedure UpdateLabel;
42 D Quellcode<br />
public<br />
Connection : iConnection;<br />
myPaxon : iApplication;<br />
SendMailNext : Boolean;<br />
myEinstieg: WideString;<br />
myBoard: WideString;<br />
myBetreff: WideString;<br />
procedure SendToMailbox(Einstieg : WideString;<br />
Board : WideString; Betreff : WideString);<br />
constructor Create(SendMailPointer : PBoolean; StringPointer:PWideString ;<br />
myLabel : TLabel; CreateSuspended : Boolean);<br />
end;<br />
implementation<br />
constructor TPaxonThread.Create(SendMailPointer : PBoolean; StringPointer :PWideString;<br />
myLabel : TLabel; CreateSuspended : Boolean);<br />
begin<br />
FreeOnTerminate := False;<br />
lblCaption := myLabel;<br />
myStringPointer := StringPointer;<br />
SendMailNextPointer := SendMailPointer;<br />
myEinstieg:= ’DB0EA’;<br />
myBoard:= ’Wetter @ DB0RES.#NRW.DEU.EU’;<br />
myBetreff:= ’Wx LH’;<br />
inherited Create(CreateSuspended);<br />
end;<br />
procedure TPaxonThread.Execute();<br />
begin<br />
Connection := nil;<br />
myPaxon := Nil;<br />
SendMailNext := True ;<br />
try<br />
If CoInitialize(NIL) S_OK then<br />
begin<br />
CoUninitialize;<br />
PaxonStr :=’Fehler’;<br />
Synchronize(UpdateLabel);<br />
exit;<br />
end;<br />
// Paxon finden<br />
if FindWindow(’tHauptfenster’, NIL) > 0 then<br />
begin<br />
myPaxon := CreateOLEObject(’Paxon.Application’) as iApplication;<br />
PaxonStr := ’Paxon-Objekt erzeugt’;<br />
Synchronize(UpdateLabel);<br />
Connect(myEinstieg);<br />
while (not Terminated) do<br />
begin<br />
if SendMailNext = True then SendToMailbox(myEinstieg,myBoard,myBetreff);<br />
Synchronize(UpdateLabel);<br />
end;<br />
end<br />
else PaxonStr := ’Application nicht erzeugt’; Synchronize(UpdateLabel);<br />
finally<br />
Connection.Disconnect;<br />
CoUninitialize;<br />
PaxonStr := ’Verbindung beendet’;<br />
Synchronize(UpdateLabel);<br />
end;<br />
end;<br />
procedure TPaxonThread.UpdateLabel;
43 D Quellcode<br />
begin<br />
lblCaption.Caption := PaxonStr;<br />
end;<br />
procedure TPaxonThread.SendSensorData();<br />
begin<br />
myString := myStringPointer^;<br />
end;<br />
procedure TPaxonThread.Connect(Call : WideString);<br />
begin<br />
Connection := myPaxon.FindConnection(Call);<br />
PaxonStr := ’Connection gefunden’;<br />
Synchronize(UpdateLabel);<br />
If Connection = Nil Then<br />
begin<br />
Connection := myPaxon.Connect(Call);<br />
PaxonStr := ’Neu verbunden’;<br />
Synchronize(UpdateLabel);<br />
end;<br />
end;<br />
procedure TPaxonThread.SendToMailbox(Einstieg : WideString; Board :<br />
WideString; Betreff : WideString);<br />
begin<br />
Connect(Einstieg);<br />
Connection.SendTextLine(’ ’);<br />
Connection.WaitForText(’=>’);<br />
Connection.SendTextLine(’m’);<br />
Connection.WaitForText(’-->’);<br />
Connection.SendTextLine(’ ’);<br />
Connection.WaitForText(’-->’);<br />
Connection.SendTextLine(’s’ + ’ ’ + Board + ’ ’ + Betreff);<br />
Connection.WaitForText(’:’);<br />
Connection.SendTextLine(’Diese Mail wurde automatisch generiert’);<br />
Synchronize(SendSensorData);<br />
Connection.SendTextLine(myString);<br />
Connection.SendTextLine(’NNNN’);<br />
Connection.WaitForText(’-->’);<br />
Connection.SendTextLine(’ ’);<br />
Connection.WaitForText(’-->’);<br />
Connection.SendTextLine(’q’);<br />
SendMailNext := False;<br />
end;<br />
end.<br />
unit CalibSensor;<br />
interface<br />
uses<br />
SysUtils, Windows, Messages, Classes, Graphics, Controls,<br />
StdCtrls, ExtCtrls, Forms, Dialogs;<br />
type TCalibArray = Array[0..7,0..255] of Single;<br />
type TEinheitArray = Array[0..7] of ShortString;<br />
type<br />
TfrmCalibSensor = class(TForm)<br />
btnOk: TButton;<br />
btnCancel: TButton;<br />
Label1: TLabel;<br />
lblSensorNr: TLabel;<br />
Label2: TLabel;<br />
Label3: TLabel;
44 D Quellcode<br />
Label4: TLabel;<br />
txt0: TEdit;<br />
txt127: TEdit;<br />
txt255: TEdit;<br />
txtEinheit: TEdit;<br />
lblEinheit: TLabel;<br />
btnSpeichern: TButton;<br />
btnLaden: TButton;<br />
txtSensorNr: TEdit;<br />
lstArray: TListBox;<br />
rdbLinear: TRadioButton;<br />
rdbEinzelauswahl: TRadioButton;<br />
btnUebernehmen: TButton;<br />
procedure btnOkClick(Sender: TObject);<br />
procedure btnSpeichernClick(Sender: TObject);<br />
procedure btnLadenClick(Sender: TObject);<br />
procedure ArrayFuellen();<br />
procedure btnCancelClick(Sender: TObject);<br />
procedure ListBoxFuellen();<br />
procedure txtSensorNrChange(Sender: TObject);<br />
procedure btnUebernehmenClick(Sender: TObject);<br />
procedure Aktualisieren();<br />
procedure lstArrayClick(Sender: TObject);<br />
public SensorNr: Byte;<br />
public CalibArray: TCalibArray;//Array[0..7,0..255] of Single;<br />
public EinheitArray: TEinheitArray;<br />
end;<br />
const DAT_PFAD = ’CalibSensor.dat’;<br />
const Einheit_PFAD = ’Einheit.dat’;<br />
var<br />
frmCalibSensor: TfrmCalibSensor;<br />
implementation<br />
{$R *.DFM}<br />
procedure TfrmCalibSensor.btnOkClick(Sender: TObject);<br />
begin<br />
Aktualisieren;<br />
frmCalibSensor.Hide;<br />
end;<br />
procedure TfrmCalibSensor.btnSpeichernClick(Sender: TObject);<br />
var f: file of TCalibArray;<br />
f1 : file of TEinheitArray;<br />
begin<br />
ArrayFuellen;<br />
AssignFile(f, DAT_PFAD);<br />
ReWrite(f);<br />
Write(f, CalibArray);<br />
CloseFile(f);<br />
AssignFile(f1, Einheit_PFAD);<br />
ReWrite(f1);<br />
Write(f1, EinheitArray);<br />
CloseFile(f1);<br />
end;<br />
procedure TfrmCalibSensor.btnLadenClick(Sender: TObject);<br />
var f: file of TCalibArray;<br />
f1 : file of TEinheitArray;<br />
begin<br />
// Array laden<br />
AssignFile(f, DAT_PFAD);<br />
Reset(f);
45 D Quellcode<br />
Read(f, CalibArray);<br />
CloseFile(f);<br />
AssignFile(f1, Einheit_PFAD);<br />
Reset(f1);<br />
Read(f1, EinheitArray);<br />
CloseFile(f1);<br />
SensorNr := StrToInt(txtSensorNr.Text);<br />
txt0.Text := FloattoStr(CalibArray[SensorNr,0]);<br />
txt127.Text := FloattoStr(CalibArray[SensorNr,127]);<br />
txt255.Text := FloattoStr(CalibArray[SensorNr,255]);<br />
txtEinheit.Text:=EinheitArray[SensorNr];<br />
ListBoxFuellen;<br />
end;<br />
procedure TfrmCalibSensor.ArrayFuellen();<br />
var klWert, miWert, hoWert, Differenz, Schritt : Single;<br />
var n : Byte;<br />
begin<br />
klWert := StrToFloat(txt0.Text);<br />
miWert := StrToFloat(txt127.Text);<br />
hoWert := StrToFloat(txt255.Text);<br />
CalibArray[SensorNr,0] := klWert;<br />
CalibArray[SensorNr,127] := miWert;<br />
CalibArray[SensorNr,255] := hoWert;<br />
EinheitArray[SensorNr] := txtEinheit.Text;<br />
if rdbLinear.Checked = True then<br />
begin<br />
Differenz := hoWert - klWert;<br />
Schritt := Differenz / 255;<br />
for n := 0 to 255 do<br />
begin<br />
CalibArray[SensorNr,n] := klWert + Schritt*n<br />
end;<br />
end;<br />
end;<br />
procedure TfrmCalibSensor.btnCancelClick(Sender: TObject);<br />
begin<br />
Hide;<br />
end;<br />
procedure TfrmCalibSensor.ListBoxFuellen();<br />
var n : Byte;<br />
begin<br />
lstArray.Items.BeginUpdate;<br />
lstArray.Items.Clear;<br />
For n := 0 to 255 do<br />
begin<br />
lstArray.Items.Add(Floattostr(CalibArray[SensorNr,n]));<br />
end;<br />
lstArray.Items.EndUpdate;<br />
end;<br />
procedure TfrmCalibSensor.txtSensorNrChange(Sender: TObject);<br />
begin<br />
SensorNr := StrToInt(txtSensorNr.Text);<br />
lblSensorNr.Caption := txtSensorNr.Text;<br />
end;<br />
procedure TfrmCalibSensor.btnUebernehmenClick(Sender: TObject);<br />
begin<br />
Aktualisieren();<br />
end;<br />
procedure TfrmCalibSensor.Aktualisieren();
46 D Quellcode<br />
begin<br />
SensorNr := StrToInt(txtSensorNr.Text);<br />
ArrayFuellen;<br />
txt0.Text := FloattoStr(CalibArray[SensorNr,0]);<br />
txt127.Text := FloattoStr(CalibArray[SensorNr,127]);<br />
txt255.Text := FloattoStr(CalibArray[SensorNr,255]);<br />
txtEinheit.Text:=EinheitArray[SensorNr];<br />
ListBoxFuellen;<br />
end;<br />
procedure TfrmCalibSensor.lstArrayClick(Sender: TObject);<br />
var AktIndex : integer;<br />
begin<br />
if rdbEinzelauswahl.Checked = true then<br />
begin<br />
AktIndex := lstArray.ItemIndex;<br />
CalibArray[SensorNr,AktIndex] := StrtoFloat(InputBox(’Bitte geben Sie einen Wert ein’,<br />
Inttostr(AktIndex) + ’ entspricht:’,<br />
lstArray.Items.Strings [AktIndex]));<br />
Aktualisieren;<br />
end;<br />
end;<br />
end.