espressif / arduino-esp32

Arduino core for the ESP32
GNU Lesser General Public License v2.1
13.34k stars 7.37k forks source link

Problem scrolling text on LCD using millis in v2.0.0 or later #6462

Closed mooballs closed 2 years ago

mooballs commented 2 years ago

Board

ESP32 Dev Module

Device Description

Standard 1602 LCD display with standard I2C convertor.

Hardware Configuration

I2C SDA=GPIO21, SCL=GPIO22

Version

v2.0.2

IDE Name

Arduino IDE

Operating System

Windows 10

Flash frequency

40Mhz

PSRAM enabled

no

Upload speed

921600

Description

The text in the attached code will scroll across the screen if I use delay() but if I try millis() it just flickers as if its flying past very quickly (regardless of the value of milliseconds I use).

Sketch

#include "LiquidCrystal_I2C.h"

unsigned long times = millis();

int lcdColumns = 16;
int lcdRows = 2;

LiquidCrystal_I2C lcd(0x27, lcdColumns, lcdRows);

void setup() {

  lcd.init();
  Serial.begin(115200);
  lcd.backlight();
}

void loop()

{{

    {
      lcd.setCursor(0, 0);
      lcd.print("Hello");

      lcd.setCursor(0, 1);
      lcd.print("Mate");
    }
  }

{ for (int positionCounter = 0; positionCounter < 16; positionCounter++) {
      //      scroll one position left:

      if ( (millis() - times) >= 350) //Has one second passed?

      {

        lcd.scrollDisplayLeft();
        times = millis();           //and reset time.
      }
    }
  }

}

Debug Message

rst:0x1 (POWERON_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)configsip: 0, SPIWP:0xeeclk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00mode:DIO, clock div:1load:0x3fff0030,len:1324ho 0 tail 12 room 4load:0x40078000,len:13508load:0x40080400,len:3604entry 0x400805f0[��mum����2-hal-cpu.c:211] setCpuFrequencyMhz(): PLL: 480 / 2 = 240 Mhz, APB: 80000000 Hz

Other Steps to Reproduce

It compiles fine, but will not display properly on the LCD (I've tried I2c and connecting the LCD directly to the esp32 with the same results). millis() works fine in v1.0.6 but I need to use 2.0.2 as some of the features in the project I'm working on are dependant on the latest version. I've also tried several different Liquid Crystal libraries and another esp32 board with no luck. I can't find any mention of the issue online at all.

I have checked existing issues, online documentation and the Troubleshooting Guide

LioRei commented 2 years ago

/!\ there is a big difference between delay and millis. Delay is a blocking function where millis is not so your code has a problem. You need to block your execution until the good amount of time has passed.

To just block, you can do a while loop like this:

for (int positionCounter = 0; positionCounter < 16; positionCounter++) {
      //      scroll one position left:

      While ( (millis() - times) >= 350) {} //Has one second passed?
        lcd.scrollDisplayLeft();
        times = millis();           //and reset time.
    }

Another thing, the comment say 1 second but you wait 350ms 😉

mooballs commented 2 years ago

Thanks for having a look. I should have said, but it needs to be unblocking as there's other stuff going on in my main sketch. I tried the while () method and it still didn't work. Either way, the point is the code I've posted should work and it doesn't. It works in v1.0.6, but not 2.x.x, which is why I've raised it as an issue. It works if I use delay() but not millis() (or micros, or esp_timer_get_time). If somebody had five minutes to hook up an LCD1602 and try it I'd be most grateful. Or point me in the direction of what could possibly be messing it up (I'll try yet another board, but I keep coming back to fact that it used to work and now I've updated the arduino-esp32 version it doesn't).

me-no-dev commented 2 years ago

I am closing this because it's a coding issue. Feel free to continue the discussion though :)

void loop(){
  static int positionCounter = -1;

  if(positionCounter < 0){
    lcd.setCursor(0, 0);
    lcd.print("Hello");

    lcd.setCursor(0, 1);
    lcd.print("Mate");

    positionCounter = 0;
    times = millis();

  } else if((positionCounter >= 0) && ((millis() - times) >= 350)){
    lcd.scrollDisplayLeft();
    times = millis();
    positionCounter++;
    if(positionCounter == 16){
      positionCounter = -1;
    }
  }
}
mooballs commented 2 years ago

Have you actually tried it with an LCD? Because your code does exactly the same as mine, which is to say, doesn't work. As I say, it works in 1.0.6, but not in 2.x.x, so if its a coding issue, how could this be? (I'm not being rude, I genuinely want to know).

me-no-dev commented 2 years ago

your code does the following thing:

mooballs commented 2 years ago

Thanks for that mate, that makes sense and I had wondered about that bit of code. BUT ; why would it work in an earlier version of arduino-esp32 (making me think the code was sound)? plus I've tried your code and I'm getting the same result as mine.

me-no-dev commented 2 years ago

the issue is probably i the library you are using. We require that Wire API is properly used. If you link me to the library, I can probably tell you what is wrong and how to fix it

mooballs commented 2 years ago

That would be amazing, I have tried a few different libraries as I'd read about that (and I've just re-tried them now with your code), but for arguments sake lets say this one:

