Scroll a text on LCD 16x1

Hello everyone,
(I do not know if I published in the good section)

Being a beginner with Arduino, I started learning to use LCD screen.

Following tutorials I learned to just display a text, make it blink .. (for 16x1 since I have only that for the moment).

However, I try for a few days to scroll my text from left to right and from right to left but I only fall on tutos for 16x2, so I simply copied pasted the code that is on this site to try to to change two things so that the text scrolls correctly but without success, the text is cut in half and scrolls in offset.

So I would like an explanation to be able to scroll correctly on my 16x1.

Here is the code I use but which is obviously not the right one to scroll on a 16x1:

 #include <LiquidCrystal.h> // we import the library
LiquidCrystal lcd (12,11,5,4,3,2); // create the screen object

void setup () {
 // set up the LCD's number of columns and rows:
 // A 1x16 Line display is addressed as 2x8
 lcd.begin (8, 2);
 // Print a message to the LCD.
 lcd.print ("Hello a");
 // Move the cursor to the beginning of the second address block
 // (note: line 1 is the second row, since counting begins with 0):
 lcd.setCursor (0, 1);
 lcd.print ("all!");
}

void loop () {

// scroll 13 positions (string length) to the left
 // to move it offscreen left:
 for (int positionCounter = 0; positionCounter <13; positionCounter ++) {
   // scroll one position left:
   lcd.scrollDisplayLeft ();
   // wait a bit:
   delay (150);
 }

 // scroll 29 positions (string length + display length) to the right
 // to move it offscreen right:
 for (int positionCounter = 0; positionCounter <29; positionCounter ++) {
   // scroll one position right:
   lcd.scrollDisplayRight ();
   // wait a bit:
   delay (150);
 }

 // scroll 16 positions (display length + string length) to the left
 // to move back to center:
 for (int positionCounter = 0; positionCounter <16; positionCounter ++) {
   // scroll one position left:
   lcd.scrollDisplayLeft ();
   // wait a bit:
   delay (150);
 }

 // delay at the end of the full loop:
 delay (1000);

}

Hoping to have been clear in my post,

Thank you.

// set up the LCD's number of columns and rows:
 // A 1x16 Line display is addressed as 2x8

why?

This type of display treats the first 8 characters (left half) as first line(Address 0x80) and the last 8 characters (right half) as second line(Address 0xC0).

Go on. You have a tiny display. Just store your complete sentence in a buffer.

Then choose the required start position in the sentence. Print the next 8 letters in columns 0-7. And the next 8 letters in columns 8-15.

Since a 16x1 is normally treated as line#0 col 0-7 and line#1 col 0-7 you use the lcd_gotoxy() to select the print column.

A 16x2 can conveniently scroll by using the cursor shift commands. A 16x1 is easier to just print 16 letters at a time. Scrolling is achieved by altering the start position in your buffer.

David.

thank you very much,
I think we have the solution soon,
but since i am french and i have to translate your answer with google translation i have a little trouble applying what you tell me, can you write it to me in code form?
thanks again..

I had issue with 16x1 LCD and asked a few months ago because it was behaving like 2x8 on one line and I had trouble getting the display to show correctly. 16x1 LCD not working as expected? - Displays - Arduino Forum Post #5 has the best answer for me.

The summary is that standard liquid crystal library sucks for 1x16 displays. Use Arduino's library manager to add hd44780 library, and try using that instead of liquid crystal library. Set your display sketch to 2x8 and it will display correctly on a 1x16 display with no messy gap, line splitting, or manual wrapping.

I understand absolutely nothing,

can you give me a code that can scroll a text on my 16x1 display.

thank you very much

wilykat:
Use Arduino's library manager to add hd44780 library, and try using that instead of liquid crystal library. Set your display sketch to 2x8 and it will display correctly on a 1x16 display with no messy gap, line splitting, or manual wrapping.

However....
While the hd44780 will allow you to write to this type of 1 line 8x2 display as if it were really a 16x1 display,
scrollDisplayRight() and scrollDisplayLeft() will not work as expected.
This is because the library does not do the actual shifting, the shifting is being handled by the hd44780 chip.
Even though the LCD is physically a 16x1 display it is hooked up the hd44780 chip as a 8x2 display.
So when a shift is done, both lines are shifted, which will cause each half of the 16x1 display to be shifted, which is more than likely not what is wanted.

When using this type of type of display, you cannot use the scrollDisplayxxx() functions.
To shift the display you will have to do it in s/w in the sketch using a buffer.

