Pong paddle on LCD is updating too late

Hi all,

I’m having a bit of an issue with an LCD project I’m trying to make (Pong) with my Arduino Uno. The paddles move absolutely fine without the ball, but with it, only update after the ball hits the edge, so it can’t move. I don’t know what the issue is or if t is fixable, but here is my code:


#include <LiquidCrystal.h>

int buttonState=0;

int buttonState2=0;

LiquidCrystal lcd(12, 11, 5, 4, 3, 2);

byte hero2 [8]={

B00000,

B00000,

B01110,

B11111,

B11111,

B11111,

B01110,

B00000

};

byte hero4[8]={

B10000,

B10000,

B10000,

B10000,

B10000,

B10000,

B10000,

B10000

};

byte hero5 [8]={

B00001,

B00001,

B00001,

B00001,

B00001,

B00001,

B00001,

B00001

};

void setup () {

pinMode (6, INPUT);

pinMode (8, INPUT);

lcd.begin (16,2);

lcd.createChar (7, hero2);

lcd.createChar (9 , hero4);

lcd.createChar (10, hero5);

lcd.setCursor (1, 0);

lcd.print ("     PONG     “)

delay (2000);

led.clear ( );

"j:

}

void loop() {

buttonState = digitalRead (6) ;

if (buttonState == HIGH) {

led.setCursor (0,0);

lcd.print(" ");

led.setCursor (0,1); lcd.write (byte (9));

} else {

led.setCursor (0,1);

lcd.print (" ");

led.setCursor (0, 0); lcd.write (byte (9));

}

buttonState2 = digitalRead (8) ;

if (buttonState2 == HIGH) {

led.setCursor (15, 0);

lcd.print (" ");

lcd.setCursor (15, 1); lcd.write (byte (10 ));

} else {

lcd.setCursor (15, 1); lcd.print (" "); 

lcd.setCursor (15, 0); lcd.write (byte (10));

}

for (int j=2;j<=15;j++) {

led.setCursor (j-1, 0);

led.print (" ");

led.setCursor (j, 0);

lcd.write(byte (7));

delay (300);

}

}

What the Hell is that?

And that?

Did you convert the code to a document and then auto-translate it to something else and then copy that text from the document to this forum ?
Can you show us the actual code ?

I tried to fix the sketch and make a Wokwi simulation, but it does not do much:

...

1 Like

Hi @Koepel,

thank you for your Wokwi preparations; I was tempted to make it work and this is probably what the sketch is expected to do ... :wink:

// Forum: https://forum.arduino.cc/t/pong-paddle-on-lcd-is-updating-too-late/1109845
// Author: niko65
// Not a working project, no buttons are read during a delay.
// Now working due to changes by
// 2023-04-02
// Thanks to Koepel for the Wokwi start sketch!
// ec2021

#include <LiquidCrystal.h>

int buttonState = 0;
int buttonState2 = 0;
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);

byte hero2[8] = {
  B00000,
  B00000,
  B01110,
  B11111,
  B11111,
  B11111,
  B01110,
  B00000
};

byte hero4[8] = {
  B10000,
  B10000,
  B10000,
  B10000,
  B10000,
  B10000,
  B10000,
  B10000
};

byte hero5[8] = {
  B00001,
  B00001,
  B00001,
  B00001,
  B00001,
  B00001,
  B00001,
  B00001
};

const int LeftMargin  =  1;
const int RightMargin = 15;
const int LeftPin     =  6;
const int RightPin    =  8;
const int LeftPad     =  9;
const int RightPad    = 10;
const int WinLevel    = 10;
boolean paddle1Up = false;
boolean paddle2Up = false;

int countLeft  = 0;
int countRight = 0;

void setup() {
  pinMode(LeftPin, INPUT);
  pinMode(RightPin, INPUT);
  lcd.begin(16, 2);
  lcd.createChar(7, hero2);
  lcd.createChar(9, hero4);
  lcd.createChar(10, hero5);
  Start();
}


void loop() {
   Handle(LeftPin, LeftMargin,  paddle1Up, LeftPad);
   Handle(RightPin,RightMargin, paddle2Up, RightPad);
   MovePong();
   CheckData();
}

