Reed switch array - false readings (programming not wiring)

Hello everyone,

I am quite new to Arduino and programming in general. This is my first post but I have spent a lot of time on this forum looking for answers for all kinds of problems and thanks to all you contributors most of the time there is an old post with exactly what I need. Hopefully one day I can also contribute!

I have wired an 8x4 reed switch matrix (it will be 8x8 but it is alot of soldering!) using Berger’s chess matrix. The matrix uses a reed switch and diode on each position, the diodes prevent ‘ghosting’ when more than one reed switch signals. The program scans one row at a time, this is the same principal as the keyboard library. All of the wiring is correct as the testFunction of the program works fine.

The program searches for a change of state, checks to see if the reed switch has gone off or on and then looks for another change of state. This is meant to work as a chess board and serial print a move such as me1e2. 90% of the time this happens but 10% of the time I get ‘Invalid move’.

I would really appreciate it if someone could have a look at my program to see if there is any obvious mistakes or if I am approaching it completely the wrong way. I have tried and tried to fix this but I think I think I have just been overambitious with this project and require the help of the forum.

Thanks,
Dan

Unfortunately the code is too long so I have attached it.

chess_matrix_FINAL.ino (9.16 KB)

That's some hefty code there. It would take me more time than I'm willing to spend to really go through it (sorry), but I will point out something that jumps out immediately - it may or may not be a problem:

You have some big globals in the form of currentState, previousState and reading. In pickFunction() you can go halfway through your i,j loop, writing to these big globals as you go, and then jump into placeFunction(). In this function you start a new i,j loop and write again partially to the previously, partially modified, globals - and can then again jump into captureFunction(). In this function you start yet another i,j loop and modify the globals. Are you really certain that each time you return from a sub-function that the globals are in a suitable state?

Without having thought it thoroughly through, I might have done this with a single 2d array and used an enum to store the state of each square, eg. EMPTY, OCCUPIED, LIFTING (during debounce), LIFTED, etc.

In any case, try printing more debug statements to determine under what conditions you are getting the invalid move. Maybe even print out the entire contents of each global when the error occurs.

something you find on the internet you should use to get ideas, and then do your own coding. if you dont know what a piece of code does your program wont do what you want.

cutting and pasting rarely if ever works.

you can use libraries to help you do things, but beware one size doesnt fit all

Is the error consistent? That is, is it always the same moves which give an error, or does it appear to be random?

The code looks a little inside-out to me. The pick function senses when a piece is lifted. This function then calls placefunction, which obviously has to loop until it senses a placement or another pick-up (indicating a capture). In general, you want something that runs off state and responds to events, not a thing that sits there waiting for events to happen.

I'd have an array current_board state and an array current_debounce state.

Each loop, you check your switches. Set "changes detected" to zero. If a switch is different from current_board_state, then increment the "changes detected" counter and make a not of what has happened (e5 has been lifted). If any switch is different from your current_debounce state, write that into your current debounce state and reset the debounce timer.

After doing this, if something has changed AND the debounce timer has expired, then it's time to look at what's changed and deal with it. Otherwise, just exit the loop().

If more than one thing has changed, then light the "oops" light and enter a state where the "oops" light stays on until the 'ok, I fixed it' switch gets frobbed. This means your main loop has to handle a "we are currently fixing an oops" state.

If only one thing has changed, then copy current_debounce_state to current_board_state (using memcpy) and work out what to do.

To do this, you need a different set of variables whose job it is to keep track of the pick/maybe-capture/place cycle. START -> PICK -> POSSIBLE-SECOND-PICK -> PLACE . This function, "handle a pick or a place" might also have to light the "oops" light if something weird has happened. All going well, it will detect a place, figure out that this place has followed a prior pick or second pick, put out some output and go back to START state.

The thing is, events should make stuff happen, you don't do manage stuff by waiting for events. This means you can do things like have an oops light, flash LEDs, run a chess clock and so on by adding handlers for them in the main loop. The reed-switch stuff shouldn't consume time by sitting there waiting for a move to finish.

Hi,

Thanks for your responses, as you said it is quite a lump to read through!

