digitalRead() mutiple pins against multiple solutions

Hello all. I have trying to compose a code that reads if a switch is on or off using the INPUT_PULLUP aspect of the Arduino. In total there is 8 switches and I am wanting three different correct solutions. I am completely unsure how to have the program compare the current state of 8 switches against a solution. For example if we have switches 1,2,3,4,5,6,7, and 8 and the solution respectively is HIGH, LOW, HIGH, LOW, HIGH, LOW, HIGH, LOW. When it reads this I want it to push an output to a relay. I also want LOW, HIGH, LOW, HIGH, LOW, HIGH, LOW, HIGH to be solution that pushes an output to another relay. I assume I will use digitalRead() for this but am unsure how to have it read multiple pins and how to compare it against the solution. Thanks so much for the information.

The state is no problem, but what board are you using to get eight digital pins?

You do a digital read of each switch into eight local variables. I recommend short names because the next suggestion gets unreadable in code.

So, declare your switch variables thus:

byte s0;
byte s1;
byte s2;
byte s3;
byte s4;
byte s5;
byte s6;
byte s7;

The you test the state of the switches like this, using your example, HIGH, LOW, HIGH, LOW, HIGH, LOW, HIGH, LOW.
if(sw0 && !sw1 && sw2 && !sw3 && sw4 && !sw5 && sw6 && !sw7){
// do sometnihg
}
This works because because false == low == zero. True ==high== not zero.
This is exactly the same code, but longer:

if(sw0==1 && sw1==0 && sw2==1 && sw3==0 && sw4==1 && sw5==0 && sw6==1 && sw7==0){
// do sometnihg
}

I'd trying doing it with direct reads of the pin ports and a little bit manipulation (assuming Arudino Uno):

const uint8_t testCase0 = 0xAA;
const uint8_t testCase1 = 0x55;
//  Add more test cases here

void setup() {
  // Port B Pins
  pinMode(8, INPUT_PULLUP);
  pinMode(9, INPUT_PULLUP);
  pinMode(10, INPUT_PULLUP);
  pinMode(11, INPUT_PULLUP);
  pinMode(12, INPUT_PULLUP);
  pinMode(13, INPUT_PULLUP);

  // Port D Pins
  pinMode(6, INPUT_PULLUP);
  pinMode(7, INPUT_PULLUP);
}

void loop() {
  uint8_t switchStates;

  switchStates = (PINB & 0x3F) | (PIND & 0xC0);
  switch (switchStates) {
    case testCase0:
      // Do something
      break;

    case testCase1:
      // Do something else
      break;

    // more cases here

    default:
      // Do nothing
      break;
  }
}

Actually, to get the pin numbers to line up nicely in the byte, you could go with:

const uint8_t testCase0 = 0xAA;
const uint8_t testCase1 = 0x55;
//  Add more test cases here

void setup() {
  // Port B Pins
  pinMode(8, INPUT_PULLUP);
  pinMode(9, INPUT_PULLUP);
  pinMode(10, INPUT_PULLUP);
  pinMode(11, INPUT_PULLUP);
  pinMode(12, INPUT_PULLUP);
  pinMode(13, INPUT_PULLUP);

  // Port D Pins
  pinMode(6, INPUT_PULLUP);
  pinMode(7, INPUT_PULLUP);
}

void loop() {
  uint8_t switchStates;

  switchStates = ((PINB & 0x3F)<<2) | ((PIND & 0xC0)>>6);
  switch (switchStates) {
    case testCase0:
      // Do something
      break;

    case testCase1:
      // Do something else
      break;

    // more cases here

    default:
      // Do nothing
      break;
  }
}

I apologize it is an Arduino Uno. Seems important to mention. lol

gfvalvo: I thought of using port registers, but decided in my response that simplicity was more expedient.

Thanks for the input. gfvalvo:do you mind explaining the testcase0= 0*AA and the other. What is that testing? For the do something would it be digtialWrite(relaypin1, LOW). Also does this check each sequentially and if one is then changed from correct to incorrect would it automatically disable the relaypin. Thanks again

Why complicate things ?

Here is a simple example using 4 inputs that I wrote for a previous query of the same kind

const byte inputPins[] = {A3, A2, A1, A0};

void setup()
{
  Serial.begin(115200);
  for (int p = 0; p < 4; p++)
  {
    pinMode(inputPins[p], INPUT_PULLUP);
  }
}

