Impressum Startseite Grund Installation Grundlagen Hilfreiches Projekte Querschläger Meckerecke

Grundlagen: Dem Raspberry Pi Analoge Eingänge spendieren.

Der Raspberry Pi ist sehr günstig und bietet viele Ein- und Ausgänge, die leider alle Voll Digital sind. Was aber wenn man Analoge Ereignisse abfragen möchte ? z.b. einen Thermowiderstand oder einen Fotowiderstand ?

Um das zu ermöglichen braucht man einen Analog Digital Converter, z.b. den MCP3008 - den kriegt man überall schon für knapp 3 Euro. Man kan auch einen MCP3208 nehmen, der hat eine höhere Auflösung, statt nur 10Bit.

Angeschlossen wird es z.b. wie folgt:

Die Hardware:

Von Pin 1 (3,3V) geht es an den MCP3008 an Pin 16 + 15 (ROT)

Von Pin 6 (GND) geht es an den MCP3008 an Pin 14+ 9 (SCHWARZ) die Channel die man nicht braucht z.b. Pin2-8 sollte man auch auf GND legen. Ist aber kein Muss, nur ohne kann es ab und zu störungen oder Fehlmessungen geben.

Von Pin 12 (GPIO18) geht es an den MCP3008 an Pin 13 (LILA) (clk)
Von Pin 16 (GPIO23 geht es an den MCP3008 an Pin 12 (GRUEN) (D out)
Von Pin 18 (GPIO24) geht es an den MCP3008 an Pin 11 (BLAU) (D In)
Von Pin 22 (GPIO25) geht es an den MCP3008 an Pin 10 (GELB) (Channel Select)

Einen Fotowiderstand (z.b. Fotowiderstand Serie VT Perkin Elmer VT 43 N1 ) kann man an GND (Pin und das andere Ende am Pin 1 des MCP3008 anschließen. Für saubere Messwerte sollte man dann noch einen Widerstand (z.b.1 KOhm) von dem 3,3V auch an Pin1 ranführen.

Wenn man ein Potentiometer anschließen möchte, sollte der mittlere gemeinsamen Kontakt an Channel 0 angeschlossen werden (Pin1 des MCP3008) und die beiden Schleifkontakte an GND und 3,3V. Dadurch haben wir einen einfachen Spannungsteiler.

Beim Anschluss habe ich mich auch an diese Anleitung gehalten: https://www.raspiprojekt.de

Fortan hat man dann bis zu 8 analoge Eingänge die man z.b. per Python abfragen kann, zumindest findet man viele beispiele im Netz wo das per Python abgefragt wird. Python ist nicht so "mein Ding", das geht bestimmt auch in BASH oder PHP also habe ich etwas rumprobiert.

Wie liest man den MCP aus ?

Nachdem ich verstanden habe das man 3 Bytes an den MCP senden muss, und gleichzeitig 3 Bytes empfängt, war es schnell Programmiert. Ein Byte sind ja 8 Bit, also wird jeweils ein Bit gesendet und jeweils ein Bit empfangen - Zeitlich gesteuert durch den Kontakt CLK der einmal auf High und wieder auf Low gesetzt wird. Die 3 Bytes die man bekommt, sind grötenteils Müll, von den 24 Bits behält man nur die letzten 10 Bit, die man in Dezimal umwandeln und weiter verarbeiten kann.

Die Software:

Anfang macht die PHP Version: Statt mit einer Schleife habe ich es mal ausgeschrieben um verständlich zu machen wie es funktioniert.

<?php
//Pins festlegen
$cs="6"; //GPIO25 Pin 22 (Chip Select) in Rot sind die "Wiring PI Pins angegeben"
$Din="5"; //GPIO24 Pin 18 (Digital in) Alle Wiring Pis bekommen man mit dem Befehl "gpio readall"
$Dout="4"; //Gpio23 Pin 16 (Digital Out)
$clk="1"; //GPIO18 Pin 12 (Clock)
$wert="";

//Ein und Ausgänge defenieren
shell_exec("gpio mode ".$Din." out");
shell_exec("gpio mode ".$Dout." in");
shell_exec("gpio mode ".$clk." out");
shell_exec("gpio mode ".$cs." out");

//Pegel Festlegen zum Auslesen des 3008er
shell_exec("gpio write ".$cs." 1");
shell_exec("gpio write ".$cs." 0");
shell_exec("gpio write ".$clk." 0");

//Das erste Byte (00000001) Schreiben und Output Lesen und verwerfen, Werte werden nicht benötigt
shell_exec("gpio write ".$Din." 0"); //Sende 0
shell_exec("gpio read ".$Dout); //Lese Wert
shell_exec("gpio write ".$clk." 1");shell_exec("gpio write ".$clk." 0");//CLK Senden

shell_exec("gpio write ".$Din." 0");//Sende 0
shell_exec("gpio read ".$Dout);
shell_exec("gpio write ".$clk." 1");shell_exec("gpio write ".$clk." 0");

shell_exec("gpio write ".$Din." 0");//Sende 0
shell_exec("gpio read ".$Dout);
shell_exec("gpio write ".$clk." 1");shell_exec("gpio write ".$clk." 0");

shell_exec("gpio write ".$Din." 0");//Sende 0
shell_exec("gpio read ".$Dout);
shell_exec("gpio write ".$clk." 1");shell_exec("gpio write ".$clk." 0");

shell_exec("gpio write ".$Din." 0");//Sende 0
shell_exec("gpio read ".$Dout);
shell_exec("gpio write ".$clk." 1");shell_exec("gpio write ".$clk." 0");

shell_exec("gpio write ".$Din." 0");//Sende 0
shell_exec("gpio read ".$Dout);
shell_exec("gpio write ".$clk." 1");shell_exec("gpio write ".$clk." 0");

shell_exec("gpio write ".$Din." 0");//Sende 0
shell_exec("gpio read ".$Dout);
shell_exec("gpio write ".$clk." 1");shell_exec("gpio write ".$clk." 0");

shell_exec("gpio write ".$Din." 1");//Sende 1
shell_exec("gpio read ".$Dout);
shell_exec("gpio write ".$clk." 1");shell_exec("gpio write ".$clk." 0");

//Das Zweite Byte (10000000) Schreiben und Output lesen und verwerfen, nur die letzten beiden Werte behalten.
//Das zweite Byte enthält auch den Channel (0)

shell_exec("gpio write ".$Din." 1");//Sende 1
shell_exec("gpio read ".$Dout); //Lese Wert
shell_exec("gpio write ".$clk." 1");shell_exec("gpio write ".$clk." 0");//CLK Senden

shell_exec("gpio write ".$Din." 0");//Sende 0
shell_exec("gpio read ".$Dout);
shell_exec("gpio write ".$clk." 1");shell_exec("gpio write ".$clk." 0");

shell_exec("gpio write ".$Din." 0");//Sende 0
shell_exec("gpio read ".$Dout);
shell_exec("gpio write ".$clk." 1");shell_exec("gpio write ".$clk." 0");

shell_exec("gpio write ".$Din." 0");//Sende 0
shell_exec("gpio read ".$Dout);
shell_exec("gpio write ".$clk." 1");shell_exec("gpio write ".$clk." 0");

shell_exec("gpio write ".$Din." 0");//Sende 0
shell_exec("gpio read ".$Dout);
shell_exec("gpio write ".$clk." 1");shell_exec("gpio write ".$clk." 0");

shell_exec("gpio write ".$Din." 0");//Sende 0
shell_exec("gpio read ".$Dout);
shell_exec("gpio write ".$clk." 1");shell_exec("gpio write ".$clk." 0");

shell_exec("gpio write ".$Din." 0");//Sende 0
$wert.=shell_exec("gpio read ".$Dout); // Erstes Bit speichern
shell_exec("gpio write ".$clk." 1");shell_exec("gpio write ".$clk." 0");

shell_exec("gpio write ".$Din." 0");//Sende 0
$wert.=shell_exec("gpio read ".$Dout); // Zweites Bit speichern
shell_exec("gpio write ".$clk." 1");shell_exec("gpio write ".$clk." 0");

//Das Dritte Byte enthält die übrigen Messwerte, gesendet werden nur Nullen

shell_exec("gpio write ".$Din." 0");//Sende 0
$wert.=shell_exec("gpio read ".$Dout);// Drittes Bit speichern
shell_exec("gpio write ".$clk." 1");shell_exec("gpio write ".$clk." 0");

shell_exec("gpio write ".$Din." 0");//Sende 0
$wert.=shell_exec("gpio read ".$Dout);// Viertes Bit speichern
shell_exec("gpio write ".$clk." 1");shell_exec("gpio write ".$clk." 0");

shell_exec("gpio write ".$Din." 0");//Sende 0
$wert.=shell_exec("gpio read ".$Dout);// Fünftes Bit speichern
shell_exec("gpio write ".$clk." 1");shell_exec("gpio write ".$clk." 0");

shell_exec("gpio write ".$Din." 0");//Sende 0
$wert.=shell_exec("gpio read ".$Dout);// Sechstes Bit speichern
shell_exec("gpio write ".$clk." 1");shell_exec("gpio write ".$clk." 0");

shell_exec("gpio write ".$Din." 0");//Sende 0
$wert.=shell_exec("gpio read ".$Dout);// Siebtes Bit speichern
shell_exec("gpio write ".$clk." 1");shell_exec("gpio write ".$clk." 0");

shell_exec("gpio write ".$Din." 0");//Sende 0
$wert.=shell_exec("gpio read ".$Dout);// Achtes Bit speichern
shell_exec("gpio write ".$clk." 1");shell_exec("gpio write ".$clk." 0");

shell_exec("gpio write ".$Din." 0");//Sende 0
$wert.=shell_exec("gpio read ".$Dout);// Neuntes Bit speichern
shell_exec("gpio write ".$clk." 1");shell_exec("gpio write ".$clk." 0");

shell_exec("gpio write ".$Din." 0");//Sende 0
$wert.=shell_exec("gpio read ".$Dout);// Zehntes Bit speichern
shell_exec("gpio write ".$clk." 1");shell_exec("gpio write ".$clk." 0");

$wert=bindec($wert); // Den 10Bit Binärcode in Dezimal umrechnen

echo $wert; //Dezimalwert ausgeben.
?>

Wenn das php als z.b. index.php auf dem Pi unter "/var/www/" gespeichert ist, kann man es durch aufruf der Webseite des Pis z.b. http://192.168.0.2 aufgerufen werden. (die IP eures PIs müsste ihr selber wissen). Jetzt sollte je nachdem wie der Spannungsteiler eingestellt ist (z.b. Fotowiderstand) ein Wert ausgegeben werden.

PHP ist natürlich nicht für so etwas gedacht, also das ganze noch mal in BASH:

/var/www/analog.sh

Aufruf z.b. durch bash /var/www/analog.sh

#!/bin/sh
#Auslesen des 3008 ADC

#Variablen
byte[1]="0,0,0,0,0,0,0,1" #immer "1" als erstes Byte senden
byte[2]="1,0,0,0,0,0,0,0" #Zweites Byte enthält immer auch den Channel (8+Channel)
byte[3]="0,0,0,0,0,0,0,0" #Drittes Byte ist immer "0"

#Deklarieren der Pins

cs="6"; # GPIO25 Pin 22 (Chip Select)
Din="5";# GPIO24 Pin 18 (Digital in)
Dout="4";# Gpio23 Pin 16 (Digital Out)
clk="1"; #GPIO18 Pin 12 (Clock)

#Ausgänge als solche deklarieren

gpio mode $cs out
gpio mode $Din out
gpio mode $Dout in
gpio mode $clk out

#Reset

gpio write $cs 1
gpio write $cs 0
gpio write $clk 0

#bytes lesen
for ((anz=1;anz<=3;anz++))
do
#Zerlegen der byte Variablen in 8 einzelne Befehle
go=(`echo ${byte[$anz]}| tr ',' ' '`)

for ((z=0;z<=7;z++))
do
#Schreibe die Low und Highs in die Pins
gpio write $Din ${go[$z]} #Schreibe Bits

vin[$anz]="$( gpio read $Dout )" #Lese die Bits

input=$input""${vin[$anz]} #Sammle die Bits in einer Zeichenkette

gpio write $clk 1
gpio write $clk 0

done

done

var=${input:14:22} #Behalte nur die letzten 10 Bytes
echo "ibase=2; $var" | bc #Ausgabe als Dezimalzahl

exit

Durch den Aufrufim Terminal bekommt man die Ausgabe des passenden Dezimalwertes des Widerstandes. Das ganze kann man jetzt weiter verarbeiten.

Man sollte Werte zwischen 0 und 1023 bekommen.

Denkbar wäre z.b. eine automatische Giessanlage für Zimmerpflanzen, man fragt den Widerstand des Bodens ab, bei einem bestimmten Trockenwert schaltet man ein Relais an, welches eine Aquariumpumpe dazu bringt Wasser in den Blumentops zu Pumpen. Sowie die Erde Feucht genug ist, wird ein Schwellwert erreicht und man schaltet das Relais und die Pumpe wieder ab. Jetzt kann die Pflanze das Wasser aufnehmen, und der Boden wird wieder trockener, so das das ganze wieder von vorn anfängt. Sollte einfach und schnell in Bash realierbar sein.

Viel Spaß beim Basteln.

Impressum Startseite Grund Installation Grundlagen Hilfreiches Projekte Querschläger Meckerecke