Mit der Arduino Plattform lassen sich allerhand Dinge anstellen. So auch Daten vom I2C Bus lesen und LCDs ansteuern. Und ganz nebenbei kann man per USB mit einem PC kommunizieren.
Grundlage ist ein Atmel Microcontroller mit etlichen I/O Anschlüssen und ein Serial/USB Adapter (auch mit einem Atmel realisiert) zum Anschluss an PCs und zur einfachen Programmierung.
Ursprünglich habe ich vor Jahren nach einem billigen Thermometer gesucht, das man an einen Server anschließen kann. Damit wollte ich damals einen improvisierten Serverraum überwachen.
Dabei bin ich auf das Webtherm Projekt gestoßen, bei dem ein DS1621 Temperatursensor mit etwas Beschaltung an den seriellen Port angeschlossen wird. Ein kleines Programm spielt dann I2C auf der RS232 und liest den Sensor, bzw. die Sensoren aus. Man kann bis zu acht DS1621 an einem I2C Bus betreiben.
Das Programm hatte seine Macken, so musste man ein paar mal lesen um einen verlässlichen Wert zu bekommen, aber es hat funktioniert. Leider werden Rechner mit RS232 immer seltener …
Von Anfang an war die Integration in Nagios ein wesentliches Ziel. Aber wenn man schon Hardware an den Server anschließt, kann man dann nicht auch mehr machen?
Wäre eine Ausgabe des aktuellen Status nicht auch nett? Zum Beispiel in Form einer Ampel? Dazu habe ich auch schon einmal einen Hack mit legacy Schnittstellen gebaut. Fein wäre noch eine Textausgabe …
Mit einem zweizeiligen LCD könnte man schon mehr Informationen transportieren als mit drei LEDs. Und hier kommen die Microcontroller ins Spiel.
Mit dem Arduino lässt sich das alles ganz einfach bewerkstelligen.
Um einmal zu sehen, ob das überhaupt funktionieren kann, habe ich einen Testaufbau mittels Breadboard erstellt.
Der IC
auf dem Schema ist besagter DS1621. Der Anschluss an den Arduino ist simpel:
PIN (DS) | Name | Arduino | Kabelfarbe | Bemerkung |
---|---|---|---|---|
1 | SDA | A4 | braun | I2C Datenleitung |
2 | SCL | A5 | weiss | I2C Clock |
3 | Tout | - | - | unbenutzt (hier könnte man bei Schwellwerten ein Signal ausgeben → Thermostat) |
4 | GND | GND | schwarz | Masse |
5 | A2 | - | schwarz | Bit 2 der Sensoradresse |
6 | A1 | - | schwarz | Bit 1 der Sensoradresse |
7 | A0 | - | schwarz | Bit 0 der Sensoradresse |
8 | VDD | +3.3V | orange | Betriebsspannung, 2,7 ~ 5,5V |
Über die Pins A0..A2 stellt man die Sensoradresse ein … jetzt ist wohl auch klar warum man nur acht DS1621 an einem I2C betreiben kann, obwohl der Bus 112 Devices adressieren könnte.
Als Display habe ich ein zweizeiliges LCD mit LED Hintergrundbeleuchtung gewählt (weil es der Hädler im Sortiment hatte). Was man wissen muss steht im Datenblatt, den Rest beschreibe ich:
PIN (LCD) | Name | Arduino | Kabelfarbe | Bemerkung |
---|---|---|---|---|
1 | VSS | GND | schwarz | Masse |
2 | VDD | +5V | rot | Betriebsspannung |
3 | V0 | - | gelb | Displaykontrast - durch einen Spannungsteiler realisiert |
4 | RS | D12 | grau | Register select |
5 | R/W | D11 | grau | Read/write select |
6 | E | D10 | grau | Operation enable |
7~10 | DB0~DB3 | - | - | siehe Datenblatt |
11~14 | DB4~DB7 | D5~D2 | grau | High order Data Bus |
15 | A | D9 | gelb | LED Hintergrundbeleuchtung - Anode |
16 | K | GND | schwarz | LED Hintergrundbeleuchtung - Kathode |
Zu meiner großen Freude benötigt man ausser dem Spannungsteiler keine analogen Bauteile.
In der realen Welt sieht das dann so aus:
Halogen-Schreibtischlampen erzeugen ganz schön viel Strahlungswärme!
Da mir die Teststrippen recht bald zu wenig waren, habe ich den Datenbus mit Flachbandkabeln realsisert. Auch für den DS1621 hatte ich zu wenig Kabel und habe daher auf die Anordnung vom alten Projekt zurückgegriffen. Der Kondensator kommt auch daher, er soll bei längeren Leitungen helfen …
Das Ganze soll ja jetzt auch untereinander und später mit der Aussenwelt kommunizieren. Dazu muss ein bischen programmiert werden.
Dank der umfangreichen Bibliotheken ist das Programm erstaunlich knapp und recht gut lesbar:
// // ds1621_lcd.pde // // This simple Arduino project reads temerature from DS1621 via I2C // and outputs to LCD and USB // // v0.3 2011-03-25 GS <goesta@smekal.at> // /* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. http://www.gnu.org/licenses */ #include <LiquidCrystal.h> // LCD interface library #include <Wire.h> // I2C library #define DEV_ID 0x90 >> 1 #define NAME "DS1621-Therm 0.3" LiquidCrystal lcd(12, 11, 10, 5, 4, 3, 2); int backLight = 9; // use digital pin 9 to control LCD backlight int dataRead = 13; // show I2C activity with on board LED void setup() { Serial.begin(9600); Serial.println(NAME); pinMode(dataRead, OUTPUT); pinMode(backLight, OUTPUT); digitalWrite(backLight, HIGH); lcd.begin(16,2); lcd.clear(); lcd.setCursor(0,0); lcd.print(NAME); lcd.setCursor(0,1); lcd.print("initializing ..."); i2cInit(); // call device to attention } void loop() { int temp; int decimal; i2cInit(); // call device to attention delay(1000); // wait for sensor to convert data digitalWrite(dataRead, HIGH); // show I2C activity Wire.beginTransmission(DEV_ID); Wire.send(0xAA); Wire.endTransmission(); Wire.requestFrom(DEV_ID, 2); // request two bytes of data temp = Wire.receive(); // integer value comes first decimal = Wire.receive(); // decimal/negative info digitalWrite(dataRead, LOW); lcd.clear(); lcd.setCursor(0,0); lcd.print(NAME); lcd.setCursor(0,1); lcd.print("Sensor0:"); lcd.setCursor(9,1); lcd.print(temp); lcd.setCursor(11,1); if ( decimal == 0 ) { // no decimal lcd.print(".0"); Serial.print(temp); Serial.println(".0 C"); } else { //.5 degrees lcd.print(".5"); Serial.print(temp); Serial.println(".5 C"); } lcd.setCursor(13,1); lcd.print(" C"); } void i2cInit() { digitalWrite(dataRead, HIGH); // show activity on LED Wire.begin(); Wire.beginTransmission(DEV_ID); // connect to DS1621 (#0) Wire.send(0xAC); // Access Config Wire.send(0x02); // set for continuous conversion Wire.beginTransmission(DEV_ID); // restart Wire.send(0xEE); // start conversions Wire.endTransmission(); digitalWrite(dataRead, LOW); }
Weil das mit dem I2C Bus keine so gute Idee ist (die Leitunslängen sind für rund einen Meter ausgelegt) werde ich das Ganze auf 1-Wire Bus umstellen. Dafür gibt es auch billige Sensoren und die Kabel können bis zu 100 Meter lang sein.
Vorher muss ich aber einkaufen gehen