I'll add a note to all the hd44780 library LineWrap examples to explain this limitation.
It will be in the next release of the library.

--- bill

/*
  LiquidCrystal Library - Hello World

 Demonstrates the use a 16x2 LCD display.  The LiquidCrystal
 library works with all LCD displays that are compatible with the
 Hitachi HD44780 driver. There are many of them out there, and you
 can usually tell them by the 16-pin interface.

 This sketch prints "Hello World!" to the LCD
 and shows the time.

  The circuit:
 * LCD RS pin to digital pin 12
 * LCD Enable pin to digital pin 11
 * LCD D4 pin to digital pin 5
 * LCD D5 pin to digital pin 4
 * LCD D6 pin to digital pin 3
 * LCD D7 pin to digital pin 2
 * LCD R/W pin to ground
 * LCD VSS pin to ground
 * LCD VCC pin to 5V
 * 10K resistor:
 * ends to +5V and ground
 * wiper to LCD VO pin (pin 3)

 Library originally added 18 Apr 2008
 by David A. Mellis
 library modified 5 Jul 2009
 by Limor Fried (http://www.ladyada.net)
 example added 9 Jul 2009
 by Tom Igoe
 modified 22 Nov 2010
 by Tom Igoe

 This example code is in the public domain.

 http://www.arduino.cc/en/Tutorial/LiquidCrystal
 */

// include the library code:
#include <LiquidCrystal.h>

// initialize the library with the numbers of the interface pins
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);

void setup() {
  // set up the LCD's number of columns and rows:
  lcd.begin(16, 2);
  // Print a message to the LCD.
  //lcd.print("hello, world!");
}

void loop() {
  // set the cursor to column 0, line 1
  // (note: line 1 is the second row, since counting begins with 0):
  
  lcd.setCursor(0, 0);
  lcd.print("hello, W");
  lcd.setCursor(0, 1);
  lcd.print("orld! ");
  delay(2000);
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("this is ");
  lcd.setCursor(0, 1);
  lcd.print("a lenght");
  delay(2000);
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("test! ");
  lcd.setCursor(0, 1);
  delay(1000);
  lcd.clear();
 
 
  // print the number of seconds since reset:
  lcd.print(millis() / 1000);
}

here is an example of how you would go about making an autoscroll in a 1x16
you just clear the thing and put In the new text (make sure you have the delays otherwise it will start spouting nonsense)

Otrack:
I understand absolutely nothing,

can you give me a code that can scroll a text on my 16x1 display.

thank you very much

Here you go. The data is written first to the left half of the LCD at the designated starting position and then again to the right half of the LCD but shifted by eight positions. This gives the illusion of a continuous 16X1 LCD which can store up to 40 characters. The regular left and right shift commands will work with this.

*Edited so it compiles. Pinout config is for an Arduino Nano

// Configure pinout of board
#define ENABLE_PORT PORTB
#define ENABLE_DDR  DDRB
#define ENABLE_BIT  0 // D8 on Nano

#define RS_PORT     PORTB
#define RS_DDR      DDRB
#define RS_BIT      2 // D10 on Nano

#define D0_PORT     PORTD
#define D0_DDR      DDRD
#define D0_BIT      0 // D0 on Nano

#define D1_PORT     PORTD
#define D1_DDR      DDRD
#define D1_BIT      1 // D1 on Nano

#define D2_PORT     PORTD
#define D2_DDR      DDRD
#define D2_BIT      2 // D2 on Nano

#define D3_PORT     PORTD
#define D3_DDR      DDRD
#define D3_BIT      3 // D3 on Nano

#define D4_PORT     PORTD
#define D4_DDR      DDRD
#define D4_BIT      4 // D4 on Nano

#define D5_PORT     PORTD
#define D5_DDR      DDRD
#define D5_BIT      5 // D5 on Nano

#define D6_PORT     PORTD
#define D6_DDR      DDRD
#define D6_BIT      6 // D6 on Nano

#define D7_PORT     PORTD
#define D7_DDR      DDRD
#define D7_BIT      7 // D7 on Nano

