![](/media/cache/img/default_profile.jpg.50x50_q85.jpg)
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.
Diff: dice.cpp
- Revision:
- 0:24177fc1e0e3
- Child:
- 1:05f369319854
diff -r 000000000000 -r 24177fc1e0e3 dice.cpp --- /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); + } +}