Accelerometro BMA180

Ho collegato l'accelerometro BMA180 con l'arduino secondo lo schema riportato in:

però qualunque listato '.ino' utilizzo, quando avvio il SerialMonitor non vedo le 'system' che ho inserito (serial.print)

Utilizzando il listato preso al link sopra specificato, il listato si blocca al metodo readFrom.

Generalizzando, come faccio a verificare se il bma180 funziona ?
Dove posso reperire un listato base che legge i valori x,y,z funzionante ?

Ho provato quel codice con il programma che visualizza su pc e non funziona.. anche se il mio acc funziona..

Tu, quale listato .ino o .pde hai utilizzato per utilizzare l'accelerometro?

Fino ad ora tuttinon ci sono riuscito.

prova con la versione 22 o 23 del'IDE, la UNO ha ancora qualche problemino... :grin:

alcuni listati dove è riportato .send o .receiver devono essere rinominati con .write e .read
Questa esigenza è legata alla versione dell'ide e quindi della libreria,
Se uso la 0.23 non è necessario rinominare i metodi ?

Ho usato il listato presente nella pagina che hai postato...

/*
Copyright (c) 2010-2011 George Rhoten

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/

/*
If you need some reference material take a look at the following:

Instrumentation in Earthquake Seismology (Modern Approaches in Geophysics) 
  by Jens Havskov, Gerardo Alguacil

BMA180 digital, triaxial acceleration sensor data sheet
  by Bosch Sensortec

The original source code can be found at:
http://www.centralnexus.com/seismograph/details_bma180.html
*/
#include <Wire.h>

// ADXL345
#define DEVICE ((byte)0x40)    //BMA180 device address

#define DATA_X0		0x02	//X-Axis Data 0
#define DATA_X1		0x03	//X-Axis Data 1
#define DATA_Y0		0x04	//Y-Axis Data 0
#define DATA_Y1		0x05	//Y-Axis Data 1
#define DATA_Z0		0x06	//Z-Axis Data 0
#define DATA_Z1		0x07	//Z-Axis Data 1
#define DATA_TEMP	0x08	//Temperature
#define SOFT_RESET	0x10	//soft_reset
#define SOFT_RESET_VAL	0xB6	//soft_reset value to reset

#define AXIS_SHIFT	2	//Amount to right shift data. The first 2 bits are status bits.

// USGS suggests rates of 20, 40 or 200 samples per second for natural earthquakes.
//#define DELAY_RATE	9990	//~100Hz
//#define DELAY_RATE	6600	//~150Hz
#define DELAY_RATE	4993	//~200Hz

// LED
#define COMMON_ANODE 4
#define RED_PIN 3
#define BLUE_PIN 5
#define GREEN_PIN 6
#define LED_VALUE_SHIFT 4

#define GRAVITY 255
#define ANALOG_MAX 0xFF
#define USE_LED 1

/**
 * The value in relation to 0xFF within the range value.
 */
static byte pinMagnitudeRangeToTop(byte range, int value) {
  if (value < 0) {
    value = -value;
  }
  if (value > 255) {
    return (byte)ANALOG_MAX - range;
  }
  return (byte)ANALOG_MAX - (byte)(((float)value / (float)GRAVITY) * (float)range);
}

//Writes val to address register on device
static void writeTo(byte address, byte val) {
  Wire.beginTransmission(DEVICE); //start transmission to device 
  Wire.send(address);        // send register address
  Wire.send(val);        // send value to write
  Wire.endTransmission(); //end transmission
}

//reads num bytes starting from address register on device in to buff array
static void readFrom(byte address, byte num, byte *buff) {
  Wire.beginTransmission(DEVICE); //start transmission to device 
  Wire.send(address);        //sends address to read from
  Wire.endTransmission(); //end transmission

  Wire.requestFrom(DEVICE, num);    // request num bytes from device
  num = Wire.available(); //device may send less than requested (abnormal)
  while(num-- > 0) {
    *(buff++) = Wire.receive(); // receive a byte
  }
}

/**
 * Writes val to address register on device if it's different from
 * the current value. This decreases the wear and tear on the EEPROM.
 */
static void writeOptionallyTo(byte address, byte val, byte mask) {
  byte value = 0;
  readFrom(address, sizeof(value), &value);
  if ((value & mask) != (val & mask)) {
    // Keep the unmasked values, and changed the masked values.
    writeTo(address, (value & ~mask) | (val & mask));
  }
}


void setup()
{
  Wire.begin();          // join i2c bus (address optional for master)
  Serial.begin(115200);  // start serial for output
  Serial.flush();

  // Wait for readings to settle down.
  // 10ms Pause is required to write registers.
  delay(15);

  writeOptionallyTo(0x0D, 0x10, 0x10); // Enable register write

  // I can't figure out how to modify the EEPROM.
  // So we reset upon startup.

  // Change calibration values based on new mode.
  // Each chip will need their own calibration.
  // Note: some offset values affect the spikiness of the values. You should test your values.
  writeOptionallyTo(0x3A, 0x76, 0xFF); // original offset MSB z=0x78 when mode_config=0
  writeOptionallyTo(0x39, 0x5C, 0xFF); // original offset MSB y=0x60 when mode_config=0
  writeOptionallyTo(0x38, 0x6D, 0xFF); // original offset MSB x=0x70 when mode_config=0
  writeOptionallyTo(0x36, 0x7C, 0xFF); // original offset LSB z=0x4, y=0xC when mode_config=0
  // Need a range of existing gravity + 1 G movment to get up to a 9.0M earthquake.
  writeOptionallyTo(0x35, 0xC4, 0xFF); // original offset LSB x=0x1, range+12bit=0x4 when mode_config=0

  writeOptionallyTo(0x30, 0x01, 0x03); // Change mode_config to lower noise mode
  writeOptionallyTo(0x21, 0x00, 0x04); // Turn off adv_int
  
  /* Earthquakes have a nominal frequency range of 0.001–50 Hz. The P and S
   * waves of >2.0M earthquakes usually have a frequency of 0.1-10 Hz. The
   * higher frequencies are attenuated by the bedrock. So you need to be
   * close to the epicenter to measure the higher frequencies. In order to
   * accurately record the lower frequencies, the bandwidth measurement must
   * be lowered in the sensor. When equal to 0x8 or 0x9, the gravity will be
   * cancelled out.
   */
  writeOptionallyTo(0x20, 0x20, 0xF0); // Change bandwidth. 0x2=40Hz 0x3=75Hz Originally 0x4

  writeOptionallyTo(0x0D, 0x00, 0x10); // Disable register write for protection

#if USE_LED
  //3 color LED
  pinMode(COMMON_ANODE, OUTPUT);
  digitalWrite(COMMON_ANODE, HIGH);

  pinMode(RED_PIN, OUTPUT);
  digitalWrite(RED_PIN, HIGH);

  pinMode(GREEN_PIN, OUTPUT);
  digitalWrite(GREEN_PIN, HIGH);

  pinMode(BLUE_PIN, OUTPUT);
  digitalWrite(BLUE_PIN, HIGH);
#endif
}

void loop()
{
  // 2 byte endian marker
  // 6 byte buffer for saving data read from the device
  // 2 byte checksum in case there is a reset in the middle of a packet.
  int axis[5] = {0x8081, 0, 0, 0, 0};

  // There are 1,000,000 microseconds per second,
  // and we want to sample about 200 per second.
  // This gives us about the right rate with the rest of the overhead.
  delayMicroseconds(DELAY_RATE - (int)(micros() % DELAY_RATE));
  
  // Each axis reading comes in 14 bit resolution (2 bytes little endian).
  readFrom(DATA_X0, 6, (byte*)(axis+1)); //read the acceleration data

  // Remove status and 0 bits
  axis[1] = axis[1] >> AXIS_SHIFT;
  axis[2] = axis[2] >> AXIS_SHIFT;
  axis[3] = axis[3] >> AXIS_SHIFT;

  // Calculate checksum.
  axis[4] = axis[1] + axis[2] + axis[3];
  // Write whole packet.
  Serial.write((byte *)axis, sizeof(axis));

#if USE_LED
  analogWrite(RED_PIN, pinMagnitudeRangeToTop(0xFF, axis[1]>>LED_VALUE_SHIFT));
  analogWrite(GREEN_PIN, pinMagnitudeRangeToTop(0xFF, axis[2]>>LED_VALUE_SHIFT));
  analogWrite(BLUE_PIN, pinMagnitudeRangeToTop(0xFF, axis[3]>>LED_VALUE_SHIFT));
#endif
}

Ho collegato l'accelerometro BMA180 secondo lo schema riportato

non ho collegato l'INTERRUPT.
Qualunque listato utilizzo (IDE 0.23) questo si blocca sulla sulla prima istruzione

Wire.endTransmission();

Suggerimenti. E' un problema di collegamenti o che cosa ?

Hai messo delle resistenze di pull up sui 3.3V e i cavi SDA ed SCL ?
quanto lunghi sono i cavi ?

ratto93:
Hai messo delle resistenze di pull up sui 3.3V e i cavi SDA ed SCL ?
quanto lunghi sono i cavi ?

ci sono le pull-up interne attive per defult, prima bisogna disattivare quelle se si usano pèull-up esterne

da qualche parte ho letto che lo stesso autore dice che non sono necessarie, come non è necessario il condensatore.

Per un attimo, e non so il perchè, il bma180 ha risposto. Quindi ho caricato altri listati pensando di il problema era risolto, e tutto è ritornato come
prima.
E' possibile che i listati che utilizzo vadano a sporcare qualcosa nei registri ?

Inoltre eseguo un listato pde che fa lo scanning dei registri, se non collego il bma180 mi da l'elenco dei registri immediatamente, mentre con il bma180
collegato il programma si blocca.