void setup() {
  // Set Ouputs
  bitWrite(ENABLE_DDR, ENABLE_BIT, 1);
  bitWrite(RS_DDR, RS_BIT, 1);
  bitWrite(D0_DDR, D0_BIT, 1);
  bitWrite(D1_DDR, D1_BIT, 1);
  bitWrite(D2_DDR, D2_BIT, 1);
  bitWrite(D3_DDR, D3_BIT, 1);
  bitWrite(D4_DDR, D4_BIT, 1);
  bitWrite(D5_DDR, D5_BIT, 1);
  bitWrite(D6_DDR, D6_BIT, 1);
  bitWrite(D7_DDR, D7_BIT, 1);
  
  delay(1);
  
  // Initialize LCD
  writeLCDcmd(0b00111000);  // Function Set: B(0, 0, 1, 8/4 bit*, 2/1 lines*, 5x11/5x8*, -, -) 1/0*
  writeLCDcmd(0b00001100);  // Display Control: B(0, 0, 0, 0, 1, Display ON/OFF*, Cursor ON/OFF*, Blinking ON/OFF*)
  writeLCDcmd(0x01);        // Clear Display
  
  // Write string and starting position of string to LCD
  writeLCDstring("Here's Johnny!", 1);
}

void loop() {
  delay(500);
  writeLCDcmd(0b00011000); // Shift characters to left
}

void writeLCDchar(uint8_t data) {
  bitWrite(RS_PORT, RS_BIT, HIGH);
  delayMicroseconds(1);
  bitWrite(ENABLE_PORT, ENABLE_BIT, HIGH);
  bitWrite(D0_PORT, D0_BIT, (data & 1));
  bitWrite(D1_PORT, D1_BIT, (data & 2)); // any number other than 0 is true for boolean
  bitWrite(D2_PORT, D2_BIT, (data & 4));
  bitWrite(D3_PORT, D3_BIT, (data & 8));
  bitWrite(D4_PORT, D4_BIT, (data & 16));
  bitWrite(D5_PORT, D5_BIT, (data & 32));
  bitWrite(D6_PORT, D6_BIT, (data & 64));
  bitWrite(D7_PORT, D7_BIT, (data & 128));
  delayMicroseconds(1);
  bitWrite(ENABLE_PORT, ENABLE_BIT, LOW);
  delayMicroseconds(40); // https://focuslcds.com/content/C161BXBSYN06WT05XAA1_Spec.pdf
}

void writeLCDcmd(uint8_t data) {
  bitWrite(RS_PORT, RS_BIT, LOW);
  delayMicroseconds(1);
  bitWrite(ENABLE_PORT, ENABLE_BIT, HIGH);
  bitWrite(D0_PORT, D0_BIT, (data & 1));
  bitWrite(D1_PORT, D1_BIT, (data & 2)); // any number other than 0 is true for boolean
  bitWrite(D2_PORT, D2_BIT, (data & 4));
  bitWrite(D3_PORT, D3_BIT, (data & 8));
  bitWrite(D4_PORT, D4_BIT, (data & 16));
  bitWrite(D5_PORT, D5_BIT, (data & 32));
  bitWrite(D6_PORT, D6_BIT, (data & 64));
  bitWrite(D7_PORT, D7_BIT, (data & 128));
  delayMicroseconds(1);
  bitWrite(ENABLE_PORT, ENABLE_BIT, LOW);
  if (data > 3) {
    delayMicroseconds(40); // https://focuslcds.com/content/C161BXBSYN06WT05XAA1_Spec.pdf
  } else {
    delayMicroseconds(2000); // "Clear Display" (0x01) and "Return Home" (0x02 or 0x03) require more execution time
  }
}

void writeLCDstring(char *Ltext, uint8_t Lstart) {
  if (Lstart < 40) {  // out of range if 40 or greater
   
    // duplicate text pointer for right half of LCD
    char *Rtext = Ltext;
   
    // Set the right start position: 0 to 7 on left is 96 to 103 on right, 8 to 39 on left is 64 to 95 on right
    uint8_t Rstart = Lstart + 96;
    if (Lstart > 7 ) { Rstart = Lstart + 56; }
   
    // write to left half of LCD
    writeLCDcmd(0x80 | Lstart);  // Set cursor position to Lstart
    while (*Ltext > 0 && Lstart < 40) {
      writeLCDchar(*Ltext++);
      Lstart++;
    }
   
    // write to right half of LCD
    writeLCDcmd(0x80 | Rstart);  // Set cursor position to Rstart
    do {
      writeLCDchar(*Rtext++);
      Rstart++;
      if (Rstart == 104) {
        Rstart = 64;
        writeLCDcmd(0x80 | Rstart);  // Set cursor position to Rstart
      }
    } while (*Rtext > 0 && Rstart != 96);
  }
}

After two years and three months, do you think he is still expecting an answer? :roll_eyes:

Paul__B:
After two years and three months, do you think he is still expecting an answer? :roll_eyes:

No. The next person who has this problem will find it useful though. :wink: