Archiv der Kategorie: Arduino

Datenknoten mit Arduino

Leider sind die Abstände, in denen ich einwenig Zeit finde, einen neuen Beitrag für den Blog zu schreiben, nicht kürzer geworden. Aber einen Beitrag pro Monat zu posten, halte ich ein… 🙂

Dieses Mal ist es kein retro Bastelprojekt aus den heimischen Gefielden oder eine Restauration eines alten Gerätes, sondern wieder etwas zum Thema Arduino. Die Idee – es soll ein Sensor gebaut werden, der wie immer, eine physikalische Größe in ein elektrisches Signal umwandelt. Das ist jetzt nichts Besonderes und um welche Art von Sensor es sich handeln wird, werde ich vorerst noch nicht beschreiben. Aber es soll nicht ein Sensorboard geben, sondern viele. Und diese Sensorboard kurz „Sensoren“ sollen in einer zweidimensionalen Matrix miteinander vernetzt werden. Man kann sich das inetwa vorstellen wie ein Schachbrett, wobei jedes der Schachbrettfelder einen Sensor darstellt. Dieses Netzwerk an Sensoren – also Sensorknoten – soll dann über eine Übergabestelle mit einem Rechner verbunden sein und die Sensordaten des jeweiligen Feldes ausgeben. Es soll dann auch möglich sein, einzelne Felder aus dem Netzwerk zu entfernen ohne dass das verbleibende Netzwerk seine Funktion verliert.

Das ganze System soll möglichst einfach und günstig aufgebaut werden. Und so ist schnell ein Systemkonzept entstanden, in dem die Knoten über den I²C Bus kommunizieren und ihre Daten zu einem Master senden. Das folgende Diagramm soll das verdeutlichen.

Dieses Konzept, so dachte ich mir, lässt sich am einfachsten mit einem ATmega Microcontroller realisieren. Der hat genügend IO´s, einen I²C Bus und UART onboard, ebenso auch analoge Eingänge und benötigt wenig Bauteilperipherie, um ihn in einem eigenen Layout zum Leben zu erwecken. Und es gibt nichts schnelleres, so einen Testaufbau eines solchen Knotennetzwerks zu realisieren, als die gut bekannten Arduino Developmentboards zu benutzen. Ich habe die günstigste Variante für einen Testaufbau gewählt -> den Chinanachbau vom ArduinoUno (Joy-IT UNO) mit dem Atmga328 im gesockelten DIL Gehäuse.

Joy-It Uno Boards

Im Bild sind zehn Stück dieser Microcontrollerboards zu sehen. Von denen soll einer als Bus-Master und neun Stück als Slaves eingesetzt werden. Jeder dieser Slaves hat natürlich eine eindeutige Bus-Adresse, die im System nur einmal vorkommt. Im Testaufbau wird diese Busadresse über den Programmcode fest vergeben, da ohnehin jeder Arduino einmal mit dem Rechner verbunden werden muß, um den Programm-Upload durchzuführen. Das soll natürlich später anders aussehen. Denn der Arduino wird auf den Atmega328 Chip, seinen Quarz und die paar Widerstände reduziert auf dem Sensorboard mit gelayoutet. Programmiert soll der Chip dann über die ISP Pins werden. Da bei vielen Boards natürlich nicht jedes Mal der Programmcode individuell angepasst wird und alle das gleiche Flashfile erhalten sollen, will ich die Sensoradresse mit einem 7Bit Dipschalter einstellen. Ein 4021 Cmos  Static Shift Register soll die Bits nach nach dem Einschalten des Controllers auslesen und seriell in den Controller schieben. Der daraus resultierende Wert steht dann in einer Variable als Busadresse zu Verfügung.

Jeder dieser Slaves mit seiner individellen Busadresse wird nun vom Masterknoten der Reihe nach abgefragt, welchen Zustand er hat und ob er einen Ausgang schalten soll, oder nicht. Das bedeutet, der Knoten hat lediglich einen DO (Digitalen Ausgang) mit dem er beispielsweise eine LED aus- und einschalten kann und einen oder mehrere DI (Digitalen Eingang) der einen Zustand, zum Beispiel eines einfachen Schalters abfragt. Diese Funktionen werden in 2 Bits eines Bytes gespeichert. Ein weiteres Byte dient zur Übertragung der Busadresse. Es werden also zwei Bytes über den Bus geschickt. Das untenstehende Bild zeigt den Testaufbau mit den „UNO-Boards“

Alle Arduinos sind mit I²C Datenbus und Spannungsversorgung verbunden

Der Ablauf läuft wie folgt:

MASTER:
Der Masterknoten sendet nach der Reihe an alle Slave-Adressen eine Anfrage und einen Schaltbefehl (der kommt für alle Knoten von einem TEST-Tastereingang am Master) für den LED-Ausgang des Knotens und sieht ob eine Antwort zurückkommt oder nicht. Wenn keine Antwort kommt, ist der Knoten nicht im Netz oder defekt. Kommt eine Antwort, so besteht diese aus der Adresse des Knotens und seinem Statusbyte. Diese Informationen werden über ein RS232 Terminal an den, am Master angeschlossenen Rechner übertragen. So kann dort beispielsweise über eine Visualisierung mittels (NI LabView, oder Matlab o.ä.) der Schaltzustand jedes einzelnen Knotens  am Bildschirm angezeigt werden. Mit einer Anpassung des MasterProgrammes ist es auch möglich, die LED-Ausgänge der Slaves über den Rechner zu schalten.

SLAVE:
Wenn der Masterknoten vom Slave Daten anfordert, so sendet der Slave zwei Bytes zurück. Wobei Byte0 wieder die Slave ID (also Busadresse ist) und Byte1 die Daten. Byte1 besteht eigentlich aus nur zwei Bit, die wie folgt kodiert sind (in dezimaler Darstellung):
 0 = LED aus | Sensor nicht ausgelöst
 1 = LED ein | Sensor nicht ausgelöst
 2 = LED aus | Sensor ausgelöst
 3 = LED ein | Sensor ausgelöst

Der Programmcode als Beispiel:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
// I2C Slave Code
// 16.05.2018 
// ver 1.3
#include <Wire.h>
#define ADDRESS 2     // adresse des slave knotens
#define PAYLOAD_SIZE 2 // anzahl der bytes  die vom masterknoten zu erwarten sind
int LED=12;            // indicator led an pin D12
int SENSOR = 8;        // sensor input an pin D8
bool actionState=0;      // sensor zustand
int busstatus;  // statusvariable 
                       // 0 = LED aus | sensor nicht belegt
                       // 1 = LED ein | sensor nicht belegt
                       // 2 = LED aus | sensor belegt
                       // 3 = LED ein | sensor belegt
 
bool sensled=0;          // sensor LED
byte nodePayload[PAYLOAD_SIZE];

void setup()
{
  pinMode(LED, OUTPUT);         //sensorLED
  pinMode(SENSOR, INPUT);       //Sensor 
  Wire.begin(ADDRESS);          // Activate I2C network
  Wire.onReceive(receiveEvent);
  Wire.onRequest(requestEvent); // auf master anforderung warten
                      //  // debug interface
                      //  Serial.begin(9600); 
}

// *********************************mainloop****************************************************
void loop()
{ 
  delay(5);
  
   if(sensled){digitalWrite(LED, HIGH);}
         else{digitalWrite(LED, LOW);}

  actionState = digitalRead(SENSOR);  //Sensoreingang abfragen        
   if((actionState==1)&&(sensled==1)) {busstatus=3;}
   else if ((actionState==0)&&(sensled==1)) {busstatus=1;}
   else if ((actionState==1)&&(sensled==0)) {busstatus=2;}
   else if ((actionState==0)&&(sensled==0)) {busstatus=0;}

                      //  Serial.println("######################");
                      //  Serial.print("busstatus neu setzen ");
                      //  Serial.println(busstatus);
                      //  Serial.print("sensled LED            ");
                      //  Serial.println(sensled);
                      //  Serial.print("actionState           ");
                      //  Serial.println(actionState);
                      //  Serial.println("######################");
  nodePayload[0] = ADDRESS;                  // Adresse in byte0 zurücksenden.  
  nodePayload[1] = busstatus;                //byte 1 ist die statusinfo der LED
}



