(not a ) switch case question (anymore...)

Ok, I have a quick question about using switch cases.

Is it possible to use a switch case within a switch case?

my goal here is to make a 7 segment display dice roller. I have already successfully made a shake-to-roll 6 sided dice (shake the breadboard and the 7seg will display 1-6 "randomly")
Now as a personal challenge, I am trying to make one 7seg display work as many different kinds of dice.
2 sided (coin flip), 4 sided, 6 sided, 8 sided.... so on, up to a 20 sided dice.
this would basically be a whole set of gaming dice in one little unit, fully controlled with the Arduino, no ICs.

I am doing this by using a press button to switch between dice modes (how many sides)
and using a tilt switch to trigger the shake-to-roll function, which will give a result on the 7seg that will be limited by which dice mode you are in.

I hope I am not being confusing...

here is an example -

default mode will be 0
mode 0 is a 2 sided coin flip or yes/no
button press
now it is mode 1 which is a 4 sided dice.
so on and so on up to mode 7 which is 20 sided, and then reset to default mode 0

I am not to the point of posting the code and asking specific questions yet, I am trying to work this out on my own. I am very new to writing code and micro controllers, and I am trying to learn, which I do best while problem solving.
All I really need to know for the moment is if you can use a switch case to change dice modes, and use a sub-switch case? to give the results also.

sorry for being so long, but I really wanted to be clear, because I am also still learning how to communicate with the Arduino crowd :stuck_out_tongue:

Yes, you can use a switch within a switch case.

-br

4 sided dice? I thought dice had 6 sides, you must be confusing those weird 4 sided pyramid dice things.

As for a case within a case, not sure, I dont have my laptop to do any tests on my end.

Edit: I guess you can.

excellent!
thank you both for the quick replies!

I had this idea last night, then changed my mind when I started writing the code. I got about halfway through the code as I was writing it last night, and decided to test it. At first it would just run the first step in a loop, regardless of any buttons or switches. I managed to fix that, but then it wouldn't change modes, I was stuck at mode 0(2 sided). Not to mention it was getting quite long and complicated.

Today I have decided to scrap that, and go with my original idea, because I think it will write up much more cleanly.
errr, I hope :wink:

@HazardsMind Yes, this would be the pyramid dice. My inspiration for this project is a digital set of D&D dice, so those are the modes I am using.
I only have one 7seg display at the moment, so I am using the dot at the bottom to indicate double digit numbers.

it's been an educational project, and really builds on many of the tutorials I have done so far :slight_smile:

Yes you can but I don't see why you'd need to in this case.

It sounds to me like you select a mode once, then roll as often as you want. You could use an array to store how many sides each mode represents then use the mode as the index. I don't really see a need for a switch statement at all but you must have another idea.

// I see it like this
int mode = 0;
int dice[] = {2, 4, 6, 8, 10, 12, 20}; // or whatever your dice are

void loop(){

// Check the button and increment mode with rollover (0..6) 

// if the device is shaken call the random function (I'll assume it's seeded)

int rollResult = random(dice[mode]); // you may want to add one to this

// display roll result

}

// there is quite a bit of code assumed in these comments I was really just demonstrating my logic

I don't see why you'd want to use a switch statement at all, for that problem. It seems to me that all you need is:

A constant array of integers holding the size of each die you're supporting.
A state variable which is an index into that array, identifying the currently-selected die.
Some event handling code to increment the selected die variable modulo the number of dice.
Some event handling code to generate a random number within the range of the currently-selected die and pass it to a display function.
A display function that renders a specified value on your display.

I'm not clear how you'd display any value over 9 on a seven-segment display, but presumably you have a scheme in mind.

ETA: Or in other words, I agree with Jimmy60. :slight_smile:

Jimmy60:
Yes you can but I don't see why you'd need to in this case.