http://todbot.com/blog/2009/11/29/i2cscanner-pde-arduino-as-i2c-bus-scanner/

se ti da quel problema.. o il BMA è partito o ti hanno venduto una porcheria oppure hai invertito SDA ed SCL...

SDA e SCL sono collegati correttamente.
quindi è un problema del bma180 che si è rotto.
a questo punto, devo buttare (se continua a non funzionare) altri 30 circa per provare.

c'e modo di testare se il bma180 è funzionante o meno ???????????

he he... ti servirebbe un DSO per testarlo.. ma se non te lo rileva proprio o è fritto oppure è montato male se tutti i collegamenti son giusti e non và... poi mettere una foto dell'acellerometro ? almeno a 1024x768 non sfocata ? :slight_smile:

ovviamente anche alla schedina su cui è montato... ed entrambi i lati :slight_smile:

gcam:
SDA e SCL sono collegati correttamente.

Sullo schema non ci sono le indispensabili resistenze di pull up su SDA e SCL, se non le hai messe è normale che non funzioni, Arduino si pianta perché le routine della I2C sono sono bloccanti in caso di errore.

Ho scoperto che il BMA180 non è rotto. Dopo tre giorni di inattività dell'arduino, casualmente ha funzionato anche se per poco. Sono riuscito a leggere l'indirizzo con lo scanner (64 dec = 40 esa).
Dopo un poco, e ritornato come prima. Ho giocherellato con le resistenze, ma senza esito positivo duraturo.
Quindi penso che il problema sta nel collegamento.

Qual'è il valore delle resistenze da utilizzare e dove collegarle con esattezza.
Allego schema di collegamento.

grazie e buone feste.

schema bma180.png

3.3K ohm tra SDA e 3.3V e la stessa cosa su SCL

Da qualche parte ho letto che bisogna limitare le scritture sulla eprom. cito testualmente:

'Controlla se il registro dell'EEPROM ctrl_reg0.ee_w è configurato per essere scritto o no in quanto è fondamentale limitarne la scrittura (possono essere riscritti al massimo 1000 volte). E' importante notare che tale valere deve essere impostato ad 1 non solo se deve essere modificata una voce di registro maggiore di 0x04, ma anche se devi modificare la memoria volatile. Voci di registro con indirizzi minori sono volatili.'

che significa ?

Devo settare il range a +-1g
e avere la possibilità di settare uno dei possibili filtri.
Ho guardato le specifiche e i valori sono espressi in bit da utilizzare.

void setFilter()
{
// Connect to the bw_tcs register and set the filtering level to 10hz
Wire.beginTransmission(DEVICE);
Wire.send(0x20);
Wire.send(B00001000);
result = Wire.endTransmission();
Serial.print("Set Filter Result: ");
Serial.println(result);
delay(10);
}
ma sulle specifiche per il filtro a 10 Hz il valore è 0000. Praticamente sono i primi 4 bit della stringa B00001000 ?????

void setRange()
{
Wire.beginTransmission(DEVICE);
Wire.send(0x35);
Wire.send(B0100);
result = Wire.endTransmission();
Serial.print("Set Range Result: ");
Serial.println(result);
delay(10);
}
sulle specifiche il valore è indicato con bit (cifre) da 000 a 110 in questo caso cosa indica B0100

Guardando un altro esempio, in questo caso non lo capisco.

void AccelerometerInit()
{
Wire.beginTransmission(0x40); // address of the accelerometer
// reset the accelerometer
Wire.send(0x10);
Wire.send(0xB6);
Wire.endTransmission();
delay(10);

Wire.beginTransmission(0x40); // address of the accelerometer
// low pass filter, range settings
Wire.send(0x0D);
Wire.send(0x10);
Wire.endTransmission();

Wire.beginTransmission(0x40); // address of the accelerometer
Wire.send(0x20); // read from here
Wire.endTransmission();
Wire.requestFrom(0x40, 1);
byte data = Wire.receive();
Wire.beginTransmission(0x40); // address of the accelerometer
Wire.send(0x20);
Wire.send(data & 0x0F); // low pass filter to 10 Hz
Wire.endTransmission();

Wire.beginTransmission(0x40); // address of the accelerometer
Wire.send(0x35); // read from here
Wire.endTransmission();
Wire.requestFrom(0x40, 1);
data = Wire.receive();
Wire.beginTransmission(0x40); // address of the accelerometer
Wire.send(0x35);
Wire.send((data & 0xF1) | 0x04); // range +/- 2g
Wire.endTransmission();
}

Inoltre l'autore del codice afferma dice 'read in the 3 axis data, each one is 16 bits'
effettivamente i valori sono compresi tra -32000 e +32000 ma il range non è -8192 e +8192

http://www.instructables.com/id/RC-Quadrotor-Helicopter/step14/Arduino-Demo-Sensor-Reading/

grazie per eventuali delucidazioni