Another dice program for the mbuino.

Dependencies:   mbed mBuino_Sleep

You probably want http://mbed.org/users/maxint/code/mBuino_Dice/ rather than this one, that was the original mbuino dice program.

This version is based off the original release of the project above. It was then significantly re-written for a mixture of power consumption, randomness and coding style reasons. Most of the changes and improvements have since been incorporated into later versions of maxint's dice program (together with a few of his later ideas being copied into this version) so there are no meaningful functional differences between the two.

This version is posted mainly to provide an example of a slightly different way to do the same thing.

dice.cpp

Committer:
AndyA
Date:
2014-09-23
Revision:
1:05f369319854
Parent:
0:24177fc1e0e3

File content as of revision 1:05f369319854:

/*
** mBuino_Dice
**
** This electronic dice application allows the user to throw an electronic dice by the press of a button
**
** On mBuino P0.4 is close to GND and the two pitch distance is exactly the same as a mini-switch!
**
** Base code from version 1 of http://mbed.org/users/maxint/code/mBuino_Dice/
**
** Modifed to improve randomness and decrease power draw and a few random changes to coding style
** Most meaningful changes are now implimented in the later versions of the above code.
*/

#include "mbed.h"
#include "mBuinoSleep.h"

InterruptIn ActionButton(P0_4);  // Vibration sensor
AnalogIn RandomIn(P0_14); // use the random noise on this analog input to seed the random generator

// LED bus value to display
uint8_t LEDValue = 0;

// sleep can be sleep, deepsleep or power down.
// clean power down and cleen deep sleep do a clean shutdown of the PLL.
// However any code called during the wakeup IRQ will then run at a slower speed.
//enum sleepMode_t {powerDown=0, deepSleep, lightSleep, cleanPowerDown, cleanDeepSleep};


// idle time to wait before sleeping
const float timeoutBeforeSleep = 15;


const uint8_t DicePattern[6] = { 0x08, // 0b 000_1_000
                                 0x22, // 0b 010_0_010
                                 0x2a, // 0b 010_1_010
                                 0x55, // 0b 101_0_101
                                 0x5d, // 0b 101_1_101
                                 0x77  // 0b 111_0_111
                               };

volatile bool fButtonPressed;

volatile bool sleepNow=false;

Timer timeTracker;
Timeout sleepMode;


// this cycles the LEDs so they are on for 1/7th of the time with only one lit at a time.
// but since it does it at 1kHz they just look a little dimmer to the human eye.
// This can give a big power saving when running on a battery.
Ticker ledCycle;

void on1msTick()
{
    static uint8_t ledIndex = 0;
    LEDs = LEDValue & 0x01<<ledIndex++;
    if (ledIndex == 7)
        ledIndex = 0;
}



// LED state setting functions.

void SetLeds(bool on)
{
    if (on)
        LEDValue=0x7f;
    else
        LEDValue=0;
}

void SetLed(uint8_t ledID, bool on)
{
    if (ledID <= 6) {
        if (on)
            LEDValue = LEDValue | (0x01 << ledID);
        else
            LEDValue = LEDValue & ~(0x01 << ledID);
    }
}

void ToggleLeds()
{
    LEDValue = ~LEDValue;
}

void ToggleLed(uint8_t ledID)
{
    if (ledID <= 6)
        LEDValue = LEDValue ^ (0x01 << ledID);
}

void BlinkLeds(bool on=true, float delay=0.1)
{
    uint8_t state = LEDValue;
    SetLeds(on);
    wait(delay);
    LEDValue = state;
    wait(delay);
}

void ShowDice(uint8_t nNumber)
{
// switch the leds of a particular dice-number on or off
    if(nNumber<1) nNumber=1;
    if(nNumber>6) nNumber=6;

    LEDValue=DicePattern[nNumber - 1];
}


void BlinkOneLed(uint8_t ledID, float delay = 0.1)
{
    ToggleLed(ledID);
    wait(delay); // delay
    ToggleLed(ledID);
    wait(delay); // delay
}

void SweepSingleLed(bool leftToRight = true, float delay = 0.2)
{
    SetLeds(false);
    for(int n=0; n<7; n++) {
        SetLed(leftToRight?n:6-n,true);
        wait(delay);
        SetLed(leftToRight?n:6-n,false);
    }
}

void StackLEDs(float delay = 0.2)
{
    SetLeds(false);
    int i;
    int j;
    for (i = 7; i > 0; i--) {
        for (j=0; j<i; j++) {
            SetLed(6-j,true);
            wait(delay);
            SetLed(6-j,false);
        }
        SetLed(7-j,true);
    }
}

void SweepAllLeds(bool leftToRight = true, float delay=0.2)
{
    for(int n=0; n<7; n++) {
        SetLed(leftToRight?n:6-n, true);
        wait(delay); // delay
    }
    for(int n=0; n<7; n++) {
        SetLed(leftToRight?6-n:n, false);
        wait(delay); // delay
    }
}


void enterSleep(enum sleepMode_t mode)
{

    SweepSingleLed(true, 0.1);
    SweepSingleLed(false, 0.1);

    // stop timers.
    timeTracker.stop();
    ledCycle.detach();

    // enter sleep
    mBuinoSleep(mode);
    
    // awake again amd running at full speed at this point.
    sleepNow = false;

    // restart timers
    timeTracker.start();
    ledCycle.attach_us(on1msTick,1000);

    // show startup animation.
    StackLEDs(0.05);
}


void enterSleepTimeout(void)
{
    sleepNow = true;
}


void buttonPressedIRQ()
{
    sleepMode.detach();
    fButtonPressed=true;
}


void setup(void)
{
    // perform initialisations

    // create a 32 bit number out of 32 LSBs from the ADC
    uint32_t seedValue = 0;
    uint16_t value;
    uint8_t counter;

    for (counter = 0; counter < 32; counter++) {
        seedValue = seedValue<<1;
        value = RandomIn.read_u16(); // reads a 10 bit ADC normalised to 16 bits.
        if (value & 0x0040)          // LSB of ADC output = 1
            seedValue++;
    }

    srand(seedValue);     // seed the random generator with the background noise of an analog input

    // start a timer used to determin delay between button presses, used to increase randomness.
    timeTracker.start();
    
    // start LED cycling ticker
    ledCycle.attach_us(on1msTick,1000);

    // startup animation.
    StackLEDs();

    // vibration sensor/button
    ActionButton.mode(PullUp);
    ActionButton.fall(buttonPressedIRQ);

    // Sleep timeout.
    sleepMode.attach(enterSleepTimeout,timeoutBeforeSleep);
}

int main()
{
    setup();
    while(true) {

        while(!fButtonPressed) {
            if (sleepNow) enterSleep(PowerDown);
        }

        uint8_t cycles = (timeTracker.read_us() % 20) + 30;
        uint8_t value = 1;

        while (cycles > 0) {
            value = rand()%6+1;
            ShowDice(value);
            wait_ms((55-cycles)*2);
            cycles--;
        }

        // clear the button flag now rather than as soon as we see it to avoid the need for de-bouncing.
        fButtonPressed=false;

        wait(0.5);

        for (int i = 0; i<3; i++) {
            BlinkLeds(false,0.2);
        }

        sleepMode.attach(enterSleepTimeout,timeoutBeforeSleep);
    }
}