Avem un BeagleBoard si dorim sa citim presiunea atmosferica prin intermediul uni senzor de presiune barometrica BMP085. Senzorul este grozav pentru pretul sau, ofera inclusiv un senzor de temperatura (totusi limitat de la 0 la 65 de grade Celsius) si cu ajutorul sau poti inclusiv sa afli altitudinea (presiunea atmosferica variaza cu altitudinea).
Senzorul BMP085 este un senzor digital ce se conecteaza prin I2C (adica el este un dispozitiv ce are o adresa si diversi registri in care scriem si dispozitivul executa o functie sau ofera informatii localizate in alti registri (pe care ii citim)).
Sa trecem la treaba:
-citim
documentatia senzorului si aflam semnificatia pinilor, mai aflam si ca
senzorul functioneaza cu niveluri logice intre 3V3 si 5V.
-punem firele necesare la senzor (SDA, SCL, GND, Vcc)
-conectorul J3 nu este fizic pe placa, deci va trebui sa il lipim acolo, am ales un conector header cu pini la 2.54mm la 90 de grade
-legam firele SDA (pin 23), SCL (pin 24), GND (pin 27 sau 28) si 5Vcc (pin 2) de la conectorul J3 de pe placa BeagleBoard.
-acum partea hardware este in buna stare, trebuie sa o folosim: trebuie instalat pachetul i2c tools:
sudo apt-get install i2c-tools
-verificam ce busuri I2C sunt disponibile pe placa - cel cu 2 e pentru expansion
header (conectorul J3):
i2cdetect -l
Rezultatul:
i2c-1 i2c OMAP I2C adapter I2C adapter
i2c-2 i2c OMAP I2C adapter I2C adapter
i2c-3 i2c OMAP I2C adapter I2C adapter
Update pt Ubuntu 14.04:
i2c-0 i2c OMAP I2C adapter I2C adapter
i2c-1 i2c OMAP I2C adapter I2C adapter
i2c-2 i2c OMAP I2C adapter I2C adapter
Inseamna ca I2C de pe J3 este disponibil - i2c-2 (sau i2c-1 pt Ubuntu 14.04)
Acum scanam sa vedem ce dispozitive sunt legate pe acest bus (-y e pt a evita intrebarea
Y/N) – daca apare un dispozitiv conectat de noi, il deconectam si mai cautam o
data pt a fi siguri ca acela este - in cazul nostru BMP085 are adresa 0x77:
sudo i2cdetect -y -r 2
0 1 2 3 4 5 6 7 8 9 a b c d e f
00: -- -- -- -- -- -- -- -- -- -- -- -- --
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
70: -- -- -- -- -- -- -- 77(sau pt Ubuntu 14.04: sudo i2cdetect -y -r 1)
-pentru programare si utilizare I2C in Python, trebuie instalat pachetul python-smbus:
sudo apt-get install python-smbus
Documentatia senzorului BMP085 ofera algoritmul de citire a temperaturii cat si al presiunii atmosferice. De asemenea ofera algoritmul de calcul al inaltimii in functie de presiunea atmosferica. Astfel ca se poate incropi cod simplu in C, in Python sau se poate lua codul gata scris de altii si adapta la aplicatie:
#! /usr/bin/env python
import smbus
import time
class BMP085():
OSS = 3
def __init__(self, i2c, address):
self.i2c = i2c
self.address = address
self.ac1 = self.readSignedWord(0xaa)
self.ac2 = self.readSignedWord(0xac)
self.ac3 = self.readSignedWord(0xae)
self.ac4 = self.readWord(0xb0)
self.ac5 = self.readWord(0xb2)
self.ac6 = self.readWord(0xb4)
self.b1 = self.readSignedWord(0xb6)
self.b2 = self.readSignedWord(0xb8)
self.mb = self.readSignedWord(0xba)
self.mc = self.readSignedWord(0xbc)
self.md = self.readSignedWord(0xbe)
def readWord(self, reg):
msb = self.i2c.read_byte_data(self.address, reg)
lsb = self.i2c.read_byte_data(self.address, reg + 1)
value = (msb << 8 ) + lsb
return value
def readSignedWord(self, reg):
msb = self.i2c.read_byte_data(self.address, reg)
lsb = self.i2c.read_byte_data(self.address, reg+1)
if (msb > 127):
msb = msb - 256
value = (msb << 8 ) + lsb
return value
def readUT(self):
self.i2c.write_byte_data(self.address, 0xf4, 0x2e)
time.sleep(0.0045)
ut = self.readWord(0xf6)
return ut
def readTemperature(self):
ut = self.readUT()
x1 = ((ut - self.ac6) * self.ac5) >> 15
x2 = (self.mc << 11) / (x1 + self.md)
self.b5 = x1 + x2
return ((self.b5 + 8 ) >> 4) / 10.0
def readUP(self):
self.i2c.write_byte_data(self.address, 0xf4, 0x34 + (self.OSS << 6))
delay = (2 + (3 << self.OSS)) / 1000.0
time.sleep(delay)
msb = self.i2c.read_byte_data(self.address, 0xf6)
lsb = self.i2c.read_byte_data(self.address, 0xf7)
xlsb = self.i2c.read_byte_data(self.address, 0xf8)
up = (msb << 16) + (lsb << 8 ) + xlsb
up = up >> (8 - self.OSS)
return up
def readPressure(self):
up = self.readUP()
b6 = self.b5 - 4000
x1 = (self.b2 * (b6 * b6)>>12)>>11
x2 = (self.ac2 * b6)>>11
x3 = x1 + x2
b3 = (self.ac1 * 4 + x3)<>2
x1 = (self.ac3 * b6) >> 13
x2 = (self.b1 * ((b6 * b6)>>12))>>16
x3 = ((x1 + x2) + 2)>>2
b4 = (self.ac4 * (x3 + 32768))>>15
b7 = (up - b3) * (50000>>self.OSS)
if (b7 < 0x80000000):
p = (b7<<1 b4="" br=""> else:
p = (b7/b4)<<1 br="">
x1 = (p>>8) * (p>>8)
x1 = (x1 * 3038)>>16
x2 = (-7357 * p)>>16
p += (x1 + x2 + 3791)>>4
return p
i2c = smbus.SMBus(2) #sau pt Ubuntu 14.04: i2c = smbus.SMBus(1)
bmp085 = BMP085(i2c, 0x77)
t = bmp085.readTemperature()
p = bmp085.readPressure()
print "Temperature: %.2f C" % t
print "Pressure: %.2f hPa" % (p / 100)
1>1>
Documentatie i2c tools:
Programarea interfetei I2C:
Ceva hardware (EEPROM si altele):
Daca folosim niveluri logice diferite, este necesar un level shifter la 3V3 la
5V (de exemplu):