Go Down

Topic: Combination of LCD 1602 and Serial.Print (Read 1 time) previous topic - next topic

psman

Hello!

I'm beginner in using Arduino and so I still do have more problems to be solved than ideas... Hopefully you can give me some hints?

For a small project, I do check the Signal in digital Port 2 of my Arduino Uno.
Port 6 is set as Output to supply a second Arduino.
The Signal is processed, some values are calculated. These values are sent to my notebook via serial.print.

I do not want to take my notebook with me all the time, so I want to use a LCD for printing the most important values. Because of that I connected a 1602aV2-LCD to the Uno (like described at http://www.dreamdealer.nl/tutorials/connecting_a_1602a_lcd_display_and_a_light_sensor_to_arduino_uno.html) via Ports 6-12. All the "Hello world" things and tests have been working fine.

Both parts are working fine.

As a next step I want to merge these two projects. To me it seems like if the combination does not work - neither the LCD nor the serial.print does work any more. In addition the second Arduino supplied by Port 6 is shut off as soon as a open the serial-window on my Laptop.

Which additional data would you need, to be able to find a solution?

Thanks in advance,
Christoph

floresta

Quote
In addition the second Arduino supplied by Port 6 is shut off as soon as a open the serial-window on my Laptop.
As I recall when you open the serial monitor the Arduino is reset which restarts your program.  Are you taking this 'feature' into account?


Quote
Which additional data would you need, to be able to find a solution?
It would help to see your program code.

psman

Hello floresta,

thank you very much for your reply! I have not heard before, that the serial monitor could restart the program, in fact this is really happening. This will delay everything, but should not cause any problem.

For data-Acquisition, processing the data and showing it in the serial monitor a shortend example is:
Code: [Select]
unsigned long counts = 0;
unsigned long AlteCounts = 0;
unsigned long AktuelleCounts = 0;
unsigned long AlteMillis = 0;
unsigned long AktuelleMillis = 0;

void setup() {
Serial.begin(9600);
pinMode(2,INPUT);
digitalWrite(2,HIGH);

pinMode(6,OUTPUT);
delay(10000);
digitalWrite(6,HIGH); //starts second Arduino
}

void loop() {
attachInterrupt(0,tube_impulse,RISING);

if(counts >= AlteCounts && millis() >= AlteMillis){
AktuelleCounts = counts;
AktuelleMillis = millis();
Serial.print(AktuelleCounts);
Serial.print(" Counts, ");
Serial.print(AktuelleMillis);
Serial.println(" Zeit");
AlteCounts = counts;
AlteMillis = millis();
};
}

void tube_impulse() {
counts++;
}


I'm using the display with the following code:
Code: [Select]
#include <LiquidCrystal.h>
LiquidCrystal lcd(12, 11, 10, 9, 8, 7);

void setup() {
  lcd.begin(16, 2);
  lcd.print("    Herzlich");
  lcd.setCursor(0,1);
  lcd.print("   Willkommen");
  delay(2000);
  lcd.setCursor(0,1);
  lcd.print("             ");
  lcd.home();
  lcd.print("hello, world!  #");
}

void loop() {
  lcd.setCursor(0, 1);
  lcd.print(millis() / 1000);
}


And my combination would be the following code:
Code: [Select]
unsigned long counts = 0;
unsigned long AlteCounts = 0;
unsigned long AktuelleCounts = 0;
unsigned long AlteMillis = 0;
unsigned long AktuelleMillis = 0;

#include <LiquidCrystal.h>
LiquidCrystal lcd(12, 11, 10, 9, 8, 7);

void setup() {
Serial.begin(9600);
pinMode(2,INPUT);
digitalWrite(2,HIGH);

lcd.begin(16, 2);// This part (4 lines) is still working!!
lcd.print("    Herzlich");
lcd.setCursor(0,1);
lcd.print("   Willkommen");

pinMode(6,OUTPUT);
delay(10000);
digitalWrite(6,HIGH); //starts second Arduino

lcd.clear(); //Clearing the display is working too
}

void loop() {
attachInterrupt(0,tube_impulse,RISING);

if(counts >= AlteCounts && millis() >= AlteMillis){
AktuelleCounts = counts;
AktuelleMillis = millis();

//from now on nothing is working any more :(
lcd.print(AktuelleCounts);
lcd.print(" Aktuelle Counts");

Serial.print(AktuelleCounts);
Serial.print(" Counts, ");
Serial.print(AktuelleMillis);
Serial.println(" Zeit");
AlteCounts = counts;
AlteMillis = millis();
};
}

void tube_impulse() {
counts++;
}



I have shortend these codes and hope, that someone can see my error. Thank you very much!

psman

Hello,

I have inserted a "lcd.home();", and now the display as well as the serial Port are working.

Not I do have two additional questions:
- I do have to print a float-number with 3-5 digits at the left side of the Komma. How can I print the Komma at always the same position of the display, for example (0,5), so that the number is not jumping around?
- How can I disable the reset when opening the serial Window?

Thank you very much for your help!

Paul__B

- I do have to print a float-number with 3-5 digits at the left side of the Comma. How can I print the Comma at always the same position of the display, for example (0,5), so that the number is not jumping around?
That one is a little more complex.  It involves printing spaces from the starting cursor position according to the size of the number.

- How can I disable the reset when opening the serial Window?
You cut the bridge in the "Reset-En" jumper on the board.


floresta

Now we will have to be ready to answer his next question based on the side-effect of cutting that jumper.  Something like 'why am I having trouble downloading sketches'.

Don

cattledog

There are several issues with your code.
1. The variable "count" is changed within the ISR and needs to be declared volatile.
2. attachInterrupt() should be in setup.
3. unchanging parts of the lcd display should be printed in setup.
4. Because "count" it is a multi byte value(non-atomic), when you read it to use in the program, you need to turn  interrupts off, transfer the value to an other variable, and re-enable interrupts to insure that the value doesn't change during the transfer.
5. if(counts >= AlteCounts && millis() >= AlteMillis) There are two problems with this line. First, I don't think you want to update the display every millisecond, and second, the millis() test will not handle roll over. Better to use
if ((AktuelleCounts >= AlteCounts) && (millis() - AlteMillis >= displayInterval))

I have modified your code with the above in mind, and use a 500 millisecond display update.  I have used tone() to generate a 50 hz signal on pin 12 to read with the interrupt on pin 2. Jumper 12 and 2. You can change this for a different frequency if you want faster or slower.

Regarding the issue reset with the serial monitor. I believe you should run the second Arduino with a second instance of the IDE. You can have two independent monitor windows open that way, and they don't interact.

Code: [Select]
#include <LiquidCrystal.h>
LiquidCrystal lcd(12, 11, 10, 9, 8, 7);

volatile unsigned long counts = 0;
unsigned long AlteCounts = 0;
unsigned long AktuelleCounts = 0;
unsigned long AlteMillis = 0;
unsigned long AktuelleMillis = 0;
unsigned long displayInterval = 500;

void setup() {
  Serial.begin(9600);
  pinMode(2, INPUT);
  digitalWrite(2, HIGH);

  lcd.begin(16, 2);
  lcd.print("waiting Pin6");

  pinMode(6, OUTPUT);
  delay(10000);
  digitalWrite(6, HIGH); //starts second Arduino
  
//print unchanging part of display
  lcd.setCursor(0, 0);
  lcd.print("         Counts"); //9 spaces and 6 letters
  lcd.setCursor(0, 1);
  lcd.print("           Zeit"); //11 spaces and 4 letters

  attachInterrupt(0, tube_impulse, RISING);
  tone(12, 50); //connect pin 12 to pin 2 for 50 hz count

  AlteMillis = millis();
}

void loop() {
  noInterrupts();
  AktuelleCounts = counts;
  interrupts();
  
  if ((AktuelleCounts >= AlteCounts) && (millis() - AlteMillis >= displayInterval))
  {
    AlteMillis += displayInterval;
    Serial.print(AktuelleCounts);
    lcd.setCursor(0, 0);
    lcd.print(AktuelleCounts);
    Serial.print(" Counts, ");
    Serial.print(millis());
    lcd.setCursor(0, 1);
    lcd.print(millis());
    Serial.println(" Zeit");
    AlteCounts = AktuelleCounts;
  }
}
void tube_impulse() {
  counts++;
}

psman

Hello again!

Thank you very much for these answers!

@floresta: At the beginning of this thread I did not know anything about reseting the device by opening the serial window. The answers in this thread told me, that I would have to change my hardware to disable this feature, that this could cause problems. So I can look these parts up in the internet myself!

@cattledog: Thank you very much, there are plenty of very helpfull hints in your reply - for example the "volatile"-thing (https://www.arduino.cc/en/pmwiki.php?n=Reference/Volatile) has been new to me!
Point 2: As far as I understood the source codes, the setup is only called once when starting the device. But the code works properly that way. It seems like if the code would remember the interrupt even when we are already in the loop.
Point 3: Is well understandable to me. That way I do only print these letters once.
Point 4: Do you know how fast the disabling and enabling happens? I have seen these commands in the lcd-examples, but have been afraid of loosing to many counts when doing that too often. Would there be any problem if I take these 3 lines (noInterrupt...) into the If-loop? That's the only part where I do copy the value and where I could run into troubles, and I would not have to use the noInterrupt too often?

@Paul__B: As far as I read some threads my only chance is to convert the float into char, check the length and write space characters if necessary (to erase characters I have printed before).

Thank's a lot to all of you!!
Christoph

cattledog

In response to your questions in point 4 as to the issue of protecting the transfer of value of "counts" when read from the ISR. You can't take these lines inside the if loop because one of the conditions for entering the if loop is the change in counts which you need to update.

I understand that the the noInterrupts()/readvalue/Interrupts() code is very quick. I don't know what you plan to do with your counts, or what the number of counts you expect in your program, but if you want to use the value from within an ISR you need to shield it when you read it.

If you only want to update counts every second, you can certainly put the reading of the counts within the current timer loop.

I also made a slight error in the conditional test and it doesn't stop the display when the counts are not increasing. It should be changed to this if you want it stopped when counts don't increase
Code: [Select]
if ((AktuelleCounts > AlteCounts) && (millis() - AlteMillis >= displayInterval))

If you want the update the display and the counts value every interval period you could have
Code: [Select]
if (millis() - AlteMillis >= displayInterval)
{
  noInterrupts();
  AktuelleCounts = counts;
  interrupts();

//do whatever to display or use the value
}


You can also put the update of the display and the update of the counts of two different millis() timers.

psman

Thank you very much cattledog, and to all the others too - you have been helping me very much!!

Kind regards,
Christoph

Go Up