void loop()
{
  byte result = 0;
  for (int bit = 0; bit < 4; bit++)
  {
    bitWrite(result, bit, digitalRead(inputPins[bit]));
  }
  Serial.println(result, BIN);
  delay(500);
  if (result == 0b00001110)
  {
    functionA();
  }
  else if (result == 0b00000111)
  {
    functionB();
  }
}

void functionA()
{
  Serial.println("functionA");
}

void functionB()
{
  Serial.println("functionB");
}

Expanding that to 8 input pins and two relay outputs:

const byte BitCount = 8;
// Pin number for pins 1 through 8
const byte InputPins[] = {2, 3, 7, 4, A3, A2, A1, A0};

const byte ARelayPin = 5;
const byte AnotherRelayPin = 6;

void setup()
{
  Serial.begin(115200);
  for (int p = 0; p < BitCount; p++)
  {
    pinMode(InputPins[p], INPUT_PULLUP);
  }

  digitalWrite(ARelayPin, HIGH);  // Most relay modules are Active LOW
  pinMode(ARelayPin, OUTPUT);

  digitalWrite(AnotherRelayPin, HIGH);  // Most relay modules are Active LOW
  pinMode(AnotherRelayPin, OUTPUT);
}

void loop()
{
  byte result = 0;
  for (int bit = 0; bit < BitCount; bit++)
  {
    bitWrite(result, bit, digitalRead(InputPins[bit]) != LOW ? 1 : 0);
  }
  Serial.println(result, BIN);
  delay(500);


  // the solution respectively is HIGH, LOW, HIGH, LOW, HIGH, LOW, HIGH, LOW.   
  if (result == 0b10101010)
  {
    // When it reads this I want it to push an output to a relay.
    digitalWrite(ARelayPin, LOW);  // Most relay modules are Active LOW
  }
  // I also want LOW, HIGH, LOW, HIGH, LOW, HIGH, LOW, HIGH to be solution...
  else if (result == 0b01010101)
  {
    // ...that pushes an output to another relay.
    digitalWrite(AnotherRelayPin, LOW);  // Most relay modules are Active LOW
  }
  else
  {
    // Not a solution.  Turn all relays off
    digitalWrite(ARelayPin, HIGH);  // Most relay modules are Active LOW
    digitalWrite(AnotherRelayPin, HIGH);  // Most relay modules are Active LOW
  }
}

Wackzitt:
Thanks for the input. gfvalvo:do you mind explaining the testcase0= 0*AA and the other. What is that testing? For the do something would it be digtialWrite(relaypin1, LOW). Also does this check each sequentially and if one is then changed from correct to incorrect would it automatically disable the relaypin. Thanks again

By careful selection of the GPIO pin assignments and use of direct port reading, the code I posted allows efficient reading of all the switch states with minimal instructions. Since no Port bank on a standard Uno allows easy use of all 8 bits, I chose 6 bits from Port B and 2 bits from Port D. I then shifted and combined them so that the I/O pins appear in the resultant bits ordered low to high.

The const variables are simply initialized with the hex representation of your "HIGH, LOW, HIGH, LOW, HIGH, LOW, HIGH, LOW" type conditions. If you prefer, you could use binary representation: 0b10101010.

The "do something" sections are code that would execute when a particular pattern is matched. It's up to you to decide what to do when each pattern is matched and also when no pattern is matched (the 'default' case). Add as many 'case' clauses as you need to cover the required possibilities.

As evidenced by the other replies, there are multiple ways to accomplish what you want. However, that's how I'd do it if it were my project.

I seem to be missing something. Johnwasser: I used the code you posted to base mine off of; however, I changed the inpurt pins and added an additional relay. I don't think that should be causing my error. When I run the code it seems to never bitWrite appropriately. Using the 8 pins (2,3,4,5,A2,A3,A4,A5) never activates a relay. However, if I change it to one pin it works perfectly. I have played around with this and attempted to change multiple things, but can not seem to get it to work. Any help will be great. Also when I run the code in serial monitor it just read a bunch of question marks. Thanks

Wackzitt:
I seem to be missing something. Johnwasser: I used the code you posted to base mine off of; however, I changed the input pins and added an additional relay. I don't think that should be causing my error.

Show your updated code and I will take a look.

const byte BitCount = 8;
// Pin number for pins 1 through 8
const byte InputPins = {2, 3, 4, 5, A2, A3, A4, A5};

const byte ARelayPin = 6;
const byte AnotherRelayPin = 7;
const byte ThirdRelayPin = 8;