void MovePong(){
  static int j = LeftMargin;
  static int Step = 1;
  static unsigned long lastMove = 0;
  if (millis()-lastMove > 300){
    lastMove = millis();
    Remove(j - Step);
    Set(j);
    if ((j == LeftMargin &&   paddle1Up) || 
        (j == RightMargin &&  paddle2Up)) {Step = -Step;}
    j = j + Step;
    if (j > RightMargin) {
        Remove(RightMargin);
        j = LeftMargin;
        countRight++;
        PrintCounter(false);
    }
    if (j < LeftMargin) {
         Remove(LeftMargin);
         j = RightMargin;
        countLeft++;
        PrintCounter(false);
    }
  }
}

// Pin 6 für Left byte(9) für paddle
// Pin 8 für Right byte(10) für paddle

void Handle(int Pin,int Margin, boolean &padPos, byte paddle){
  boolean buttonState = digitalRead(Pin);
  if (buttonState == HIGH) {
    lcd.setCursor(Margin, 0);
    lcd.print(" ");
    lcd.setCursor(Margin, 1); 
    lcd.write(paddle);
    padPos = false;
  } else {
    lcd.setCursor(Margin, 1);
    lcd.print(" ");
    lcd.setCursor(Margin, 0); 
    lcd.write(paddle);
    padPos = true;
  }
}

void Remove(int at){
    lcd.setCursor(at, 0);
    lcd.print(" ");
}

void Set(int at){
    lcd.setCursor(at, 0);
    lcd.write(byte(7));
}

void Start(){
  lcd.clear();
  lcd.setCursor(1, 0);
  lcd.print("     PONG     ");
  delay(2000);
  lcd.clear();
  PrintCounter(true);
}


void PrintCounter(boolean Reset){
    static int oldLeft = -1;
    static int oldRight = -1;
    if (Reset) {
      oldLeft = -1;
      oldRight = -1;
      countLeft = 0;
      countRight = 0;
    }
    if (oldLeft != countLeft){
        oldLeft = countLeft;
        int lm = LeftMargin+1;
        lcd.setCursor(lm, 1);
        lcd.print("00");
        if (countLeft<10) lm++;
        lcd.setCursor(lm, 1);
        lcd.print(countLeft);
   }
   if (oldRight != countRight){
        oldRight = countRight;    
        int rm = RightMargin-2;
        lcd.setCursor(rm, 1);
        lcd.print("00");
        if (countRight < 10) rm++;
        lcd.setCursor(rm, 1);
        lcd.print(countRight);
   }
}

void CheckData(){
   if (countLeft >= WinLevel)  { 
     Lost("  Left has lost ");
     return;
   };
   if (countRight >= WinLevel) { 
       Lost(" Right has lost ");
   }
}

void Lost(String Loser){
      lcd.setCursor(0,0);
      lcd.print(Loser);
      delay(2000);
      Start();
}

Check out here

ec2021

Sorry part of it was lost in translation as for some reason I couldn’t save the code so I had to take pictures and copy and paste from them, which ruins some of the code, like the j:

I’m still unable to save the code so I’ll try again later

Hi @niko65,

the main reason for your problem is that you move the "ball"

  • in a for-loop() and
  • with the use of delay()

If you like you may check out the sketch from my post #5 to see how the movement can be done without blocking loop() ... (This blocks and does not let the other functions get processing time).

There are also a lot of other changes, mainly to avoid double coding and to keep each routine/function short enough that it may fit on one screen without scrolling. It is also advisable to use const expressions for data which you use at more than one place and which you might want to change in future.

So you can play a bit with e.g. the WinLevel and also the left and right margins where your paddles are placed.

Have fun coding!
ec2021

I’ve read the code and don’t fully understand it as I have a limited understanding of C++, which is why I am doing this project (which is why I haven’t just copy/paste it). There was a void Set that summoned the ball and a void remove to get rid of it, but I tried using just that section in my code and the ball doesn’t appear. You also mentioned how just moving the ball in a for loop is bad, and I don’t know what else to do.

Start by reading this: https://docs.arduino.cc/built-in-examples/digital/BlinkWithoutDelay
Then you see that a millis timer is used to move the ball.

Don't worry, that's a usual situation for beginners...

