Inconsistent printing on a dot matrix display

so i'm trying to make a tic tac toe game using a 3x3 keypad and a 8x8 dot matrix display, and an lcd screen that i'm still working in. one problem i'm consistently having is that the input seems to be inconsistent. The way the code currently works, the arduino treats the keypad as two keypads, one with the x coordinates, and one with the y coordinates, and from there it places an "x" (or a / due to size constraints) or an "o" (a ), then flips the turn. unfortunately, though the arduino detects an input from the keypad, it flips the turn without displaying an x or o. what would be the best way to solve this issue?
here's my code (ignore the win detection, it's incomplete, though has no effect on the issue)

#include <LedControl.h>
#include <Keypad.h>
#include <LiquidCrystal.h>

//lcd init
const int rs = 2, en = 3, d4 = 4, d5 = 5, d6 = 6, d7 = 7;
LiquidCrystal lcd(rs, en, d4, d5, d6, d7);

//keypad init
const byte ROWS = 3;
const byte COLS = 3;

const byte yValues[ROWS][COLS] =
{
  {1,1,1},
  {2,2,2},
  {3,3,3},
};

const byte xValues[ROWS][COLS] =
{
  {3,2,1},
  {3,2,1},
  {3,2,1},
};

const byte colPins[COLS] = {11,12,13};
const byte rowPins[ROWS] = {8,9,10};

Keypad keypadX = Keypad( makeKeymap(xValues), rowPins, colPins , ROWS, COLS);
Keypad keypadY = Keypad( makeKeymap(yValues), rowPins, colPins , ROWS, COLS);

//dot matrix init
int DIN = A0;
int CS = A1;
int CLK = A2;
LedControl lc = LedControl(DIN, CLK, CS, 0);

//game init
int turn = 1;

char* gameTable[3][3] = {
  " ", " ", " ",
  " ", " ", " ",
  " ", " ", " ",
};

//setup loop
void setup() {
  
  lcd.begin(16, 2);
  
  lc.shutdown(0, false);
  lc.setIntensity (0, 1);
  lc.clearDisplay(0);
  
  byte Table [8] = {B00100100, B00100100, B11111111, B00100100, B00100100, B11111111, B00100100, B00100100};
  for (int i = 0; i < 8; i += 1) {
    lc.setRow(0, i, Table[i]);
  }}

//void loop
void loop() {
   char keyX = keypadX.getKey();
   char keyY = keypadY.getKey();

   //gets coordinates from keypad input and places accordingly.
   if (keyX or keyY) {
    
    if (turn == 0) {
      
      placeX(keyX, keyY);
      turn = 1;
      delay(500);
    
    } else if (turn == 1) {
      
      placeO(keyX, keyY);
      turn = 0;
      delay(500);
    }

  if (turn == 0) {
    
    lcd.setCursor(0,0);
    lcd.print("Player 1's turn!");
  
  } else if (turn == 1) {
    
    lcd.setCursor(0,0);
    lcd.print("Player 2's turn!");
}}}

//place cross funcion
void placeX(int x, int y) {
  int xProjected = (x - 1) * 3;
  int yProjected = (y - 1) * 3;
  lc.setLed(0, xProjected, yProjected, true);
  lc.setLed(0, xProjected + 1, yProjected + 1, true);
  gameTable[x -1][y -1] = "x";
}

//place circle funcion
void placeO(int x, int y) {
  int xProjected = (x - 1) * 3;
  int yProjected = (y - 1) * 3;
  lc.setLed(0, xProjected + 1, yProjected, true);
  lc.setLed(0, xProjected, yProjected + 1, true);
  gameTable[x -1][y -1] = "o";
}

//win detection for rows
void checkRows() {
  for (int y = 0; y < 3; y += 1) {
    if (gameTable[1][y] == gameTable[2][y] && gameTable[1][y] == gameTable[3][y]) {
      if (gameTable[1][y] = "o") {
        //player 1 wins
      } else if (gameTable[1][y] = "x"){
        //player 2 wins
}}}}

//win detection for columns
void checkCols() {
  for (int x = 0; x < 3; x += 1) {
    if (gameTable[x][1] == gameTable[x][2] && gameTable[x][1] == gameTable[x][3]) {
      if (gameTable[x][1] = "o") {
        //player 1 wins
      } else if (gameTable[x][1] = "x"){
        //player 2 wins
}}}}