// *********************************************************************************************
void requestEvent()
{ Wire.write(nodePayload,PAYLOAD_SIZE);  
  Serial.println("bytes status schreiben");
  Serial.println(nodePayload[0]);
  Serial.println(nodePayload[1]);
  delay(5);
}

// *********************************************************************************************
void receiveEvent(int bytes)  //einen wert vom I2C lesen
      
{
  
  busstatus = Wire.read(); //If the value received was true turn the led on, otherwise turn it off  
                              //  Serial.println("status empfangen");
                              //  Serial.println(busstatus);
  if((busstatus==1)||(busstatus==3)){sensled = 1;}
                                else{sensled = 0;}
                                              
}

 

Die Busadresse ist in diesem Slave-Code noch individuell einzugeben. In der nächsten Version ist dann der vorherbeschriebene „Serializer“ der parallelen Dip-Schaltervariante implementiert. Das folgende Codebeispiel ist von Masterknoten, der die Slaves ausliest und mittel Prüftaster ein LEDmuster an die Sensorslaves sendet:

 

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
// I2C masterknoten 
// 16.05.2018 
// ver 1.2
// changes abfrage wenn kein knoten am bus dann 255 ausgeben
#include <Wire.h>

#define busbytes 2          // wievele byte vom I2C knoten zu erwarten sind
#define maxKNOTEN  10       // anzahl der zu scannenden slaves
#define startKNOTEN 2       // startadresse der slaves
#define DELAY 5             // einfach ein delay ....

int i; int j=0;
int buttonPin = 12;
int testbut = 0; int anim = 0;
int buttonState = 0;
int DATEN[busbytes];
int adresse; int busstatus;  
byte sensorbelegt; byte ledsensoron;

                       // 0 = LED aus | Sensor nicht belegt
                       // 1 = LED ein | Sensor nicht belegt
                       // 2 = LED aus | Sensor belegt
                       // 3 = LED ein | Sensor belegt

int leddat1[] = {1,1,1,1,0,1,1,1,1}; // -
int leddat2[] = {0,0,0,0,1,0,0,0,0}; // |

void setup()
{
  Serial.begin(9600);  
  Serial.println("MASTER-KNOTEN");
  Serial.print("Maximum Slaveknoten: ");
  Serial.println(maxKNOTEN);
  Serial.print("Datengroesse in byte: ");
  Serial.println(busbytes);
  Serial.println("***********************");
  
  Wire.begin();                 // Activate I2C link
  pinMode(buttonPin, INPUT);    // test-tastereingang festlegen
}


//#####################################################################################################
void loop()
    
{
  for (int Knotenadresse = startKNOTEN;         //alle knoten scannen
           Knotenadresse <= maxKNOTEN; 
           Knotenadresse++) 

        
    //################################################################################################       
    { 
     // testbut = 0;  
     anim = 0;   
    Wire.requestFrom(Knotenadresse, busbytes);        // daten vom jeweiligen knoten anfordern
                                                 
           DATEN[0]=255; DATEN[1]=255;   // wenn kein knoten dann auf 255 setzen    
          if(Wire.available() == busbytes) {                                    // wenn knoten und daten dann
            for (i = 0; i < busbytes; i++) DATEN[i] = Wire.read();          // daten holen (zuerst busID, dann daten)
           // for (j = 0; j < busbytes; j++) Serial.println(DATEN[j]);        // daten an rs232 ausgeben   
          }            

//            Serial.println(Knotenadresse);
//            Serial.println(DATEN[0]);
//            Serial.println(DATEN[1]);
//            Serial.println(" ");
           
            adresse=DATEN[0]; 
            busstatus=DATEN[1];
           
            if(busstatus == 0)       {sensorbelegt=false;  ledsensoron=false;}
            else if (busstatus == 1) {sensorbelegt=false;  ledsensoron=true;}
            else if (busstatus == 2) {sensorbelegt=true;  ledsensoron=false;}
            else if (busstatus == 3) {sensorbelegt=true;  ledsensoron=true;}
      
         //################################################################################################
         //Testbutton Status lesen und variable testbut entsprechend setzen
       
          buttonState = digitalRead(buttonPin);               //tastereingang einlesen
          if(buttonState == HIGH){                            //wenn taster aktiv dann variable anim setzen
          anim = 1;
          //delay(5); 
          }
            
//            //debug debuginfo tasterstatus auf rs232 ausgeben
//            Serial.println("#######################");
//            Serial.print("Knoten Adresse    :");
//            Serial.println(adresse);
//            Serial.print("Busstatus         :");
//            Serial.println(busstatus);
//            
//            Serial.println("----------------");
//            Serial.print("Fliese belegt    :");
//            Serial.println(sensorbelegt);
//            Serial.print("LED Fliese       :");
//            Serial.println(ledsensoron);
//            Serial.print("#######################");
//            Serial.println(" ");
      
          //################################################################################################
          //Testbutton Status an jeweiligen knoten senden
      
          Wire.beginTransmission(Knotenadresse);           // transmit to device actual in for loop
          //anim schreiben
                    
           if (anim==0) {testbut=leddat1[j]; j++;}
                   else {testbut=leddat2[j]; j++;}
           if (j>8){j=0;}
          
          Wire.write(testbut);                             // senden des tasterstatus
          Wire.endTransmission();                          // ende gelände mit uerbertragung
       
          delay(DELAY);
          

    }
   
}

 

Mit dieser Anordnung ist es jetzt möglich alle Arduinos und deren Eingang auszulesen bzw. die LED über den Bus zu steuern. Im nächsten Schritt wird ein „Sensor“ gebaut, eine Platine gelayoutet und der ArduinoUno auf seinen Microcontroller reduziert. Darüber werde ich in einem der nächsten Posts berichten…

 

 

 

Schweben mit Ultraschall – Der Tractor Beam

Schwebendes Kügelchen

Ein cooles Projekt hat auf  instructables.com vorgestellt. Es handelt sich dabei um eine Anordnung von Ultraschalltransducern, deren Schallwellen so ausgerichtet sind, dass sich Schallkeulen ausbilden, in denen ein leichter Körper (zum Beispiel ein Styroporkügelchen) schwebend gehalten werden kann. Da das Projekt auf http://www.instructables.com/id/Acoustic-Tractor-Beam/ sehr ausführlich beschrieben ist und wir (Mario, Bernd und ich) smarte Jungs sind 🙂 haben wir und gedacht, wir bauen das nach.

Die Elektronik  besteht aus einem H-Brückenmodul, einem Arduino Nano sowie einem China DC/DC – Converter.  Das Zusammenschrauben der Module funktioniert prinzipiell ganz gut, aber als Elektroniker macht man natürlich eine eigene Platine, auf der alles nötige drauf ist. Also habe schnell ein geeignetes Layout erstellt und per nasschemischer Fertigung hergestellt. Es mag zwar immer Leute geben, die Platinen gerne in einen Fräsbohrplotter einspannen und die Maschine per spanendem Verfahren Material abtragen lassen, aber wenn es schnell gehen und auch schön werden soll, dann wird natürlich geätzt. So sind auch dünnste Leiterbahnen problemlos möglich. Und der ganze Prozess (egal wie groß die Platine ist) dauert gerade einmal 30 Minuten.

Also wie üblich die Schaltung auf Basis Asier Marzos Projektangaben gezeichnet und einwenig optimiert und in den Schematic-Editor eingegeben, ein Layout geroutet und die Belichtungsfolien erstellt.

Die unterschiedlichen Bohrlöcher für die THT Bauteile macht auch hier die Maschine.

