Ich liebe die Attiny 85-Serie und gerne alles zu erkunden, was, die man damit machen können. Da sie nicht zu viele Pins, ist mit I2C-Hardware auf es eine gute Idee. I2C auf den Attiny kann ein bisschen knifflig sein, da es die Draht-Bibliothek kann nicht kompiliert werden, aber die TinyWireM-Bibliothek funktioniert.
BMP180-Druck-Sensor ist ein relativ billig und beliebt Sensor Luftdruck zu lesen. Zusätzlich können sie die Temperatur ablesen. Wenn dieser Sensor auf einem Arduino verwenden möchten, Adafruit verfügt über eine Bibliothek (für die BMP085 und der BMP180), Wil es für Sie zu lesen. Aber die neue Bibliothek benötigt auch ihre allgemeine Sensor-Bibliothek und das sind Speicher Guzzlers. OK, vielleicht auf einem Arduino, aber nicht auf einen Attiny. Sie haben eine für den Tiny85 sowie. SparkFun hat auch eine Bibliothek für den Arduino.
Also, wenn Sie den BMP180-Sensor auf einen Attiny lesen möchten, müssten Sie einige Arbeit zu tun. Glücklicherweise ist das Datenblatt sehr sehr deutlich. Seite 15 sagt uns genau, was Sie tun. Die Reihenfolge lautet wie folgt: 1-Read Chip Kalibrierung Daten 2-lesen Sie die unkorrigierte Temparature Wert 3-lesen Sie die unkorrigierte Druckwert 4-berechnen wahre Temperatur 5-wahre Druck berechnen
Es zeigt dir auch was in einer Schleife sein sollte und was nicht: lesen die Kalibrierdaten nur einmal getan werden muss und daher geht in die "Setup"-Routine. Der Rest wird in einer Schleife und geht damit in die "Schleife" Routine.
Also, Programmierung ist ein Kinderspiel, wenn Sie das Flussdiagramm auf Seite 15 folgen... Wir brauchen nur zu "übersetzen", die in Sprache, die das I2C Protokoll versteht. Daher beginnen wir das Programm mit einige allgemeine Parameter definieren: für den Attiny es die TinyWireM-Bibliothek, die eine I2C Protokoll auf die Attiny implementiert ist, also müssen wir die Bibliothek zu laden. Wir brauchen die I2C-Adresse des BMP180 (das 0x77), und wir müssen eine ganze Reihe von Variablen zu deklarieren. Die meisten der verwendeten Variablen werden die Chip-Kalibrierung-Daten, die wir lesen werden aus dem Chip EEPROM, benötigen wir einige Variablen für die verschiedenen Berechnungen und brauchen wir einige Variablen enthalten die Ausgabe (Temperatur und Druck), halten es einfach, ich Namen für die Variablen gewählt haben wie erwähnt im Datenblatt enthalten.
Nur ein Wort der Erklärung auf die Geräte-Adresse 0x77. Seite 20 des Datenblatts erwähnt zwei Geräteadressen: 0xEE für Lese- und 0xEF zum schreiben.
Eine I2C-Geräteadresse kann als eine 7-Bit-Adresse angegeben werden, die 7 Bits, die ein Gerät von einem anderen unterscheiden kann. Oder als ein Byte, die das R/W Bit in die LSB-Position.
Bosch Datenblatt gibt keinen 7-Bit-Adresse, an die 0x77 ist. Stattdessen gibt es (Seite 20) 8-Bit Schreibadresse, die 0xEE ist und der 8-Bit Read-Adresse, die 0xEF ist. Beide sind 0x77 R/W
0x77 = 111 0111
0xEE = 111 01110
0xEF = 111 01111
in der TinywireM Bibliothek zwei Werte definiert sind #define USI_SEND 0 / / zeigt auf TWI Sendung #define USI_RCVE 1 / / gibt an, von TWIthese empfangen werden kombiniert mit der 7-Bit-Adresse angeben, lesen oder schreiben Aktion
So, werden die ersten Zeilen eines Programms wie folgt aussehen:
//The connection for Attiny & BMP180 are SDA pin 5 ,SCL pin 7 for I2C #include <TinyWireM.h> #define BMP180_ADDRESS 0x77 // I2C address of BMP180 // define calibration data for temperature: int ac1; int ac2; int ac3; unsigned int ac4; unsigned int ac5; unsigned int ac6; int b1; int b2; int mb; int mc; int md; long b5; //define variables for pressure and temperature calculation long x1,x2; //define variables for pressure calculation long x3,b3,b6,p; unsigned long b4,b7; //define variables for temperature and pressure reading short temperature; long pressure; const unsigned char OSS = 0; // Oversampling Setting /* blz 12 Datasheet OSS=0 ultra Low Power Setting, 1 sample, 4.5 ms 3uA OSS=1 Standard Power Setting, 2 samples, 7.5 ms 5uA OSS=2 High Resolution, 4 samples, 13.5 ms 7uA OSS=3 Ultra High Resolution, 2 samples, 25.5 ms 12uA */
Dann haben wir die "Setup"-Routine zu definieren. Ehrlich gesagt, ist das einzige, was, das wir dort tun musst, die Kalibrierdaten lesen. Um es einfach zu halten, nenne nur ich eine Prozedur "bmp180ReadInt(address)", die wir dann später umsetzen können. Unsere Einrichtung wird daher wie folgt aussehen:
void setup() { // First read calibration data from EEPROM ac1 = bmp180ReadInt(0xAA); ac2 = bmp180ReadInt(0xAC); ac3 = bmp180ReadInt(0xAE); ac4 = bmp180ReadInt(0xB0); ac5 = bmp180ReadInt(0xB2); ac6 = bmp180ReadInt(0xB4); b1 = bmp180ReadInt(0xB6); b2 = bmp180ReadInt(0xB8); mb = bmp180ReadInt(0xBA); mc = bmp180ReadInt(0xBC); md = bmp180ReadInt(0xBE); }
Natürlich konnte nur 1 Verfahren und Aufruf dieser "bmp180ReadCalibration" rief ich habe aber das Verfahren dann das gleiche tun würde, wie ich jetzt schon in den Einstellungen definiert
Die "Schleife" Verfahren ist genauso einfach. Es ist im Grunde nicht korrigierte Temperatur korrigieren, nicht korrigierte Temperatur unkorrigierte Druck richtig das unkorrigierte lesen lesen Druck aber da niemand den unkorrigierten Daten interessiert ist, machen wir dieses Verfahren: Correct(Read Uncorrected temperature) Correct(Read Uncorrected pressure) wie folgt:
void loop() { // first, read uncompensated temperature //temperature = bmp180ReadUT(); //and then calculate calibrated temperature temperature = bmp180CorrectTemperature(bmp180ReadUT()); // then , read uncompensated pressure //pressure = bmp180ReadUP(); //and then calculate calibrated pressure pressure = bmp180CorrectPressure(bmp180ReadUP()); }
So das war's. Jetzt müssen wir nur die Verfahren zu definieren, die wir nennen. Wir beginnen mit "bmp180ReadInt(address)" das Verfahren wird die TinyWireM-Bibliothek verwenden, um eine ganze Zahl von einer bestimmten Adresse zu lesen. Im Abrufen von Daten aus einem I2C-Gerät, die allgemeine Regel ist, zuerst zu diesem Gerät es dazu zu sagen, was zu schreiben und dann das Ergebnis an einer bestimmten Adresse zu lesen. Wie wir aus dem EEPROM gelesen wird gibt es keine bestimmten Befehl haben wir senden, außer um den I2C Port zu informieren, wo wir werden (auf die I2C-Adresse des Chips) und die Adresse, die wir lesen wollen und wie viele Bytes senden wollen, wir lesen wollen. Wir kombinieren diese beiden Butes in eine Ganzzahl und zurück, die. Unsere Precedure wird daher wie folgt aussehen:
int bmp180ReadInt(unsigned char address) { unsigned char msb, lsb; TinyWireM.beginTransmission(BMP180_ADDRESS); TinyWireM.send(address); TinyWireM.endTransmission(); TinyWireM.requestFrom(BMP180_ADDRESS, 2); while(TinyWireM.available()<2); msb = TinyWireM.receive(); lsb = TinyWireM.receive(); return (int) msb<<8 | lsb; }
Der nächste Schritt, was wir brauchen ist die nicht kompensierte Temperatur ablesen. Zu bekommen, wir zuerst den Wert von 0x2E Register 0xF4 und warten Sie mindestens 4,5 msec zukommen lassen müssen. D. h. die Zeit muss der Chip 1 Messung durchzuführen. Nachdem wir gewartet werden wir die nicht kompensierte Temperatur aus Registern 0xF6 und 0xf7 lesen. Zuletzt gelesen, dass haben wir mit dem früheren definierten "bmp180ReadInt"-Verfahren, die 2 Byte liest und kombiniert sie in eine ganze Zahl. Das Verfahren wird daher wie folgt aussehen:
unsigned int bmp180ReadUT() { unsigned int ut; // Write 0x2E into Register 0xF4 and wait at least 4.5mS // This requests a temperature reading // with results in 0xF6 and 0xF7 TinyWireM.beginTransmission(BMP180_ADDRESS); TinyWireM.send(0xF4); TinyWireM.send(0x2E); TinyWireM.endTransmission(); // Wait at least 4.5ms delay(5); // Then read two bytes from registers 0xF6 (MSB) and 0xF7 (LSB) // and combine as unsigned integer ut = bmp180ReadInt(0xF6); return ut; }
Anschließend haben wir die korrigierte Temperatur von der nicht korrigierte Temperatur berechnet. Das Datenblatt, die wie folgt definiert: UT = unkompensierten Temperatur X1 =(UT-AC6) * AC5/2 ^ 15 X 2 = (MC * 2 ^ 11 /(X1+MD) B5 = X 1 + X 2 T =(B5+8)/2 ^ 4 in Software, die wie folgt aussieht
double bmp180CorrectTemperature(unsigned int ut) { x1 = (((long)ut - (long)ac6)*(long)ac5) >> 15; x2 = ((long)mc << 11)/(x1 + md); b5 = x1 + x2; return (((b5 + 8)>>4)); }
Die Temperatur ist gut gemacht, jetzt wir die nicht kompensierten Druck abgelesen müssen. Für die, die wir den Wert 0x34 in das Register 0xF4 schreiben müssen, aber wir müssen auch der Wert Vor der Oversampling Rate festgelegt. Die Oversampling Rate bestimmt die Höhe der Proben, die der Chip, bevor ein Ergebnis liefern machen muss. Seite 4 des Datenblatts sagt wir haben 4 Möglichkeiten: OSS = ultra Low Power Einstellung 0, 1 Probe, 4,5 ms 3uA OSS = 1 Power-Standardeinstellung, 2 Proben, 7,5 ms 5uA OSS = 2 hochauflösende, 4 Proben, 13,5 ms 7uA OSS = 3 Ultra hochauflösende, 12 Proben, 25,5 ms 12uA für dieses Programm habe ich mich entschieden, dem OSS 0 OSS enthält Bits 6 und 7 im register 0xF4. Bit 0-4 bestimmen die Kontrolle der Messung. Wenn wir den Wert 0x34 zu schreiben, in Binär: 00110100. Bits 0 bis 4 sind vorerst nicht so wichtig, aber Bit 5 wird auch eingestellt werden und somit die Konvertierung zu starten. Es wird während der Konvertierung hoch bleiben und nach der Konvertierung auf LOW zurückgesetzt. Um die Bits 6 und 7 müssen wir den Wert des OSS Linksverschiebung 6. Angenommen Sie, wir wollten OSS als 3 festgelegt. 0b11 ist, wenn wir Verschiebung 6 Links, die Binär werden 11000000 (= 192d oder 0xC0), die Bits 6 und 7 eingestellt werden. 0x34 + 0xC0 = 0xF4 = 0b11110100, wie wir sehen können ist das gleiche wie 0x34 plus bit 6 und 7 gesetzt. Da wir '0' für den OSS-Wert verwenden, werden beide Bit 6 und 7 nicht festgelegt werden. Nachdem wir die Konvertierung zu starten, müssen wir zwischen 4,5 und 25,5 ms (je nach OSS) warten. Da wir OSS haben = 0 wir 5msec warten. Anschließend lesen wir 3 Bytes, da die Temperatur eine "lange" (4 Bytes) keine Ganzzahl ist, benötigen wir jedoch nur 3 Bytes. Im Hinblick auf die Verzögerung wäre es schön, wenn wir es als Abhängigkeit des OSS definieren, so müssen Sie nicht manuell ändern, wenn Sie das OSS ändern. Das Adafruit Bibliothek Solevs dies mit einigen IF-Anweisungen:
Wenn (oversampling == BMP085_ULTRALOWPOWER) delay(5);
ElseIf (oversampling == BMP085_STANDARD) delay(8);
ElseIf (oversampling == BMP085_HIGHRES) delay(14);
sonst delay(26);
Allerdings hatte ich gehofft, eine Formel zu finden, die es bestimmen. Da es keine streng lineare Funktion ist, die nächste man bekommt ist die Formel: 5+(OSS*5). OSS = 0 -> 5 OSS = 1 -> 10 OSS = 2 -> 15 OSS = 3 -> 25 gut, ich denke, das wäre nahe genug, die Vorgehensweise ist wie folgt
/------------------------------------------- // Read the uncompensated pressure value unsigned long bmp180ReadUP() { unsigned char msb, lsb, xlsb; unsigned long up = 0; // Write 0x34+(OSS<<6) into register 0xF4 // Request a pressure reading w/ oversampling setting TinyWireM.beginTransmission(BMP180_ADDRESS); TinyWireM.send(0xF4); TinyWireM.send(0x34 + (OSS<<6)); TinyWireM.endTransmission(); // Wait for conversion, delay time dependent on OSS delay(5 + (5*OSS)); // Read register 0xF6 (MSB), 0xF7 (LSB), and 0xF8 (XLSB) TinyWireM.beginTransmission(BMP180_ADDRESS); TinyWireM.send(0xF6); TinyWireM.endTransmission(); TinyWireM.requestFrom(BMP180_ADDRESS, 3); // Wait for data to become available while(TinyWireM.available() < 3) ; msb = TinyWireM.receive(); lsb = TinyWireM.receive(); xlsb = TinyWireM.receive(); up = (((unsigned long) msb << 16) | ((unsigned long) lsb << 8) | (unsigned long) xlsb) >> (8-OSS); return up; }
Nun, fertig ist, müssen wir die nicht kompensierten Druck zu korrigieren. Das Ergebnis wird in Pascal sein.
double bmp180CorrectPressure(unsigned long up) { b6 = b5 - 4000; // Calculate B3 x1 = (b2 * (b6 * b6)>>12)>>11; x2 = (ac2 * b6)>>11; x3 = x1 + x2; b3 = (((((long)ac1)*4 + x3)<<OSS) + 2)>>2; // Calculate B4 x1 = (ac3 * b6)>>13; x2 = (b1 * ((b6 * b6)>>12))>>16; x3 = ((x1 + x2) + 2)>>2; b4 = (ac4 * (unsigned long)(x3 + 32768))>>15; b7 = ((unsigned long)(up - b3) * (50000>>OSS)); if (b7 < 0x80000000) p = (b7<<1)/b4; else p = (b7/b4)<<1; x1 = (p>>8) * (p>>8); x1 = (x1 * 3038)>>16; x2 = (-7357 * p)>>16; p += (x1 + x2 + 3791)>>4; return p; }
Mit dem oben genannten Programm kann entscheiden für sich selbst was mit den gefundenen Daten zu tun: schicken Sie es an eine Anzeige oder vielleicht an einer Basisstation über einen RF-Link senden. Wie gesagt, ist die Ausgabe von die Druckanzeige in Pascal (Pa). Hektopascal sind ein bequemer. Einige andere Einheiten in berechenbar sind: 1 hPa = 100 Pa = 1 Mbar = 0,001 bar 1 hPa = 0.75006168 Torr 1 hPa = 0.01450377 Psi (Pfund pro Quadratzoll) 1 hPa = 0.02953337 InHg (Zoll Quecksilber) 1 Hpa = 0.00098692 atm (standard Atmosphären)
Einen letzten Rat noch: Wenn Sie die BMP180 verwenden, denken Sie daran, es braucht 3,3 Volt. 5 Volt wird es zu töten. Einsatz auf den I2C aus einer 5 Volt Mikrocontroller verwechselt Ursache ein Problem aber. Verschiedenen Pause Außenborder haben tatsächlich einen 3.3 Spannungsregler drauf.
Warnung 1: In das oben genannte Programm gibt es schon einige "Angelhaken" und leider Instructables (und andere Websites) haben eine Tendenz, die manchmal als HTML-Code sehen. Ich habe gründlich überprüft, wenn der Code OK ist und ich denke, es ist. Allerdings empfiehlt es sich, den Code zu überprüfen, den ich mit in mein nächster Schritt verknüpft wird.
Warnung 2: Wenn ich die Werte von den BMP180 gefunden anzeigen wollte, schnappte ich mir zunächst eine zwei-Draht-LCD-Schnittstelle, dass ich mit einem 164 Schieberegister zu bauen hatte, wie ich das zur Verfügung hatte. Ich versuchte daraufhin für mehrere Stunden herauszufinden, warum ich anständige lesen raus war nicht. In der Tat ändern nicht ausgelesenen Wetter ich die BMP180 verbunden oder nicht. Nach vielen vielen versuchen ich begonnen, meine Anzeige vermuten und beschloss, hook up ein I2C-LCD. Das funktioniert wie ein Charme. Die LiquidCrystal_I2C von Francisco Malpertida funktioniert nicht auf den Attiny85. Früher habe ich die klassische LiquidCrystal_I2C, die auf den Attiny85 sowie arbeiten von Bro Hogan angepasst ist. Er tat dies, indem Sie die Zeile ändern:
#include <Wire.h>
in#if defined(__AVR_ATtiny85__) || (__AVR_ATtiny2313__) #include "TinyWireM.h"
// include this if ATtiny85 or ATtiny2313
#else
#include <Wire.h> // original lib include #endif // original lib include #endif