void setup()
{
Serial.begin(115200);
for (int p = 0; p < BitCount; p++)
{
pinMode(InputPins[p], INPUT_PULLUP);
}

digitalWrite(ARelayPin, HIGH); // Most relay modules are Active LOW
pinMode(ARelayPin, OUTPUT);

digitalWrite(AnotherRelayPin, HIGH); // Most relay modules are Active LOW
pinMode(AnotherRelayPin, OUTPUT);

digitalWrite(ThirdRelayPin, HIGH); // Most relay modules are Active LOW
pinMode(ThirdRelayPin, OUTPUT);
}

void loop()
{
byte result = 0;
for (int bit = 0; bit < BitCount; bit++)
{
bitWrite(result, bit, digitalRead(InputPins[bit]) != LOW ? 1 : 0);
}
Serial.println(result, BIN);
delay(500);

// the solution respectively is HIGH, LOW, HIGH, LOW, HIGH, LOW, HIGH, LOW.
if (result == 0b10101010)
{
// When it reads this I want it to push an output to a relay.
digitalWrite(ARelayPin, LOW); // Most relay modules are Active LOW
}
// I also want LOW, HIGH, LOW, HIGH, LOW, HIGH, LOW, HIGH to be solution…
else if (result == 0b01010101)
{
// …that pushes an output to another relay.
digitalWrite(AnotherRelayPin, LOW); // Most relay modules are Active LOW
}
else if (result == 0b01010101)
{
// …that pushes an output to another relay.
digitalWrite(ThirdRelayPin, LOW); // Most relay modules are Active LOW
}
else
{
// Not a solution. Turn all relays off
digitalWrite(ARelayPin, HIGH); // Most relay modules are Active LOW
digitalWrite(AnotherRelayPin, HIGH); // Most relay modules are Active LOW
digitalWrite(ThirdRelayPin, HIGH);
}
}

Wackzitt:

else if (result == 0b01010101)

{
    // ...that pushes an output to another relay.
    digitalWrite(AnotherRelayPin, LOW);  // Most relay modules are Active LOW
  }
  else if (result == 0b01010101)
  {
    // ...that pushes an output to another relay.
    digitalWrite(ThirdRelayPin, LOW);  // Most relay modules are Active LOW
  }

You can't use the same pattern for two different relays.
Now that you're extending beyond two 'else if' clauses and all the comparisons are 'variable == constant' we can switch from if/else if/else if/else to switch/case/case/case/default to make it easier to read. This also has the advantage that you will get an "error: duplicate case value" if you try to use a pattern more than once.

  switch (result)
  {
    case 0b10101010:
      // the solution respectively is HIGH, LOW, HIGH, LOW, HIGH, LOW, HIGH, LOW.
      // When it reads this I want it to push an output to a relay.
      digitalWrite(ARelayPin, LOW);  // Most relay modules are Active LOW
      break;


    case 0b01010101:
      // I also want LOW, HIGH, LOW, HIGH, LOW, HIGH, LOW, HIGH to be solution
      // that pushes an output to another relay.
      digitalWrite(AnotherRelayPin, LOW);  // Most relay modules are Active LOW
      break;


    case 0b01010101:
      // ...that pushes an output to another relay.
      digitalWrite(ThirdRelayPin, LOW);  // Most relay modules are Active LOW
      break;


    default:
      // Not a solution.  Turn all relays off
      digitalWrite(ARelayPin, HIGH);  // Most relay modules are Active LOW
      digitalWrite(AnotherRelayPin, HIGH);  // Most relay modules are Active LOW
      digitalWrite(ThirdRelayPin, HIGH);
      break;
  }

So i updated the code to what you were saying and have since then attempted to run the puzzle multiple times and am having no luck. It seems as though it does not wish to properly right digitalRead into result. If i reduce it to one switch and change result = 1; it works for that one switch. Something seems to be causing while either writing or reading multiple input pins. Thanks again.

void loop()
{
  byte result = 0;
  for (int bit = 0; bit < BitCount; bit++)
  {
    bitWrite(result, bit, digitalRead(InputPins[bit]) != LOW ? 1 : 0);
  }
  Serial.println(result, BIN);
  delay(500);

switch (result)
  {
    case 0b10101010:
      // the solution respectively is HIGH, LOW, HIGH, LOW, HIGH, LOW, HIGH, LOW.
      // When it reads this I want it to push an output to a relay.
      digitalWrite(ARelayPin, LOW);  // Most relay modules are Active LOW
      break;


    case 0b01010101:
      // I also want LOW, HIGH, LOW, HIGH, LOW, HIGH, LOW, HIGH to be solution
      // that pushes an output to another relay.
      digitalWrite(AnotherRelayPin, LOW);  // Most relay modules are Active LOW
      break;


    case 0b11110000:
      // ...that pushes an output to another relay.
      digitalWrite(ThirdRelayPin, LOW);  // Most relay modules are Active LOW
      break;


    default:
      // Not a solution.  Turn all relays off
      digitalWrite(ARelayPin, HIGH);  // Most relay modules are Active LOW
      digitalWrite(AnotherRelayPin, HIGH);  // Most relay modules are Active LOW
      digitalWrite(ThirdRelayPin, HIGH);
      break;
  }
}

