Jump to content
43oh

Electronic LED Dice


Recommended Posts

Here is a project i worked on just before christmas last year. my main use for this has been to ask it a question like a magic 8 ball and recieve an answer ranging from 1=no 6=yes

 

 

 

Top:

28qr9s8.jpg

 

Bottom (strip/vero board is lovely to work with):

fmhunn.jpg

 

lol no current limiting resistors.

6h262x.jpg

 

im not too sure where ive put the code, but the msp430g2231 sits in Low power mode 4 until it recieves a button press interrupt

then it runs rand() and displays the number then back to sleep, ill try to keep looking for my main.c :) it will be around somewhere.

 

battery still good 9 months later.

Link to post
Share on other sites
  • 3 months later...

I saw this thread orphan of code so I thought of doing the code for @chibiace's hardware. In the end I simplified it sligthly to have 7 instead of 9 LED's, thus using only P1.x. But the idea is precisely the same.

The code is not yet perfect though as I am struggling to time the turning off of the LED's. I asked for help in another thread too, so as soon as this is sorted out here or there I can update the code. I will also try to upload a video of my set up.

I'm a begginer so my code may have other flaws, please fell free to point them out.

 

EDIT - issue with turning off the LED's has been resolved in the other thread. It introduces a new problem though as I am now operating all the time in LPM0. I am trying to make it exit LPM4 inside the button ISR to allow the timer to work and then go back to LMP4 once the timer ISR finishes, but am having trouble. Will update the code once that is sorted out.

#include <msp430.h>
#include <stdlib.h>

// Constants
#define TIMEWAIT 3000 // ms

// Global variables
int i; // For timer overflow counter
int lfsr = 0xAF;

// Function prototypes
void turn_leds_off ( void );
int rand ( void );

int main( void )
{
  //---------------- //
  // Hardware config //
  //---------------- //
  
  WDTCTL = WDTPW + WDTHOLD; // Stop watchdog timer
  
  // DCO configuration
  DCOCTL  = CALDCO_1MHZ; //Set DCO to 1 MHz
  BCSCTL1 = CALBC1_1MHZ; // Calibrate internal clock for 1 MHz
  
  // Timer_A configuration
  CCTL0 = CCIE;
  CCR0 = 125; // 1 ms period
  TACTL = TASSEL_2 + TACLR + ID_3 + MC_0; // Stopped to begin with
    
  // P1.x
  P1DIR = 0xF7; // All pins output except P1.3
  P1IE |= BIT3;    // P1.3 interrupt enable
  P1IES |= BIT3;  // P1.3 detection edge
  P1IFG &= ~BIT3;  // P1.3 interrupt flag cleared
  P1REN = 0x00; //Pull-up
    
  //----------- //  
  // Main logic //
  //----------- //

  // Turn off all leds just in case
  turn_leds_off();
  
  // Reset counter
  i = 0;
  
   // Low power mode 0
  _BIS_SR(GIE + LPM0_bits);
}

void turn_leds_off ( void )
{
  P1OUT = 0x00;
}

int rand ( void )
{
  //unsigned int lfsr; // 16 bit version from Wikipedia
  unsigned bit;
  
  // LFSR polinomy x^{ 8 }+x^{ 6 }+x^{ 5 }+x^{ 4 }+1
  bit = ((lfsr>>0)^(lfsr>>2)^(lfsr>>3)^(lfsr>>4)) & 1;
  lfsr = (lfsr>>1) | (bit<<7);
  
  // 16 bit version from Wikipedia
  //bit = ((lfsr>>0)^(lfsr>>2)^(lfsr>>3)^(lfsr>>5)) & 1;
  //lfsr = (lfsr>>1) | (bit<<15);
  
  return lfsr;
}

#pragma vector = PORT1_VECTOR
__interrupt void button( void )
{  
  int x;
  turn_leds_off(); // Turn off all leds just in case
   
  // Rolls the dice
  do
  {
    x = rand () % 7;
  }
  while (x == 0);
  
  // Turn on the corresponding leds
    // Layout of the leds P1.x as below
    //  |0| |1| |2|
    //  | | |7| | |
    //  |4| |5| |6|
  
  switch (x)
  {
  case 1:
    P1OUT |= BIT7;
    break;
  case 2:
    P1OUT |= BIT2+BIT4;
    break;
  case 3:
    P1OUT |= BIT2+BIT7+BIT4;
    break;
  case 4:
    P1OUT |= BIT0+BIT2+BIT4+BIT6;
    break;
  case 5:
    P1OUT |= BIT0+BIT2+BIT7+BIT4+BIT6;
    break;
  case 6:
    P1OUT |= BIT0+BIT1+BIT2+BIT4+BIT5+BIT6;
    break;
  default:
    P1OUT = 0x00;
  }
  
  TACTL |= MC_1; // Wait a little - start timer A
  P1IFG &= ~BIT3; // Clears interrupt flag
}
    
#pragma vector = TIMERA0_VECTOR
__interrupt void Timer_A (void)
{
  if (i++ >= TIMEWAIT)
  {
    TACTL = TASSEL_2 + TACLR + ID_3 + MC_0; // Stops timer
    i = 0;
    turn_leds_off();
  }
}
Link to post
Share on other sites

You could also do this trick using the G2230 (a 8-pin version). Only you'd need to link LEDs (0,0) and (2,2) together, as well as (1,0) and (1,2). Same for (2,0) and (0,2), then drop LEDs (1,0) and (1,2). Now you'd only need four outputs. Then use the RESET pin as an input for the button :D

 

Also, using a random number generator without a realtime clock is kind of pointless. I made a dice like this once, but I used the timespan the use pressed the button as an input (using DCO as clock source, so that's 1 MHz). I assume humans aren't that precise in pressing buttons (since you'd need microsecond precision to tamper with the dice).

 

Also, for fair dice, make sure you don't consume more cycles at the wrap around than you'd do at the normal increment :)

Link to post
Share on other sites

Ah, that's right. I could save a few other output pins indeed! That might be useful when I do my next "step" in this project which is to have multiple dices.

 

I decided to use the LFSR pseudo-random routine as I think it was good enough for now and I liked the fact that it relies mostly in bit operations which I think are quite efficient. I implemented an 8 bit version of it which has a 255 long period but I think I can easily convert it into a 16 bit version with a much longer period (65535). Either of them are long enough so the average human can not memorize it. But one thing annoys me - as my "seed" is fixed, if you reset the MCU then it will always give the same number to start with (I think it is 5 in above code) and then follow the usual sequence. So one could take advantage of that by memorizing at least the first few numbers and resetting the dice every know and then.

I could probably randomize the seed by using a value read from the ADC or something, but then well... why not use that to use the random number itself?!

So yes, I might change the method of acquiring the "random" number :-)

Link to post
Share on other sites

If you plan on having multiple dice, you could use this method to have 4 driven elements (LEDs or LED pairs) per dice. You could use charlieplexing schemes to add more than the 4 dice a 20-pin MSP430G would allow you to. At 16 I/O lines (minus 1 for the button, unless using the reset as button input) you could drive 15 * 14 = 210 elements, 210/4 = 52.5. So a theoretical maximum of 52 dice, and two extra LEDs.... erm... you won't need this ;)

Link to post
Share on other sites
  • 5 months later...

Hi. I'm using your code with a 7 segment display and a CD4511 and I don't know what's happening but, when I'm getting my finger close to the button, the numbers scroll randomly and only stops is I put the hand away from the board or press (without release) the button...

 

Basically I have a cool dice that scrolls the numbers like a touch sensor. That's cool, but that's not what I want :lol:

Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...