Danach werden in einem Bad gleich mehrere Platinen in einem „Ruck“ geätzt.

Jetzt wird bestückt und gelötet.

Die fertige Platine mit aufgestecktem Arduino Nano

Der Träger für die Ultraschalltransducer wird im 3D-Drucker aus ABS gedruckt. Das Stereolithographie-File kann auf der „instructables“ Website heruntergeladen werden.

Wir haben hier unterschiedliche Druckverfahren getestet. Mit Polyvinylalcohol als Support-Material und auch ohne Support…

Das Supportmaterial kann nach dem Druck im warmen Wasser herausgelöst werden. Das dauert in diesem Fall aber einige Stunden.

Nach dem Lösen des Supportmaterials sieht der Ultraschallträger dann so aus.

Mario und Bernd konstruieren zwischenzeitlich eine Halterung für Platine und Akku, auf die der Schallkopf schlussendlich aufgeschraubt werden soll.

Grate entfernen und Feinarbeiten werden mit dem Dremel gemacht.

Jetzt werden alle Ultraschallgeber (Transducer) auf Polarität und Gleichphasigkeit geprüft und bei Abweichungen entsprechend sortiert. Da in der Halbschale insgesamt vier Arrays aus Transducern verschaltet und getrennt angesteuert werden, ist es besonders wichtig, dass alle Transducer innerhalb eines Arrays die selbe Phasenlage erzeugen.

Jetzt kann ich alle Schallgeber in die Halbschale einbauen und entsprechend verdrahten.

Das fertige Werk wird nun an die Platine angeschlossen und der Arduino Microcontroller mit Programmcode versehen.

Nach dem Einschalten und den ersten Messungen, ob alle Spannungen vorhanden sind und die Transducerarrays phasengleich angesteuert werden, kann über einem Wasserbad die Ausbildung der Schallkeulen überprüft werden.

Der Erfolg zeigt sich, wenn ein Styroporkügelchen schwebend gehalten wird …

Ein kurzes Video, das den Aufbau und Test des Tractor-Beam Projektes zeigt, ist hier zu sehen:

 

 

 

 

 

 

 

Raspberry als Datenlogger – Teil.3 Arduino nano als I²C Converter

DSC_4790
Raspberry PI als Datenlogger
 

Im letzten Teil des Projektes „Raspberry Pi als Datenlogger“ habe ich einen Raspberry Pi als Datenlogger für unterschiedliche Sensoren konfiguriert. Als Schnittstelle dient der I²C Bus und die RS232 Leitungen, an denen die Sensoren angeschlossen sind. Die Sensoren waren ein HYT939 (Luftfeuchtigkeit und Temperatur), ein BME280 (Luftdruck, Luftfeuchte und Temperatur) sowie ein Ultimate GPS Board an der seriellen Schnittstelle. Der Raspberry Pi ist dabei in eine Box eingebaut, wird mit einer Powerbank, die sich ebenfalls in der Box befindet, versorgt und stellt als Schnittstelle eine 8 polige RJ45 Buchse mit I²C und RS232 nach aussen zur Verfügung. An diese Buchse können dann die Sensoren angeschlossen werden.   Will man die Sensorik nun änderen, bzw. erweitern, so können einfach weitere I²C Bus – Sensoren angeschlossen werden. Es muß lediglich noch die Software (in diesem Fall Pythonscripten) angepasst werden und schon können die Daten des neuen Sensors empfangen und aufgezeichnet werden. Wie aber geht das System um, wenn der Sensor nicht über I²C spricht? Wenn zum Beispiel ein analoger Wert eingelesen werden soll? Ganz einfach: Soll die Hardware des Datenloggers nun nicht mehr modifiziert werden, so muß man einfach dafür sorgen, dass der neue Sensor, der beispielsweise analoge Spannungen ausgibt, diese an eine, nennen wir sie BlackBox weitergibt, die wiederum an ihrem Ausgang ein I²C Bussignal bereit stellt. Das kann dann wieder in das bestehende System integriert werden.

dsc_2872
Arduino Nano als I²C Converter

 

Und genau diese Aufgabe erfüllt ein Microcontroller. Praktischer Weise habe ich diesmal einen Arduino Nano dazu verwendet. Der Arduino Nano mit dem Atmega 328 besitzt ja mehrere analoge und Digitale Eingänge, sowie zwei Interrupts. Über entsprechende Libraries ist einfach das I²C Bus Protokoll zu realisieren. Somit ist das geeignete Black-Box Gerät gefunden.

 

Der folgende Arduino Code stellt einen einfachen I²C Bus Slave dar. Die Busadresse soll beispielsweise 0x08 sein, von einer Messung haben wir den Messwert 1.3321 erhalten. Dieser Wert soll bei Anfrage an diese Busadresse gesendet werden. Das Beispiel sieht wie folgt aus:


// I2C Slave
#include
int address = 8;           //i2c busaddresse
float wert = 1.3321;       // testwert .... kommt zb aus sensorberechnung

char tmp[6];
void setup() {

Wire.begin(address);           // i2c adresse 0x08
Wire.onRequest(requestEvent);  // register event
}

void loop() {}

void requestEvent() {
dtostrf(wert,1,3,tmp);      // float "wert" in char array umwandeln
Wire.write(tmp);            // char array senden
}

Im script ist eine Funktion „dtostrf“ zu sehen. Sie  wandelt den Inhalt einer Variable des Datentyps „floating point“ in ein charakter Array um. Infos sind hier zu sehen. Im Python Interpretor des Raspberry können wir nun überprüfen, ob die Daten ankommen. Doch zuvor soll der gesamte Aufbau einmal schematisch dargestellt werden.

blockschaltbild
Schematische Darstellung des Systems

Sind alle Sensoren inklusive des Arduino angeschlossen, so kann das folgende Python-Script aus der Linux Konsole des Raspberry aufgerufen werden:

 

# Reading data from arduino as sensor slave
# V0.1 by bihlo 09/2016

import smbus, time

bus = smbus.SMBus(1)    # Raspberry Rev. 2
address = 0x08          # Fixed default address of Arduino

# Initialize sensor to acquire measurements
#def MeasurementRequest():
# void = bus.write_quick(address)
#time.sleep(0.1)

# Read from bus
def ReadMeasurement():
void= bus.write_quick(address)

time.sleep(0.1)
# Acquire 6 byte from sensor
Readout = bus.read_i2c_block_data(address,0,6)

out=''.join(chr(i) for i in Readout) #byte array von ascii in string wandeln

print "Antwort vom Arduino: ", Readout, " ."
print "Antwort als String:  ", out

ReadMeasurement()

Wenn der Python Interpretor jetzt keinen Fehler meldet und der Inhalt der Variable „wert“ des Arduino in Ascii und im Klartext dargestellt wird, dann kann jetzt mit einem „richtigen“ Messwert eines Sensors weiter gearbeitet werden.

dsc_2873
Partikeldetektor

Als Sensor soll an an den Arduino ein DSM501 Dust Sensor Module angeschlossen werden. Der DSM501A ist ein Staubsensor, der mit 5V bei einer Stromaufnahme von 90mA betrieben wird. Er erkennt Partikel ab einer durchschnittlichen Größe von 1µm bei einer Konzentration von 0 bis ca. 1.4mg pro Kubikmeter Raumluft. Laut Datenblatt und Herstellerinformationen wird die Luft im Bereich der Messkammer erhitzt, sodass eine Luftzirkulation entsteht. Die sich ständig bewegende Luft wird mit einem getakteten Lichtstrahl beleuchtet. Ein in einem Winkel zur Lichtquelle angebrachter Fotodetektor empfängt nun, im Falle dass sich Partikel im Licht befinden, dessen Streulicht. Die Intensität des Streulichtes ist von der Anzahl und Größe der Partikel abhängig und kann so erfasst werden. Als Ausgangssignal erzeugt der Sensor ein Puls/Pausensignal mit einer Periode von 100ms. Das Verhältnis von High- zu Lowtime stellt nun die Grundlage für die Berechnung der Partikelanzahl bzw. -dichte dar. Über einen Countereingang des Arduino werden die Impulse gemessen und der korrespondierende Partikelwert errechnet. Dieser Wert wird nun wie oben beschrieben als Busdatum für den I2C Bus herangezogen und bei Auslösen des Bus Events übertragen. Somit hat der Arduino die Aufgabe eines einfachen Protokollkonverters übernommen. Mit dieser Methode lassen sich alle möglichen Messwerte so aufbereiten, dass der Raspberry mit einer Schnittstelle damit umgehen kann.

