J’adore la série Attiny 85 et souhaitez découvrir toutes les choses que vous pouvez faire avec lui. Comme il n’a pas trop d’épingles, en utilisant des matériels I2C sur elle est une bonne idée. I2C sur l’attiny peut être un peu fastidieux car il impossible de compiler la bibliothèque de fils, mais la bibliothèque de TinyWireM fonctionne très bien.
Le capteur de pression BMP180 est un capteur relativement bon marché et populaire pour lire la pression atmosphérique. En outre, il peut lire la température. Si vous souhaitez utiliser ce capteur sur un arduino, Adafruit possède une bibliothèque (pour le BMP085 et le BMP180) que wil Lisez-le pour vous. Toutefois, la nouvelle bibliothèque doit aussi leur bibliothèque générale « Sensor » et voilà guzzlers de mémoire. OK peut-être sur un Arduino, mais pas sur un attiny. Ils ont l’un pour le Tiny85 aussi bien. Sparkfun dispose également d’une bibliothèque pour l’Arduino.
Donc, si vous voulez lire le capteur BMP180 sur un attiny, vous devrez faire certains travaux vous-même. Heureusement, la feuille de données est très très clair. Page 15 nous dit exactement quoi faire. La séquence est la suivante: 1-Lire la puce étalonnage spécifique 2-lecture de données la temparature sans correction valeur 3-lire la valeur de pression non corrigé 4-calculer la température réelle 5-calculer la pression vraie
Il vous montre également ce qui devrait être dans une boucle et ce qui pas : lecture des données d’étalonnage ne doit être fait une fois et va donc dans la routine « Setup ». Le reste est en boucle et va donc dans la routine de la « boucle ».
Ainsi, la programmation est une brise si vous suivez l’organigramme en page 15... Nous avons seulement besoin de « traduire » en langue que comprend le protocole I2C. Nous commençons donc le programme de définir certains paramètres généraux : pour le Attiny il y a la bibliothèque TinyWireM qui implémente un protocole I2C sur l’attiny, donc nous devons charger cette bibliothèque. Nous avons besoin de l’adresse I2C de le BMP180 (c'est-à-dire 0x77), et nous devons déclarer tout un tas de variables. La plupart des variables utilisées contiendra les données d’étalonnage spécifique de puce qui nous liront de EEPROM la puce, nous aurons besoin de quelques variables pour les divers calculs et nous aurons besoin de quelques variables pour contenir la sortie (température et pression) pour le garder simple, j’ai choisi les noms des variables tel que mentionné dans la fiche technique.
Juste un mot d’explication sur l’adresse 0x77. Page 20 de la feuille de données mentionne deux adresses de périphérique : 0xEE pour lire et 0xEF pour écrire.
Une adresse de périphérique I2C peut-être être spécifiée comme une adresse de 7 bits, ce qui est 7 bits qui peut distinguer un appareil d’une autre. Ou sous forme d’octet qui incluent le bit R/W en position LSB.
La fiche de Bosch ne précise pas l’adresse de 7 bits, ce qui est 0x77. Au lieu de cela, il précise (page 20) l’adresse d’écriture de 8 bits, qui est 0xEE et l’adresse de lecture, ce qui est 0xEF de 8 bits. Les deux sont 0x77 R/W
0x77 = 111 0111
0xEE = 111 01110
0xEF = 111 01111
dans le TinywireM bibliothèque deux valeurs sont définies #define USI_SEND 0 / / indique l’envoi à TWI #define USI_RCVE 1 / / indique la réception de TWIthese sont combinés avec l’adresse de 7 bits pour indiquer une lecture ou écriture action
Ainsi, les premières lignes d’un programme ressemblera à ceci :
//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 */
Ensuite nous devons définir la routine « Setup ». Franchement, la seule chose que nous devons faire il est lire les données d’étalonnage. Pour faire simple, je vais juste appeler une procédure « bmp180ReadInt(address) », que nous pouvons alors réaliser plus tard. C’est pourquoi notre configuration ressemblera à ceci :
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); }
Bien sûr je pourrais juste appelé 1 procédure et appel que « bmp180ReadCalibration » mais que la procédure puis ferait la même chose que j’ai maintenant déjà définis dans le programme d’installation
La procédure de « boucle » est tout aussi simple. C’est fondamentalement lire la température sans correction Correct que sans correction de température lire sans correction pression correcte que non corrigée de pression, mais comme personne n’est intéressé par les données non corrigées, nous faisons cette procédure : Correct(Read Uncorrected temperature) Correct(Read Uncorrected pressure) comme ceci :
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()); }
Donc c’est tout. Nous disposons seulement de définir les procédures que nous appelons. Nous allons commencer avec « bmp180ReadInt(address) » cela procédure utilisera la bibliothèque TinyWireM pour lire un nombre entier d’une adresse donnée. Dans l’obtention de données à partir d’un périphérique I2C, la règle générale est d’abord écrire à ce dispositif pour lui dire quoi faire et puis à lire à une adresse spécifique pour le résultat. Comme nous liront de l’EEPROM il n’y a aucune commande spécifique, que nous devons envoyer, autres que pour notifier le port I2C où nous voulons être (à l’adresse I2C de la puce) et envoyer l’adresse que nous voulons lire et combien d’octets, nous voulons lire. Nous avons ensuite combiner ces deux butes dans un nombre entier et qui retournent. Notre precedure ressemblera donc à ceci :
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; }
La procédure suivante, que nous avons besoin est de lire la température sans compensation. Pour obtenir qu’il faut tout d’abord envoyer la valeur de 0x2E à l’indicateur 0xF4 et attendez au moins 4,5 msec. C’est l’époque la puce doit prendre 1 lecture. Après que nous avons attendu, nous lirons la température sans compensation dans les registres 0xF6 et 0xf7. Qui en dernière lecture que nous le faisons avec la procédure définie « bmp180ReadInt » antérieure qui lit des octets 2 et les combine en un entier. La procédure donc ressemblera à ceci :
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; }
Par la suite, il faut calculer la température corrigée de la température non corrigée. La feuille de données qui définit comme suit: UT = sans compensation de température X1 =(UT-AC6) * AC5/2 ^ 15 X 2 = (MC * 2 ^ 11 /(X1+MD) B5 = X 1 + X 2 T =(B5+8)/2 ^ 4 dans le logiciel qui ressemble à ceci
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)); }
La température est bien faite, maintenant nous avons besoin de lire la pression sans compensation. Pour que nous avons besoin écrire la valeur 0 x 34 dans le registre 0xF4, mais il faudra également définir la valeur vor le taux de suréchantillonnage. Le taux de suréchantillonnage détermine la quantité d’échantillons que la puce doit faire avant de donner un résultat. Page 4 de la fiche technique dit nous avons 4 choix: OSS = 0 réglage de puissance ultra basse, 1 échantillon, 4,5 ms 3uA OSS = 1 réglage de puissance Standard, 2 échantillons, 7,5 ms 5uA OSS = 2 haute résolution, 4 biopsies, 13,5 ms 7uA OSS = 3 Ultra haute résolution, 12 échantillons, 25,5 ms 12uA pour ce programme, j’ai choisi l’OSS à 0 l’OSS contienne les bits 6 et 7 en 0xF4 vous inscrire. Bit 0-4 déterminer le contrôle de la mesure. Si nous écrivons la valeur 0 x 34 en binaire : 00110100. Bits 0 à 4 ne sont pas si importantes pour l’instant, mais le bit 5 sera également ensemble et ainsi lancer la conversion. Il va rester élevé pendant la conversion et remis à faible après la conversion. Afin de définir les bits 6 et 7, nous avons à gauche MAJ 6 la valeur des systèmes d’exploitation. Supposons que nous avions voulu définir OSS 3. en binaire c’est 0b11 si nous avons quitté MAJ 6 qui, il sera 11000000 (= 192d ou 0xC0), qui définira les bits 6 et 7. 0 x 34 + 0xC0 = 0xF4 = 0b11110100, qui comme nous pouvons le constater est le même que 0 x 34 plus bit défini 6 et 7. Comme nous utilisons « 0 » pour la valeur de l’OSS, les deux bits 6 et 7 ne définira pas. après qu’on commence la conversion qu'il faut attendre entre 4,5 et 25,5 ms (selon OSS). Comme nous l’avons OSS = 0, on va attendre 5msec. Par la suite, nous lirons 3 octets, comme la température est de type 'long' (4 octets) pas un nombre entier, il faudra toutefois que 3 octets. En ce qui concerne le retard, ce serait bien si nous allons le définir comme une dépendance de l’OSS, vous n’avez pas besoin de le changer manuellement lorsque vous modifiez l’OSS. Le solevs de bibliothèque Adafruit cela avec quelques instructions IF :
Si (suréchantillonnage == BMP085_ULTRALOWPOWER) delay(5) ;
ElseIf (suréchantillonnage == BMP085_STANDARD) delay(8) ;
ElseIf (suréchantillonnage == BMP085_HIGHRES) delay(14) ;
d’autre delay(26) ;
Cependant, je souhaitais trouver une formule qui permettra de le déterminer. Comme il n’est pas une fonction linéaire stricte, le plus proche, on obtient est la formule : 5+(OSS*5). OSS = 0 -> 5 OSS = 1 -> 10 OSS = 2 -> 15 OSS = 3 -> 25 Eh bien, je suppose que ce serait assez proche la procédure est la suivante
/------------------------------------------- // 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; }
Maintenant que le fait, il faut corriger la pression sans compensation. Le résultat sera en Pascal
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; }
Avec le programme ci-dessus on peut décider pour soi-même ce qu’il faut faire avec les données trouvées : envoyez-le à un affichage, ou peut-être l’envoyer via une liaison RF à une station de base. Comme l’a dit, le résultat de la lecture de la pression est Pascal (Pa). hectoPascals constituent une unité plus commode. Certaines autres unités, il peut être calculé en sont: 1 hPa = 100 Pa = 1 mbar = 0,001 bar 1 hPa = 0.75006168 Torr 1 hPa = 0.01450377 psi (livres par pouce carré) 1 hPa = 0.02953337 inHg (pouces de mercure) 1 hpa = 0.00098692 atm (atmosphère standard)
Un dernier Conseil encore : lorsque vous utilisez le BMP180, n’oubliez pas il a besoin de 3,3 volts. 5 volt le tuera. L’utiliser sur l’I2C d’une cause de Cetarticle 5 volts microcontrôleur un problème cependant. Divers moteurs hors-bord de rupture ont effectivement un régulateur de tension 3,3 là-dessus.
Avertissement 1: Il y a un certain « hameçons » dans le programme ci-dessus et malheureusement instructables (et autres sites) ont tendance à voir parfois ceux que le code html. J’ai vérifié minutieusement si le code est OK et je pense que c’est. Toutefois, il est préférable de vérifier le code que je vais relier à dans ma prochaine étape.
Mise en garde 2: Quand j’ai voulu afficher les valeurs trouvées par le BMP180, j’ai attrapé au départ une interface LCD à deux fils que j’avais construit avec un registre à décalage 164 comme je l’avais qui sont disponibles. Par la suite, j’ai essayé de comprendre pendant plusieurs heures, pourquoi je n’étais pas sortir toute lecture décent. En fait, la lecture n’a pas changé de météo, j’ai branché le BMP180 ou non. Après beaucoup de nombreux essais, j’ai commencé à soupçonner mon interface d’affichage et a décidé d’accrocher un écran LCD I2C. Cela a fonctionné comme un charme. Le LiquidCrystal_I2C de Francisco Malpertida ne fonctionne pas sur le Attiny85. J’ai utilisé le LiquidCrystal_I2C classique qui est adapté par Bro Hogan pour travailler sur le Attiny85 ainsi. Il a fait cela en modifiant la ligne :
#include <Wire.h>
dans#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