Arduarn and Paul, you seem to have similar ideas (I think). At one point I did try to just monitor the positions and once all the demands for a pick/place/capture are met go to a function or 'oops light' if something weird has happened. Unfortunately I failed miserably at it but I think I dismissed it too early.

In regards to the randomness, it is completely random but it only ever happens when I place a piece. When I print all the globals' content, they all just show the same position which is where I place it and where the invalid move position shows.

Joeblogs, I used the wiring diagram from Berger's chess matrix as a foundation and the code is mine. I did try to use the keyboard library at one point but I couldn't get it to work that way.

I'll have another go at it using the advice you guys have given me and let you know how I get on. I am going away for three weeks with work on Sunday and I'm in two minds whether I want to be taking a circuit board and parts on a plane with me so it might be a little while before I get to it :/

Dan

I have fixed this, thanks for all your help!

The program now works as follows:

First Function to check the pick and place counter, depending on the outcome it will go to a pick/place/capture/invalid move function.
Second Function to search for a state change, record the state change and add one to a pick or place counter.
back to first function.

pick/place/capture functions serial print “m(pick position)(place position)”
invalid move function is a while loop asking to remove from the invalid position.

There is still a lot more I need to do but I feel more confident about it now, so thanks :slight_smile:

#define rows 8 // define number of rows
#define columns 4 //define number of columns
 
int rowpins[rows] = {12, 13, 2, 3, 4, 5, 6, 7} ; // set row pin numbers
int columnpins[columns] = {8, 9, 10, 11} ; // set column pins
int currentState[rows][columns]; // array for current state during pick
int previousState[rows][columns]; // array for comparing state during pick
int reading[rows][columns]; // array for pin read value
int pick_i = 0;
int pick_j = 0;
int place_i = 0;
int place_j = 0;
int secondPick_i = 0;
int secondPick_j = 0;
int pickCount = 0;
int placeCount = 0;
int invalidMoveCheck = 0;
 
unsigned long debounceDelay = 50;
unsigned long lastDebounceTime[rows][columns]; // array for saving debounce times
 
const char* positionArray [rows][columns] = {{"a1", "a2", "a3", "a4"},
                                            {"b1", "b2", "b3", "b4"},
                                            {"c1", "c2", "c3", "c4"},
                                            {"d1", "d2", "d3", "d4"},
                                            {"e1", "e2", "e3", "e4"},
                                            {"f1", "f2", "f3", "f4"},
                                            {"g1", "g2", "g3", "g4"},
                                            {"h1", "h2", "h3", "h4"}}; // set array position names
                                            
 
void setup () {
 
  Serial.begin (9600); // Start serial comms
  delay (2000);
  initialise (); // initialise function
 
}
 
void loop () {
 
  moveCheck();
  searchFunction();
 
}
 
void initialise () {

  Serial.println ("Board initialising");
 
  for (int i = 0; i < rows; i++) { // Set rows to LOW INPUT
    pinMode (rowpins[i], INPUT);
    digitalWrite (rowpins[i], LOW);
  }
 
  for (int j = 0; j < columns; j++) { // set columns to INPUT with PULLUP
    pinMode (columnpins[j], INPUT);
    digitalWrite (columnpins[j], HIGH);
  }
 
  for (int i = 0; i < rows; i++) {
    pinMode (rowpins[i], OUTPUT); // set row to LOW OUTPUT
    for (int j = 0; j < columns; j++) {
    reading[i][j] = digitalRead (columnpins[j]); // read board positions and set for initialise
    currentState[i][j] = reading[i][j];
    previousState[i][j] = reading[i][j];
    }
    pinMode (rowpins[i], INPUT); // set row back to INPUT
  }

  Serial.println (" ");
  Serial.println ("Current Layout:");
  Serial.println (" ");

  for (int a = 0; a < rows; a++) {
    for (int b = 0; b < columns; b++) {
      Serial.print (reading[a][b]);
      Serial.print ("  ");
    }
    Serial.println (" ");
  }
}

