Собрал недавно arduino на atmega8, поморгал диодом, захотелось большего. Начал изучать различные шилды, цены в РФ на них мягко говоря высокие, а собирать самому дороже выйдет, микросхемы тоже ведь покупать надо.
И тут в голову пришло, ведь на работе куча системных плат от различных телефонов. Почти в каждом современном телефоне есть акселерометр, цифровой термометр и т. д., почему их не использовать? Оказалось в большинстве телефонов используется одна и та же микросхема акселерометра LIS302DL от ST.
По питанию поставил кренку на 3,3 вольта. На всякий пожарный добавил два керамических конденсатора на 10 Мкф и 100 нФ в цепь питания, как на даташите. Vdd io запитал от этой же кренки через дроссель, выпаянный из этого же телефона. Для активации шины I2C кинул перемычку с CS на + питания. Саму микросхемку приклеил к платке на супер клей и подпаялся к ней навесным монтажом. Сверху это дело лучше залить клеем, получится этакий компаунд.
#include <LiquidCrystal.h>
#include <Wire.h>
// based on Sketch by bGatti from http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1213072318
// for use with http://www.nkcelectronics.com/triple-axis-accelerometer-breakout--lis30302.html
// tested with a seeeduino board, i2c connection established using the breakout pads with angled
// pin headers soldered in.
// Copyright Shu Ning Bian 2008, released under GPLv2
int _slave_id = 0x1D;
int backlight_pin = 3;
LiquidCrystal lcd(5,6,7,8,9,10,11);
uint8_t read_register(uint8_t sub)
{
i2c_send(_slave_id, &sub, 1);
return i2c_read(_slave_id);
}
void write_register(uint8_t sub, uint8_t data)
{
uint8_t bytes[] = {sub, data};
i2c_send(_slave_id, bytes, 2);
}
uint8_t i2c_read(uint8_t id)
{
Wire.requestFrom(_slave_id, 1);
while(!Wire.available())
{
delay(10);
}
return Wire.receive();
}
void i2c_send(uint8_t id, uint8_t * data, uint8_t len)
{
Wire.beginTransmission(id);
for(int i = 0; i < len; ++i)
{
Wire.send(data[i]);
}
Wire.endTransmission();
}
void dot_print(int val)
{
/* prints a number in the form of i.f where i is from val/10 and f
from val%10
*/
int i = val/10;
int f = val%10;
if ( val < 0 )
{
f*=-1;
}
if ( i>=0 )
{
// print a + to counter the - which is added by print when val is negative
lcd.print("+");
}
lcd.print(i, DEC);
lcd.print(".");
lcd.print(f,DEC);
if (i<10)
{
lcd.print(" ");
}
}
void pretty_print(char x, char y, char z)
{
/* The divisor of x,y, and z are chosen to give the "correct" value at 1g. They are worked out
by trial and error, but a rough starting point can be calculated as follows:
1. divided by 128 to normalise the range
2. multiply by 2 since the range is +/- 2,
* combined so this gives divided by 64, giving acceleration in gs
3. multiply by 9.8 to give acceleration in ms/s/s,
* combined this gives multiply by 9.8/64
4. to make things into nicer integer maths, invert 9.8/64 to give 6.5
5. now we can truncate and use divisor of 6, an integer, or sacrifice some cycles and use
a floating value around 6 which gives the "correct" value of 9.8m/s/s for an axis when that
axis is "pointing" towards the centre of the earth.
Note I have multiplied everything by 10 implicitly to keep us in int domain
*/
int xx = x * 100 / 55;
int yy = y * 100 / 55;
int zz = z * 100 / 63;
lcd.clear();
lcd.print("X:");dot_print(xx);lcd.print(" ");
lcd.print("Y:");dot_print(yy);lcd.print(" ");
lcd.setCursor(0, 1);
lcd.print("Z:");dot_print(zz);lcd.print(" (m/s/s)");
}
#define CTRL_REG2 0x21
#define CTRL_REG1 0x20
void setup()
{
Wire.begin(); // join i2c bus (address optional for master)
lcd.print("Setting up...");
write_register(CTRL_REG2, B01000000);
/* 0 - SPI mode selection
1 - reboot memory contents
0 - none
0 - filtered data selection, 0 = bypassed
0 - high pass filter enable for freefall/wakeup #2, 0 = bypassed
0 - high pass filter enable for freefall/wakeup #1, 0 = bypassed
0 - high pass coefficient 2
0 - high pass coefficient 1
the last 2 bits configure the high pass filter cutoff frequency
*/
write_register(CTRL_REG1, B01000111);
/* 0 - data rate selection, 1=100Hz
1 - power down control, 1 = active mode
0 - full scale selection, 0 = +/- 2g, 1 = +/- 8g
0 - self test P enable, 0 = normal mode
0 - self test M enabled, 0 = normal mode
1 - z axis enable, 1 = enabled
1 - y axis enable, 1 = enabled
1 - x axis enable, 1 = enabled
*/
pinMode(backlight_pin, OUTPUT);
analogWrite(backlight_pin, 128);
}
void loop()
{
#define OUT_X 0x29
#define OUT_Y 0x2B
#define OUT_Z 0x2D
#define STATUS_REG 0x27
//----------Status Register-----------------------
byte status = read_register(STATUS_REG);
#define ZYXDA 0x08
if ( status & ZYXDA == 0)
{
// ZYXDA is 1 when new set of data is available, so since its 0, lets skip
return;
}
//----------X Values-----------------------
char x_val = read_register(OUT_X);
//----------Y Values-----------------------
char y_val = read_register(OUT_Y);
//----------Z Values-----------------------
char z_val = read_register(OUT_Z);
//Serial.print("status "); Serial.println(status, BIN);
pretty_print(x_val, y_val, z_val);
delay(200);
}
Если нет дисплея, можно увидеть результат в Serial monitor: