sabato 12 aprile 2008

Arduino con accelerometro KXPS5


Questo post descrive come utilizzare un accelerometro Kionix KXPS5 con la piattaforma Arduino Diecimila tramite protocollo I2C.
L'accelerometro è montato su una development board Crodnet.


I documenti di riferimento sono i seguenti:
Specifiche tecniche del sensore
KXPS5
Specifiche Tecniche della Crodnet development board

Il protocollo I²C è un sistema di comunicazione seriale utilizzato tra circuiti integrati basato su due fili : SDA (Serial DAta line) per i Dati e SCL (Serial Clock Line) per il clock.
La tipica architettura I2C comprende un master e uno o piu' slave. Nel nostro caso Arduino opera come master e l'accelerometro opera come slave.

La distribuzione di Arduino contiene una libreria per l'impiego del protocollo I2C.
Seguendo quanto indicato nella documentazione di Arduino (http://www.arduino.cc/en/Reference/Libraries) per l'impiego della interfaccia Two Wire (I2C) devono essere utilizzati i pin analogici 4 e 5 rispettivamente per SDA e SCL.


Occorre tener conto delle seguenti specifiche:
  • KXPS5 è progettato per funzionare solo con il voltaggio 3.3V
  • Nella modalita' I2C KXPS5 opera come slave device.
  • Dopo aver dato tensione, il master deve eseguire l'operazione di scrittura su due registri: CTRL_REG B 0x0D e CTRL_REG C 0x0E rispettivamente con i valori 0x42 e 0x00.

I2C impiega per indirizzare i device slave, 7 bit di indirizzo seguiti da un bit 0 per le operazioni di scrittura o 1 per le operazioni di lettura.
Dalla documentazione del sensore apprendiamo che l'indirizzo della scheda KXPS5 è 001100X dove X e' un bit programmabile che dipende dal valore del PIN ADDR (ADDR->GND X=0; ADDR->VCC X=1).
Il bit meno significativo dell'Address dipende dall'operazione che vogliamo eseguire: 0 per write; 1 per read.


Quindi se ADDR e' connesso a GND (X=0) e il master vuole eseguire una operazione di scrittura su un regsitro del dispositivo slave l'indirizzo e'
0011 0000 0x30 (write)
0011 0001 0x31 (read)

Osservando il codice della libreria Wire (e leggendo http://gottfriedhaider.com/texts/show/2008/03/23/arduino-vs-i2c) si comprende che la libreria Wire aggiunge in automatico il bit meno significativo allo slave address shiftando a sinistra l'indirizzo che viene passato.
Pertanto è necessario passare alla funzione di libreria l'indirizzo shiftato a destra:
0001 1000 -> 0x18

I valori delle accelerazioni sui tre assi sono disponibili sui registri ad otto bit che vanno da 0x00 a 0x05:
XOUT_H 0x00
XOUT_L 0x01
YOUT_H 0x02
YOUT_L 0x03
ZOUT_H 0x04
ZOUT_L 0x05

per ottenere i valori delle accelerazioni è pertanto sufficiente leggere 6 byte a partire dall'indirizzo 0x00.

Ciascun valore dell'accelerazione lungo un asse e' formato dai 12 bit piu' significativi dei due byte (parte alta e parte bassa).
Pertanto i valori per ciascuna componetente dell'accelerazione sono compresi tra 0 e 4096 (2^12)
2048 corrisponde a 0g
4096 corrisponde a 3g
0 corrisponde a -3g


Lo schema delle connessioni e' il seguente (per utilizzare il codice riportato sotto)

arduino -------- Crodnet KXPS5

3V3 -------- VCC
GND -------- GND
ANALOG 4 --------- SDA
ANALOG 5 --------- SCL
DIGITAL 13 --------- ENABLE
DIGITAL 12 --------- MOT ENABLE

inoltre sullo slave occorre connettere:
CS -> VCC
ADDR -> GND (X=0)


Di seguito viene riportato il codice:


#include <wire.h>;

// KXPS5 I2C




void setup()
{
Wire.begin(); // join i2c bus (address optional for master)
int ENABLE = 13;
int MOTENABLE = 12;
pinMode(ENABLE, OUTPUT);
pinMode(MOTENABLE, OUTPUT);
digitalWrite(ENABLE, HIGH);
digitalWrite(MOTENABLE, LOW);
Serial.begin(9600); // start serial for output

Wire.beginTransmission(0x18); // transmit to device 0x18 = 00011000
Wire.send(0x0C); // load 0x42 in register 0x0D and 0x0 in register 0x0E
Wire.send(0x00);
Wire.send(0x42);
Wire.endTransmission(); // stop transmitting
}

void loop()
{

byte x = 0;
int a = 0;

Wire.beginTransmission(0x18); // transmit to device
Wire.send(0x0); //
//Wire.send(x); // sends one byte
Wire.endTransmission(); // stop transmitting

Wire.requestFrom(0x18, 0x06); // request 6 bytes from slave device #2
while(a = Wire.available()) // slave may send less than requested
{
unsigned int xh = Wire.receive(); // receive a byte as character
unsigned int xl = Wire.receive();
unsigned int yh = Wire.receive();
unsigned int yl = Wire.receive();
unsigned int zh = Wire.receive();
unsigned int zl = Wire.receive();
//delay(100);
unsigned int x = xh * 256 + xl;
unsigned int y = yh * 256 + yl;
unsigned int z = zh * 256 + zl;
x=x>>4;
y=y>>4;
z=z>>4;

Serial.print(x, DEC); // print the character
Serial.print(' ');

Serial.print(y, DEC);
Serial.print(' ');
Serial.print(z, DEC);


}
Serial.println(' ');
//delay(500);

}



A questo punto non resta che provare l'accelerometro con un'applicazione. Nel video qui sotto una scatola "virtuale" riproduce le inclinazioni dell'accelerometro.



*ringrazio il mio amico gerda che mi ha gentilmente messo a disposizione un paio di schede arduino e un accelerometro digitale.