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-17
- Revision:
- 0:24177fc1e0e3
- Child:
- 1:05f369319854
File content as of revision 0:24177fc1e0e3:
/* ** 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); } }