//win detection for diagonals
void checkDiag() {
  if (gameTable[1][1] == gameTable[2][2] && gameTable[1][1] == gameTable[3][3]) {
    if (gameTable[1][1] = "o") {
      //player 1 wins
    } else if (gameTable[1][1] = "x"){
      //player 2 wins
    }
  } else if (gameTable[3][1] == gameTable[2][2] && gameTable[1][1] == gameTable[1][3]) {
    if (gameTable[3][1] = "o") {
      //player 1 wins
    } else if (gameTable[3][1] = "x"){
      //player 2 wins
}}}pe or paste code here

Looks good intersecting. It would be easier to read if you used the IDE Autoformat tool.

Do it right now and paste the result right where your code is now, then I'll delete this message and no one will know it wasn't always so pretty!

At a glance I got nothing except may be the code is a little complicated for what it does, which might be hiding some issue.

I'll try it when I get to the lab.

Autoformat…

a7

i clicked autoformat, idk if it did much. i did change from using delay() to using millis() though, it helped a bit but is still inconsistent

#include <LedControl.h>
#include <Keypad.h>
#include <LiquidCrystal.h>

//lcd init
const int rs = 2, en = 3, d4 = 4, d5 = 5, d6 = 6, d7 = 7;
LiquidCrystal lcd(rs, en, d4, d5, d6, d7);

//keypad init
const byte ROWS = 3;
const byte COLS = 3;

const byte yValues[ROWS][COLS] = {
  { 1, 1, 1 },
  { 2, 2, 2 },
  { 3, 3, 3 },
};

const byte xValues[ROWS][COLS] = {
  { 3, 2, 1 },
  { 3, 2, 1 },
  { 3, 2, 1 },
};

const byte colPins[COLS] = { 11, 12, 13 };
const byte rowPins[ROWS] = { 8, 9, 10 };

Keypad keypadX = Keypad(makeKeymap(xValues), rowPins, colPins, ROWS, COLS);
Keypad keypadY = Keypad(makeKeymap(yValues), rowPins, colPins, ROWS, COLS);

//dot matrix init
int DIN = A0;
int CS = A1;
int CLK = A2;
LedControl lc = LedControl(DIN, CLK, CS, 0);

//game init
int turn = 1;

char* gameTable[3][3] = {
  " ",
  " ",
  " ",
  " ",
  " ",
  " ",
  " ",
  " ",
  " ",
};

//misc init
unsigned long time = millis();
unsigned long lastPressed = 0;
unsigned long interval = 350;

//setup loop
void setup() {

  lcd.begin(16, 2);

  lc.shutdown(0, false);
  lc.setIntensity(0, 1);
  lc.clearDisplay(0);

  byte Table[8] = { B00100100, B00100100, B11111111, B00100100, B00100100, B11111111, B00100100, B00100100 };
  for (int i = 0; i < 8; i += 1) {
    lc.setRow(0, i, Table[i]);
  }
}

//void loop
void loop() {
  char keyX = keypadX.getKey();
  char keyY = keypadY.getKey();

  //gets coordinates from keypad input and places accordingly.
  if (keyX or keyY && (lastPressed + interval) < time) {

    if (turn == 0) {

      placeX(keyX, keyY);
      turn = 1;

    } else if (turn == 1) {

      placeO(keyX, keyY);
      turn = 0;
    }

    lastPressed = time;

    if (turn == 0) {

      lcd.setCursor(0, 0);
      lcd.print("Player 2's turn!");

    } else if (turn == 1) {

      lcd.setCursor(0, 0);
      lcd.print("Player 1's turn!");
    }
  }
}

//place cross funcion
void placeX(int x, int y) {
  int xProjected = (x - 1) * 3;
  int yProjected = (y - 1) * 3;
  lc.setLed(0, xProjected, yProjected, true);
  lc.setLed(0, xProjected + 1, yProjected + 1, true);
  gameTable[x - 1][y - 1] = "x";
}

//place circle funcion
void placeO(int x, int y) {
  int xProjected = (x - 1) * 3;
  int yProjected = (y - 1) * 3;
  lc.setLed(0, xProjected + 1, yProjected, true);
  lc.setLed(0, xProjected, yProjected + 1, true);
  gameTable[x - 1][y - 1] = "o";
}

