My code is the same thing.
The % is a modulo.
%500 is update every half sec
%250 is uparte every quarter spec
The image I posted above shows how it looks when it updates every ms.
By skipping millis()/1000, I don't truncate the milliseconds.
Your code and what Don suggested are not the same thing.
The code Don suggests updates the display as fast as possible but only changes the value being updated/written to the display updates at most once per second.
The timing of the code in loop() does not matter.
Your code is attempting to detect a time interval based on looking at the millis() value.
to decide when to run code to update the display.
If that code happens to catch the millis counter value when it is EXACTLY an even multiple of the modulo value the update code is run.
This is not guaranteed to happen every interval of time unless the code can look at the millis value more often than once/ms.
The timing of the code in loop() very much matters.
It is not possible to update the display every ms.
The LiquidCrystal code simply cannot update the display that fast with the output you are creating.
Here is the details of the timing problem: (numbers assume a 16Mhz AVR)
The current LiquidCrystal library on IDE 1.8.5 takes 285us to send a single byte to the display.
The older LiquidCrystal library on pre 1.6.6 takes 353us to send a single byte to the display.
Your display update code sets the cursor position then prints a number:
To set the cursor position, you have to send a byte to the display.
Then there is a byte for each printed digit.
Even if you are using IDE 1.8.5 as soon as the millis() number is larger than 999 (bigger than 3 digits) the amount of time to set the cursor and print the millis() number is going to be more than 1ms.
285us + 3 * 285us = 1.140ms
And this is just the overhead to send the bytes, and does not include any other overhead like the Print class code to form the digits or the other loop() code or the code outside of loop() that calls loop().
As the millis() number gets more digits the timing extends even more.
If the modulo code is attempting to update the display more often than the amount of time it takes to update the display it obviously won't work as expected.
I think before you go too much further, I think it would be good to show us how you have hooked up your contrast pin on the LCD module.
All you said was:
I used a 1500Ω resistor to limit contrast.
That doesn't fully tell us how you hooked it up.
In the larger picture, trying to update the display every ms with a value that changes every ms makes no sense.
Even if it was possible to update the the display that fast, the human eye takes several 10s of ms to be able to see something. So the lower digits would just be a blur.
And then there is the actual time it takes the liquid crystal liquid in the LCD to actually flip the molecules to change a pixel.
Some of these low cost LCDs can take many 10s of ms up to 100+ms to fully flip pixels.
So depending on what the code is doing, the speed of the liquid crystal, and the temperature, you can potentially see some ghosting.
That said, a slow liquid Crystal liquid may not be your only issue.
The issue can be aggravated by how you are updating the display, how often what is being written to the display is changing, as well as our own eyes.
i.e. it can take as long as 50ms for the "pixels" inside our eyes to fade.
Now if you say you see ghosting if you set your modulo value to 1000 or 500.
Then you have a slow LCD display or you have some kind of contrast control issue.
The LCDs I have are cheap LCDs off ebay, and you definitely can see the that the liquidCrystal takes a bit of time to flip pixels. It is perhaps not quite a quarter second.
So if even if you are displaying something that is only changing once per second, if you look really closely, you can see a bit of overlap as the pixels change from one digit to another.
I notice these effects much more on the reverse displays (dark background with light pixels).
I'm guessing that this may be because the persistence of vision inside the eye. So the brain perceives the and senses old pixels as still being on just a bit longer then they actually are which contributes to the issue.