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.

Committer:
AndyA
Date:
Wed Sep 17 13:48:57 2014 +0000
Revision:
0:24177fc1e0e3
Child:
1:05f369319854
Dice

Who changed what in which revision?

UserRevisionLine numberNew contents of line
AndyA 0:24177fc1e0e3 1 /*
AndyA 0:24177fc1e0e3 2 ** mBuino_Dice
AndyA 0:24177fc1e0e3 3 **
AndyA 0:24177fc1e0e3 4 ** This electronic dice application allows the user to throw an electronic dice by the press of a button
AndyA 0:24177fc1e0e3 5 **
AndyA 0:24177fc1e0e3 6 ** On mBuino P0.4 is close to GND and the two pitch distance is exactly the same as a mini-switch!
AndyA 0:24177fc1e0e3 7 **
AndyA 0:24177fc1e0e3 8 ** Base code from version 1 of http://mbed.org/users/maxint/code/mBuino_Dice/
AndyA 0:24177fc1e0e3 9 **
AndyA 0:24177fc1e0e3 10 ** Modifed to improve randomness and decrease power draw and a few random changes to coding style
AndyA 0:24177fc1e0e3 11 ** Most meaningful changes are now implimented in the later versions of the above code.
AndyA 0:24177fc1e0e3 12 */
AndyA 0:24177fc1e0e3 13
AndyA 0:24177fc1e0e3 14 #include "mbed.h"
AndyA 0:24177fc1e0e3 15
AndyA 0:24177fc1e0e3 16 BusOut LEDOuts(LED1, LED2, LED3, LED4, LED5, LED6, LED7);// declare 7 LEDs
AndyA 0:24177fc1e0e3 17 InterruptIn ActionButton(P0_4); // Vibration sensor
AndyA 0:24177fc1e0e3 18 AnalogIn RandomIn(P0_14); // use the random noise on this analog input to seed the random generator
AndyA 0:24177fc1e0e3 19
AndyA 0:24177fc1e0e3 20 // LED bus value to display
AndyA 0:24177fc1e0e3 21 uint8_t LEDs = 0;
AndyA 0:24177fc1e0e3 22
AndyA 0:24177fc1e0e3 23 // fix power draw
AndyA 0:24177fc1e0e3 24 DigitalIn progMode(P0_3);
AndyA 0:24177fc1e0e3 25
AndyA 0:24177fc1e0e3 26 // sleep can be sleep, deepsleep or power down.
AndyA 0:24177fc1e0e3 27 // clean power down and cleen deep sleep do a clean shutdown of the PLL.
AndyA 0:24177fc1e0e3 28 // However any code called during the wakeup IRQ will then run at a slower speed.
AndyA 0:24177fc1e0e3 29 enum sleepMode_t {powerDown=0, deepSleep, lightSleep, cleanPowerDown, cleanDeepSleep};
AndyA 0:24177fc1e0e3 30
AndyA 0:24177fc1e0e3 31
AndyA 0:24177fc1e0e3 32 // idle time to wait before sleeping
AndyA 0:24177fc1e0e3 33 const float timeoutBeforeSleep = 15;
AndyA 0:24177fc1e0e3 34
AndyA 0:24177fc1e0e3 35
AndyA 0:24177fc1e0e3 36 const uint8_t DicePattern[6] = { 0x08, // 0b 000_1_000
AndyA 0:24177fc1e0e3 37 0x22, // 0b 010_0_010
AndyA 0:24177fc1e0e3 38 0x2a, // 0b 010_1_010
AndyA 0:24177fc1e0e3 39 0x55, // 0b 101_0_101
AndyA 0:24177fc1e0e3 40 0x5d, // 0b 101_1_101
AndyA 0:24177fc1e0e3 41 0x77 // 0b 111_0_111
AndyA 0:24177fc1e0e3 42 };
AndyA 0:24177fc1e0e3 43
AndyA 0:24177fc1e0e3 44 volatile bool fButtonPressed;
AndyA 0:24177fc1e0e3 45
AndyA 0:24177fc1e0e3 46 volatile bool sleepNow=false;
AndyA 0:24177fc1e0e3 47
AndyA 0:24177fc1e0e3 48 Timer timeTracker;
AndyA 0:24177fc1e0e3 49 Timeout sleepMode;
AndyA 0:24177fc1e0e3 50
AndyA 0:24177fc1e0e3 51
AndyA 0:24177fc1e0e3 52 // this cycles the LEDs so they are on for 1/7th of the time with only one lit at a time.
AndyA 0:24177fc1e0e3 53 // but since it does it at 1kHz they just look a little dimmer to the human eye.
AndyA 0:24177fc1e0e3 54 // This can give a big power saving when running on a battery.
AndyA 0:24177fc1e0e3 55 Ticker ledCycle;
AndyA 0:24177fc1e0e3 56
AndyA 0:24177fc1e0e3 57 void on1msTick()
AndyA 0:24177fc1e0e3 58 {
AndyA 0:24177fc1e0e3 59 static uint8_t ledIndex = 0;
AndyA 0:24177fc1e0e3 60 LEDOuts = LEDs & 0x01<<ledIndex++;
AndyA 0:24177fc1e0e3 61 if (ledIndex == 7)
AndyA 0:24177fc1e0e3 62 ledIndex = 0;
AndyA 0:24177fc1e0e3 63 }
AndyA 0:24177fc1e0e3 64
AndyA 0:24177fc1e0e3 65
AndyA 0:24177fc1e0e3 66
AndyA 0:24177fc1e0e3 67 // LED state setting functions.
AndyA 0:24177fc1e0e3 68
AndyA 0:24177fc1e0e3 69 void SetLeds(bool on)
AndyA 0:24177fc1e0e3 70 {
AndyA 0:24177fc1e0e3 71 if (on)
AndyA 0:24177fc1e0e3 72 LEDs=0x7f;
AndyA 0:24177fc1e0e3 73 else
AndyA 0:24177fc1e0e3 74 LEDs=0;
AndyA 0:24177fc1e0e3 75 }
AndyA 0:24177fc1e0e3 76
AndyA 0:24177fc1e0e3 77 void SetLed(uint8_t ledID, bool on)
AndyA 0:24177fc1e0e3 78 {
AndyA 0:24177fc1e0e3 79 if (ledID <= 6) {
AndyA 0:24177fc1e0e3 80 if (on)
AndyA 0:24177fc1e0e3 81 LEDs = LEDs | (0x01 << ledID);
AndyA 0:24177fc1e0e3 82 else
AndyA 0:24177fc1e0e3 83 LEDs = LEDs & ~(0x01 << ledID);
AndyA 0:24177fc1e0e3 84 }
AndyA 0:24177fc1e0e3 85 }
AndyA 0:24177fc1e0e3 86
AndyA 0:24177fc1e0e3 87 void ToggleLeds()
AndyA 0:24177fc1e0e3 88 {
AndyA 0:24177fc1e0e3 89 LEDs = ~LEDs;
AndyA 0:24177fc1e0e3 90 }
AndyA 0:24177fc1e0e3 91
AndyA 0:24177fc1e0e3 92 void ToggleLed(uint8_t ledID)
AndyA 0:24177fc1e0e3 93 {
AndyA 0:24177fc1e0e3 94 if (ledID <= 6)
AndyA 0:24177fc1e0e3 95 LEDs = LEDs ^ (0x01 << ledID);
AndyA 0:24177fc1e0e3 96 }
AndyA 0:24177fc1e0e3 97
AndyA 0:24177fc1e0e3 98 void BlinkLeds(bool on=true, float delay=0.1)
AndyA 0:24177fc1e0e3 99 {
AndyA 0:24177fc1e0e3 100 uint8_t state = LEDs;
AndyA 0:24177fc1e0e3 101 SetLeds(on);
AndyA 0:24177fc1e0e3 102 wait(delay);
AndyA 0:24177fc1e0e3 103 LEDs = state;
AndyA 0:24177fc1e0e3 104 wait(delay);
AndyA 0:24177fc1e0e3 105 }
AndyA 0:24177fc1e0e3 106
AndyA 0:24177fc1e0e3 107 void ShowDice(uint8_t nNumber)
AndyA 0:24177fc1e0e3 108 {
AndyA 0:24177fc1e0e3 109 // switch the leds of a particular dice-number on or off
AndyA 0:24177fc1e0e3 110 if(nNumber<1) nNumber=1;
AndyA 0:24177fc1e0e3 111 if(nNumber>6) nNumber=6;
AndyA 0:24177fc1e0e3 112
AndyA 0:24177fc1e0e3 113 LEDs=DicePattern[nNumber - 1];
AndyA 0:24177fc1e0e3 114 }
AndyA 0:24177fc1e0e3 115
AndyA 0:24177fc1e0e3 116
AndyA 0:24177fc1e0e3 117 void BlinkOneLed(uint8_t ledID, float delay = 0.1)
AndyA 0:24177fc1e0e3 118 {
AndyA 0:24177fc1e0e3 119 ToggleLed(ledID);
AndyA 0:24177fc1e0e3 120 wait(delay); // delay
AndyA 0:24177fc1e0e3 121 ToggleLed(ledID);
AndyA 0:24177fc1e0e3 122 wait(delay); // delay
AndyA 0:24177fc1e0e3 123 }
AndyA 0:24177fc1e0e3 124
AndyA 0:24177fc1e0e3 125 void SweepSingleLed(bool leftToRight = true, float delay = 0.2)
AndyA 0:24177fc1e0e3 126 {
AndyA 0:24177fc1e0e3 127 SetLeds(false);
AndyA 0:24177fc1e0e3 128 for(int n=0; n<7; n++)
AndyA 0:24177fc1e0e3 129 BlinkOneLed(leftToRight?n:6-n, delay);
AndyA 0:24177fc1e0e3 130 }
AndyA 0:24177fc1e0e3 131
AndyA 0:24177fc1e0e3 132 void StackLEDs(float delay = 0.2)
AndyA 0:24177fc1e0e3 133 {
AndyA 0:24177fc1e0e3 134 SetLeds(false);
AndyA 0:24177fc1e0e3 135 int i;
AndyA 0:24177fc1e0e3 136 int j;
AndyA 0:24177fc1e0e3 137 for (i = 7; i > 0; i--) {
AndyA 0:24177fc1e0e3 138 for (j=0; j<i; j++) {
AndyA 0:24177fc1e0e3 139 SetLed(6-j,true);
AndyA 0:24177fc1e0e3 140 wait(delay);
AndyA 0:24177fc1e0e3 141 SetLed(6-j,false);
AndyA 0:24177fc1e0e3 142 }
AndyA 0:24177fc1e0e3 143 SetLed(7-j,true);
AndyA 0:24177fc1e0e3 144 }
AndyA 0:24177fc1e0e3 145 }
AndyA 0:24177fc1e0e3 146
AndyA 0:24177fc1e0e3 147 void SweepAllLeds(bool leftToRight = true, float delay=0.2)
AndyA 0:24177fc1e0e3 148 {
AndyA 0:24177fc1e0e3 149 for(int n=0; n<7; n++) {
AndyA 0:24177fc1e0e3 150 SetLed(leftToRight?n:6-n, true);
AndyA 0:24177fc1e0e3 151 wait(delay); // delay
AndyA 0:24177fc1e0e3 152 }
AndyA 0:24177fc1e0e3 153 for(int n=0; n<7; n++) {
AndyA 0:24177fc1e0e3 154 SetLed(leftToRight?6-n:n, false);
AndyA 0:24177fc1e0e3 155 wait(delay); // delay
AndyA 0:24177fc1e0e3 156 }
AndyA 0:24177fc1e0e3 157 }
AndyA 0:24177fc1e0e3 158
AndyA 0:24177fc1e0e3 159
AndyA 0:24177fc1e0e3 160 void mySleep() // ONLY CALL FROM MAIN LOOP
AndyA 0:24177fc1e0e3 161 {
AndyA 0:24177fc1e0e3 162
AndyA 0:24177fc1e0e3 163 LPC_PMU->PCON = 0x0;
AndyA 0:24177fc1e0e3 164 SCB->SCR &= ~SCB_SCR_SLEEPDEEP_Msk;
AndyA 0:24177fc1e0e3 165 __WFI();
AndyA 0:24177fc1e0e3 166 }
AndyA 0:24177fc1e0e3 167
AndyA 0:24177fc1e0e3 168 // deepSleep is higher power but faster wakeup
AndyA 0:24177fc1e0e3 169 // clean PLL shutdown is technically needed but seems to work without it.
AndyA 0:24177fc1e0e3 170 // Note - If using clean PLL shutdown the IRQ that wakes us runs on the IRC
AndyA 0:24177fc1e0e3 171 // not the system clock because the clock isn't set up until after the IRQ is complete.
AndyA 0:24177fc1e0e3 172 void myPowerDown(bool cleanPLLShutdown = false, bool deepSleep = false)
AndyA 0:24177fc1e0e3 173 {
AndyA 0:24177fc1e0e3 174
AndyA 0:24177fc1e0e3 175 if (deepSleep)
AndyA 0:24177fc1e0e3 176 LPC_PMU->PCON = 0x1;
AndyA 0:24177fc1e0e3 177 else
AndyA 0:24177fc1e0e3 178 LPC_PMU->PCON = 0x2;
AndyA 0:24177fc1e0e3 179
AndyA 0:24177fc1e0e3 180
AndyA 0:24177fc1e0e3 181 LPC_SYSCON->PDSLEEPCFG |= 0x7f; // shut off everything we can.
AndyA 0:24177fc1e0e3 182 SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;
AndyA 0:24177fc1e0e3 183
AndyA 0:24177fc1e0e3 184 bool IRCPowered = (LPC_SYSCON->PDRUNCFG & 0x01); // only used for cleen shutdown but defined here for scope reasons.
AndyA 0:24177fc1e0e3 185
AndyA 0:24177fc1e0e3 186 if (cleanPLLShutdown) {
AndyA 0:24177fc1e0e3 187 if (!IRCPowered)
AndyA 0:24177fc1e0e3 188 LPC_SYSCON->PDRUNCFG &= 0xfffffffe; // power up the IRC
AndyA 0:24177fc1e0e3 189
AndyA 0:24177fc1e0e3 190 LPC_SYSCON->MAINCLKSEL = 0x00; // switch to IRC to avoid glitches
AndyA 0:24177fc1e0e3 191 LPC_SYSCON->MAINCLKUEN = 0x01; /* Update MCLK Clock Source */
AndyA 0:24177fc1e0e3 192 LPC_SYSCON->MAINCLKUEN = 0x00; /* Toggle Update Register */
AndyA 0:24177fc1e0e3 193 LPC_SYSCON->MAINCLKUEN = 0x01;
AndyA 0:24177fc1e0e3 194 while (!(LPC_SYSCON->MAINCLKUEN & 0x01)); /* Wait Until Updated */
AndyA 0:24177fc1e0e3 195 }
AndyA 0:24177fc1e0e3 196
AndyA 0:24177fc1e0e3 197 LPC_SYSCON->PDAWAKECFG = LPC_SYSCON->PDRUNCFG; // switch on everything that is currently on when we wake up.
AndyA 0:24177fc1e0e3 198
AndyA 0:24177fc1e0e3 199 __WFI();
AndyA 0:24177fc1e0e3 200
AndyA 0:24177fc1e0e3 201 if (cleanPLLShutdown) {
AndyA 0:24177fc1e0e3 202 LPC_SYSCON->MAINCLKSEL = 0x03; // switch to PLL output
AndyA 0:24177fc1e0e3 203 LPC_SYSCON->MAINCLKUEN = 0x01; /* Update MCLK Clock Source */
AndyA 0:24177fc1e0e3 204 LPC_SYSCON->MAINCLKUEN = 0x00; /* Toggle Update Register */
AndyA 0:24177fc1e0e3 205 LPC_SYSCON->MAINCLKUEN = 0x01;
AndyA 0:24177fc1e0e3 206 while (!(LPC_SYSCON->MAINCLKUEN & 0x01)); /* Wait Until Updated */
AndyA 0:24177fc1e0e3 207
AndyA 0:24177fc1e0e3 208 if (!IRCPowered)
AndyA 0:24177fc1e0e3 209 LPC_SYSCON->PDRUNCFG |= 0x01; // power down the IRC
AndyA 0:24177fc1e0e3 210 }
AndyA 0:24177fc1e0e3 211 }
AndyA 0:24177fc1e0e3 212
AndyA 0:24177fc1e0e3 213
AndyA 0:24177fc1e0e3 214 void enterSleep(enum sleepMode_t mode = powerDown)
AndyA 0:24177fc1e0e3 215 {
AndyA 0:24177fc1e0e3 216
AndyA 0:24177fc1e0e3 217 SweepSingleLed(0.1);
AndyA 0:24177fc1e0e3 218
AndyA 0:24177fc1e0e3 219 // all LEDs off.
AndyA 0:24177fc1e0e3 220 SetLeds(false);
AndyA 0:24177fc1e0e3 221 // stop timers.
AndyA 0:24177fc1e0e3 222 timeTracker.stop();
AndyA 0:24177fc1e0e3 223 ledCycle.detach();
AndyA 0:24177fc1e0e3 224
AndyA 0:24177fc1e0e3 225 switch (mode) {
AndyA 0:24177fc1e0e3 226 case powerDown:
AndyA 0:24177fc1e0e3 227 case cleanPowerDown:
AndyA 0:24177fc1e0e3 228 default:
AndyA 0:24177fc1e0e3 229 myPowerDown(mode == cleanPowerDown);
AndyA 0:24177fc1e0e3 230 break;
AndyA 0:24177fc1e0e3 231 case lightSleep:
AndyA 0:24177fc1e0e3 232 mySleep();
AndyA 0:24177fc1e0e3 233 break;
AndyA 0:24177fc1e0e3 234 case deepSleep:
AndyA 0:24177fc1e0e3 235 case cleanDeepSleep:
AndyA 0:24177fc1e0e3 236 myPowerDown(mode == cleanDeepSleep, true);
AndyA 0:24177fc1e0e3 237 break;
AndyA 0:24177fc1e0e3 238 }
AndyA 0:24177fc1e0e3 239
AndyA 0:24177fc1e0e3 240 // awake again amd running at full speed at this point.
AndyA 0:24177fc1e0e3 241 timeTracker.start();
AndyA 0:24177fc1e0e3 242 ledCycle.attach_us(on1msTick,1000);
AndyA 0:24177fc1e0e3 243 sleepNow = false;
AndyA 0:24177fc1e0e3 244 StackLEDs(0.1);
AndyA 0:24177fc1e0e3 245 // SweepAllLeds();
AndyA 0:24177fc1e0e3 246 }
AndyA 0:24177fc1e0e3 247
AndyA 0:24177fc1e0e3 248
AndyA 0:24177fc1e0e3 249 void enterSleepTimeout(void)
AndyA 0:24177fc1e0e3 250 {
AndyA 0:24177fc1e0e3 251 sleepNow = true;
AndyA 0:24177fc1e0e3 252 }
AndyA 0:24177fc1e0e3 253
AndyA 0:24177fc1e0e3 254
AndyA 0:24177fc1e0e3 255 void buttonPressedIRQ()
AndyA 0:24177fc1e0e3 256 {
AndyA 0:24177fc1e0e3 257 sleepMode.detach();
AndyA 0:24177fc1e0e3 258 fButtonPressed=true;
AndyA 0:24177fc1e0e3 259 }
AndyA 0:24177fc1e0e3 260
AndyA 0:24177fc1e0e3 261
AndyA 0:24177fc1e0e3 262
AndyA 0:24177fc1e0e3 263 void setup(void)
AndyA 0:24177fc1e0e3 264 {
AndyA 0:24177fc1e0e3 265 // perform initialisations
AndyA 0:24177fc1e0e3 266
AndyA 0:24177fc1e0e3 267 // ensure no pullup on the progMode pin
AndyA 0:24177fc1e0e3 268 progMode.mode(PullNone);
AndyA 0:24177fc1e0e3 269
AndyA 0:24177fc1e0e3 270 // create a 32 bit number out of 32 LSBs from the ADC
AndyA 0:24177fc1e0e3 271 uint32_t seedValue = 0;
AndyA 0:24177fc1e0e3 272 uint16_t value;
AndyA 0:24177fc1e0e3 273 uint8_t counter;
AndyA 0:24177fc1e0e3 274
AndyA 0:24177fc1e0e3 275 for (counter = 0; counter < 32; counter++) {
AndyA 0:24177fc1e0e3 276 seedValue = seedValue<<1;
AndyA 0:24177fc1e0e3 277 value = RandomIn.read_u16(); // reads a 10 bit ADC normalised to 16 bits.
AndyA 0:24177fc1e0e3 278 if (value & 0x0040) // LSB of ADC output = 1
AndyA 0:24177fc1e0e3 279 seedValue++;
AndyA 0:24177fc1e0e3 280 }
AndyA 0:24177fc1e0e3 281
AndyA 0:24177fc1e0e3 282 srand(seedValue); // seed the random generator with the background noise of an analog input
AndyA 0:24177fc1e0e3 283
AndyA 0:24177fc1e0e3 284 // start a timer used to determin delay between button presses, used to increase randomness.
AndyA 0:24177fc1e0e3 285 timeTracker.start();
AndyA 0:24177fc1e0e3 286
AndyA 0:24177fc1e0e3 287 // start LED cycling ticker
AndyA 0:24177fc1e0e3 288 ledCycle.attach_us(on1msTick,1000);
AndyA 0:24177fc1e0e3 289
AndyA 0:24177fc1e0e3 290 // startup animation.
AndyA 0:24177fc1e0e3 291 StackLEDs();
AndyA 0:24177fc1e0e3 292
AndyA 0:24177fc1e0e3 293 // vibration sensor/button
AndyA 0:24177fc1e0e3 294 ActionButton.fall(buttonPressedIRQ);
AndyA 0:24177fc1e0e3 295
AndyA 0:24177fc1e0e3 296 // Sleep timeout.
AndyA 0:24177fc1e0e3 297 sleepMode.attach(enterSleepTimeout,timeoutBeforeSleep);
AndyA 0:24177fc1e0e3 298 }
AndyA 0:24177fc1e0e3 299
AndyA 0:24177fc1e0e3 300 int main()
AndyA 0:24177fc1e0e3 301 {
AndyA 0:24177fc1e0e3 302 setup();
AndyA 0:24177fc1e0e3 303 while(true) {
AndyA 0:24177fc1e0e3 304
AndyA 0:24177fc1e0e3 305 while(!fButtonPressed) {
AndyA 0:24177fc1e0e3 306 if (sleepNow) enterSleep(cleanPowerDown);
AndyA 0:24177fc1e0e3 307 }
AndyA 0:24177fc1e0e3 308
AndyA 0:24177fc1e0e3 309 uint8_t cycles = (timeTracker.read_us() % 20) + 30;
AndyA 0:24177fc1e0e3 310 uint8_t value = 1;
AndyA 0:24177fc1e0e3 311
AndyA 0:24177fc1e0e3 312 while (cycles > 0) {
AndyA 0:24177fc1e0e3 313 value = rand()%6+1;
AndyA 0:24177fc1e0e3 314 ShowDice(value);
AndyA 0:24177fc1e0e3 315 wait_ms((55-cycles)*2);
AndyA 0:24177fc1e0e3 316 cycles--;
AndyA 0:24177fc1e0e3 317 }
AndyA 0:24177fc1e0e3 318
AndyA 0:24177fc1e0e3 319 // clear the button flag now rather than as soon as we see it to avoid the need for de-bouncing.
AndyA 0:24177fc1e0e3 320 fButtonPressed=false;
AndyA 0:24177fc1e0e3 321
AndyA 0:24177fc1e0e3 322 wait(0.5);
AndyA 0:24177fc1e0e3 323
AndyA 0:24177fc1e0e3 324 for (int i = 0; i<3; i++) {
AndyA 0:24177fc1e0e3 325 BlinkLeds(false,0.2);
AndyA 0:24177fc1e0e3 326 }
AndyA 0:24177fc1e0e3 327
AndyA 0:24177fc1e0e3 328 sleepMode.attach(enterSleepTimeout,timeoutBeforeSleep);
AndyA 0:24177fc1e0e3 329 }
AndyA 0:24177fc1e0e3 330 }