If you are interested to learn there is plenty of support in this forum as well as on the Internet.

Coding being one task of developing requires knowledge, understanding and training

Read, try, fail, (swear if you like) and keep on learning. Then you 'll quickly increase your knowledge and skills.

ec2021

It's obligatory.

1 Like

Hi @niko65,

as you are not the only one struggling with this topic when beginning to code I have taken some time to write some shorter examples which I coded and placed on Wokwi so that everyone interested can check the functionality:

Short Millis() Function Example

Selfmade For Loop I (Explaining how to create your "own" for loop in loop() )

Selfmade For Loop II (Demonstration why for-loop with delay() ususally blocks loop() )

Selfmade For Loop III (showing the use of the Selfmade For Loop to achieve a non-blocking loop())

Selfmade For-Loop IV (like III but with separate functions to increase understanding and maintainability)

I will publish the code in a separate thread to keep this thread clean but post the link to it after it has been established. They are probably not best practice in all aspects therefore I am open for improvements so that these examples may grow and can be used in future as a simple reference for beginners.

ec2021

The link to the source code is

I checked all the links and I kind of understand how it works, so I continued the code (I’m not finished, so far only the right side can lose and the ball goes only in one direction and nothing happens if button is low which will soon change ball direction and there is no scoring system) but as soon as I add the if at the end, to add some part of pong to it, it starts to spam the words “LEFT SIDE WINS!” I also added a millis timer (I think). Here is my code:


#include <LiquidCrystal.h>
int buttonState=0;
unsigned long previousMillis;
unsigned
long currentMillis;
const long period = 1000;
int buttonState2=0;
int i = 1;
int d =
0;
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);
byte hero2[8]={
  B00000,
  B00000,
  B01110,
B11111,
  B11111,
  B11111,
  B01110,
  B00000
};
byte hero4[8]={
 B10000,
 B10000,
B10000,
B10000,
B10000,
B10000,
B10000,
B10000 };
byte hero5[8]={
B00001,
 B00001,
 B00001,
 B00001,
 B00001,
 B00001,

 B00001,
 B00001
};
   void setup() {
  previousMillis = millis();
  pinMode(6, INPUT_PULLUP);
  pinMode(8, INPUT_PULLUP);
  lcd.begin(16,2);
lcd.createChar(7, hero2);
lcd.createChar(9, hero4);
lcd.createChar(10, hero5);
  lcd.setCursor(1,0);
lcd.print("
  delay(2000);
  lcd.clear();
}
void loop() {
PONG ");
  currentMillis = millis();
  unsigned long previousMillis = millis();
if(currentMillis - previousMillis >= period) {
    previousMillis = currentMillis;
lcd.clear();
    i=i+1;
  }
  lcd.setCursor(i,d);
  lcd.write(byte(7));
buttonState =
digitalRead(6);
  if (buttonState == HIGH) {
    lcd.setCursor(0,0);
        lcd.print(" ");
    lcd.setCursor(0,1);
    lcd.write(byte(9));
  } else {
lcd.setCursor(0,1);
        lcd.print(" ");
    lcd.setCursor(0,0);
lcd.write(byte(9));
  }
buttonState2 = digitalRead(8);
if (buttonState2 == HIGH) {

Powered by TCPDF (www.tcpdf.org)
  lcd.setCursor(15,0);
    lcd.print(" ");
    lcd.setCursor(15,1);
lcd.write(byte(10));
  } else {
lcd.print(" ");
};
lcd.setCursor(15,1);
            lcd.setCursor(15,0);
            lcd.write(byte(10));
if(i==16 and d==0 and buttonState2 == LOW) {
  } else {
    lcd.clear();
lcd.print("LEFT SIDE WINS!");
  }
}

I think something got garbled in transmission.

See @anon56112670 's post! There is definitely something wrong with the code in your last post.

I also recommend to write single function calls for code parts that can be handled separately. Give them meaningful names!

That has a lot of advantages:

  • Smaller functions can be tested separately.
  • It is much easier to understand what each single function does (or does not do).
  • It is much easier to understand and check the sequence of the different functions.

Keep loop() as lean as possible...

All this is not mandatory but helps during development and to understand and maintain code over a long time.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.