Lokale Peripheriefunktionen

II. ADC (Analog Digital Converter)

JControl-basierte Geräte verfügen über mehrere ADC-Eingänge, mit denen (analoge) Eingangsspannungen gemessen werden können. Dieses Tutorial zeigt, wie sich mit Hilfe der Klasse jcontrol.io.ADC an den ADC-Eingängen anliegende Spannungen messen lassen.

Bild 1: Beispiel für (mit Vole) visualisierte, analoge Werte

Bild 1 zeigt ein Beispiel, wie analoge Werte angezeigt werden können. In diesem Fall wurden Komponenten aus der graphischen Bibliothek Vole verwendet. Wie diese Komponten benutzt werden, erfahren sie in dem entsprechenden Tutorial. Das in diesem Tutorial behandelte Beispiel beschränkt sich auf die einfache Akquirierung von Analogwerten. Sie werden am Ende des Tutorials als reine Zahlenwerte auf dem LC-Display des JControl-Moduls ausgegeben.

Vorraussetzungen: Für dieses Tutorial wird eine Installation der JControl-Tools sowie ein JControl-Modul mit LC-Display (SmartDisplay, Sticker oder PLUI) benötigt.

Download: http://www.jcontrol.org/examples/ADCExample.zip Dieses Tutorial mit allen Quelltexten und Ressourcen als JControl/IDE-Projekt (ZIP-Archiv).




Die ADC-Kanäle

Viele JControl-Geräte sind mit einem 8-Bit Analog-Digital-Konverter mit mehreren Eingangskanälen (ADC-Kanäle) ausgestattet. Diese können zum Messen anliegender Spannungen verwendet werden, die z.B. durch einen Temperatur-Fühler erzeugt werden. Die genaue Pinbelegung kann der API Dokumentation http://www.jcontrol.org/current/docs/api/jcontrol/io/GPIO.html von GPIO oder den Produkt-Datenblättern http://www.domologic.com/support/ch1/index_de.html entnommen werden.

Die Klasse ADC stellt lediglich eine Funktion zur Verfügung, die statische Methode getValue(int channel). Ihr Aufruf liefert einen 8-Bit Wert zwischen 0 und 255 zurück. Dieser Wert entspricht dem aktuellen Messwert des durch channel ausgewählten ADC-Kanals mit Bezug auf die an Pin VDDA anliegende Referenzspannung (standardmäßig die Versorgungsspannung), wobei 255 aussagt, dass die anliegende Spannung gleich oder größer der Referenzspannung ist.

Achtung: Die zu messende Eingangsspannung an den ADC-Kanälen darf die Versorgungsspannung keinesfalls um mehr als 0.3V überschreiten und nicht kleiner als -0.3V sein.



Abfragen der ADC-Kanäle

In dem folgenden Beispiel wird gezeigt, wie die Multithreading-Fähigkeiten von JControl verwendet werden können, um in einer Applikation kontinuierlich die Messwerte der ADC-Kanäle aufzunehmen, ohne den normalen Programmablauf dadurch zu beeinträchtigen. So kann im Vordergrund beispielsweise eine grafische Benutzerschnittstelle angezeigt werden, während im Hintergrund automatisch auf Änderungen von Messwerten reagiert wird.

Unsere Applikation soll zunächst herausfinden, wie viele ADC-Kanäle auf dem System verfügbar sind und dann entsprechend viele Threads starten, die die Messwerte kontinuierlich einlesen. Der folgende Quelltext zeigt, wie diese Aufgabe mit JControl realisiert werden kann.

1    import jcontrol.io.ADC;
2    import jcontrol.io.Display;
3    import jcontrol.lang.ThreadExt;
4    import jcontrol.system.Management;
5    
6    /**
7     * This example shows how to read out ADC values on JControl.
8     * Furthermore, the usage of multiple threads in one application
9     * is demonstrated.
10    
11     * <p>(C) DOMOLOGIC Home Automation GmbH 2003</p>
12     */
13    public class ADCExample {
14      /** array to store ADCReader instances in */
15      ADCReader adcreaders[];
16     
17     
18      /**
19       * Inner class <code>ADCReader</code> realizes a thread
20       * that continuously reads and stores ADC values.
21       */
22      class ADCReader extends Thread {
23        /** adc channel */   
24        int channel;
25        /** last read value */
26        int value = 0;   
27        /** thread instance */
28        Thread instance = null;
29       
30        /**
31         * Constructs an <code>ADCReader</code> thread.
32         * @param channel the ADC input channel to read values from
33         */
34        public ADCReader(int channel) {
35          instance = this;
36          this.channel = channel;
37          this.start();
38        }
39       
40        /**
41         * This method is invoked when the thread execution starts.
42         * @see java.lang.Runnable#run()
43         */
44        public void run() {
45          while (instance == this) {
46            // read current adc value
47            value = ADC.getValue(channel);
48           
49            // sleep for 100 millis
50            try {
51              ThreadExt.sleep(100);
52            } catch (InterruptedException e) {}
53          }
54        }
55       
56        /**
57         * Stop thread execution.
58         */
59        public void quit() {
60          instance = null;
61        }
62       
63        /**
64         * Retrieve current adc value
65         */
66        public int getValue() {
67          return value;
68        }
69      }
70    
71    
72      /**
73       * Constructs an <code>ADCExample</code> instance.
74       * We start as many <code>ADCReader</code> threads as
75       * adc input channels exist.
76       */
77      public ADCExample() {
78        String s = Management.getProperty("io.adcchannels");
79        int numchannels = Integer.parseInt(s);
80       
81        adcreaders = new ADCReader[numchannels];
82       
83        // create ADCReader threads and store instances into an array
84        for (int i=0; i<numchannels; i++)
85          adcreaders[i] = new ADCReader(i);
86         
87        // draw adc status continuously on lcd   
88        drawStatus();
89      }
90     
91     
92      /**
93       * Draw ADC values (read by ADCReader threads) on lcd
94       */
95      void drawStatus() {
96        Display lcd = new Display();
97       
98        while (true) {
99          lcd.clearDisplay();
100         
101          // show adc values on lcd   
102          for (int i=0; i<adcreaders.length; i++) {
103            lcd.drawString("ADC channel ".concat(
104                            String.valueOf(i)).concat(" value: ").concat(
105                            String.valueOf(adcreaders[i].getValue())),
106                           0, 8*i);
107          }
108         
109          // sleep for 500 millis
110          try {
111            ThreadExt.sleep(500);
112          } catch (InterruptedException e) {}
113        }
114      }
115    
116      /**
117       * Main method. Program execution starts here.
118       */
119      public static void main(String[] args) {
120        new ADCExample();
121      }
122    }
Listing 1: ADCExample.java