void searchFunction () { // Search for a pick position
 
  for (int i = 0; i < rows; i++) {
    pinMode (rowpins[i], OUTPUT); // set row to LOW OUTPUT
    for (int j = 0; j < columns; j++) {
      reading[i][j] = digitalRead (columnpins[j]); // read the pin state
      if (reading[i][j] != previousState[i][j]) { // if the reading is different to the last reading
        lastDebounceTime[i][j] = millis(); // reset the debounce timer
      }
      if ((millis() - lastDebounceTime[i][j]) > debounceDelay) { // if the reading has stayed the same for the debounce time
        if (reading[i][j] != currentState[i][j]) { // if the reading is different to last saved state
          currentState[i][j] = reading[i][j]; // save the current reading as the current state
          if (currentState[i][j] == 1) { // if part not present
            pickCount ++;
            Serial.print ("Pick ");
            Serial.print (positionArray[i][j]);
            Serial.print ("  Pick count: ");
            Serial.println (pickCount);
            if (pickCount == 1) {
              pick_i = i;
              pick_j = j;
            }
            else {
              secondPick_i = i;
              secondPick_j = j;
            }
            pinMode (rowpins[i], INPUT); // set row back to INPUT
          }
          if (currentState[i][j] == 0) { // if part present
            placeCount ++;
            Serial.print ("Place ");
            Serial.print (positionArray[i][j]);
            Serial.print ("  Place count: ");
            Serial.println (placeCount);
            place_i = i;
            place_j = j;
            pinMode (rowpins[i], INPUT); // set row back to INPUT
          }
        }
      }
      previousState[i][j] = reading[i][j]; // set previous state as reading
    }
    pinMode (rowpins[i], INPUT); // set row back to INPUT
  }
}

void moveCheck () {
  if (pickCount == 1 && placeCount == 1) {
    placeFunction();
  }
  if (pickCount == 0 && placeCount > 0) {
    invalidPlaceFunction();
  }
  if (pickCount == 2 && placeCount == 1) {
    captureFunction();
  }
}

void placeFunction () { // serial print move position
 
  Serial.print ("m");
  Serial.print (positionArray[pick_i][pick_j]);
  Serial.println (positionArray[place_i][place_j]); // serial print position, i.e. ma1c1
  previousState[place_i][place_j] = reading[place_i][place_j]; // set previous state as reading
  resetint();
}

void invalidPlaceFunction () {
  pinMode (rowpins[place_i], OUTPUT);
  Serial.print ("Invalid place position, please remove from ");
  Serial.println (positionArray[place_i][place_j]);
  invalidMoveCheck = digitalRead (columnpins[place_j]);
  while (invalidMoveCheck == 0) {
      invalidMoveCheck = digitalRead (columnpins[place_j]);
  }
  pinMode (rowpins[place_i], INPUT);
  Serial.println ("Thank You");
  currentState[place_i][place_j] = 1;
  resetint();
}

void captureFunction () {
  if (positionArray[pick_i][pick_j] == positionArray[place_i][place_j]){
  Serial.print ("m");
  Serial.print (positionArray[secondPick_i][secondPick_j]);
  Serial.println (positionArray[place_i][place_j]); // serial print position, i.e. ma1c1
  previousState[place_i][place_j] = reading[place_i][place_j]; // set previous state as reading
  resetint();
  }
  else { 
  pinMode (rowpins[place_i], OUTPUT);
  Serial.print ("Invalid place position, please remove from ");
  Serial.println (positionArray[place_i][place_j]);
  invalidMoveCheck = digitalRead (columnpins[place_j]);
  while (invalidMoveCheck == 0) {
      invalidMoveCheck = digitalRead (columnpins[place_j]);
  }
  pinMode (rowpins[place_i], INPUT);
  Serial.println ("Thank You. The only valid position is");
  Serial.println (positionArray[pick_i][pick_j]);
  currentState[place_i][place_j] = 1;
  placeCount --;
    }
}

void invalidPickFunction () {
  
}

void resetint () {
  pick_i = 0; // reset positions and counters
  pick_j = 0;
  secondPick_i = 0;
  secondPick_j = 0;
  place_i = 0;
  place_j = 0;
  pickCount = 0;
  placeCount = 0;
}

Hello so whats happen whith ur project is it done ?