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.

Files at this revision

API Documentation at this revision

Comitter:
AndyA
Date:
Wed Sep 17 13:48:57 2014 +0000
Child:
1:05f369319854
Commit message:
Dice

Changed in this revision

dice.cpp Show annotated file Show diff for this revision Revisions of this file
mbed.bld Show annotated file Show diff for this revision Revisions of this file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dice.cpp	Wed Sep 17 13:48:57 2014 +0000
@@ -0,0 +1,330 @@
+/*
+** 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"
+
+BusOut LEDOuts(LED1, LED2, LED3, LED4, LED5, LED6, LED7);// declare 7 LEDs
+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 LEDs = 0;
+
+// fix power draw
+DigitalIn progMode(P0_3);
+
+// 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;
+    LEDOuts = LEDs & 0x01<<ledIndex++;
+    if (ledIndex == 7)
+        ledIndex = 0;
+}
+
+
+
+// LED state setting functions.
+
+void SetLeds(bool on)
+{
+    if (on)
+        LEDs=0x7f;
+    else
+        LEDs=0;
+}
+
+void SetLed(uint8_t ledID, bool on)
+{
+    if (ledID <= 6) {
+        if (on)
+            LEDs = LEDs | (0x01 << ledID);
+        else
+            LEDs = LEDs & ~(0x01 << ledID);
+    }
+}
+
+void ToggleLeds()
+{
+    LEDs = ~LEDs;
+}
+
+void ToggleLed(uint8_t ledID)
+{
+    if (ledID <= 6)
+        LEDs = LEDs ^ (0x01 << ledID);
+}
+
+void BlinkLeds(bool on=true, float delay=0.1)
+{
+    uint8_t state = LEDs;
+    SetLeds(on);
+    wait(delay);
+    LEDs = 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;
+
+    LEDs=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++)
+        BlinkOneLed(leftToRight?n:6-n, delay);
+}
+
+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 mySleep() // ONLY CALL FROM MAIN LOOP
+{
+
+    LPC_PMU->PCON = 0x0;
+    SCB->SCR &= ~SCB_SCR_SLEEPDEEP_Msk;
+    __WFI();
+}
+
+// deepSleep is higher power but faster wakeup
+// clean PLL shutdown is technically needed but seems to work without it.
+// Note - If using clean PLL shutdown the IRQ that wakes us runs on the IRC
+// not the system clock because the clock isn't set up until after the IRQ is complete.
+void myPowerDown(bool cleanPLLShutdown = false, bool deepSleep = false)
+{
+
+    if (deepSleep)
+        LPC_PMU->PCON = 0x1;
+    else
+        LPC_PMU->PCON = 0x2;
+
+
+    LPC_SYSCON->PDSLEEPCFG |= 0x7f;  // shut off everything we can.
+    SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;
+
+    bool IRCPowered = (LPC_SYSCON->PDRUNCFG & 0x01); // only used for cleen shutdown but defined here for scope reasons.
+
+    if (cleanPLLShutdown) {
+        if (!IRCPowered)
+            LPC_SYSCON->PDRUNCFG &= 0xfffffffe; // power up the IRC
+
+        LPC_SYSCON->MAINCLKSEL    = 0x00; // switch to IRC to avoid glitches
+        LPC_SYSCON->MAINCLKUEN    = 0x01;               /* Update MCLK Clock Source */
+        LPC_SYSCON->MAINCLKUEN    = 0x00;               /* Toggle Update Register   */
+        LPC_SYSCON->MAINCLKUEN    = 0x01;
+        while (!(LPC_SYSCON->MAINCLKUEN & 0x01));       /* Wait Until Updated       */
+    }
+
+    LPC_SYSCON->PDAWAKECFG = LPC_SYSCON->PDRUNCFG; // switch on everything that is currently on when we wake up.
+
+    __WFI();
+
+    if (cleanPLLShutdown) {
+        LPC_SYSCON->MAINCLKSEL    = 0x03; // switch to PLL output
+        LPC_SYSCON->MAINCLKUEN    = 0x01;               /* Update MCLK Clock Source */
+        LPC_SYSCON->MAINCLKUEN    = 0x00;               /* Toggle Update Register   */
+        LPC_SYSCON->MAINCLKUEN    = 0x01;
+        while (!(LPC_SYSCON->MAINCLKUEN & 0x01));       /* Wait Until Updated       */
+
+        if (!IRCPowered)
+            LPC_SYSCON->PDRUNCFG |= 0x01; // power down the IRC
+    }
+}
+
+
+void enterSleep(enum sleepMode_t mode = powerDown)
+{
+
+    SweepSingleLed(0.1);
+
+    // all LEDs off.
+    SetLeds(false);
+    // stop timers.
+    timeTracker.stop();
+    ledCycle.detach();
+
+    switch (mode) {
+        case powerDown:
+        case cleanPowerDown:
+        default:
+            myPowerDown(mode == cleanPowerDown);
+            break;
+        case lightSleep:
+            mySleep();
+            break;
+        case deepSleep:
+        case cleanDeepSleep:
+            myPowerDown(mode == cleanDeepSleep, true);
+            break;
+    }
+
+    // awake again amd running at full speed at this point.
+    timeTracker.start();
+    ledCycle.attach_us(on1msTick,1000);
+    sleepNow = false;
+    StackLEDs(0.1);
+    //  SweepAllLeds();
+}
+
+
+void enterSleepTimeout(void)
+{
+    sleepNow = true;
+}
+
+
+void buttonPressedIRQ()
+{
+    sleepMode.detach();
+    fButtonPressed=true;
+}
+
+
+
+void setup(void)
+{
+    // perform initialisations
+
+    // ensure no pullup on the progMode pin
+    progMode.mode(PullNone);
+
+    // 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.fall(buttonPressedIRQ);
+
+    // Sleep timeout.
+    sleepMode.attach(enterSleepTimeout,timeoutBeforeSleep);
+}
+
+int main()
+{
+    setup();
+    while(true) {
+
+        while(!fButtonPressed) {
+            if (sleepNow) enterSleep(cleanPowerDown);
+        }
+
+        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);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed.bld	Wed Sep 17 13:48:57 2014 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/mbed_official/code/mbed/builds/552587b429a1
\ No newline at end of file