Wie das im Detail funktioniert und wie der Code dazu aussieht, werde ich vielleicht später einmal posten.

Geigerzähler – die Software

DSC_2266Wie vor längerer Zeit im Blog angekündigt, soll der Geigerzähler nun eine Software bekommen, die nicht nur die Pulse des Zählrohres zählt, sondern sie auch auf eine Einheit bezieht. Hierzu waren aber noch kleine Änderungen an der Hardware notwendig. (genauergesagt habe ich andere Pins des Arduino verwendet – was bedeutet: Leiterbahnen durchtrennen und mit Schaltlitzen neu verlegen). Hier eine Liste der Änderungen:

 

  • die Leitung von Pin4 Arduino zu Pin D7 vom LCD unterbrechen
  • die Leitung von Pin5 Arduino zu Pin D6 vom LCD unterbrechen
  • D7 vom LCD an Pin12 vom Arduino verbinden
  • D6 vom LCD an Pin13 vom Arduino verbinden
  • der Zählimpuls wird von TP3 auf Arduino Pin4 geschaltet
  • die Verbindung TP3 zu Arduino Pin23 wird getrennt

Daraus ergibt sich folgende I/O Port/Pin Belegung:

LCD Display:

RS – Ardunio PIN18 – Arduino  I12
EN – Arduino PIN17 – Arduino  I11
D4 – Arduino PIN11 – Arduino  I5
D5 – Arduino PIN6  – Arduino  I4
D6 – Arduino PIN13 – Arduino I7
D7 – Arduino PIN12 – Arduino  I6

Weitere Pins:

COUNT – Arduino PIN4 – Arduino I2
BUZZ – Arduino PIN14 – Arduino I9
STATUS – Arduino PIN3 – Arduino I1
SET – Arduino PIN2 – Arduino I1

Hier der Arduino Code:

</pre>
/*&nbsp; Geiger Vx.1 geändertes pinning
*&nbsp; Pinzuordnungen allgemein für LCD
* RS to IO12 (pin18)
* EN to IO11 (pin17)
* D4 to IO5&nbsp; (pin11)
* D5 to IO4&nbsp; (pin6)
* D6 to IO7&nbsp; (pin13)
* D7 to IO6&nbsp; (pin12)
* R/W to ground
* VSS to ground
* Pinzuordnungen für Counter
* count to IO2 (ic pin4) = INT0
* buzzer to IO9 (ic pin15)
*/

// include libraries
#include <LiquidCrystal.h>

// interfacepins initialisieren
LiquidCrystal lcd(12,11,5,4,7,6);

// Dosiskobersionsfaktor - CPM to uSV/h
#define dconv 0.007  //(ca Umrechnung aus Diagramm Datenblatt des ZP1400 Zählrohrs)

// Konstanten Hardware I/Os
const int buzzerpin = 9;
const int geiger_input = 2;
const int keystat = 0;
const int keyset = 1;

// Variablen
long count = 0;
long countPerMinute = 0;
long timePrevious = 0;
long timePreviousMeassure = 0;
long time = 0;
long countPrevious = 0;
float radiationValue = 0.0;

void setup(){
pinMode(geiger_input, INPUT);
Serial.begin(19200);

//setup LCD und Begruessungsanzeige
lcd.begin(8, 2);
lcd.clear();
lcd.setCursor(0, 0);
lcd.print(" Geiger ");
lcd.setCursor(0,1);
lcd.print("Counter ");
delay(1000);

lcd.clear();
lcd.setCursor(0, 0);
lcd.print("V0.0 beta");
delay(1000);

lcd.clear();
lcd.setCursor(0,1);
lcd.print("ibiretro");
delay(500);
for (int i=0;i<8;i++){
delay(200);
tone(buzzerpin,i*100,100);
lcd.scrollDisplayLeft();
}

delay(500);

lcd.clear();
lcd.setCursor(0, 0);
lcd.print("CPM=");
lcd.setCursor(4,0);
lcd.print(6*count);
lcd.setCursor(0,1);
lcd.print(radiationValue);

attachInterrupt(0,countPulse,RISING);

}

void loop(){
if (millis()-timePreviousMeassure > 10000){
countPerMinute = 6*count;
radiationValue = countPerMinute*dkonv;
timePreviousMeassure = millis();

lcd.clear();
lcd.setCursor(0, 0);
lcd.print("CPM=");
lcd.setCursor(4,0);
lcd.print(countPerMinute);
lcd.setCursor(0,1);
lcd.print(radiationValue,4);
lcd.setCursor(6,1);
lcd.print(" uSv/h");
/* zum debuggen 
Serial.print("cpm=");Serial.print(countPerMinute,DEC);
Serial.print("uSph=");Serial.println(radiationValue,4);
*/
count = 0;

}

}

void countPulse(){
detachInterrupt(0);
count++;
tone(buzzerpin,1000,10);
while(digitalRead(2)==1){
}
attachInterrupt(0,countPulse,RISING);
}
<pre>

Geigerzähler – die Nächste

Das Thema „Radioaktive Strahlung“ bzw. deren Messung, beschäftigt mich auch immer wieder. In einem alten Weblogeintrag habe ich bereits einmal einen Geigerzähler geplant und ihn als Ausbildungsprojekt mit dem damaligen Elektroniker-Lehrling gebaut. Als Zählrohr kam ein Philips-Rohr ZP1400 aus meinen alten Lagerbeständen zum Einsatz. Die benötigte Betriebsspannung für das Zählrohr generierte ein, über einen 555er angesteuerter Transformator/Wandler mit nachgeschalteter Greinacherkaskade. Diese Schaltung hat den Nachteil, dass sie relativ viele und große Komponenten benötigt und somit auch einen unhandlichen Aufbau nach sich zieht.  Die Schaltung hat die Impulse lediglich auch nur hörbar gemacht. Einen Zähler, oder Integrator hat die Schaltung nicht mehr bekommen. -> man konnte ja optional ein Mikrocontroller Board (Arduino UNO , PIC, etc.) anschliessen…

geiger (16)Auf jeden Fall wollte ich noch einen anderen Detektor bauen. Irgendwann habe ich bei Neuhold-Elektronik günstig ein weiteres Zählrohr gefunden und auch gleich bestellt. Dabei handelt es sich um eine Geiger-Müller Röhre RFT VA-Z-114 (70014NR) aus DDR Beständen. Also warum damit nicht noch einen weiteren Geiger-Müller Zähler basteln. Diesmal sollte die Elektronik jedoch um einiges kleiner ausfallen. Als Grundlage für den neuen Zähler diente das Konzept eines Bausatzes von Pollin, der schon lange nicht mehr lieferbar ist, jedoch noch immer auf der Webseite publiziert wird. Teile dieses Schaltungskonzeptes habe ich nun für dieses Projekt herangezogen. Hier wird die Hochspannung mit einem Boostconverter – IC MC34063 der über einen FET eine 330uH Induktivität schaltet, erzeugt. Die Impulse der Röhre werden über Schmitt-Trigger und Filter aufbereitet und die Software in einem ATTINY2313 übernimmt das Zählen.

