TinyCircuits

TinyDuino Bubble Level

TinyDuino Bubble Level
« on: May 15, 2014, 04:23:18 PM »
TinyBubble is a bubble level using the accelerometer and edge LED shields.

Code: [Select]
/*
 * TinyBubble - Bubble Level
 *
 * Uses Accelerometer and 16 or 21-LED TinyShields
 *
 * Version 140515
 */

#include <Wire.h>
#include <math.h>

#define SENSITIVITY 15
#define CALIBRATION 0.0

#define BMA250_I2CADDR      0x18
#define BMA250_BW           0x08   // 7.81Hz

int N_LEDs;

void setup()
{
    Wire.begin();

    // Setup the filter bandwidth
    Wire.beginTransmission(BMA250_I2CADDR);
    Wire.write(0x10);
    Wire.write(BMA250_BW);
    Wire.endTransmission();

    // Distinguish between 16 and 21 LED boards by detecting LED #21
    pinMode(4, INPUT);
    pinMode(9, OUTPUT);
    bool led_21 = ((digitalWrite(9, HIGH), digitalRead(4)) &&
                   (digitalWrite(9, LOW), !digitalRead(4)));
    pinMode(9, INPUT);

    N_LEDs = led_21 ? 21 : 16;
}

void loop()
{
    static int led;
    static int clock4;           // 4-bit clock
    clock4 = (clock4 + 1) & 15;  // range: [0, 15]

    // Read X and Y
    Wire.beginTransmission(BMA250_I2CADDR);
    Wire.write(0x02);
    Wire.endTransmission();
    Wire.requestFrom(BMA250_I2CADDR, 4);

    int x_lsb = Wire.read();
    int x_msb = Wire.read();
    int y_lsb = Wire.read();
    int y_msb = Wire.read();

    int X = ((x_msb << 8) | x_lsb) >> 6;
    int Y = ((y_msb << 8) | y_lsb) >> 6;

    if (((long) X*X + (long) Y*Y) < SENSITIVITY) {
        // Spin if board is level within sensitivity
        if (++led > N_LEDs)
            led = 1;
    }
    else {
        // Compute angle
        float angle = atan2(-X, -Y) * (10.5 / M_PI);  // range: [-10.5, 10.5]
        float ramp = (clock4 - 7.5) * (1.0 / 18.75);  // range: [-0.4, 0.4]
        led = angle + ramp + 19.5 + CALIBRATION;      // range: [8, 29]

        if (led > 21)
            led -= 21;
    }

    LED_on(led);
}

void LED_on(int n)
{
    static uint8_t high_pin[21] = {5, 6, 5, 7, 6, 7, 6, 8, 5, 8, 8, 7, 9, 7, 9, 8, 5, 9, 6, 9, 9};
    static uint8_t low_pin [21] = {6, 5, 7, 5, 7, 6, 8, 6, 8, 5, 7, 8, 7, 9, 8, 9, 9, 5, 9, 6, 4};

    for (int i = 4; i <= 9; i++)
        pinMode(i, INPUT);

    if (n >= 1 && n <= N_LEDs) {
        digitalWrite(high_pin[n - 1], HIGH);
        digitalWrite(low_pin [n - 1], LOW);

        pinMode(high_pin[n - 1], OUTPUT);
        pinMode(low_pin [n - 1], OUTPUT);
    }
}

Re: TinyDuino Bubble Level
« Reply #1 on: May 23, 2014, 12:56:33 AM »
Hi Blue, nice code! I was playing with this shield as well and noted that since the pin values are all between 4 and 9 for the LEDs you can store both the 'high' pin number and the 'low' pin number in a single byte, just store it as hex, so 0x95 is 'high' pin #9 and 'low' pin #5.  Cuts down a bit on RAM usage, which of course is unnecessary in a simple example but might come in handy if you are doing more computation or need more RAM.

--Chuck

Re: TinyDuino Bubble Level
« Reply #2 on: March 26, 2017, 12:11:55 PM »
Thank you! I really enjoyed this project.  It was only my second build with my new TinyDuino, and I have not done any programming since I took a course in PASCAL in 1981.  I had to go through and remove the "invisible characters" which were not UNICODE.  They all seemed to be embedded with the spaces in the code.  Then it worked like a charm.