It sounds to me like you select a mode once, then roll as often as you want. You could use an array to store how many sides each mode represents then use the mode as the index. I don't really see a need for a switch statement at all but you must have another idea.

// I see it like this

int mode = 0;
int dice[] = {2, 4, 6, 8, 10, 12, 20}; // or whatever your dice are

void loop(){

// Check the button and increment mode with rollover (0..6)

// if the device is shaken call the random function (I'll assume it's seeded)

int rollResult = random(dice[mode]); // you may want to add one to this

// display roll result

}

// there is quite a bit of code assumed in these comments I was really just demonstrating my logic

lol, you actually jumped ahead of me a bit :stuck_out_tongue:
right now, I am trying to work this out step by step. Then once I have it working and I know why it works the way it does, I was planning on implementing an array to shorten it and learn some short cuts in the code.
I did this with my last project (sonar distance sensor with LED bar graph and Piezzo buzzer tones) and felt like I learned much more by figuring out two totally different ways to "skin this cat"

I have a lot of plans on things I want to build with the Arduino, and I am trying to focus on making projects that teach me code that I can use later for some of these bigger projects.
makes toys now to learn off of, and when I know better what I am doing, start working on bigger more complicated projects for my home :slight_smile:
working on getting "off grid" step by step, and I can see many ways in which Arduino will make this much easier!
Plus I am a tinker-er at heart, and thoroughly enjoy the process.

Thanks for the advice, and when I get this one working today, I am sure I will be back to work out how to work in arrays and lose the switches :slight_smile:

PeterH:
I don't see why you'd want to use a switch statement at all, for that problem. It seems to me that all you need is:

A constant array of integers holding the size of each die you're supporting.
A state variable which is an index into that array, identifying the currently-selected die.
Some event handling code to increment the selected die variable modulo the number of dice.
Some event handling code to generate a random number within the range of the currently-selected die and pass it to a display function.
A display function that renders a specified value on your display.

I'm not clear how you'd display any value over 9 on a seven-segment display, but presumably you have a scheme in mind.

ETA: Or in other words, I agree with Jimmy60. :slight_smile:

Thanks for the reply Peter!
since I will not need to display any number higher than 20, I am using the dot to indicate double digits.
1-9 are normal,
now for 10, you would see a 0 and the dot on the bottom lit up
like this - 0.
then 11 = 1.
12 = 2.
continue up to 19 = 9.
for 20 it will display what will look like l l. (both sides lit up, all middle segments off and the dot on. it's supposed to be the roman numeral II, best idea I could come up with)

its a personal challenge, to learn as much as I can from each project by doing it two different ways.

edit: plus, the random number generating method I am using here uses randomSeed(analogRead(0)) to generate the random number, then the switch case to light up the right segments of the display.
it was the easiest way I found to make the 6 sided I made last night.
when that worked out so well, I went for the bigger challenge of multiple dice modes.

well, I got it done, and it works great!

I worked it out both ways, though the first way I did it was buggy and clumsy, but it worked.
I am quite sure I can improve upon it, and might try someday :slight_smile:

I also took the advice I was given on this forum and make a v2.0
It took a bit longer to finish than I was hoping for, but it's a pretty slick little device, if you don't mind translating a single digit display into a two digit answer...
but no ICs are used off the board, and it has a dice range of 2, 4, 6, 8, 10, 12, and 20
will post the code for review and possible suggestions for improvement, cause I love to learn, and there seem to be many ways to do about anything with the Arduino, and some are much easier than others :stuck_out_tongue:

/* this is a sketch to use a single 7 segment display as many different kinds of dice.
the choices of dice value are 2, 4, 6, 8, 10, 12, and 20, based around a complete set of D&D dice values
it uses a button press to select and display which mode of dice you are using
and a tilt switch for shake-to-roll activation of random number generator.
no external ICs were harmed (or used) in the making of this sketch */

byte Display[23][8] = //define 7seg digit patern
{
{0,1,1,0,0,0,0,0}, // "1"
{1,1,0,1,1,0,1,0}, // "2"
{1,1,1,1,0,0,1,0}, // "3"
{0,1,1,0,0,1,1,0}, // "4"
{1,0,1,1,0,1,1,0}, // "5"
{1,0,1,1,1,1,1,0}, // "6"
{1,1,1,0,0,0,0,0}, // "7"
{1,1,1,1,1,1,1,0}, // "8"
{1,1,1,0,0,1,1,0}, // "9"
{1,1,1,1,1,1,0,1}, // "10"
{0,1,1,0,0,0,0,1}, // "11"
{1,1,0,1,1,0,1,1}, // "12"
{1,1,1,1,0,0,1,1}, // "13"
{0,1,1,0,0,1,1,1}, // "14"
{1,0,1,1,0,1,1,1}, // "15"
{1,0,1,1,1,1,1,1}, // "16"
{1,1,1,0,0,0,0,0}, // "17"
{1,1,1,1,1,1,1,1}, // "18"
{1,1,1,0,0,1,1,1}, // "19"
{0,1,1,0,1,1,0,1}, // "20"
{1,1,1,1,1,1,0,0}, // "0"
{0,1,1,1,1,0,1,0}, // "d"
{0,0,0,0,0,0,0,0}, // off
};

int dValue[] = //define dice value array
{2, 4, 6, 8, 10, 12, 20};

const int Button = 12; //assign push button to pin 12
const int Tilt = 11; //assign tilt switch to pin 11
int mode = 0; //assign variable mode, and store
int oldMode = 0; //assign variable old mode, and store
int val = 0; //assign variable val, and store
int oldVal = 0; //assign variable old val and store
int state = 0; //assign variable state, and store

void setup()
{
pinMode(Button, INPUT); //assign each pin used as input or output
pinMode(Tilt, INPUT);
pinMode(2, OUTPUT);
pinMode(3, OUTPUT);
pinMode(4, OUTPUT);
pinMode(5, OUTPUT);
pinMode(6, OUTPUT);
pinMode(7, OUTPUT);
pinMode(8, OUTPUT);
pinMode(9, OUTPUT);
pinMode(13, OUTPUT);
writeDot(0); //start with "dot" off

randomSeed(analogRead(0)); //read analog pin 0 to seed random number
}

void writeDot(byte dot) //assign function writeDot as a byte named "dot"
{
digitalWrite(9, dot); //write dot to pin 9
}

void sevenSegWrite(byte digit) //assign function sevenSegWrite to byte "digit"
{
byte pin = 2; //start writing sevenSegWrite at pin 2
for (byte segCount = 0; segCount < 8; ++segCount) // increpent segCount up by one
{
digitalWrite(pin, Display[digit][segCount]); //Write "pin" 1 or 0 according to the defined array
++pin; //advance to next pin
}
}

void loop()
{
{
mode = digitalRead(Button); //read push button
if ((mode == HIGH) && (oldMode == LOW)) //check button state
{
state++; //if button mode has changed, increment state up by one
{
sevenSegWrite(21); //if state has gone up, display "d" on 7seg
delay(500); //delay .5 second
sevenSegWrite(22); //turn 7seg off
delay(250); // delay .25 second
sevenSegWrite(dValue[state] - 1); //display the dice value currently selected
delay(500); //delay .5 second
sevenSegWrite(22); //turn off 7seg
}
}
if (state > 6) //if state is greater than 6 roll back to 0 then delay 10mS
{
state = 0;
delay(10);
}
oldMode = mode; //old mode is now the mode
}

val = digitalRead(Tilt); //read tilt switch
if ((val == HIGH) && (oldVal== LOW)) //check for switch state change
{
{
digitalWrite(9, HIGH); //displays a . . . on 7 seg
delay(250); //before showing dice result
digitalWrite(9,LOW); //did this for dice rolling effect
delay(250); //dramatic pause kind of thing
digitalWrite(9, HIGH);
delay(250);
digitalWrite(9,LOW);
delay(250);
digitalWrite(9, HIGH);
delay(250);
digitalWrite(9,LOW);
delay(250);
}
{
byte Result = random(dValue[state]); //assign variable Result and set it equal to the random seed related to the state count as a upper limit
sevenSegWrite(Result); //display the result on 7seg
delay(3000); //delay 3 seconds
sevenSegWrite(22); //turn off 7seg
}
}
digitalWrite(13, HIGH); //turn on led @ pin 13 as "on" indicator light
}

let me know what you think!

let me know what you think!

byte Display[23][8]

I think you're using eight times as much RAM as you need to.

@AWOL

thanks for the reply :slight_smile:

TBH I have only had my arduino for less than two weeks, and haven't wrote a sketch large enough to even begin wondering how much is "too much". (at least not as far as I know. haven't "hit the wall" yet and had to figure out why)

If you don't mind, could you explain how it is too much, and maybe give me a clue as to how to start making it more efficient.

I do notice that your estimate of how much I am over-using RAM matches the [8] at the end of the quote, I am guessing there is a relationship?

The bit of code I learned that array function from was very sparsely commented, and I had to figure out what much of it meant by trial and error.
If I made a change that didn't work with my sketch, I would go back and change something else until I got closer to what I wanted.
There are even a few lines in there that I am not completely clear on what they are doing. (which you may have guessed at by the vagueness of my own commenting)

Also, the original sketch where that line came from was made to just count down from 9 and start over automatically, with no control input. I adapted it for what I wanted, the best I know how so far. I assumed that the way it was wrote simply told the arduino how many digit to look for to define each byte that was displayed on the 7seg.

Thank you for the honest reply. I know sometimes people don't want to crit someone else' work, but I am here to learn, and that means doing it wrong until I know how to do it right....

any suggestions for improvement, or a point in the right direction is greatly appreciated!

Can you see that :

byte Display[23][8] =  //define 7seg digit patern
{
  {0,1,1,0,0,0,0,0},  // "1"
  {1,1,0,1,1,0,1,0},  // "2"
  {1,1,1,1,0,0,1,0},  // "3"
  {0,1,1,0,0,1,1,0},  // "4"
  {1,0,1,1,0,1,1,0},  // "5"
  {1,0,1,1,1,1,1,0},  // "6"
  {1,1,1,0,0,0,0,0},  // "7"
  {1,1,1,1,1,1,1,0},  // "8"
  {1,1,1,0,0,1,1,0},  // "9"
  {1,1,1,1,1,1,0,1},  // "10"
  {0,1,1,0,0,0,0,1},  // "11"
  {1,1,0,1,1,0,1,1},  // "12"
  {1,1,1,1,0,0,1,1},  // "13"
  {0,1,1,0,0,1,1,1},  // "14"
  {1,0,1,1,0,1,1,1},  // "15"
  {1,0,1,1,1,1,1,1},  // "16"
  {1,1,1,0,0,0,0,0},  // "17"
  {1,1,1,1,1,1,1,1},  // "18"
  {1,1,1,0,0,1,1,1},  // "19"
  {0,1,1,0,1,1,0,1},  // "20"
  {1,1,1,1,1,1,0,0},  // "0"
  {0,1,1,1,1,0,1,0},  // "d"
  {0,0,0,0,0,0,0,0},  // off
};

could be written

byte Display[23] =  //define 7seg digit pattern
{
  0b01100000,  // "1"
  0b11011010,  // "2"
  0b11110010,  // "3"
  0b01100110,  // "4"
//and so on until
  0  // off
};

?

I wonder If you can save a little more RAM if you make the display digits in HEX instead of binary.

You're joking, right?