schematicDie Spannungserzeugung habe ich hier übernommen. Für die Auswertung kommt jedoch der Atmega328 zum Einsatz. Ein kleines LC-Display (mit 8×2 Zeichen) wird die Impulse anzeigen. Ein paar andere Funktionen, wie Batteriespannung etc. sollen auch noch implementiert werden, da der Atmega ja auch A/D- Converter Eingänge hat und mit 10Bit auch eine genügend hohe Auflösung. Die ganze Schaltung sollte dann so groß werden, dass sie in einem 15x8x5cm großen Gehäuse Platz findet. Als Energiequelle wird eine 9V Blockbatterie zum Einsatz kommen.

Der Schaltplan ist schnell gezeichnet und daraus ein Layout erstellt.

 

layout

Das ist das Platinenlayout in der ersten Version. Eine einseitig gelayoutete Platine mit ausschließlich bedrahteten Bauteilen wird hier völlig ausreichend sein und kann die geplante Größe einfach erreichen. Nach den folgenden drei Fertigungsschritten: (auch hier zu sehen)

geiger (8)

Bohrplotten

geiger (9)Belichten und Entwickeln

geiger (10)

und abschließend Ätzen,

ist die Platine soweit fertig, dass sie bestückt werden kann. Vorher wird auf die Kupferseite noch eine Schicht Lötlack aufgetragen, um hässliche Korrosionen der Kupferschicht zu vermeiden und eine gute Lötoberfläche zu erhalten.

geiger (14)

geiger (12)Das ist die Platine in der bestückten Ausführung. Hier fehlen noch der Mikrocontroller, das LC-Display und natürlich das Zählrohr. Doch zuerst habe ich begonnen, das Gehäuse vorzubereiten und eine Alu-Frontplatte zu erstellen, die dem ganzen Konstrukt ein etwas schöneres Aussehen verleiht. Ein Layout hierfür kann mit allen möglichen Konstruktionstools erstellt werden, die die Möglichkeit bieten, die Zeichnung beispielsweise im „dxf“-Format zu exportieren. Die vhf-Fräsbohrplotter müssen jedenfalls mit den Exportformaten umgehen können und sie idealerweise auch maßstabsgetreu auf den Rohling übertragen können.

geiger (4)

Das Ergebnis der Fräsarbeiten, sind diese beiden Platten, die dann miteinander verschraubt werden, das Display, die Schalter und Taster halten sollen. Damit die eingefrästen Vertiefungen in der Aluminiumplatte schlussendlich auch schön kontrastreich zu sehen sind, werden sie mit schwarzem Acryllack gefüllt.

geiger (6)

So sieht die fertige Frontplatte aus.

DSC_2264

Jetzt wird die Elektronik im Gehäuse untergebracht. Wie hier gut zu erkennen ist, hat wieder das ZP1400 Zählrohr von Philips seinen Platz gefunden. Leider war dem Neuhold – DDR Zählrohr trotz vieler Experimente kein einziger Impuls zu entlocken. Ich vermute, das Rohr hat im Laufe der vielen Lagerjahre Luft gezogen und ist einfach defekt.

DSC_2267

Alle Komponenten haben ihren Platz gefunden. Die „Trennkammern“ sind kupferbeschichtete FR4 Platten, die einerseits die Röhre in Position halten und andererseits eine Kammer für die 9 Volt Blockbatterie darstellen.

DSC_2266

Hier ist nun alles zusammengebaut. Als Testsoftware werden die Impulse vorerst lediglich nur über einen IRQ Eingang gezählt und über den kleinen Lautsprecher hörbar gemacht. Wenn das Programm dann einmal fertig ist, werde ich es hier wieder veröffentlichen…

 

 

 

HYT939 und NTC an Matlab über Arduino

DSC_2311In den letzten Blogeinträgen habe ich mit dem Arduino einen NTC-Widerstand  über einen Spannungsteiler an den Analogeingang des Arduino-UNO angeschlossen und ihn als eigenständiges Programmchen am Arduino als Temperatursensor laufen lassen. Die aktuellen Messwerte wurden auf einem LC-Display angezeigt. Dann habe ich die selbe Hardware über die Matlab Software und das „Arduino for Matlab“-Package betrieben und mittels Matlabcode direkt den Temperaturverlauf geloggt. Im vorhergehenden Blog war dann ein kombinierter Temperatur und Luftfeuchtigkeitssensor (Type HYT939) an der Reihe, der über den I²C Bus am Arduino seine Daten lieferte und wieder am LCD ausgegeben hat.

In diesem Bericht kommt nun wieder Matlab ins Spiel. Hier habe ich versucht, beide Sensoren, den NTC am Analogeingang und den HYT am I²C Bus, gleichzeitig auszulesen. Das sollte über einen mehrere Minuten andauernden Zeitraum passieren, wobei die Messwerte gleich mitgeloggt werden, um sie danach in einem Vergleichsdiagramm zu plotten. Der Hardwareaufbau ist wieder ganz einfach. Der NTC ist in Serie mit einem 2k2 Widerstand geschaltet. Die Enden des Spannungsteilers gehen an die +5V Versorgung und GND und der Teilerpunkt wird an den A0 – Eingang des Arduino Uno angeschlossen. Der HYT bekommt ebenfalls seine 5V vom Arduino selbst und an A4 und A5 ist der I²C anzuschließen (genaue Pinbelegung s. vorgehenden Bericht). Jetzt fehlt noch das Matlab-Script. Es ist hier einzusehen:

 

 

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Beispielscript um mit ArduinoUno einen Temperaturverlauf aufzuzeichnen
% Sensoren an A0 (Spannungsteiler mit NTC) und HYT939 an I2C
% 03/2016 by I.Bihlo
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
a = arduino('com4','Uno','libraries','I2C')
analogpin=0; %Anschlusspin analog des UNO
analog=0; %Variable für den Analogwert festlegen
nn=600; %anzahl der messpunkte
addr='0x28'; %addresse für digitalsensor
bus=i2cdev(a, addr) %i2c object erzeugen
%ein paar konstanten für die weiteren berechnungen
r=2200; %Spannungsteilerwiderstand
rt=0; %das wird der errechnete widerstand des NTC
urt=0; %das wird der errechnete Spannungsabfall am NTC
% konstanten für berechnung der Temperatur aus NTC Widerstand
% B25=3977K
a1=3.354016E-03;
b1=3.2569850E-04;
c1=2.61013E-06;
d1=6.38309e-08;
rref=2200;
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Lesen des I2C Bus
% Lesen eines Temperaturabhängigen Widerstandes am Analog Eingang A0
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
for x=1:nn
%%%% Analog 
analog(x)=readVoltage(a, analogpin); %Liest den AnalogIn von A0 und gibt in Volt aus
urt(x)=5-analog(x); %spannungsabfall am NTC 
rt(x)=(r/analog(x))*urt(x); %widerstand des NTC
pause(0.5);
%%%%Digital
data = read(bus, 4); %4 byte von i2c auslsesen
pause(0.5);
%Rohdaten aus Puffer lesen und zusammenbauen
humrawh=dec2bin(data(1),8); %byte 1 auf 8bit festlegen in binär wandeln
humrawl=dec2bin(data(2),8); %byte 2 auf 8bit festlegen in binär wandeln
humrawall=strcat(humrawh,humrawl); % beide bins concentenaten
humraw=bin2dec(humrawall); % die ganze kette wieder in dec wandeln
%tempraw=uint16(data(3))*256+uint16(data(4));
temprawh=dec2bin(data(4),8);
temprawl=dec2bin(data(3),8);
temprawall=strcat(temprawl,temprawh);
temprawall=temprawall(1:14); %% die letzten beiden bits abschneiden
tempraw=bin2dec(temprawall);
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Humidity berechnen lt. Datenblatt
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
hum(x)=double(100/(16384-1))*double(humraw);
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Temperatur berechnen lt. Datenblatt
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
temp(x)=double(165/(16384-1))*double(tempraw)-40.0;
%berechung der analogtemperatur
rvsrref(x)=rt(x)/rref; 
tempa(x)=1/(a1+(b1*log(rvsrref(x)))+(c1*(log(rvsrref(x)^2)))+(d1*(log(rvsrref(x)^3))));
tempc(x)=tempa(x)-273.15 %Kelin in Celsius umrechnen
pause(1);
end
clear a;
time=1:nn;
%plotten der daten
figure(1);
subplot(2,1,1);
plot(time,tempc,'m');
grid on; hold on;
%plot(time,analog,'b');
%plot(time,rt/1000,'r');
%plot(time,urt,'g'); 
plot(time,temp,'g');
legend('Temperatur NTC[°C]','Temperatur HYT939 [°C]');
%legend('Analogspannung des ADC','Widerstand des NTC in kOhm','Spannung am NTC','Temperatur [°C]');
subplot(2,1,2);
plot(time,hum,'m');
grid on; hold on;
legend('Rel Luftfeuchtigkeit HYT939 [%RH]');
%ende

