OK, I'm working on a project where I want to have multiple toggle switches create a "code" to determine further actions. This is essentially 5-bit communication process that will create output with a 32-bit range of outcomes from 00000 to 11111.
I'm testing the method with three switches, so if the first and third switch are HIGH/on it will read 101. Second and third, 011 etc. I'm not versed enough to know if there is a better method here, but is there a better way to do this?
// Define the pins being used
int pin_switch = 10;
int pin_switch2 = 11;
int pin_switch3 = 12;
// create int for 3-digit code
int code = 000;
void setup()
{
Serial.begin(9600);
pinMode(pin_switch, INPUT);
pinMode(pin_switch2, INPUT);
pinMode(pin_switch3, INPUT);
}
void loop()
{
if pin_switch == HIGH;
{code += 100;}
if pin_switch2 == HIGH;
{code += 10;}
if pin_switch3 == HIGH;
{code += 1;}
Serial.print(code);
// operate based on code output
if code == 101;
{do 101 stuff}
if code == 001
{do 001 stuff}
// reset code for next loop so numbers don't keep rising
code = 000;
}
-
1Note: don't write leading zeros in a decimal number in C or C++ (or a bunch of other languages) - the numbers will be treated as octal rather than decimal which is very rarely what you want.Mat– Mat2021年08月23日 15:55:17 +00:00Commented Aug 23, 2021 at 15:55
2 Answers 2
It would be more convenient and less typing if you put all your switch pins in an array. That way you can loop over it to configure the ports and read them rather than copy/pasting the "same" code over and over.
The calculation of the resulting code is a classic "shift and add" loop. I put both the decimal version you seem to want and the more "usual" binary version in the snippet below.
The idea behind that sort of loop is:
- start with an empty (zero) code
- multiply the code by 10 (or left-shift once for binary)
- read a switch, add 1 to the code if it is HIGH
- go back to step 2 if there are more switches.
The value of the switches already read get "pushed" one slot to the left before reading the next switch, resulting in the code you want.
The order in which you list the ports in the array is important: the first port in the array will change the leftmost (most significant) digit/bit in the code.
const uint8_t switch_pin[] = { 10, 11, 12 };
const uint8_t num_switches = sizeof(switch_pin)/sizeof(switch_pin[0]);
void setup() {
// Set all switch pins to input mode
for (uint8_t i = 0; i < num_switches; ++i) {
pinMode(switch_pin[i], INPUT);
}
Serial.begin(9600);
}
void loop() {
int code = 0;
// Read each switch and compute the code
for (uint8_t i = 0; i < num_switches; ++i) {
// If the code is supposed to be in decimal
code = code * 10;
code += digitalRead(switch_pin[i]);
/* For a binary version, code only needs to be 8 bits long:
code <<= 1;
code |= digitalRead(switch_pin[i]);
*/
}
// Do stuff with the code
Serial.println(code);
delay(200);
}
-
Oh thank you Mat, I think Shift and Add is the terminology I was lacking! I think I do want to go Binary, I'm thinking I will expand this to five switches so the shifting aspect simplifies that in my mind. Looking at your code here: code <<= 1; How would I shift and add for the other parts of the code? The prior would output 010, right? Would I just need to do <<<=1; AND <<= 1 to get 110? Thank you for the help.Mulcch– Mulcch2021年08月23日 15:56:40 +00:00Commented Aug 23, 2021 at 15:56
-
1If
code
is 1010,code <<= 1
(which is the same ascode = code << 1
) will result in10100
(shift left, insert a zero at the right). Thecode |= 1;
would "fill" the last position to10101
.code |= 0;
would do nothing.Mat– Mat2021年08月23日 16:07:55 +00:00Commented Aug 23, 2021 at 16:07
Unfortunately your code is all over the place. You have to use C/C++ syntax, which you don't. Also you don't actually read any input.
if statements look like this:
if(condition){ my_code(); }
if(pin_switch == HIGH)
(corrected syntax) will always be false, sincepin_switch
is of value10
. Its just the pin number. To actually read the pin, you need to usedigitalRead()
like this:if(digitalRead(pin_switch) == HIGH)
or even simpler
if(digitalRead(pin_switch))
It seems that you want to manipulate the bits with
code += 100;
, but the compiler takes numbers as decimal. So you are adding 100 tocode
. Please look into the bitwise operators. Also: You can actually write numbers in binary or hex by using0b101
or0xF3
respectively (the values here are just examples). This also means, thatint code = 000;
is the same asint code = 0;
.
To build the 3 digit code from input you could put them together via bitwise operators:
code = (digitalRead(pin_switch3) << 2) | (digitalRead(pin_switch2) << 1) | digitalRead(pin_switch);
Depending on your used Arduino and the used pins you can get this even easier. The pins are sorted into ports. Each port has a Special Function register, which holds the current state of the pins. You can mask away any unwanted pins and shift the number to be right justified. For example: On the Uno and Nano pins 2 to 7 belong to PORTD. So, if you use pins 2 to 4 for your 3 switches, you could get the code like:
code = (PIND & 0b00011100) >> 2;
This is a bit more difficult to understand, but it will help you later on, when pursuing Arduino more.
For deciding what action to do based on the code, it is normally easier to use a switch case statement:
switch(code){
case 0b101:
do_something();
break;
case 0b011:
do_something_else();
break;
}
-
Thank you! Yes my code was thrown together hastily from an example to test the method. Really appreciate the direction here, I'll dig into bitwise operators more!Mulcch– Mulcch2021年08月23日 16:06:29 +00:00Commented Aug 23, 2021 at 16:06
-
1@Mulcch oops, corrected a small error. I used
PORTD
instead ofPIND
. The former is used to set the output state of a pin, the latter reflects the current input state.chrisl– chrisl2021年08月23日 16:22:39 +00:00Commented Aug 23, 2021 at 16:22 -
Thanks for catching! I'm not sure I'll go that route, but really helpful to know about that.Mulcch– Mulcch2021年08月23日 17:41:06 +00:00Commented Aug 23, 2021 at 17:41