Mini Bewegungsmelder
- Details
- Geschrieben von Alexander Schulz
- Kategorie: Sonstige
- Zugriffe: 32953
Die Anweseinheits- und Bewegungserkennung ist für Hausautomationsysteme durchaus interessant. Daher habe ich mich nach einem (für Arduino auswertbaren) PIR-Modul umgesehen. Bei eBay werden viele derartige Modulle sehr günstig angeboten (natürlich aus China). Die allermeisten Modelle scheinen geringfügige Variationen von derselben Art zu sein (HC-SR501).
Neulich kam meine Bestellung an.
Technische Daten laut Angebotsbeschreibung:
Betriebsspannungsbereich | 4,5 - 20V |
Ruhestrom | <50µA |
Ausgang | High 3,3V, Low 0V |
Triggereinstellung | H (wiederholbar), L (nicht wiederholbar) |
Verzögerungszeit | 5-200S |
Blockade-Zeit | 2,5S |
Größe | 32mm x 24mm |
Erfassungswinkel | <100° |
Reichweite | 3-4 m (seitlich), 5-8 m (vorn) |
Betriebstemperatur | -15 bis 70 °C |
Die Einschaltzeit und die Empfindlichkeit können über zwei Regler (Potis) eingestellt werden. Die Trigger-Vorwal wird mittels eines Jumpers vorgegeben. Position 'H' bedeutet, dass bei einer erneut erkannter Bewegung während der Einschaltzeit diese Zeit verlängert wird. Bei der Einstellung 'L' wird der Ausgang nach dem Ablauf der eingestellter Zeitspanne in jedem Fall ausgeschaltet. Die erneute Bewegung kann erst nach Ablauf der Blockadezeit erkannt werden.
Nach dem Einschalten des Sensors benötigt dieser ca. 1 Minute zur Initialisierung. Erst nach dieser Zeit werden die Bewegungen sicher erkannt.
Die Verwendung mit dem Arduino ist denkbar einfach. Außer Betriebspannung ist lediglich der Ausgang an einen beliebigen digitalen Arduino-Pin anzuschließen und dessen Zustand auszuwerden. Bei einer erkannten Bewegung setzt der Sensor die Ausgangsleitung auf HIGH.
Folgender Sketch soll das auf einfache Weise demonstrieren.
/* Testprogramm für Mini Bewegungsmelder. Alexander Schulz Das Programm benutzt den PIR-Sensor zum Schalten des auf dem Arduino Board befindlichen LED (an PIN13). Verdrahtung (UNO, Nano...) Sensor pin VCC pin an 5V Sensor pin out an Pin 2 Sensor pin GND pin an GND */ int ledPin = 13; int sensorPin = 2; void setup() { pinMode(ledPin, OUTPUT); pinMode(sensorPin, INPUT); } void loop() { digitalWrite(ledPin, digitalRead(sensorPin)); delay(50); }
Winterschlaf für Arduino
- Details
- Geschrieben von Alexander Schulz
- Kategorie: Arduino / ATMEL
- Zugriffe: 94508
Für mein Vorhaben, einen batteriebetrieben Außensensor auf Arduino-Basis zu bauen, ist ein möglichst sparsames System von großer Bedeutung. Es wäre wenig praktikabel, alle paar Tage die Batterien erneuern zu müssen. Auch alle paar Monate nicht. Es wird eine Mindestlaufzeit von einem Jahr oder mehr angestrebt.
Es sollen die verbreiteten AA-Batterien (aka Mignon) verwendet werden. Sie stellen einen guten Kompromis zwischen größe, Verfügbarkeit, Kapazität und Prei dar. Unter der Annahme einer mittleren Kapazität von 2500mAh, darf die Platine incl. aller Peripherie nicht mehr als etwa 0,29 mA verbrauchen. Es soll jedoch möglich sein, einen Atmel (Arduino-CPU) mit wenigen µA (im Leerlauf) zu betreiben. Das ist mein Ziel.
Der erste Schritt besteht darin, ein möglichst sparsames Board auszuwählen. Meine Wahl fiel auf ein Arduino Pro Mini (http://arduino.cc/de/Main/ArduinoBoardProMini). Dieses Board hat keinen fest eingelöteten USB-Serial-Konverter, das allein spart schon etwas Energie. Dazu ist es sehr klein, was für meine Zwecke von Vorteil ist.
Der Stromverbrauch einer CPU steigt mit den höheren Spannung (quadratisch) und Frequenz (linear). Von Arduino Pro Mini gibt es Versionen mit 5V/16Mhz und 3,3V/8Mhz. Die zweite Variante muss definitiv genügsamer sein und lässt sich auch besser mit Batterien oder Akkus versorgen (z.B. 3 x 1,2V (Akku) ergibt 3,6V - praktisch perfekt). Leider besitze ich gerade jetzt kein solches Arduino, daher werde ich meine ersten Tests mit der 5V-Version durchführen.
Ein typischer Außensensor tut die meiste Zeit nichts. In weiten Abständen (mehrere Minuten können für einen Mikroprozessor eine halbe Ewigkeit bedeuten) werden angeschlossenen Sensoren abgefragt und die ermittelten Werte an die Basisstation übermittelt. Wie viell Strom bei der Auswertung und der Übertragung fliesst ist nicht so wichtig, denn genau das passiert im Vergleich mit der Ruhezeit sehr selten und dauert jeweils nur ganz kurz. Interessant ist der Verbrauch in der restlichen Zeit.
Was tut ein Prozessor, wenn er nichts zu tun hat?
Der einfachste Fall: CPU läuft in einer Schleife und tut gar nichts (sinnvolles). Um zu sehen, was dabei an Strom verbraucht wird, habe ich das Arduino Standardbeispiel 'Blink' leicht modifiziert. Mein Programm lässt eine LED in einer Endlosschleife für 1 Sekunde leuchten und anschließend wird sie für 4 Sekunden gelöscht. Die Werte 1 und 4 sind aus Bequemlichkeitsgründen gewählt. Zwar wären Werte wie 1 Sekunde (Auswertung und Übertragung) zu 5 Minuten (Inaktivitästszeit) realitätsnäher, zu Testzwecken sind jedoch kürzere Zeiträume wesentlich bequemer.
// Pin 13 has an LED connected on most Arduino boards. // give it a name: int led = 13; // the setup routine runs once when you press reset: void setup() { // initialize the digital pin as an output. pinMode(led, OUTPUT); } // the loop routine runs over and over again forever: void loop() { digitalWrite(led, HIGH); // turn the LED on (HIGH is the voltage level) delay(1000); // wait for a second digitalWrite(led, LOW); // turn the LED off by making the voltage LOW delay(4000); // wait 4 seconds }
Die Messwerte sind ernüchternd: 18,95 mA (Ruhephase) zu 21,40 mA mit der leuchtenden LED. Der Unterschied liegt durchaus im Bereicht eines typischen Verbrauchs einer LowCurrent LED. Dem zweiten Wert wird ab jetzt nicht weiter Beachtung geschenkt.
Bei diesem Ruheverbrauch wird die Batterie nach ca. 132 Stunden leer. Das sind gerade mal 5,5 Tage. Völlig inakzeptabel.
Das Board im Bild wird von einem Programmer (USBasp) versorgt. Dieser tut an sich nichts zur Sache. Es war mir damit gerade einfacher, einen Ampermeter in Arduinos Stromkreis einzuschleusen (wollte gerade kein USB-Kabel aufschneiden).
Der zweite Ansatz führt in die Tiefe der Prozessor-Technik. Die CPU hat mehrere Stromsparmodi: "Idle", "Powerdown", "Powersave", "Standby" und "ADC Noise Reduction mode" (genauer nachzulesen z.B. hier). Der sparsamste davon ist der Modus "Powersave".
Nach einer kurzer Suche habe ich einen Beispiel gefunden, der praktisch alles an Funktionalität enthält, was ich für meine Zwecke benötige (link). Im Quellcode ist zu sehen, wie der Prozessor in den tiefen Schlaf zu versetzen ist und auch wie man ihn daraus wieder weckt. Letztere ist nicht so selbstverständlich, wie man zunächst denken kann. Denn eine tief schlummernde CPU führt keine Programme mehr und reagiert auch auf fast nichts. Um aufzuwachen muss diese "unterbrochen" werden. Dafür wird hier ein sogenannter "Watchdog" genutzt.Ein Watchdog ist eine Schaltung im CPU, die eine Art Countdown durchführt und beim Ablauf diesen einen Reset auslöst. Normalerweise wird im Programm der Timer immer ieder zurückgesetzt. Wenn der Prozessor "hängt", starter der "Wachhund" ihn neu. Eine dre Massnahmen, um eine hohe Systemverfügbarkeit zu garantieren. Der Wachtdog kann bei Atmel-Prozessoren auch dazu verwendet werden, um diese aus dem Schlafmodus aufzuwecken. Auch wenn diese Schaltung im aktiven Zustand selbst etwas Strom verbraucht, scheint sie in diesem Fall genau das richtige Mittel zu sein.
In dem (hoffentlich irgendwann) fertigen Gerät kann ich mich auch eine Taste gut verstellen (z.B. um die aktuelle Werte auf dem LCD anzuzeigen), die auch zum Wiederaufwachen führt. Dies wird wohl mittels eines Interraupts geschehen müssen. Dies soll aner an dieser Stelle ohne Beachtung bleiben.
Ich habe den gefundenen Beispielcode (s.o.) etwas für meine Zwecke modifiziert.
#include <avr/sleep.h> #include <avr/wdt.h> // Macros zum Setzen und Löschen von Steuer-Bits #ifndef cbi #define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit)) #endif #ifndef sbi #define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit)) #endif // Pin 13 has an LED connected on most Arduino boards. int led = 13; // Steuervariable. Erkennung des Timerablaufs (um z.B. andere Interrupts zu ignorieren) volatile boolean f_wdt=1; void setup() { // initialize the digital pin as an output. pinMode(led, OUTPUT); // CPU Sleep Modes // SM2 SM1 SM0 Sleep Mode // 0 0 0 Idle // 0 0 1 ADC Noise Reduction // 0 1 0 Power-down // 0 1 1 Power-save // 1 0 0 Reserved // 1 0 1 Reserved // 1 1 0 Standby(1) cbi( SMCR,SE ); // sleep enable, power down mode cbi( SMCR,SM0 ); // power down mode sbi( SMCR,SM1 ); // power down mode cbi( SMCR,SM2 ); // power down mode setup_watchdog(8); } // the loop routine runs over and over again forever: void loop() { if (f_wdt==1) { // wait for timed out watchdog / flag is set when a watchdog timeout occurs f_wdt=0; // reset flag digitalWrite(led, HIGH); // turn the LED on (HIGH is the voltage level) delay(1000); // wait for a second digitalWrite(led, LOW); // turn the LED off by making the voltage LOW } pinMode(led,INPUT); // set all used port to intput to save power system_sleep(); pinMode(led,OUTPUT); // set all ports into state before sleep } //**************************************************************** // set system into the sleep state // system wakes up when wtchdog is timed out void system_sleep() { cbi(ADCSRA,ADEN); // switch Analog to Digitalconverter OFF set_sleep_mode(SLEEP_MODE_PWR_DOWN); // sleep mode is set here sleep_enable(); sleep_mode(); // System sleeps here sleep_disable(); // System continues execution here when watchdog timed out sbi(ADCSRA,ADEN); // switch Analog to Digitalconverter ON } //**************************************************************** // 0=16ms, 1=32ms,2=64ms,3=128ms,4=250ms,5=500ms // 6=1 sec,7=2 sec, 8=4 sec, 9= 8sec void setup_watchdog(int ii) { byte bb; //int ww; if (ii > 9 ) ii=9; bb=ii & 7; if (ii > 7) bb|= (1<<5); bb|= (1<<WDCE); //ww=bb; //Serial.println(ww); MCUSR &= ~(1<<WDRF); // start timed sequence WDTCSR |= (1<<WDCE) | (1<<WDE); // set new watchdog timeout value WDTCSR = bb; WDTCSR |= _BV(WDIE); } //**************************************************************** // Watchdog Interrupt Service / is executed when watchdog timed out ISR(WDT_vect) { f_wdt=1; // set global flag }
Schon besser. Bei diesem Stromverbrauch hält die Batterie ca. 31 Tage. Immer noch Faktor 10 zu wenig, aber die Richtung stimmt.
An dieser Stelle denke ich an die hell läuchtende PowerLED. Diese kann sich durchaus 2-4 mA genehmigen. Leider kann sie nicht softwaretechnisch aufgeschaltet werden und mus daher ausgelötet werden. Dies ist nicht ganz einfach, denn es andelt sich hier um eine sehr kleine SMD-Version. Ich werde diese Tätigkeit in die Zukunft verschieben, wenn meine sparsame 3,3V Boards geliefert werden.
Der ober Code funktioniert schon recht gut, jedoch will man so ein Mix von Low-Level Anweisungen nicht unbedingt im geschäftslogik-Teil des fertigen Programms sehen. Es muss eine Bibliothek her. Bevor man jedoch eine neue schreibt, sollte man nachsehen, ob nicht schon so eine existiert.
Schnell sind mehrere gefunden: Narcoleptic, Low-Power, Enerlib.
Bei Narcoleptic gefiel mir ihre Einfachheit, geringe Größe und die Möglichkeit, den Inaktivitätsdauer frei vorzugeben. Die Bibliothek wird jedoch seit längerem nicht mehr weiterentwickelt und verursachte im Test einen etwas höheren Verbrauch alt der Code oben. Der Grund dazu ist nicht deaktivierter Analog-Digital-Wandler.
Enerlib hat mir auch nicht zugesagt. Diese könnte ich nicht ohne Modifikation verwendet, denn sie erlaub gar keine Zeitvogabe für den Tielschlaf.
Dafür ist die Low-Power ein Glückstreffer. Gut dokumentiert, mit vielen Hintergrunfinformationen fersehen, sehr mächtig und aktuell. Was mir nicht so gefällt, ist die starre Vorgabe des Schlafdauers. Es sind nur wenige feste Werte (max. 8 Sekunden) möglich (low-level, eben das, was der Watchdog-Timer bietet). Dafür kannn eine sehr feine Konfiguration bezüglich den abzuschaltenden Hardwarekomponenten vorgegeben werden. Gefällt mir sehr. Ich möchte allerdings eine Methode schreiben schreiben, um eine einfache und flexible "delay"-Funktion (etwa wie im Narcoleptic) zu erhalten. Bis dahin werde ich noch einige Test mit Narcoleptic durchführen. Zuvor schalte ich zusätzlich noch den A/D-Wandler mit ab.
#include <Narcoleptic.h> #ifndef cbi #define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit)) #endif #ifndef sbi #define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit)) #endif // Pin 13 has an LED connected on most Arduino boards. // give it a name: int led = 13; // the setup routine runs once when you press reset: void setup() { // initialize the digital pin as an output. pinMode(led, OUTPUT); } // the loop routine runs over and over again forever: void loop() { digitalWrite(led, HIGH); // turn the LED on (HIGH is the voltage level) delay(1000); // wait for a second digitalWrite(led, LOW); // turn the LED off by making the voltage LOW cbi(ADCSRA,ADEN); // disable A/C-Converter pinMode(led,INPUT); // set all used port to intput to save power Narcoleptic.delay(4000); pinMode(led,OUTPUT); // set all ports into state before sleep sbi(ADCSRA,ADEN); // enable A/C-Converter }
Eigentlich ist mein Board mit 16mHz nicht für 3,3V geeignet, es lief mit dieser Spannung jedoch stabil. Der Verbrauch sank auf 1,57 mA. Das entspricht schon ca. 66 Tagen.
Um den Verbrauch weiter zu senken, sind schon radikalere Maßnahmen notwendig. Dafür habe ich die Power-LED abgeschaltet. Dafür habe ich den LED-Vorwiderstand herausgelötet. (War etwas schwierig, die SMD-Bauteile liegen auf dem Boars recht eng).
Die Maßnahme wirkt. Der Verbrauch liegt bei 29,5 µA! Und das bei 5 Volt. Damit habe ich mein oben definiertes Ziel eigentlich schon erreicht. Bei den Werten darf die Batterie Jahre halten. Da fällt schon Selbstentladung ins Gewicht.
Aus dem sportlichen Interesse will ich wissen, was man noch ohne größeren Aufwand erreichen kann.
3,3 Volt-Test war zunächts misslungen. Im µA-Bereich hat das Messgerät wohl einen etwas höheren Widerstand, so dass sich das Board sofort wieder resettet hat. Das habe ich bestimmt dem Brown out Detector (BOD erkennt eine Unterspannung und bewirkt daraufhin Reset der CPU. Damit wird instabiler Betrieb verhindert) zu verdanken. In mA-Bereich war der Wert 0,02 mA angezeigt.
Also muss noch der BOD raus. Das soll aus dem laufenden Programm möglich sein, aber nicht mit Narcoleptic. Eine andere Methode führt über einen neuen Arduino-Bootloader. Eine gute Anleitung dazu liefert 'Rocket Scream', der Hersteller von Low-Power-Bibloithek (Link).
Ich habe die Datei 'boards.txt' (Arduino IDE, Verzeichnis 'hardware\arduino') um eine neue Sektion erweitert.
############################################################## pro5v328BOD.name=Arduino Pro or Pro Mini (5V, 16 MHz) w/ ATmega328 without BOD pro5v328BOD.upload.protocol=arduino pro5v328BOD.upload.maximum_size=30720 pro5v328BOD.upload.speed=57600 pro5v328BOD.bootloader.low_fuses=0xFF pro5v328BOD.bootloader.high_fuses=0xDA pro5v328BOD.bootloader.extended_fuses=0x07 pro5v328BOD.bootloader.path=atmega pro5v328BOD.bootloader.file=ATmegaBOOT_168_atmega328.hex pro5v328BOD.bootloader.unlock_bits=0x3F pro5v328BOD.bootloader.lock_bits=0x0F pro5v328BOD.build.mcu=atmega328p pro5v328BOD.build.f_cpu=16000000L pro5v328BOD.build.core=arduino pro5v328BOD.build.variant=standard ##############################################################
Damit kennt IDE jetzt ein 'neues' Board. Der einzige Unterschied zum Original ist eine anders gesetzt Fuse (Original: ...extended_fuses=0x05).
Nach dem Flaschen des Bootloaders (hier war der Programmer notwendig) war der BOD aus. Das sieht man gut an dem Stromverbrauch und an der Tatsache, dass das Board jetzt mit dem Ampermeter in µA-Bereich bei 3,3V problemlos funktioniert.
Der Wert ist zwar nicht so fantastisch, wie bei Rocket Scream beschrieben, aber dennoch sehr beeindrückend. Ich bin gespannt, wie das mit dem 8mHz Arduino aussieht. ;-) In jedem Fall ist der Prozessor nicht der limitierende Faktor für die Laufzeit. In einer fertigen Schaltung werden andere Komponenten über den endgültigen Verbrauch stärker entscheiden. So führt sogar ein angeschlossener FTDI-Chip (zuständig für USB-Anschluss) zu einem messbaren Mehrverbrauch. Dabei war der Chip nicht mal an die USB-Schnittstelle des Computers angeschlossen.
Eine weitere Möglichkeit wäre die Verwendung des internen Oszillators zum Erzeugen des CPU-Taktes. Da dieser nicht so genau wie ein Quarzoszillator ist, kann dabei zu Problemen z.B. bei seriellen Verbindungen kommen (zumindest bei höheren Baudraten). Aus diesem Grund will ich diesen Ansatz nicht weiter verfolgen.
Nachdem ich mit den Tests fertig war, habe ich den LED-Vorwiderstand wiedereingelötet. Es ist leider etwas schief geworden, war bei diesem kleinen Raster nicht ganz einfach. Merkwürdigerweise muss dabei der Bootloader Schaden genommen haben. Das Board lief nicht mehr und ließ sich auch nicht über USB bespielen. Mit einem Programmer konnte ich jedoch einen neuen über die ISP-Schnittstelle installieren. Jetzt läuft Pro Mini wieder einwandfrei. Ich verstehe nicht ganz, wie das passieren konnte. Evtl. hat das etwas mit statischen Elektrizität zu tun.
Im Folgenden noch mein Testprogramm unter der Verwendung der LowPower-Bibliothek.
/* * PowerSave * * Author: Alexander Schulz * Version: 1.0 * Datum: 17.07.2013 * * Dieses Programm lässt die auf dem Arduino- Board vorhandene LED * alle 4 Sekunden blinken. In den Pausen wird der Prozessor * in den Schlaffmodus versetzt. * */ #include <LowPower.h> // Pin 13 ist auf den meisten Boards mit einer LED verbunden. int led = 13; void setup() { // Definiert den LED-Pin als Ausgang. pinMode(led, OUTPUT); } void loop() { digitalWrite(led, HIGH); // LED an (Ausgang HIGH) delay(1000); // eine Sekunde brennen lassen digitalWrite(led, LOW); // wieder ausmachen (Ausgang LOW) pinMode(led,INPUT); // Alle benutzen Ports als Eingang definieren, das spart Energie delay(4000); pinMode(led,OUTPUT); // benutzte Ports wieder in den benötigten Zustand versetzen } /* * Versetzt den Prozessort für eine angegebene Zeitspanne ins Tiefschlaf. * Nach dem Auswecken wird geprüft, ob die gewünschte Zeit bereits abgelaufen ist * und wird ggf. wieder Schlafmodus aktiviert. * Man sollte bei der Dauer nicht mit einer besonderen Genauigkeit rechnen. */ void delay(int milliseconds) { while (milliseconds >= 8000) { sleep(SLEEP_8S); milliseconds -= 8000; } if (milliseconds >= 4000) { sleep(SLEEP_4S); milliseconds -= 4000; } if (milliseconds >= 2000) { sleep(SLEEP_2S); milliseconds -= 2000; } if (milliseconds >= 1000) { sleep(SLEEP_1S); milliseconds -= 1000; } if (milliseconds >= 500) { sleep(SLEEP_500MS); milliseconds -= 500; } if (milliseconds >= 250) { sleep(SLEEP_250MS); milliseconds -= 250; } if (milliseconds >= 125) { sleep(SLEEP_120MS); milliseconds -= 120; } if (milliseconds >= 64) { sleep(SLEEP_60MS); milliseconds -= 60; } if (milliseconds >= 32) { sleep(SLEEP_30MS); milliseconds -= 30; } if (milliseconds >= 16) { sleep(SLEEP_15Ms); milliseconds -= 15; } } /* * Verwendet LowPower-Bibliothek zum Aktivieren des Schlafmodus der CPU. */ void sleep(period_t period) { LowPower.powerDown(period, ADC_OFF, BOD_OFF); }
Luftdrucksensor BMP085
- Details
- Geschrieben von Alexander Schulz
- Kategorie: I²C
- Zugriffe: 40932
Vor einiger Zeit habe ich bei einem meiner lieblings China-eBay-Verkäufern ein günstiges Luftdrucksensor entdeckt: eine BMP085-Breakout-Board. Die technische Daten sahen vielversprechend aus und der Preis war mehr als bezahlbar. Gesehen-bestellt-gewartet... und jetzt liegt der gute Stück hier und schreit danach, getestet zu werden. ;-)
Laut Beschreibung handelt es sich beim BMP085 um einen 'hochpräzisen' Sensor mit 'ultra-niedrigen' Stromverbrauch. Der Sensor ist vorkalibriert und temperaturkompensiert. Die Temperatur kann auch ausgelesen werden.
Die Angaben des Verkäufers:
- Genauigkeit beträgt bis zu 0.03hPa (0.25 m) in Präzisionsmodus und 0.06hPa (0.5 m) sonst
- Stromverbrauch Standardmodus liegt bei 5μA und bei 3μA sonst, in Standby begnügt sich der Chip mit 0.1μA
- Messbereich von 300 bis 1100 hPa (das wären etwa 9000 Meter über dem Meeresspiegel bis hinzu -500 m).
- I²C-Schnittstelle
- typische Antwortzeit 7.5ms
- Betriebsspanung von 1,8 bis 3,6 V
- Größe: 2cm x 1.5cm
Auch wenn der Verkäufer die Betriebsspannung für das Board mit <3,6 V angiebt (was für den Chip selbst auch stimmt), sehe ich auf dem Bord ein 3,3V-Festspannungsregler (662K). Das Board erzeugt sich offenbar die notwendige Spannung selbst. Laut Datenblatt des Reglers darf die Eingangsspannung bis zum 6 V betragen. Ein Hacken hat das Ganze aber doch. Die Datenleitungen des Chips sind nicht 5V-tolerant. Dank der PullUp-Wiederständen (an 3,3 V), die man deutlich im Bild sehen kann, wird die Spannung auf ein erträgliches Maß begrenzt. Das funktioniert aber nur, wenn keine PullUps an die 5V-Schiene existieren! Diese würden die Spannung auf ein höheres Niveau ziehen, was für den Chip möglicherweise schon zu viel des Guten wäre. Man darf zusammen mit diesem Board keine 5V-Komponente an dem geminsamen I²C-Bus betreiben! Zumendest nicht ohne Level-Shifter.
Die Anschlüsse:
- VCC - Betriebsspannung (3 bis 5 V sind wohl OK)
- SDA, SCL (Serial Data und Serial Clock) - I²C Bus
- XCLR (Master Clear (low-active)) - damit kann der Sensor reinitialisiert werden
- EOC (End of conversion output) - signalisiert, dass die Daten berechnet sind und können angeholt werden
- GND - Masse
So, jetzt wollen wir sehen, wie das Ganze funktioniert. Die Reinitialisierung brauchen wir nicht, auch müssen die Werte nicht sonderlich oft abgefragt werden, daher sind für die Verbindung zum Arduino nur 4 Leitungen notwendig: 5V-Spannung, Masse und die Leitungen des I²C Busses: SDA und SCL. Diese befinden sich an den Pins A4 und A5 des Arduinos.
Zur Ansteuerung gibt es eine leicht zu nutzende Bibliothek 'Adafruit' (https://github.com/adafruit/Adafruit_BMP085_Unified/). Im Packet ist auch ein Testprogramm zu finden.
Hier ist mein Testaufbau:
Und das ist die Programmausgabe:
Als der erste Durchstich ist das schon mal ganz gut. Spannender ist jedoch etwas nützlicheres zu bauen.
Dafür nahm ich ein anderes Arduino-Board und ein LCD-Shield. Da an den letzten nichts weiter angeschlossen werden kann, steckte ich ein "Sensor-Shield" (Anschlussplatine) dazwischen.
Und so sieht das aus. Schrit 1, Arduino UNO mit dem Sensor-Shied:
Der fertige Aufbau mit dem LCD:
Es fehlt noch die nötige Software. Mit dem folgendem Sketch verwandelt sich ein totes Stück Elektronik in ein Digitalbarometer.
#include <Wire.h> #include <Adafruit_BMP085.h> #include <LiquidCrystal.h> /* * Barometer_LCD * * Author: Alexander Schulz * Version: 1.0 * Datum: 06.07.2013 * * Das Programm benutzt den Luftdrucksensor BMP085 und * zeigt die Werte für Druck und Temperatur auf einem 16x2-Symbol-LCD. * * Verdrahtung (UNO, Nano...) * * BMP085: * Sensor SCL pin an A5 * Sensor SDA pin an A4 * Sensor VDD pin an 5V * Sensor GND pin an GND * * LCD in 4-Bit-Modus: * LCD RS pin an digital pin 8 * LCD RW pin an digital pin 13 * LCD Enable pin an digital pin 9 * LCD D4 pin an digital pin 4 * LCD D5 pin an digital pin 5 * LCD D6 pin an digital pin 6 * LCD D7 pin an digital pin 7 */ // Setup für LCD-Shield LiquidCrystal lcd(8, 13, 9, 4, 5, 6, 7); Adafruit_BMP085 bmp; void setup() { // Diaplay initialisieren lcd.clear(); lcd.begin(16, 2); lcd.setCursor(0,0); lcd.print("Initializing..."); delay(500); lcd.clear(); // Prüfen, ob Sensor vorhanden ist if (!bmp.begin()) { lcd.clear(); lcd.setCursor(0,0); lcd.print("BMP085 not found"); lcd.setCursor(0,1); lcd.print("check wiring!"); while (1) { delay(1000); } } } void loop() { // Textvariablen char bmp_temperature[7]; char bmp_pressure[7]; // Werte auslesen und aufbereiten dtostrf(bmp.readTemperature(), 6, 2, bmp_temperature); dtostrf((float)bmp.readPressure()/1000, 6, 2, bmp_pressure); // Werte auf LCD anzeigen lcd.setCursor(0,0); lcd.print("Temp: "); lcd.setCursor(6,0); lcd.print(bmp_temperature); lcd.setCursor(12,0); lcd.print(" *C"); lcd.setCursor(0,1); lcd.print("Pres: "); lcd.setCursor(6,1); lcd.print(bmp_pressure); lcd.setCursor(13,1); lcd.print("kPa"); delay(1000); }
Die Werte liegen zwischen dem, was meine Wetterstation sagt und die Angaben des Wetterdienstes, dürften also recht gut sein. Die Temperatur von gut 28 Grad ist der Wäreme des Laptops zu verdanken.
Und so entsteht aus Bauteilen für ca. 30 Euro eine unvollständige Wetterstation. Dafür kann man schon eine "richtige" bekommen :-)
Arduino Pro Mini
- Details
- Geschrieben von Alexander Schulz
- Kategorie: Arduino / ATMEL
- Zugriffe: 42892
Der Postbote brachte heute wieder mal ein China-Päckchen. Diesmal war ein neues Board dabei: Arduino Pro Mini mit ATmega328. Das Board ist fertig aufgebaut bis auf die Stiftleisten. Bei dem Preis von unter 4 Euro löte ich diese gern selbst ein.
Das Board ist sehr klein und sieht schon fast niedlich aus ;-)
Die Größe beträgt nur 33mm x 18 mm x 3mm. Als CPU wird ein ATmega328 verwendet, diese läuft mit 16MHz und es wird ein externer Quarzresonator (0.5% Toleranz) verwendet. USB ist nicht mit an Board (erfordert externes FTDI-Breakout-Board). Die zulässige Betriebsspannung darf im Bereich von 5 bis 12 V liegen, für Schutz von Überspannung und falscher Polarität wird gesorgt. Der maximale Gesamtoutput soll 150mA betragen dürfen. Es sind zwei LEDs eingelötet: Power und Status (die letzte kann programmtechnisch angesteuert werden).
Technische Daten:
Microcontroller | ATmega328 |
Betriebsspannung | 5V (es gibt auch eine Version mit 3,3V und 8MHz) |
Spannung min/max | 5 - 12V |
Digitale I/O Pins | 14 (6 davon unterstützen PWM) |
Analoge Pins | 8 |
max. Belastung pro I/O Pin | 40 mA |
Flash Memory | 16 KB (2 KB davon sind durch bootloader belegt) |
SRAM | 1 KB |
EEPROM | 512 bytes |
Taktfrequenz | 16 MHz (es gibt Versionen mit 8MHz bi 3,3V) |
Weitere Informationen sind bei http://arduino.cc/en/Main/ArduinoBoardProMini zu finden. Dieses Board ist etwas anders aufgebaut (vor Allem wird ein anderer Microcontroller verwendet), aber die meisten Beschreibungen passen.
Ein- und Ausgänge:
- Serial: Zum Empfangen und Senden von Seriellen Daten werden Pins 0 (RX / Empfangen) und 1 (TX / Senden) verwendet.
- Interupts: Externe Interrunpts können über Pins 2 und 3 ausgelöst werden. Dafür müssen sie entsprechend konfiguriert werden (entsprehende Funktion ist attachInterrupt(), Interrupts werden durch LOW-Pegel, fallende oder rsteigene Kante und Wertveränderung ausgelöst werden).
- PWM (Pulsweitenmodulation): Pins 3, 5, 6, 9, 10, und 11 stellen 8-bit PWM zur Verfügung (s. Funktion analogWrite()).
- I2C (TWI): Diese Schnitstelle erforder 2 Leitungen. Diese liegen auf den analogen Pins A4 (SDA) und A5 (SCL). Die Schnittstelle wird durch die Wire Bibliothek unterstützt.
- SPI (Serial Peripheral Interface): Diese Schnittstelle liegt auf Pins 10 (SS), 11 (MOSI), 12 (MISO) und 13 (SCK). Diese SPI wird durch Hardware des Microcontroller bereitgestellt, eine spezielle Unterstützung in Arduino Sprache ist jedoch nicht vorhanden.
Einen ICSP-Anschluss hat das Board nicht. Wenn man diese (zum Anschluss des Programmers) benötigt, müssen entsprechende Pins direkt wervendet werden.
So war das Board geliefert.
Na dann vollen wir mal das kleine Ding fertiglöten!
Und nun der erste Test. Nachdem ich die korrekte Einstellungen für COM-Port und Boardtyp im IDE vorgenommen habe, konnte ich ein Testprogramm auf das Board laden. Fertig geflasht, kann das Board natürlich auch ohne USB-Serial-Konverterboard verwendet werden. Was man jedoch im Unterschied zu den meisten anderen Arduino-Boards nicht hat - ist eine 3,3V-Quelle.
Jetzt soll das kleine Ding nur noch auf ein Steckboard und dann bin ich für's Erste fertig.
Nachtrag
Ich habe jetzt noch eine weitere Version von MiniPro erworben. Diesmal eine mit 3,3V (Grenzwerte: 3.35 -12 V) und 8MHz. Dieses Board ist natürlich wesentlich langsamer, mir geht es hier aber um eine besondere Sparsamkeit beim Stromverbrauch. Ich plane, auf dieser Basis einen batteriebetriebenen Außensensor aufzubauen.
Und noch eine Version. Etwas gewundert habe ich mich über den Zweck der 6 Lötkontakte, die auf den ersten Blick nach ICSP aussehen und die gleichen Signale führen, jedoch bei näherem Hinsehen doch eine andere Belegung aufweisen. Da alle diese Anschlüsse bereits an anderen Pins vorhanden sind, habe ich sie gar nicht erst eingelötet.
Seite 14 von 14