Nachdem der Code nun nach einigen Anpassungen läuft, habe ich beide Sensoren (wie am Titelbild zu sehen) nebeneinander angeordnet und vor Beginn der Messung mit Kältespray (Kälte75 von KontaktChemie) heruntergekühlt. Dann startete das Script und begann aufzuzeichnen. Im Ergebnis sollte der Verlauf der Erwärmung auf die Raumtemperatur zu sehen sein. Da die Kälte am Metallgehäuse des HYT sofort eine Schicht aus gefrorenem Kondensat bildet die langsam taut, erwartete ich mir einen Luftfeuchtigkeitswert im Bereich der Sättigung. (was dann auch deutlich im Plot zu sehen ist).

HYTvsNTC

Feuchtesensor am Arduino

DSC_2268In den letzten Blog-Einträgen habe ich mit Hilfe des Arduino Uno – Experimentierboards auf unterschiedliche Weise einen NTC-Widerstand zur Messung der Temperatur eingesetzt. Aus einem anderen Projekt habe ich auch noch einen Feuchte/Temperatursensor der Firma IST (Innovative Sensor Technologie) zur Verfügung, der mit einem Raspberry und in Python ausgelesen wurde. Es handelt sich um den digitalen Sensor HYT939, der über den I²C Bus ausgelesen wird. Er zeichnet sich laut Datenblatt mit folgenden Merkmalen aus:

  • DSC_2269chemisch sehr resistent
  • sehr weiter Temperatur- und Feuchtigkeitsmessbereich (-40°C .. +125°C, 0% ..100% RH)
  • mechanisch robuste Bauform
  • kalibriert und temperaturkompensiert
  • sehr geringer Drift
  • einsetzbar bis zu einem Umgebungsdruck von 16bar
  • Versorgungsspannung von 2.7 bis 5.5V
  • Auflösung von +/- 0.02% RH und 0.015°C
  • Genauigkeit von +/- 1.8% RH bei +23°C und +/-0.2K

Also wollte ich diesen Sensor auch mit dem Arduino betreiben und vielleicht in weiterer Folge auch den NTC parallel auslesen und die Ergebnisse vergleichen. Aber zurerst einmal wird der HYT an den Arduino angeschlossen.

hytpinDas Bild zeigt das Pinout des HYT in der Ansicht von unten. Die Belegung der Pins lautet:

  • 1…SCL
  • 2…VCC
  • 3…GND
  • 4…SDA

Somit lässt sich der Sensorchip ganz einfach an den Arduino anschließen, wobei die Pins SDA auf den Arduino Pin A4 und SCL auf den Pin A5 gelegt sind. Die Ausgabe der ausgelesenen Werte soll wieder wie beim NTC auf dem LC-Display stattfinden. Nachstehend ist der Code gelistet:

 

/*
 &nbsp; HYT939 bei Arduino UNO an:
 &nbsp; SDA pin A4
 &nbsp; SCL pin A5
 &nbsp; HYT939 bei MEGA2560 an:
 &nbsp; SDA pin 20
 &nbsp; SCL pin 21
 &nbsp; LCDisplay
 &nbsp; Pinzuordnungen allgemein für LCD
 &nbsp; RS to digital 12
 &nbsp; EN to digital 11
 &nbsp; D4 to digital 5
 &nbsp; D5 to digital 4
 &nbsp; D6 to digital 3
 &nbsp; D7 to digital 2
 &nbsp; R/W to ground
 &nbsp; VSS to ground
 */
 //I2C Addresse festlegen
 #define ADDR 0x28
 
 //Variablen und Datentypen festlegen
 double temp;
 double hum;
 unsigned int tempraw;
 unsigned int humraw;
 int x;
 unsigned char buffer[4];
 
 //Libraries laden
 #include <Wire.h>
 #include <LiquidCrystal.h>
 
 // interfacepins initialisieren
 LiquidCrystal lcd(12, 11, 5, 4, 3, 2);
 
 &nbsp; void setup()
 &nbsp; {
 &nbsp; //I2C und LCD Interface initialisieren,
 &nbsp; Wire.begin();
 &nbsp; lcd.begin(20, 4);
 &nbsp;&nbsp;
 &nbsp; Serial.begin(9600);
 &nbsp; lcd.println("HYT939-Sensor");
 &nbsp; }
 
 void loop()
 &nbsp; {
 &nbsp; //I2C auselesen
 &nbsp; Wire.beginTransmission(ADDR);&nbsp;
 &nbsp; Wire.endTransmission();
 &nbsp; delay(200);
 
 &nbsp; //4 Bytes auslesen
 &nbsp; Wire.requestFrom(ADDR, 4,true);
 &nbsp; x=0;
 &nbsp; while(Wire.available())&nbsp;
 &nbsp; { char c = Wire.read(); buffer[x]=c; x++; }
 
 //Rohdaten aus Puffer lesen
 tempraw=buffer[2]*256+buffer[3];
 humraw=buffer[0]*256+buffer[1];
 
 //Daten laut Datenblatt maskieren
 tempraw&=0xfffc;
 humraw&=0x3fff;
 tempraw=tempraw/4;
 
 //Rohdaten in Ausgabeformat umrechnen
 temp=(double)tempraw/99.2909; &nbsp;//skalieren laut datasheet
 temp=temp-40.0;
 hum=(double)humraw/163.83;
 
 //Daten auf LCD schreiben
 &nbsp; lcd.setCursor(0, 2); &nbsp;
 &nbsp; lcd.print("Temperatur =");
 &nbsp; lcd.setCursor(11, 2);
 &nbsp; lcd.print(temp);
 &nbsp;&nbsp;
 &nbsp; lcd.setCursor(0, 3); &nbsp;
 &nbsp; lcd.print("Humidity =");
 &nbsp; lcd.setCursor(14, 3);
 &nbsp; lcd.print(hum);
 //lcd.setCursor(0, 2);
 //lcd.print('Buffer0 =');
 //lcd.setCursor(11, 2);
 //lcd.print(buffer[2]);
 //lcd.setCursor(0, 3);
 //lcd.print('Buffer1 =');
 //lcd.setCursor(11, 3);
 //lcd.print(buffer[3]);
 }

 

NTC am Arduino

ArduTemp(2)Nach dem kleinen Projektchen „Arduino mit Matlab“ möchte ich der Vollständigkeit halber den selben Aufbau auch noch ohne Matlab laufen lassen. Dabei soll der Code mit der mitgelieferten Arduino Entwicklungsumgebung „Arduino Software 1.6.7“ erstellt und in den Atmega 328 geladen werden. Damit man in dieser Stand-Alone-Variante auch was sehen kann, soll ein altes vierzeiliges LC-Display angeschlossen werden. Idealerweise gibt es hier eine schöne library namens LiquidCrystal.h, mit der das LCD im 4Bit Betrieb ganz einfach angesteuert werden kann.