https://github.com/marcoschwartz/LiquidCrystal_I2C/archive/master.zip

me-no-dev commented 2 years ago

library worked fine :) are you sure you have powered the I2C expander with 5V? it will not work on 3.3 unless you adjust the contrast

mooballs commented 2 years ago

Yeah man, its all set up correctly. Its so bizarre that it works in the earlier version but not in the later ones (both your code and, weirdly, mine). Thanks for helping anyway, I don't know what I'm going to do now but I'll keep digging.

me-no-dev commented 2 years ago

it must be contrast issue. Library and code (my code) worked out of the box here. First I connected the LCD to 3.3V which was too low (later adjusting contrast made it show the text) and it worked out of the box on 5V. No changes to the library or anything.

mooballs commented 2 years ago

Very weird. Many thanks for trying it with an LCD though, at least I know its definitely something specific to my setup. It can't be the contrast though, as I can get it to display nicely either statically or with delay(). Also, this works that I found online

#include <LiquidCrystal_I2C.h>

#include <string.h>

// initialize the library with the numbers of the interface pins
int lcdColumns = 16;
int lcdRows = 2;
int scrolltime = 350; 
LiquidCrystal_I2C lcd(0x27, lcdColumns, lcdRows);

char message[] = "This is some long message that will end up scrolling";
int previous = 0;
int pos = 0;

void setup() {
  // set up the LCD's number of columns and rows: 
  lcd.init();
  Serial.begin(115200);
  lcd.backlight();
  // Print a message to the LCD.
  //lcd.print(message);
}

void printLine(int refreshSeconds){
  //Check if the current second since restart is a mod of refresh seconds , 
  //if it is then update the display , it must also not equal the previously 
  //stored value to prevent duplicate refreshes
  if((millis()) % refreshSeconds == 0 && previous != (millis())){
    previous =  (millis());//Store the current time we entered for comparison on the next cycle
    lcd.setCursor(0, 1);//Set our draw position , set second param to 0 to use the top line
    char lcdTop[16];//Create a char array to store the text for the line
    int copySize = 16; // What is the size of our screen , this could probably be moved outside the loop but its more dynamic like this
    if(strlen(message) < 16)
    {
        //if the message is bigger than the current buffer use its length instead;
        copySize = strlen(message);
    }
    //Store the current position temporarily and invert its sign if its negative since we are going in reverse
    int tempPos = pos;
    if(tempPos < 0)
    {
        tempPos = -(tempPos);
    }
    //Build the lcd text by copying the required text out of our template message variable 
    memcpy(&lcdTop[0],&message[tempPos],copySize);
    lcd.print(lcdTop);//Print it from position 0
    //Increase the current position and check if the position + 16 (screen size) would be larger than the message length , if it is go in reverse by inverting the sign.
    pos += 1;
    if(pos +16 == strlen(message))
    {
      pos = -(pos);
    }
  }
}

void loop() {  
  printLine(350);
}

But I'm having trouble integrating it into my sketch so I think the only thing I haven't tried is a completely new board (I realised both of mine were from the same ebayer, could both be dodgy). Having just uninstalled and reinstalled arduino and it still doing the same thing, I'm going to wait for the new board to come and if it still does it then I'm going to throw it all in the bin and drink lots of beer. Thanks again mate.

me-no-dev commented 2 years ago

Wish you luck!