Die Hauptklasse ADCExample enthält eine innere Klasse ADCReader, welche die Eigenschaften eines Thread-Objekts erfüllt. Wenn der Thread durch einen Aufruf der Methode start gestartet wird, (hier im Konstruktor public ADCReader(int channel)), folgt automatisch ein Aufruf der Methode run(). Diese liest in einer Endlosschleife alle 100ms den aktuellen Wert des im Konstruktor spezifizierten ADC-Kanals ein. Dazu wird die getValue-Methode aus der ADC-Klasse verwendet.

Die Aufgabe der Hauptklasse ADCExample ist einfach: Es müssen lediglich genau so viele ADCReader-Instanzen erzeugt werden wie ADC-Kanäle im System verfügbar sind. Die Anzahl letzterer kann durch einen Aufruf der Methode Management.getProperty("io.adcchannels") auf jedem JControl-System erfragt werden. Wurden die ADCReader-Instanzen erzeugt, läuft die kontinuierliche Messwerterfassung ohne weiteres Zutun der Hauptklasse automatisch im Hintergrund.



Darstellung der Messwerte auf dem LC-Display

Um die im Beispiel gemessenen Werte der A/D-Wandler visuell kontrollieren zu können, soll das ADCExample nun um eine Funktion zur Darstellung der Messwerte auf dem LCD erweitert werden. Diese soll parallel und unabhängig zur Messwerterfassung laufen.

Da die Hauptklasse nach der Instantiierung der ADCReader-Threads nichts weiter zu tun hat, bietet es sich an, den Programmthread selbst für die Darstellung der Messwerte zu benutzen. Die folgende Methode drawStatus() erledigt dies, indem sie alle 500ms die aktuellen Messwerte aller ADCReader-Threads einliest und auf dem LCD als Strings ausgibt.

94    /**
95     * Draw ADC values (read by ADCReader threads) on lcd
96     */
97    void drawStatus() {
98      Display lcd = new Display();
99    
100      while (true) {
101        lcd.clearDisplay();
102    
103        // show adc values on lcd
104        for (int i=0; i<adcreaders.length; i++) {
105          lcd.drawString("ADC channel ".concat(
106                          String.valueOf(i)).concat(" value: ").concat(
107                          String.valueOf(adcreaders[i].getValue())),
108                         0, 8*i);
109        }
110    
111        // sleep for 500 millis
112        try {
113          ThreadExt.sleep(500);
114        } catch (InterruptedException e) {}
115      }
116    }
Listing 2: Auszug aus ADCExample.java

Fügt man dem ADCExample-Konstruktor nun noch einen Aufruf drawStatus() hinzu, ist das ADCExample vollständig. Statt die Messwerte lediglich anzuzeigen, können auf die in diesem Tutorial beschriebene Art und Weise auch komplexe Steuer- und Regelsysteme implementiert werden. Die Implementierung der Messwerterfassung in Form von Threads garantiert, dass die Messwerte völlig unabhängig von der Applikationslogik kontinuierlich aktualisiert werden.

Der Test: Probieren Sie nun das ADCExample auf Ihrem JControl-System aus! Laden Sie den Quelltext zum ADCExample.java herunter und fügen Sie ihn einem leeren JControl/IDE-Projekt hinzu. Nach dem Hochladen auf Ihr JControl-Modul werden Sie eine Darstellung ähnlich dem folgenden Bild 2 sehen.

Bild 2: Das ADCExample auf dem JControl/Sticker



© 2000-2006 DOMOLOGIC Home Automation GmbH. All Rights Reserved.