Also schnell die benötigten Pins des LCD (übrigens ein JM204A) aus dem Datenblatt herausgesucht und mit Flachbandkabel und Pinheadern versorgt und an den Arduino angeschlossen. (die Belegung des Arduino habe ich im Script angegeben)

 

ArduTemp(1)Der NTC-Spannungsteiler bleibt, wie er ist. Und schon kann’s losgehen. Da wir die vier schönen Zeilen mit 20 Zeichen pro Zeile am LCD zur Verfügung haben, kann auch viel Information angezeigt werden. Ich habe mich entschieden, den Integer Wert des 10Bit ADC anzuzeigen (0-1023), den errechneten Widerstandswert des NTC´s und natürlich die daraus errechnete Temperatur.

Und das hier ist der simple Code 😉 …

 

/* ingmarsretro 2016
* Pinzuordnungen fürs LCDisplay
&nbsp;* RS to digital 12
&nbsp;* EN to digital 11
&nbsp;* D4 to digital 5
&nbsp;* D5 to digital 4
&nbsp;* D6 to digital 3
&nbsp;* D7 to digital 2
&nbsp;* R/W to ground
&nbsp;* VSS to ground
*/

// include libraries
#include <LiquidCrystal.h>
#include <math.h>
int analogpin = 0;
int analogvalue = 0;
double a1=3.354016E-03;
double b1=3.2569850E-04;
double c1=2.61013E-06;
double d1=6.38309e-08;
double urt=0;
double rt=0;
double rvsrref=0;
double temp=0;
double tempc=0;
double r=2200;
double rref=2200;
double analog=0;

// interfacepins initialisieren
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);

void setup() {
&nbsp; // setup LCD spalten und reihen
&nbsp; lcd.begin(20, 4);
&nbsp; lcd.print("Testprogramm NTC");
&nbsp; Serial.begin(9600);
}

