LCD catching noise ?

I'm rather new to electronics and Arduino.
I fear it's a generic question and rather basic, and not really LCD specific, so I put it here.

I've got an Arduino UNO and a 20x2 LCD Display (Epson EA-D20025AR = Hitachi LM032L = HD44780) connected via a 30 cm (1 ft) flat cable with GND, 5V, RS, E, D4 .. D7 from the LCD to the Arduino (GND and 5V go to a breadboard, where I also added a 47µF cap)
RW is connected to GND at the LCD, and the contrast pin is wired to a pot between LCD pin1 and pin2 (0V / 5V) next to the LCD module as well.
I'm using the LiquidCrystal library, and in general, all works well.
If there's nothing else than described above, my sketch runs for days, proving that millis() on my Arduino is wrong by about 0.1 % (a minute per day)

Goal is not to check this by watching myself, but compare it with pulses derived from mains ( 50Hz in Europe ) , which I get via an optocoupler, whose emitter is tied to GND and the collector is fed via 4.7k from 5V. When looking at the collector signal via analogRead(), it's nearly square between 5V and 0.5V
Connecting it to pin2 (next to pins 4... feeding the LCD), it works fine for a while, but suddenly (typically when I leave it alone after a few minutes) the LCD displays garbage in locations where I nerver write anything, and Arduino needs a reset to recover.

I'm pretty sure the optocoupler is wired correctly, provides a galvanic separation, so I fear this low power lcd module (2mA ?) is rather sensitive catching noise from the air? Is that possible/normal?
Is it ok to leave LCD D0..D3 unconnected?
Do I need a shielded cable? Pull down lcd signals?

In my use case, I do not read back from the LCD, thus all Arduino pins should be outputs always.
How can the arduino sketch itself be affected?
In an additional test I added a blink output to pin13, which sometimes stops as well until reset ???

edits: just spelling

Try running more ground wires parallel to the ribbon cable, and ground any unused wires in it, also add a 4k7 resistor from Arduino reset to +5V to make that more robust to noise. Keep the flat cable away from mains wiring...

Post your code and connection pictures. What you may have overlooked could have caused the problem besides some suspected interference.

Here's my code: repeating tests, I think something happens after about about 10 minutes (32768 external pulses?)
Probably you find it faster than me, liudr.

@MarkT:
The code stops blinking, and triggering pin3 does not help any more then.
But pressing reset helps. It does not harm, but I do not see how pulling up RESET might help in my case.
Is there a way how external noise might "halfway" triggers a reset ?
IMO such noise either resets or it does not ( in my case it never restarted counting by itself )

#include <LiquidCrystal.h>
#include <stdio.h>
#define LED 13

#define HOURS   (50*60*60)
#define MINUTES (50*60)
#define SECONDS 50
#define TENTHS  5

// initialize the library with the numbers of the interface pins
LiquidCrystal lcd(9, 8, 4,5,6,7);

volatile unsigned long pulses;

void setup() {
  pinMode(LED,OUTPUT);

  pinMode(2, INPUT);
  digitalWrite(2, LOW);  // external pullup, reading open collector 
  pinMode(3, INPUT);
  digitalWrite(3, HIGH);  // with pullup, connect to GND for function 

  digitalWrite(LED, LOW);  

  // set up the LCD's number of columns and rows:
  lcd.begin(20, 2);

  pulses = millis()/20; // sync
  attachInterrupt(0, puls,FALLING);  // pin 2 = optocoupler collector, no signal = HIGH

  digitalWrite(LED, HIGH);  

}

void puls() {
  pulses++;
}

unsigned long lastm;

byte si;
byte mi;
byte hi;

char* itime = "00:00:00";

byte te;
byte se;
byte me;
byte he;
char* etime = "00:00:00.0";


void loop() {
  unsigned long curtime = millis();
  if (digitalRead(3) == LOW) {
    // --- let's hope this helps ---
    // set up the LCD's number of columns and rows:
    lcd.begin(20, 2);
    lcd.write("RESET");
    delay(100);
  }
  else if (curtime - lastm  > 1000) 
  {
    lastm += 1000;
    if (++si ==60)
    {
      si=0;
      if (++mi == 60)
      {
        mi = 0;
        if (++hi == 24) {
          hi = 0;
        }   
      } 
    }
    sprintf(itime, "%02u:%02u:%02u", hi,mi,si);

    lcd.setCursor(0, 0);
    // print the internal time since reset:
    lcd.print(itime);

    digitalWrite(LED, si & 0x01); // blink: odd seconds = HIGH  

    noInterrupts();
    he = pulses /  HOURS;
    unsigned long pm = pulses - he*HOURS;
    interrupts();

    me = pm / MINUTES;
    unsigned long ps = pm - me*MINUTES;
    se = ps/SECONDS; 
    unsigned int te =(ps - se*SECONDS)/ TENTHS;  
    sprintf(etime, "%02u:%02u:%02u.%1u", he,me,se,te);
    lcd.setCursor(0, 1); // second row
    lcd.print(etime);

  }    

}

<don't use the IDE function "Copy for Forum", or you have to remove lots of color tags :wink: >

#define HOURS (506060)

This def is your source of trouble. Find a calculator and see if this number fits in an integer.

And again it's -- partially -- in the wrong forum:
Removing the previous "unsigned long to bytes" arithmetics makes my code survive 506012 pulses ( 12 minutes ), still going strong - with some tinfoil wrapped around the cable connected to GND and a 4k7 resistor between RESET and 5V.