@AWOL
I know they are the same representation,-_- but does it take the lenght into consideration too or just what it represents?
I dont know whats easier on the compiler, even though in the end, it is still 1s and 0s.

Edit: I answered my own question, and no change.

AWOL:
could be written

byte Display[23] =  //define 7seg digit pattern

{
  0b01100000,  // "1"
  0b11011010,  // "2"
  0b11110010,  // "3"
  0b01100110,  // "4"
//and so on until
  0  // off
};


?

OK, I think I see where you are going with this :slight_smile:
the way I wrote it, it has to remember every char each time the display is activated, where as the way you wrote it, cherry-picks the line requested and leaves out the rest?
at least that is the best way I can come up with to explain it, sorry communication isn't my strong suit...

forgive me for asking, but what exactly does the "0b" do at the beginning (starting to think I am answering my own question here) of each line.
My first thought on that would be, the "0" sets the start point, and "b" tells the arduino where to begin reading each line. It digitalWrites each pin I/0 until it hits the next "0b" where it stops.

No, "0b" is the C binary constant prefix, just as "0x" is the hex constant prefix, and "0" is the octal constant prefix

0b00000100 = 810 = 0x08 = 010

I notice that the definitions of the number representations start at '1'. I guess that this is because none of your dice have a zero on them. :slight_smile: Nevertheless, it would make your display code more reusable (and exclude a possible source of off-by-one errors) if you started the numbers from '0'. This would enable you to use the number directly as an index into the array.

AWOL:
No, "0b" is the C binary constant prefix, just as "0x" is the hex constant prefix, and "0" is the octal constant prefix

0b00000100 = 810 = 0x08 = 010

lol, what I know about C, or writing code in general, wouldn't even be a decent size drop in the overall bucket...

I very much appreciate you pointing me in the correct direction though, and I am off to do some research and learn a bit more about how and why your suggestion would work.

I did attempt to change my code as suggested, but I must be missing something somewhere. Now when I shake the breadboard to "roll the dice" I only get the very top-middle segment to light up, so I guess its time to actually go through some C tutorials and learn more about the language so I can use it properly.

Thank you so much for your help and guidance though!
my lack of experience in the subject sort of makes communicating a bit tougher, and you have been very patient to follow along and explain things to me :slight_smile:
I do understand the direction you are pointing me in, just not the "how" and "why" of it yet. I will get there

PeterH:
I notice that the definitions of the number representations start at '1'. I guess that this is because none of your dice have a zero on them. :slight_smile: Nevertheless, it would make your display code more reusable (and exclude a possible source of off-by-one errors) if you started the numbers from '0'. This would enable you to use the number directly as an index into the array.

actually, I ran into that very problem and this is how I fixed it. I originally had "0" at the top of the list, but that was displaying the dice result from 0-Xdice mode instead of 1-Xdice mode. I put "0" at the end, which screwed up my code to display which dice mode you were in, by saying "d1" instead of "d2" or "d9" instead of "d0." (for d10). To fix that, I used the "sevenSegWrite(dValue[state] - 1)" and everything worked out just right.
I could have just of easily used sevenSegWrite(Result + 1) but I didn't see that at the time. Once I had it working, I was fairly timid to try and change it again.

Thank you for the suggestion though!
Very much appreciated, and I agree, starting at 0 and adding 1 to the result would have made some other parts of the code easier to write for accessing the array.
I am just happy to have the thing working at this point. I feel like I have come a long way in a very short time, though it is clear I have a long way to go to be proficient in the least.

I just skimmed your code and one thing I see is that it doesn't appear that you have a way to show the mode without changing it. If you were playing a game that used different sided dies then it would be nice to see the mode before shaking.

My approach to this would be to use two push buttons. One to display and one to change modes. I would have it display the mode as long as one button was held down. I'd also make it so that you have to display the mode before you can change it. So you'd hold down that button to display the mode then use the other button to change through the modes. This would also make accidentally changing modes more difficult.