//win detection for rows
void checkRows() {
  for (int y = 0; y < 3; y += 1) {
    if (gameTable[1][y] == gameTable[2][y] && gameTable[1][y] == gameTable[3][y]) {
      if (gameTable[1][y] = "o") {
        //player 1 wins
      } else if (gameTable[1][y] = "x") {
        //player 2 wins
      }
    }
  }
}

//win detection for columns
void checkCols() {
  for (int x = 0; x < 3; x += 1) {
    if (gameTable[x][1] == gameTable[x][2] && gameTable[x][1] == gameTable[x][3]) {
      if (gameTable[x][1] = "o") {
        //player 1 wins
      } else if (gameTable[x][1] = "x") {
        //player 2 wins
      }
    }
  }
}

//win detection for diagonals
void checkDiag() {
  if (gameTable[1][1] == gameTable[2][2] && gameTable[1][1] == gameTable[3][3]) {
    if (gameTable[1][1] = "o") {
      //player 1 wins
    } else if (gameTable[1][1] = "x") {
      //player 2 wins
    }
  } else if (gameTable[3][1] == gameTable[2][2] && gameTable[1][1] == gameTable[1][3]) {
    if (gameTable[3][1] = "o") {
      //player 1 wins
    } else if (gameTable[3][1] = "x") {
      //player 2 wins
    }
  }
}

OOPS

oops?

  • Did you mean ?

if (gameTable[1][1] == ‘o’) {

nope, the table is char*, not char, so it's strings

strcmp()

strcmp() function in Arduino is used to compare two C-style strings (character arrays)

alr... anyways that's not exactly the problem i'm trying to solve here.

A 3x3 keypad already uniquely defines both row and column, why are you splitting it into two logical keypads?

The dual read through the same pins is
à mistake…

I wonder. There are two keypad objects, both of which examine some pins. Both of which will report a key press.

And the table each works from will result in row number and column number.

Yes, there are easier harder ways to do that. I mean it's naive but I think effective. One might even say charming, clever.

There's a tiny timing issue wherein one keypad will report a stroke, and the other will not. This should be tested: only when both keypads have reported is the x, y nature of the stroke valid.

It would probably be easier to use one keypad with key codes that have x and y built in, like the lower nibble is x and the upper nibble is y.

a7

I don't think this is doing what you want. I'm all for leaving off parentheses when they don't matter, here what is your intent?

if (keyX or keyY && (lastPressed + interval) < time) {

a7

It’s the same pins

Where does time ever get updated???

Yeth. That's the point. There is but one physical keypad.

Each keypad object reads the same pins and reports a key code.

If you look at the keymaps and the code you see the net result is in the form of x and y, one from each keypad object.

It's a long way to go.

That part works. The keypad library does all the debouncing, the return of a valid code is an event corresponding to pressing a key. Use it or lose it.

So the sketch can lose debouncing.

Another low lying fruit would be to switch and commit to characters and arrays of them for use throughout the sketch. strings are wasteful here, and can't be used like you'd thing in either = or ==.

I don't see the functions that check being used. Yet?

a7

Well - you have two contexts being maintained in parallel by reading from the same pins .- you might be missing some events depending on how bouncy your keypad is .

It’s also unnecessary… as you say

@groberton


Figure-1:

1. OP has a single physical Kepad1 (Fig-1) with labels as shown.
2. OP has another pseudo physical Keypad2 (Fig-1) with labels as shown.
3. OP has made for himself two physical Keypads by creating two objects:

keypadX
keypadY

4. Whenever OP presses 2 (R2C1) on Keypad1 and executes the following codes, he immediately gets two values: keyX = 0x32 and keyY = 0x33.

 char keyX = keypadX.getKey();
 char keyY = keypadY.getKey();

5. What objective (s) does OP wish to achieve from this type of two Keypad?

I guess the idea was to be able to extract the X and Y position of the key being pressed.

Orginal Keypad layout is (Fig-1); where, K21 is labeled '4' which when pessed delivers value: 0x34 from which extracting K21's co-ordinate (x, y) is a bit cumbersome process though not impossible.

From OP's two keypad concept, it is easier to get the value of x ad y. 0x32 & 0x0F ----> 2 and 0x33 & 0x0F ----> 3.


Figure-1:
2.