Don't know where the programming error is, nor why it behaves so bad.
Sure 506060 does not fit into an int16, but cannot Arduino do unsigned long arithmetics ?

I simply adapted the way I used for the millis() part:

...
digitalWrite(LED, si & 0x01); // blink: odd seconds = HIGH

noInterrupts();
tmp = pulses;
interrupts();

while ( (tmp-lastp) >= TENTHS )
{
lastp += TENTHS;
if(++te == 10)
{
te=0;
if (++se == 60)
{
se=0;
if (++me == 60)
{
me = 0;
if (++he == 24)
{
he = 0;
}
}
}
}
}
sprintf(etime, "%02u:%02u:%02u.%1u", he,me,se,te);
lcd.setCursor(0, 1); // second row
lcd.print(etime);

}

}

Thanks for the hints, which at least don't harm, and triggered me to have a closer look at my "simple" but bad code.
BTW: My 50Hz clock is very accurate !

The trick is to tell the precompiler the right number in the right data type. By default the precompiler uses sigend integer. To force it to use unsigned long (which is necessary), just do:

#define HOURS 180000L

And don't use the (506060) again since I don't think you fully understand how pre-compile processes work.

but cannot Arduino do unsigned long arithmetics ?

It can but only if you tell it to.

liudr:
And don't use the (506060) again since I don't think you fully understand how pre-compile processes work.

:wink: I know the brackets are (or at least: might be ) required. The rest I leave to the preprocessor and compiler to optimize. In general 506060 is more understandable than 180000. Is 180000L different to 180000 ( without producing a compiler error ?) ...perhaps I'm a bit spoiled by 64 bit environments ...

Are you sure that

volatile unsigned long pulses;
//...
 byte he = pulses / (50*60*60);

is different to
byte he = pulses / 180000L;

??? ( Shouldn't both do long arthmetics ?)

What about

#define PULSESPERSECOND 50L
#define MINUTES (PULSESPERSECOND60)
#define HOURS (MINUTES
60)
...
byte he = pulses / HOURS;
unsigned long pm = pulses - he*HOURS;

And my really frightening question: how can, whatever the compiler produces, this make the arduino hang as soon as pulses > 0x00008000L ???

So, it's not just misunderstanding pre-compiler directives then.

 byte he = pulses / (50*60*60);

Everything in the parentheses will be treated as signed integer literal and the calculation carries on even if the result overflows.

byte he = pulses / 180000L;

The pulses is converted to long and the operation yields correct result, then the result is converted into byte type, regardless if it overflows byte.

I don't think 64-bit operation spoils anyone. You just don't know data types as well as C/C++ requires you to know. These explanations are supposed to be the first few chapters of C, even before conditionals and loops. Did you come from a loose data type programming background like java, java script or some other scripting language or maybe matlab? You need basic reading on data types.

Hi liudr,
nice to start a small chat in the wrong forum. ( Luckily I added "LCD" in the topic to catch your attention : )

My background is FORTRAN programming , then assembler of a machine that does not exist any more
(AEG 80-20 with instructions like LIH(R0,1000H) standing for Load Immediate Halfword, which puts 16 bits into a register )
After the C compiler for this machine was working, it died.

Now I'm doing Java and C#, and have enough c++ knowledge to think it's made for masochists, if it's about smart pointers, templates and such stuff :wink:
In reality, I'm a bit older than my avatar ...
For my new Arduino, I think the "enhanced c" (with "class", but without "new" keyword and destructors) is just fine. It's nice to fall back to good old <stdio.h>

liudr:
So, it's not just misunderstanding pre-compiler directives then.

byte he = pulses / (50*60*60);Everything in the parentheses will be treated as signed integer literal and the calculation carries on even if the result overflows.

byte he = pulses / 180000L;The pulses is converted to long and the operation yields correct result,

As you seem to not be offended to easily :wink: : did you consider the unsigned long pulses; declaration ? Shouldn't any expression involving a long "yield the correct result" , even in the first case?
And if ((506060) != 180000L) why doesn't the compiler tell me ?

Now that my suspected hardware problems disappeared 8) , I can experiment a bit on that...

And if ((506060) != 180000L) why doesn't the compiler tell me ?

Because the compiler warnings are suppressed in the arduino IDE in an effort not to frighten newcomers.

Grumpy_Mike:
... effort not to frighten newcomers.

Yes, I remember I was fascinated getting my first blink sketch running immediately.

Making easy things even easier has its downsides.

Thanks for the reply!

Any comment on how such a bug sends garbage to the LCD and freezes the Arduino ?
(The really frightening thing at runtime after minutes of operation)

Any comment on how such a bug sends garbage to the LCD and freezes the Arduino

Well not really but I suspect it was the most significant bit of some variable being set that caused a long loop to be executed or a loop waiting for a condition that could not be fulfilled.

You know that computers never actually freeze, they just get stuck somewhere executing instructions in a loop. Remember a 1 second loop executed -1 times (0xFFFF) will take over 18 hours to complete, so it might look like a freeze but it isn't.

Data type conversion only happens when mismatched data are supplied in one operation, not proactively as you may think. So with order of operation telling the machine to do 506060 first, there were no mismatched data types and the calculations were done with integers and overflow happens. Then with pulses, the overflown integer is converted into long, at which point it was too late. The following are all correct:
50L6060
5060L60
506060L

As Mike said, your dressing is due to this overflow. Maybe more overflow happens but fix this first.