Hi guys,
I need to print some arrays of Strings using millis(); Somehow I cannot make my LCD to do that. Probably it's just one silly mistake, but I've spent quite some hours figuring this out. My whole program is 430 lines of code, so instead I am sharing the part I am interested in:
#include <Wire.h>
#include <LiquidCrystal.h> // includes the LiquidCrystal Library
LiquidCrystal lcd(32, 30, 28, 26, 24, 22);
//LiquidCrystal lcd_name(rs, en, d4, d5, d6, d7);
void setup() {
//My LCD was 16x2
lcd.begin (16, 2);
lcd.home(); // go home
}
void loop() {
//bunch of other stuff here
kalba();
}
void kalba() {
//function telling users they should select the language
//four languages should switch between with the delay of 2 sec.
unsigned long currentLCDMillis = millis(); //check current time
long interval2 = 2000;
int previousLCDMillis = 0; //set first old time to 0
String languages[4] = {"Kalba?", "Language?", "Runa?", "Y3Ik?"};
if (currentLCDMillis - previousLCDMillis > interval2) {
for (int i = 0; i < 4; i++) {
lcd.setCursor (6, 0);
lcd.print(" "); //delete the old text
lcd.setCursor (6, 0);
lcd.print(languages[i]); //This shows every language at the same time, flickering LCD. A pretty nice effect though
previousLCDMillis = currentLCDMillis;
}
}
}
int previousLCDMillis = 0; //set first old time to 0
Every time the function (kalba()) is called, previousLCDMillis is set to 0. Probably not what you want? Make previousLCDMillis static so that it keeps its value from call to call. And make it unsigned long because it holds a time. The interval2 variable should, also, be unsigned long. All values that deal with time (millis() or micros()) should be unsigned long.
unsigned long currentLCDMillis = millis(); //check current time
unsigned long interval2 = 2000;
static unsigned long previousLCDMillis = 0; //set first old time to 0
Thanks!
Somehow I haven't copied the code from my full program - thus wrong data types.
After the change LCD shows the last message only. It runs through the function very fast when the interval is passed. It should wait those 2000 millis. I probably made it more complicated than it should be.
I imagine loop should also restart itself once all 4 languages have been displayed.
Now I've made this, but only String no.2 of an array is being showed. Aghh.
void kalba() {
//function telling users they should select the language
//four languages should switch between with the delay of 2 sec.
unsigned long currentLCDMillis = millis(); //check current time
unsigned long interval2 = 2000;
static unsigned long previousLCDMillis = 0; //set first old time to 0
String languages[4] = {"Kalba?", "Language?", "Runa?", "Y3Ik?"};
int i = 0;
if (currentLCDMillis - previousLCDMillis > interval2) {
i++;
lcd.setCursor (6, 0);
lcd.print(" "); //delete the old text
lcd.setCursor (6, 0);
lcd.print(languages[i]);
previousLCDMillis = currentLCDMillis;
if (i == 3) {
i = 0;
}
}
}
int i = 0;
if (currentLCDMillis - previousLCDMillis > interval2) {
i++;
lcd.setCursor (6, 0);
lcd.print(" "); //delete the old text
lcd.setCursor (6, 0);
lcd.print(languages[i]);
The first time that languages is accessed, i=1. You don't want to increment i until AFTER it has been used the first time.
Since that function is called over and over, it seems likely that i should be static.
if (currentLCDMillis - previousLCDMillis > interval2) {
i++;
lcd.setCursor (6, 0);
lcd.print(" "); //delete the old text
lcd.setCursor (6, 0);
lcd.print(languages[i]);
The first time that languages is accessed, i=1. You don't want to increment i until AFTER it has been used the first time.
Since that function is called over and over, it seems likely that i should be static.
And, i is a crappy name for a static variable.
Thanks, it works better now. Only problem - it does not delete old text. Tried writing spaces on top and use lcd.clear();
I hate the name i also, but isn't it a default name for variables that being incremented?
void kalba() {
//function telling users they should select the language
//four languages should switch between with the delay of 2 sec.
unsigned long currentLCDMillis = millis(); //check current time
unsigned long interval2 = 2000;
static unsigned long previousLCDMillis = 0; //set first old time to 0
String languages[4] = {"Kalba?", "Language?", "Runa?", "Y3Ik?"};
int langCycle = 0; //cycle is 0, it is used and waits for millis to hit 2000
if (currentLCDMillis - previousLCDMillis > interval2) {
langCycle++;
lcd.setCursor (6, 0);
lcd.print(" "); //delete the old text - DOES NOT WORK
previousLCDMillis = currentLCDMillis;
}
lcd.setCursor (6, 0);
lcd.print(languages[langCycle]);
if (langCycle == 3) {
langCycle = 0;
}
}
Of course, complete code, where lcd.print(" "); won't delete old text :
#include <Wire.h>
#include <LiquidCrystal.h> // includes the LiquidCrystal Library
LiquidCrystal lcd(32, 30, 28, 26, 24, 22);
//LiquidCrystal lcd_name(rs, en, d4, d5, d6, d7);
int previousLCDMillis = 0; //set first old time to 0
void setup() {
//My LCD was 16x2
lcd.begin (16, 2);
lcd.home(); // go home
}
void loop() {
//bunch of other stuff here
kalba();
}
void kalba() {
//function telling users they should select the language
//four languages should switch between with the delay of 2 sec.
unsigned long currentLCDMillis = millis(); //check current time
unsigned long interval2 = 2000;
static unsigned long previousLCDMillis = 0; //set first old time to 0
String languages[4] = {"Kalba?", "Language?", "Runa?", "Y3Ik?"};
int langCycle = 0; //cycle is 0, it is used and waits for millis to hit 2000
if (currentLCDMillis - previousLCDMillis > interval2) {
langCycle++;
lcd.setCursor (6, 0);
lcd.print(" "); //delete the old text - DOES NOT WORK
previousLCDMillis = currentLCDMillis;
}
lcd.setCursor (6, 0);
lcd.print(languages[langCycle]);
if (langCycle == 3) {
langCycle = 0;
}
}
You are writing to the LCD every time that function is called, and only erasing text every two seconds. Immediately after you erase, you write new data, so it's hard to understand why you think that writing spaces isn't erasing data.
PaulS:
langCycle is better, but it still isn't static.
You are writing to the LCD every time that function is called, and only erasing text every two seconds. Immediately after you erase, you write new data, so it's hard to understand why you think that writing spaces isn't erasing data.
But I need langCycle to be dynamic, no? I should be able to switch between languages[4].
[edit] Also langCycle++; doesn't work it seems. Serial.print shows 0 all along.
if (currentLCDMillis - previousLCDMillis > interval2)
Which of the two different variables named previousLCDMillis is this checking ?
The global one or the local one ?
Local one. Serial.println(currentLCDMillis - previousLCDMillis); shows values 0-2000ish and reseting.
Thanks PaulS, now it works.
#include <Wire.h>
#include <LiquidCrystal.h> // includes the LiquidCrystal Library
LiquidCrystal lcd(32, 30, 28, 26, 24, 22);
//LiquidCrystal lcd_name(rs, en, d4, d5, d6, d7);
int previousLCDMillis = 0; //set first old time to 0
void setup() {
//My LCD was 16x2
lcd.begin (16, 2);
lcd.home(); // go home
Serial.begin(9600);
}
void loop() {
//bunch of other stuff here
kalba();
}
void kalba() {
//function telling users they should select the language
//four languages should switch between with the delay of 2 sec.
unsigned long currentLCDMillis = millis(); //check current time
unsigned long interval2 = 2000;
static unsigned long previousLCDMillis = 0; //set first old time to 0
String languages[4] = {"Kalba?", "Language?", "Runa?", "Y3Ik?"};
static int langCycle = 0; //cycle is 0, it is used and waits for millis to hit 2000
if (currentLCDMillis - previousLCDMillis > interval2) {
langCycle++;
lcd.setCursor (6, 0);
lcd.print(" "); //delete the old text - DOES NOT WORK
previousLCDMillis = currentLCDMillis;
}
lcd.setCursor (6, 0);
lcd.print(languages[langCycle]);
// Serial.println(langCycle);
// Serial.println(currentLCDMillis - previousLCDMillis);
if (langCycle == 4) {
langCycle = 0;
}
}
I suggest that you get rid of the global one as its only purpose is to confuse anyone reading the code.
You have to be very careful when you have variables with the same name in different scopes, particularly when one of them has global scope. For instance, look at this program
I don’t recall ever making that mistake in C. In the industrial computers I work with daily, the local scope takes precedent. Usually it gets interesting when the OIT display doesn’t match the variable in the subroutine. The OIT programs default to the global variables. Several hours after you notice the difference is when you realize you have a local and a global variable of the same name.
Let the OP stew on the issue for while and then post up what happens in C/C++.
UKHeliBob:
Again, before running it can you predict what it will print ?
I would guess first sketch will print millis() and the second - a bunch of zeros?
[after running it] WRONG, other way around.
Yes, now I have no global, seems now everything is working fine.
I will need some custom characters, since this LCD does not support cyrillic alphabet.
code without global:
#include <Wire.h>
#include <LiquidCrystal.h> // includes the LiquidCrystal Library
LiquidCrystal lcd(32, 30, 28, 26, 24, 22);
//LiquidCrystal lcd_name(rs, en, d4, d5, d6, d7);
void setup() {
//My LCD was 16x2
lcd.begin (16, 2);
lcd.home(); // go home
Serial.begin(9600);
}
void loop() {
//bunch of other stuff here
kalba();
}
void kalba() {
//function telling users they should select the language
//four languages should switch between with the delay of 2 sec.
unsigned long currentLCDMillis = millis(); //check current time
unsigned long interval2 = 2000;
static unsigned long previousLCDMillis = 0; //set first old time to 0
String languages[4] = {"Kalba?", "Language?", "Runa?", "Yazyk?"};
static int langCycle = 0; //cycle is 0, it is used and waits for millis to hit 2000
if (currentLCDMillis - previousLCDMillis > interval2) {
langCycle++;
lcd.setCursor (6, 0);
lcd.print(" "); //delete the old text - DOES NOT WORK
previousLCDMillis = currentLCDMillis;
}
lcd.setCursor (6, 0);
lcd.print(languages[langCycle]);
if (langCycle == 4) {
langCycle = 0;
}
}
Don't use String™. It can cause hangs and crashes at random times, especially when your program runs for a long time, or when you add features to your program. You don't even use String methods on those constants. Simply change the languages array declaration to this:
The LCD print doesn't have to change. It can print char *, too:
lcd.print(languages[langCycle]);
Arrays of characters are much more efficient than using the String class. They are also called "C strings" (note the lowercase "string").
If you have questions about how to do something with C strings, just ask. There are many C string functions to choose from. The complete list of functions is here, and some tutorials are here and here. Good alternative reference here.
Don't use String™. It can cause hangs and crashes at random times, especially when your program runs for a long time, or when you add features to your program.
Thank you! I thought String/string should be avoided only in high complexity programs (not a silly one like mine:)). Changed it to const char *. Works fine! Should it be const char * languages[4]? (with a space before the name I guess?)
Thanks again, apparently it is quite easy to change these data types.
If you ever change the languages array, you don't have to change all the places you used a 4. The constant and the array dimensions will automatically be adjusted to match the number of language strings you put between the {} braces.
Yup, I still like to hardcode :/// In this case it was because I knew I will change the last language to cyrillic alphabet made out of custom characters.
Probably this last part could be smarter.
void kalba() {
//function telling users they should select the language
//four languages should switch between with the delay of 2 sec.
unsigned long currentLCDMillis = millis(); //check current time
unsigned long interval2 = 2000;
static unsigned long previousLCDMillis = 0; //set first old time to 0
const char *languages[] = {"Kalba?", "Language?", "Valoda?", ""};
static int langCycle = -1; //I want to increment it only AFTER it has been used the first time
const size_t MAX_LANG = sizeof(languages) / sizeof(languages[0]);
if (currentLCDMillis - previousLCDMillis > interval2) {
langCycle++;
lcd.setCursor (6, 0);
lcd.print(" "); //delete the old text
previousLCDMillis = currentLCDMillis;
if (langCycle == MAX_LANG - 1) {
yazik();
}
if (langCycle == MAX_LANG) {
langCycle = 0;
}
}
lcd.setCursor (6, 0);
lcd.print(languages[langCycle]);
}
//russian language made out of custom chars
void yazik() {
lcd.setCursor (6, 0);
lcd.write((byte)2);
lcd.print("3");
lcd.write((byte)3);
lcd.print("IK?");
}