this task would be much simpler with arrays.

then you can just loop though for matches.

if you want to test multiple codes then a loop inside a loop would be nessesarry to try them all.

this is untested but should work

// put the pins you are using in this array
int pins []{1,2,3,4,5,6,7,8};

// here is three sets of acceptable combos
int answers[3][8]{
  {1,0,1,0,1,0,1,1},
  {1,0,1,0,1,1,1,1},
  {1,0,0,0,1,0,1,1}
  
  };

void setup() {
  Serial.begin(9600);
 int i = 8;
// set all the pin modes on the board
 while(i>0){i--;pinMode(pins[i], INPUT_PULLUP);}
}

void check (){
  
  int match;
  int i = 3;
  // loop through 3 different combinations
  while(i>0){i--; 
  int i2=8;match = i;
   // loop through each pin and compair to combo
    while(i2>0){i2--; 
    if(digitalRead(pins[i])!=answers[i][i2]){
    match=1000;i2 = 0;
  } }
  if(match<1000){Serial.println("matched code number:"+String(match));i=0;}
  }
  
  }

void loop() {

  
}
//bitWrite(result, bit, digitalRead(InputPins[bit]) != LOW ? 1 : 0);
bitWrite(result1, bit, digitalRead(InputPins[bit]));

The syntax for the ternary operator with bitWrite is not correct. UKHeliBob had it correct in reply #7 See below

const byte BitCount = 8;
// Pin number for pins 1 through 8
const byte InputPins[] = {2, 3, 4, 5, A2, A3, A4, A5};

void setup()
{
  Serial.begin(115200);
  for (int p = 0; p < BitCount; p++)
  {
    pinMode(InputPins[p], INPUT_PULLUP);
  }

  byte result = 0;
  byte result1 = 0;
  byte result2 = 0;
  for (int bit = 0; bit < BitCount; bit++)
  {
    bitWrite(result, bit, digitalRead(InputPins[bit]) != LOW ? 1 : 0);
    Serial.print(result,BIN);
    Serial.print('\t');
    bitWrite(result1, bit, digitalRead(InputPins[bit]));
    Serial.print(result1,BIN);
    Serial.print('\t');
    bitWrite(result2, bit, digitalRead(InputPins[bit]) != LOW ? bitWrite(result2,bit,1) : bitWrite(result2,bit,0)); 
    Serial.println(result2,BIN);
  }
  Serial.print("result= ");
  Serial.println(result, BIN);
  Serial.print("result1= ");
  Serial.println(result1, BIN);
  Serial.print("result2= ");
  Serial.println(result2, BIN);
}
void loop()
{}

cattledog:

//bitWrite(result, bit, digitalRead(InputPins[bit]) != LOW ? 1 : 0);

bitWrite(result1, bit, digitalRead(InputPins[bit]));



The syntax for the ternary operator with bitWrite is not correct.

You are correct! I had not anticipated the Arduino.h 'bitWrite' macro to be so poorly written:

#define bitWrite(value, bit, bitvalue) (bitvalue ? bitSet(value, bit) : bitClear(value, bit))

I expected that they would take the normal precaution of putting parens around each use of each argument!

Normal coding practice for macros would be:

#define bitWrite(value, bit, bitvalue) ((bitvalue) ? bitSet((value), (bit)) : bitClear((value), (bit)))

This can be fixed by adding parens to the macro argument myself:

    bitWrite(result, bit, (digitalRead(InputPins[bit]) != LOW ? 1 : 0));

There was an open issue for the 'bitWrite' macro but it got closed in a bureaucratic shuffle. I have opened a new issue for the AVR core: Arduino.h bitWrite() macro has no parens around argument expansion · Issue #105 · arduino/ArduinoCore-avr · GitHub

I apologize but I dont seem to understand what it is you guys are talking about in regards to the bitWrite(). I looked at the code cattledog posted; however, I am unsure as to why it is is posted in the void setup () section. If i then try to type if statements in void loop() it requires me to state what result(1)(2) are. I am sorry that I am having so much trouble with this. Thanks again.