void loop() {
&nbsp; analogvalue=analogRead(analogpin);
&nbsp; analog=(0.004882812*analogvalue);
&nbsp; urt=5-analog;
&nbsp; rt=((r/analog)*urt);

&nbsp; rvsrref=rt/rref;
&nbsp; temp=(1/(a1+(b1*log(rvsrref))+(c1*(log(rvsrref*rvsrref)))+(d1*(log(rvsrref*rvsrref*rvsrref)))));
&nbsp; tempc=temp-273.15;
&nbsp;
&nbsp; //&nbsp; column 0, line 1
&nbsp; // (note: line 1 is the second row, since counting begins with 0):
&nbsp; lcd.setCursor(0,1);lcd.print("ADC-Wert =");
&nbsp; lcd.setCursor(11,1);
&nbsp; lcd.print(analogvalue);
&nbsp;
&nbsp; lcd.setCursor(0, 2); &nbsp;
&nbsp; lcd.print("Widerstd =");
&nbsp; lcd.setCursor(11, 2);
&nbsp; lcd.print(rt);

&nbsp; lcd.setCursor(0, 3); &nbsp;
&nbsp; lcd.print("Temp Cels=");
&nbsp; lcd.setCursor(11, 3);
&nbsp; lcd.print(tempc);

 

Arduino mit Matlab … Der Sensor

Nachdem ich im letzten Teil die Installation der Arduino-Matlab Packages zum Laufen bekommen habe, kann es nun weitergehen. Ziel dieses kleinen Beispiels ist es ja, an einen Arduino Uno einen NTC-Widerstand anzuschließen. Dieser soll als analoger Temperatursensor dienen (was er ja ist 😀 ) und über einen der A/D – Eingänge des Arduino eingelesen werden. Matlab soll dann schlussendlich die eingelesenen A/D- Werte  in Temperaturwerte umrechnen. Das Ganze soll über eine gewisse Zeit laufen, wobei alle paar n-Sekunden ein Wert eingelesen wird. Am Ende soll ein wunderschöner Temperaturplot mit Temperatur über Zeit erstellt werden.

Doch zuerst zum Sensor. Ich verwende hier einen NTC-Widerstand von dem Hersteller VISHAY mit einem R25 von 2200 Ohm (s.Datenblatt). Das bedeutet, er hat bei 25°C einen ohmschen Widerstand von 2.2kOhm. Je wärmer es nun wird, umso kleiner wird der Widerstand und umgekehrt. Der analoge Eingang des Arduino hat eine Auflösung von 10Bit. Das bedeutet, er kann den Spannungshub am Eingang (eingestellt durch die ADC Referenz) in 210 , also 1024 Teile auflösen (zerlegen). Der Standard beim Arduino ist 0V bis 5V. Also 0V am Eingang bedeutet einen ADC-Wert von 0 und 5V bedeutet einen ADC-Wert von 1024. Die Auflösung, also die kleinste auflösbare Spannungsänderung  ist daher:
formelarduino01 (2)Gibt der ADC beispielsweise einen Wert von 558 aus, so entspricht dies einer Spannung am Eingang von 558*0.00488V = 2.72304V. Doch wie soll der NTC jetzt an den Eingang angeschlossen werden? Ganz einfach. Man nehme einen Spannungsteiler und dimensioniere ihn so, dass der Strom durch die beiden Widerstände nie so groß werden kann, dass er zum einen die Versorgung des Arduino gefährdet und zum anderen auch nie so groß werden kann, dass er den NTC selbst erwärmt. In der Skizze ist nun dargestellt wie der Spannungsteiler aufgebaut und angeschlossen ist. Jetzt gilt es noch herauszufinden, wie aus der Spannung am ADC der gemessene Widerstandswert berechnet werden kann. Hier hilft die Spannungsteilerregel:
formel2
In diesem Beispiel hier besteht der Spannungsteiler aus dem NTC (2k2 @ 25°C) und einem 2k2 Festwiderstand. Wenn der NTC null Ohm haben sollte (nur rein theoretisch), so fließt ein maximaler Strom von 0.002A durch die Widerstände (5V/2200Ohm). Wir lesen jetzt in Matlab den Spannungsabfall am NTC ein und können uns über den Spannungsteiler den Widerstandswert berechnen. Jetzt fehlt nur noch die Formel zur Berechnung der Temperatur. Und die ist, samt den notwendigen Konstanten A1, B1, C1 und D1, im Datenblatt angegeben:formel3Das Ergebnis dieser Berechnung ist die Temperatur in Kelvin. Um die Temperatur aber in °Celsius angezeigt zu bekommen, rechnet man: °C = °K-273,15. Mit all diesen Informationen kann man jetzt ein Matlab-Script schreiben, das dann in etwa so aussieht:
 
 
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Beispielscript um mit ArduinoUno einen Temperaturverlauf aufzuzeichnen
% 02/2016 by I.Bihlo
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
&nbsp;
%a = arduino('com5','Uno');
&nbsp; a = arduino('com5','Uno','TraceOn', true)
&nbsp; analogpin=0;
&nbsp; analog=0;
&nbsp;
&nbsp; %ein paar konstanten für die weiteren berechnungen
&nbsp; %
&nbsp; r=2200;&nbsp; %Spannungsteilerwiderstand
&nbsp; rt=0; %das wird der errechnete widerstand des NTC
&nbsp; urt=0; %das wird der errechnete Spannungsabfall am NTC
&nbsp;
&nbsp; % konstanten für berechnung der Temperatur aus NTC Widerstand
&nbsp; % B25=3977K
&nbsp; a1=3.354016E-03;
&nbsp; b1=3.2569850E-04;
&nbsp; c1=2.61013E-06;
&nbsp; d1=6.38309e-08;
&nbsp; rref=2200;
&nbsp;
&nbsp;
&nbsp;
&nbsp; %Lesen eines Temperaturabhängigen Widerstandes am Analog Eingang A0
&nbsp; %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
&nbsp;
&nbsp; for x=1:50
&nbsp; analog(x)=readVoltage(a, analogpin) %Liest den AnalogIn von A0 und gibt in Volt aus
&nbsp; urt(x)=5-analog(x); %spannungsabfall am NTC
&nbsp; rt(x)=(r/analog(x))*urt(x); %widerstand des NTC
&nbsp;
&nbsp; %berechung der temperatur
&nbsp; rvsrref(x)=rt(x)/rref;
&nbsp; temp(x)=1/(a1+(b1*log(rvsrref(x)))+(c1*(log(rvsrref(x)^2)))+(d1*(log(rvsrref(x)^3))));
&nbsp; tempc(x)=temp(x)-273.15 %Kelin in Celsius umrechnen
&nbsp; pause(2);
&nbsp;
&nbsp; end
&nbsp;
&nbsp; clear a;
&nbsp;
&nbsp; %plot den mist
&nbsp; figure(1);
&nbsp; time=1:50;
&nbsp; plot(time,analog,'b');
&nbsp; grid on; hold on;
&nbsp; plot(time,rt/1000,'r');
&nbsp; plot(time,urt,'g');
&nbsp; plot(time,tempc,'m');
&nbsp; legend('Analogspannung des ADC','Widerstand des NTC in kOhm','Spannung am NTC','Temperatur [°C]'); 
&nbsp; %ende

 

 
temperaturgraph
So sieht der Graph mit dem Temperaturlog danach aus…

Arduino mit Matlab … Startschwierigkeiten

arduino01 (4)Heute möchte ich ein Thema vorstellen, mit dem ich mich kurz im Rahmen einer Recherche beschäftigt habe. Viele (Techniker) kennen vielleicht die Software Matlab von der Firma Matworks. Das ist ein extrem umfangreiches Softwarepaket, das bei uns in der Lehre eingesetzt wird, um Studierende in allen möglichen technischen Bereichen zu unterrichten. Sei es Signalverarbeitung, Regelungstechnik, Bildverarbeitung, etc. – Matlab ist das Tool, um all das professionell umzusetzen. Auch wenn es um Messdatenerfassung geht, muß man nicht unbedingt auf Tools zurückgreifen, mit denen ein Projekt oder Programm „gezeichnet“ wird. Das ist zwar toll für den Einstieg, kann (und wird) in späterer Folge aber aufgrund des riesen Overheads und der benötigten PC Resourcen viel zu umständlich, wenn man schnell einmal über eine externe Hardware irgendwelche physikalischen Größen aufzeichnen und verarbeiten will.

In diesem kleinen Projektchen möchte ich nun zeigen, wie einfach man mit Hilfe eines Arduino Uno Boards zusammen mit Matlab eine Temperaturmessung realisieren kann. Der Sensor soll hier ein ganz einfacher NTC Widerstand sein. Das bedeutet, der ohmsche Widerstand des Bauteils ändert sich mit der Temperatur, in dessen Umgebung sich das Bauteil befindet. Die Änderung passiert hier folgendermaßen: wenn die Temperatur steigt, so wird der ohmsche Widerstand kleiner. (Negativer Temperatur Koeffizient) (Coefficient engl. -> NTC). Einziger kleiner Haken – die Änderung passiert nicht linear wie zum Beispiel beim PT100. Das bedeutet der Verlauf  des Widerstands bei Änderung der Temperatur ist keine Gerade mit irgendeiner Steigung, sondern eine e-Funktion. Das wiederum bedeutet, dass, will man aus den gemessenen Widerstandwerten in eine Temperatur zurückrechnen, die Funktionsgleichung zum NTC gefunden werden muss. Glücklicherweise findet man diese aber fix und fertig in den Herstellerdatenblättern 😉 aber dazu später.

Man hat nun einen temperaturabhängigen Widerstand, ein Arduino Uno – Board und einen PC auf dem Matlab läuft. Wie geht´s nun weiter? Nehmen wir als Beispiel an, dass Matlab 2014b installiert ist. Nun gibt es in Matlab unter dem Tab „Home“ eine Rubrik, die sich „Add-Ons“ nennt. Klick man auf  diese, so klappt ein Menue auf, in dem man den Eintrag „Get Hardware Support Packages“ findet. Den klickt man an und es öffnet sich ein Fenster namens „Support Package Installer“.

Unter „Install from Internet“ und „Next>“ kommt man zu einem Auswahlmenue der verfügbaren Packages. Hier sucht man sich „Arduino“ aus und setzt im rechten Bereich des Fensters einen Haken – und zwar bei dem Paket „Aquire inputs and send outputs on Arduino Uno…“. Danach wieder auf „Next>“ klicken und die Installation vollenden.

Ist alles erledigt so kann man den Arduino am USB-Port anstecken. Windows sollte einen Treiber zuordnen. (Unter Systemsteuerung – Gerätemanger – Anschlüsse > sollte ein Arduino Uno (COMx) zu finden sein). Ist das der Fall, dann sollte es klappen 🙂

Jetzt kann in der Matlab Console folgender Befehl eingegeben werden:

arduino()

Folgende Antwort kommt nun zurück:

 arduino with properties:

Port: 'COM5'
Board: 'Uno'
AvailableAnalogPins: [0, 1, 2, 3, 4, 5]
AvailableDigitalPins: [2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13]
Libraries: {'I2C', 'SPI', 'Servo'}

Der COM-Port unterscheidet sich natürlich und wird meist auf den nächsten freien COM gemappt. Hat das aber geklappt, so ist der erste Teil schon gewonnen. Matlab kommuniziert mit dem Arduinoboard. Es kann aber auch vorkommen, dass Fehlermeldungen auftauchen. Wie bei mir der Fall:

Cannot detect Arduino hardware. Make sure original Arduino hardware is properly plugged in. If
using unofficial(clone) hardware, specify port and board type. For more information, see the
arduino function reference page.

Das war die erste Meldung nach der Installation: Dafür gibt’s aber auch Abhilfe. Man gibt folgendes ein:

a = arduino('com5','Uno')

Wenn auch dann eine Fehlermeldung kommt, so wie natürlich bei mir, dann kann man mit folgendem commando auf Fehlersuche gehen:

 a = arduino('com5','Uno','TraceOn', true)

Jetzt kam bei mir die Meldung : Updating server code on Arduino Uno (COM5). Please wait.  Und danach gleich ein Errorfenster mit einem „avr-gcc.exe
Die Anwendung konnte nicht korrekt gestartet werden (0xc00000142)“ Fehler. Danach habe ich lange in diversen Foren gesucht, Tracelogs verglichen und nach den Fehlermeldungen gegoogelt. Hier gab es Tips von: die make.exe in den Tiefen des SupportPackages Ordner ist nicht kompatibel mit 64bit Systemen, mit Windows8.1 und Windows10 gibt es Zugriffsrechteprobleme und und und. Leider war aber nie ein Lösungsvorschlag dabei der bei mir funktionierte. Also habe ich auf einem zweiten Rechner eine jungfräuliche Installation von Matlab und dem Arduino Matlab Package durchgeführt. Und siehe da – es funktionierte. Aber wie jetzt nach dem Fehler suchen, oder ihn beheben. Also habe ich auf dem funktionierenden Rechner einen Tracelog durchgeführt, indem ich beim Aufrufen der Arduinofunktion einen Port angegeben habe, auf dem ein anderes NICHT Arudino Gerät angeschlossen ist. Und siehe da, der Errortracelog war seeehr lange und ausführlich. Man konnte ansehen was die Funktion alles aufruft. Und irgendwo ganz unten im Log las ich was von avrdude… Da kam mir die Idee. Auf meinem PC sind einige Entwicklungsumgebungen installiert. Unter anderem auch AVR-Studio und der WinAVR20100110 Compiler. Und genau der war das Problem. Den WinAVR gelöscht und schon klappte es.

Also steht dem weiteren Aufbau zur Realisierung des Projektchens nichts mehr im Weg. Aber darüber scheibe ich beim nächsten Mal in Teil 2…