Difference between revisions of "ATtiny85 8MHz and ADXL345 via I2C with Arduino code"
Line 19: | Line 19: | ||
* #0/PB0 -> SDA | * #0/PB0 -> SDA | ||
* #2/PB2 -> SCL | * #2/PB2 -> SCL | ||
== Libraries == | |||
* [https://github.com/adafruit/TinyWireM TinyWireM] - Using the USI on ATtiny to emulate TWI/I2C, improved by Adafruit | |||
== Speed == | |||
Add this section to the hardware.txt in the attiny folder. | |||
<code> | |||
trinket1.name=Adafruit Trinket 1MHz | |||
trinket1.bootloader.low_fuses=0xF1 | |||
trinket1.bootloader.high_fuses=0xD5 | |||
trinket1.bootloader.extended_fuses=0xFE | |||
trinket1.upload.maximum_size=5310 | |||
trinket1.build.mcu=attiny85 | |||
trinket1.build.f_cpu=1000000L | |||
trinket1.build.core=arduino:arduino | |||
trinket1.build.variant=tiny8 | |||
</code> | |||
== Code == | == Code == | ||
arduino_adxl345.ino: | |||
<code> | <code> | ||
/* ATtiny85 and ADXL345 demo code | |||
by ivc <ivc at x-pec.com> 2015 | |||
This sensor test will enable the red LED on the Trinket board when the y-axis is positive, e.g. tilted to one side, and turn | |||
off when tilted the other way. | |||
The TWI/I2C speed is determined by the F_CPU speed selected during compiling (Tools -> Board -> Adafruit Trinket 1/8/16MHz). | |||
Due to inherent instability of the internal RC oscillator in the ATtiny, 8MHz does not always work - try 1MHz. Also, a pull-up | |||
higher than 4.7K Ohm will introduce slew on the rising edge, causing the signal fail to be recognized. Try 2K Ohm pull-ups | |||
on 3.3V setups, and 4.7K on 5V (3.3V/1.5mA = 2K Ohm). | |||
Beware: ADXL345 sensor can easily be damaged if handled improperly. Always keep a couple extras to swap out and for testing. | |||
*/ | |||
#include <TinyWireM.h> | |||
#include <avr/power.h> | |||
float x, y, z; | |||
void setup(void) | |||
{ | |||
// Dynamically change processing speed - use Tools -> Board -> Adafruit Trinket 1/8/16MHz to adjust | |||
if (F_CPU == 16000000) { clock_prescale_set(clock_div_1); | |||
} else if (F_CPU == 8000000) { clock_prescale_set(clock_div_1); | |||
} else if (F_CPU == 4000000) { clock_prescale_set(clock_div_2); | |||
} else if (F_CPU == 2000000) { clock_prescale_set(clock_div_4); | |||
} else if (F_CPU == 1000000) { clock_prescale_set(clock_div_8); } | |||
// On-board Red LED | |||
pinMode(PB1, OUTPUT); | |||
digitalWrite(PB1, LOW); | |||
// Setup ADXL345 | |||
adxl345_init(); | |||
} | |||
void loop(void) | |||
{ | |||
// Update accelerometer values | |||
readAccel(&x, &y, &z); | |||
// Enable LED of tilted over mid-point | |||
if (x > 0) digitalWrite(PB1, HIGH); | |||
else digitalWrite(PB1, LOW); | |||
// Wait a small period to update | |||
delay(100); | |||
} | |||
</code> | |||
adxl345_sensor.ino: | |||
<code> | |||
/************************************************************************ | |||
* This program is free software; you can redistribute it and/or modify * | |||
* it under the terms of the GNU License V2. * | |||
* This program is distributed in the hope that it will be useful, * | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of * | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * | |||
* GNU General Public License, version 2 for more details * | |||
* * | |||
* Bare bones ADXL345 i2c example for Arduino 1.0 * | |||
* by Jens C Brynildsen <http://www.flashgamer.com> * | |||
* This version is not reliant of any external lib * | |||
* (Adapted for Arduino 1.0 from http://code.google.com/p/adxl345driver)* | |||
* * | |||
* Demonstrates use of ADXL345 (using the Sparkfun ADXL345 breakout) * | |||
* with i2c communication. Datasheet: * | |||
* http://www.sparkfun.com/datasheets/Sensors/Accelerometer/ADXL345.pdf * | |||
* If you need more advanced features such as freefall and tap * | |||
* detection, check out: * | |||
* https://github.com/jenschr/Arduino-libraries * | |||
***********************************************************************/ | |||
#include <TinyWireM.h> | |||
#define DEVICE (0x53) // Device address as specified in datasheet | |||
#define SENSORS_GRAVITY_STANDARD (9.80665F) // Const float | |||
#define MG2G_MULTIPLIER (0.004) // 4mg/LSB | |||
byte _buff[2]; // Buffer array | |||
char POWER_CTL = 0x2D; //Power Control Register | |||
char DATA_FORMAT = 0x31; // Data format control | |||
char DATAX0 = 0x32; // X-Axis Data 0 | |||
char DATAX1 = 0x33; // X-Axis Data 1 | |||
char DATAY0 = 0x34; // Y-Axis Data 0 | |||
char DATAY1 = 0x35; // Y-Axis Data 1 | |||
char DATAZ0 = 0x36; // Z-Axis Data 0 | |||
char DATAZ1 = 0x37; // Z-Axis Data 1 | |||
char BW_RATE = 0x2C; // Data rate and power mode control | |||
void adxl345_init() | |||
{ | |||
TinyWireM.begin(); // Join i2c bus (address optional for master) | |||
// Setup ADXL345 registers, see datahsheet to configure for your liking | |||
writeTo(DATA_FORMAT, B00000000); // Enable most sensitive 2g range, B1B0 | |||
writeTo(BW_RATE, B00001100); // Set 400Hz output update rate - not I2C but data output, B4B3B2B1 | |||
writeTo(POWER_CTL, 0); // Always be sure to zero out register, don't asume it's zero | |||
writeTo(POWER_CTL, B00001000); // Enter measurement mode, B4 | |||
} | |||
void readAccel(float *x, float *y, float *z) | |||
{ | |||
// How many bytes to request from ADXL345 - it seems there are problems doing more than 4 bytes, keep it at 2 bytes. | |||
// Z-axis DATAZ1 register is sometimes is bad, only first DATAZ1 register return valid data | |||
uint8_t howManyBytesToRead = 2; | |||
// Zero buffer array | |||
memset(_buff, 0, 6); | |||
// Each axis reading comes in 10 bit resolution, i.e. 2 bytes, least significat byte first!! | |||
// Thus we are converting both bytes in to one int - shift bytes to align like DATAX1DATAX0 | |||
// If the bytes seem switched from the sensor, change [1] to [0] and verse visa | |||
readFrom( DATAX0, howManyBytesToRead, _buff); //read the acceleration data from the ADXL345 | |||
*x = ((((int)_buff[0]) << 8) | _buff[1]) * MG2G_MULTIPLIER * SENSORS_GRAVITY_STANDARD; | |||
// Zero buffer array | |||
memset(_buff, 0, 6); | |||
readFrom( DATAY0, howManyBytesToRead, _buff); //read the acceleration data from the ADXL345 | |||
*y = ((((int)_buff[0]) << 8) | _buff[1]) * MG2G_MULTIPLIER * SENSORS_GRAVITY_STANDARD; | |||
// Zero buffer array | |||
memset(_buff, 0, 6); | |||
readFrom( DATAZ0, howManyBytesToRead, _buff); //read the acceleration data from the ADXL345 | |||
*z = ((((int)_buff[1]) << 8) | _buff[0]) * MG2G_MULTIPLIER * SENSORS_GRAVITY_STANDARD; | |||
// Test single bit | |||
//if ( (_buff[0] & 0B10000000) ) digitalWrite(PB1, HIGH); | |||
//else digitalWrite(PB1, LOW); | |||
} | |||
// Write vale to register address | |||
void writeTo(byte address, byte val) { | |||
TinyWireM.beginTransmission(DEVICE); // start transmission to device | |||
TinyWireM.write(address); // send register address | |||
TinyWireM.write(val); // send value to write | |||
TinyWireM.endTransmission(); // end transmission | |||
} | |||
// Reads num bytes starting from address register on device in to _buff array | |||
void readFrom(byte address, int num, byte _buff[]) { | |||
TinyWireM.beginTransmission(DEVICE); // start transmission to device | |||
TinyWireM.write(address); // sends address to read from | |||
TinyWireM.endTransmission(); // end transmission | |||
//TinyWireM.beginTransmission(DEVICE); // start transmission to device | |||
TinyWireM.requestFrom(DEVICE, num); // request 6 bytes from device | |||
int i = 0; | |||
while(TinyWireM.available()) // device may send less than requested (abnormal) | |||
{ | |||
_buff[i] = TinyWireM.read(); // receive a byte | |||
i++; | |||
} | |||
//TinyWireM.endTransmission(); // end transmission | |||
} | |||
</code> | </code> |
Revision as of 01:31, 14 May 2015
This is a small setup based on the ATtiny85 to make use of the advanced features of the ADXL345 accelerometer.
Parts
- Adafruit Trinket 3V ATtiny85 board
- No need for level shifting for ADXL345 I2C
- Comes with [Trinket Bootloader] to upload binary with USB during the first 10 seconds of power-up/reset
- Red LED on #1/PB1 is handy for debugging
- GY-291 ADXL345 Digital 3-Axis accelerometer breakout
- On-board 3.3V LDO for ADXL345
- I2C 4.7k pull-ups
- CS 4.7k pull-up - enable I2C, not SPI
- SDO 4.7k pull-down - I2C address 0x53
- Comes with 2.54mm pin header
Wiring
- ATtiny -> ADXL345
- USB -> VCC
- GND -> GND
- #0/PB0 -> SDA
- #2/PB2 -> SCL
Libraries
- TinyWireM - Using the USI on ATtiny to emulate TWI/I2C, improved by Adafruit
Speed
Add this section to the hardware.txt in the attiny folder.
trinket1.name=Adafruit Trinket 1MHz
trinket1.bootloader.low_fuses=0xF1
trinket1.bootloader.high_fuses=0xD5
trinket1.bootloader.extended_fuses=0xFE
trinket1.upload.maximum_size=5310
trinket1.build.mcu=attiny85
trinket1.build.f_cpu=1000000L
trinket1.build.core=arduino:arduino
trinket1.build.variant=tiny8
Code
arduino_adxl345.ino:
/* ATtiny85 and ADXL345 demo code
by ivc <ivc at x-pec.com> 2015
This sensor test will enable the red LED on the Trinket board when the y-axis is positive, e.g. tilted to one side, and turn
off when tilted the other way.
The TWI/I2C speed is determined by the F_CPU speed selected during compiling (Tools -> Board -> Adafruit Trinket 1/8/16MHz).
Due to inherent instability of the internal RC oscillator in the ATtiny, 8MHz does not always work - try 1MHz. Also, a pull-up
higher than 4.7K Ohm will introduce slew on the rising edge, causing the signal fail to be recognized. Try 2K Ohm pull-ups
on 3.3V setups, and 4.7K on 5V (3.3V/1.5mA = 2K Ohm).
Beware: ADXL345 sensor can easily be damaged if handled improperly. Always keep a couple extras to swap out and for testing.
- /
- include <TinyWireM.h>
- include <avr/power.h>
float x, y, z;
void setup(void)
{
// Dynamically change processing speed - use Tools -> Board -> Adafruit Trinket 1/8/16MHz to adjust
if (F_CPU == 16000000) { clock_prescale_set(clock_div_1);
} else if (F_CPU == 8000000) { clock_prescale_set(clock_div_1);
} else if (F_CPU == 4000000) { clock_prescale_set(clock_div_2);
} else if (F_CPU == 2000000) { clock_prescale_set(clock_div_4);
} else if (F_CPU == 1000000) { clock_prescale_set(clock_div_8); }
// On-board Red LED
pinMode(PB1, OUTPUT);
digitalWrite(PB1, LOW);
// Setup ADXL345
adxl345_init();
}
void loop(void)
{
// Update accelerometer values
readAccel(&x, &y, &z);
// Enable LED of tilted over mid-point
if (x > 0) digitalWrite(PB1, HIGH);
else digitalWrite(PB1, LOW);
// Wait a small period to update
delay(100);
}
adxl345_sensor.ino:
/************************************************************************
- This program is free software; you can redistribute it and/or modify *
- it under the terms of the GNU License V2. *
- This program is distributed in the hope that it will be useful, *
- but WITHOUT ANY WARRANTY; without even the implied warranty of *
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
- GNU General Public License, version 2 for more details *
- *
- Bare bones ADXL345 i2c example for Arduino 1.0 *
- by Jens C Brynildsen <http://www.flashgamer.com> *
- This version is not reliant of any external lib *
- (Adapted for Arduino 1.0 from http://code.google.com/p/adxl345driver)*
- *
- Demonstrates use of ADXL345 (using the Sparkfun ADXL345 breakout) *
- with i2c communication. Datasheet: *
- http://www.sparkfun.com/datasheets/Sensors/Accelerometer/ADXL345.pdf *
- If you need more advanced features such as freefall and tap *
- detection, check out: *
- https://github.com/jenschr/Arduino-libraries *
- /
- include <TinyWireM.h>
- define DEVICE (0x53) // Device address as specified in datasheet
- define SENSORS_GRAVITY_STANDARD (9.80665F) // Const float
- define MG2G_MULTIPLIER (0.004) // 4mg/LSB
byte _buff[2]; // Buffer array
char POWER_CTL = 0x2D; //Power Control Register
char DATA_FORMAT = 0x31; // Data format control
char DATAX0 = 0x32; // X-Axis Data 0
char DATAX1 = 0x33; // X-Axis Data 1
char DATAY0 = 0x34; // Y-Axis Data 0
char DATAY1 = 0x35; // Y-Axis Data 1
char DATAZ0 = 0x36; // Z-Axis Data 0
char DATAZ1 = 0x37; // Z-Axis Data 1
char BW_RATE = 0x2C; // Data rate and power mode control
void adxl345_init()
{
TinyWireM.begin(); // Join i2c bus (address optional for master)
// Setup ADXL345 registers, see datahsheet to configure for your liking
writeTo(DATA_FORMAT, B00000000); // Enable most sensitive 2g range, B1B0
writeTo(BW_RATE, B00001100); // Set 400Hz output update rate - not I2C but data output, B4B3B2B1
writeTo(POWER_CTL, 0); // Always be sure to zero out register, don't asume it's zero
writeTo(POWER_CTL, B00001000); // Enter measurement mode, B4
}
void readAccel(float *x, float *y, float *z)
{
// How many bytes to request from ADXL345 - it seems there are problems doing more than 4 bytes, keep it at 2 bytes.
// Z-axis DATAZ1 register is sometimes is bad, only first DATAZ1 register return valid data
uint8_t howManyBytesToRead = 2;
// Zero buffer array
memset(_buff, 0, 6);
// Each axis reading comes in 10 bit resolution, i.e. 2 bytes, least significat byte first!!
// Thus we are converting both bytes in to one int - shift bytes to align like DATAX1DATAX0
// If the bytes seem switched from the sensor, change [1] to [0] and verse visa
readFrom( DATAX0, howManyBytesToRead, _buff); //read the acceleration data from the ADXL345
*x = ((((int)_buff[0]) << 8) | _buff[1]) * MG2G_MULTIPLIER * SENSORS_GRAVITY_STANDARD;
// Zero buffer array
memset(_buff, 0, 6);
readFrom( DATAY0, howManyBytesToRead, _buff); //read the acceleration data from the ADXL345
*y = ((((int)_buff[0]) << 8) | _buff[1]) * MG2G_MULTIPLIER * SENSORS_GRAVITY_STANDARD;
// Zero buffer array
memset(_buff, 0, 6);
readFrom( DATAZ0, howManyBytesToRead, _buff); //read the acceleration data from the ADXL345
*z = ((((int)_buff[1]) << 8) | _buff[0]) * MG2G_MULTIPLIER * SENSORS_GRAVITY_STANDARD;
// Test single bit
//if ( (_buff[0] & 0B10000000) ) digitalWrite(PB1, HIGH);
//else digitalWrite(PB1, LOW);
}
// Write vale to register address
void writeTo(byte address, byte val) {
TinyWireM.beginTransmission(DEVICE); // start transmission to device
TinyWireM.write(address); // send register address
TinyWireM.write(val); // send value to write
TinyWireM.endTransmission(); // end transmission
}
// Reads num bytes starting from address register on device in to _buff array
void readFrom(byte address, int num, byte _buff[]) {
TinyWireM.beginTransmission(DEVICE); // start transmission to device
TinyWireM.write(address); // sends address to read from
TinyWireM.endTransmission(); // end transmission
//TinyWireM.beginTransmission(DEVICE); // start transmission to device
TinyWireM.requestFrom(DEVICE, num); // request 6 bytes from device
int i = 0;
while(TinyWireM.available()) // device may send less than requested (abnormal)
{
_buff[i] = TinyWireM.read(); // receive a byte
i++;
}
//TinyWireM.endTransmission(); // end transmission
}