Skip to main content

4.2. Autoscroll text

Under construction
Short example demonstration video

Here we will explore how we can use the autoscrolling feature on LCD to scroll text to the left to display text that otherwise wouldn't be able to fit in one line.

At the end of this example you will learn:

  • How to use autoscrolling feature
  • How to use hardware based interrupts
  • How to use timer based interrupts
ℹ️

Parts required:

  • Soldered NULA Mini Board
  • Breadboard
  • 16x2 LCD Display
  • 1 x Pushbutton
  • 1 x Qwiic cable
  • Some jumper wires
Under construction
Required components

Putting the components together

  • Place the first pushbutton on the breadboard, connect one side of the terminal to pin 5, and the other opposite side to GND.
  • Place the second pushbutton on the breadboard, connect one side of the terminal to pin 4, and the other opposite side to GND.
  • Connect the LCD via Qwiic cable to the NULA Mini board
Under construction
Components connected together

Code Example

Import LCD driver with other necessary modules.

from LCD import LCD_I2C
from machine import I2C, Pin, Timer
import time

Set up I2C connection with LCD display, define the button pins and set them to PULL_UP so they read HIGH (1) while not pressed.

i2c = I2C(0, scl=Pin(7), sda=Pin(6))
lcd = LCD_I2C(i2c)

BUTTON_A_PIN = 4
BUTTON_B_PIN = 5

btn_A = Pin(BUTTON_A_PIN, Pin.IN, Pin.PULL_UP)
btn_B = Pin(BUTTON_B_PIN, Pin.IN, Pin.PULL_UP)

Turn on the backlight of the LCD and start communication over I2C.

lcd.backlight()
lcd.begin()

Print initial message on the display, pause the program for 2 seconds and clear the display.

lcd.setCursor(0, 0)
lcd.print("Button A PAUSE")
lcd.setCursor(0, 1)
lcd.print("Button B RESUME")

time.sleep(2)
lcd.clear()

Define the text you want to display. Set global flags paused to control program running state and tick for timer interrupts.

sentence = "Autoscrolling example "

paused = False
tick = False

# Debounce time
DEBOUNCE_MS = 30

# Last pressed time for buttons A and B
last_A = 0
last_B = 0

This is the interrupt handling function which will be triggered every time one of the buttons was pressed. The job of this function is to set the global paused flag which stops/resumes autoscrolling action. With interrupts, the microcontroller stops the execution of the main program to perform a task, this way we eliminate the need to constantly check the pin values. When a change is detected, trigger an event (call a function). The interrupt handling function should be as simple as possible (like setting a global variable) so that the processor can get back to the execution of the main program quickly.

def irq_handler(pin):
# Use global ('outside') variables to change the values outside the function
global paused, last_A, last_B
# Get current time in ms
now = time.ticks_ms()
# Check if button A was pressed
if pin is btn_A:
if time.ticks_diff(now, last_A) > DEBOUNCE_MS:
# Update last pressed time for button A
last_A = now
# Update paused state
paused = True
# Button B pressed
else:
if time.ticks_diff(now, last_B) > DEBOUNCE_MS:
# Update last pressed time for button B
last_B = now
# Update paused state
paused = False

Interrupt callback function triggered by timer, set to trigger every 0.3 seconds.

def on_tick(t):
# Use global 'tick' variable
global tick
# Update tick state
tick = True

Here we attach interrupts to pins on which pushbuttons are connected, this is done with irq() method which accepts these arguments:

  • trigger: defines one of 3 different trigger modes:
    • Pin.IRQ_FALLING: set to trigger the interrupt when the pin goes from HIGH to LOW
    • Pin.IRQ_RISING: set to trigger the interrupt when the pin goes from LOW to HIGH
    • 3: trigger the interrupt whenever the change is detected (both edges)
  • handler: a function that will be called when an interrupt is detected
# Attach interrupts to buttons A and B on pins 4 and 5
btn_A.irq(trigger=Pin.IRQ_FALLING, handler=irq_handler)
btn_B.irq(trigger=Pin.IRQ_FALLING, handler=irq_handler)

To initialize the timer interrupt, first we need to create a Timer object. Then we initialize a timer using init() method by passing as argument the timer mode, period, and callback function. Timer mode has 2 options:

  • Timer.PERIODIC: triggers callback function repeatedly based on specified period
  • Timer.ONE_SHOT: triggers the callback function once after a defined period
tim = Timer(0)
tim.init(period=300, mode=Timer.PERIODIC, callback=on_tick)

Enable the autoscrolling and set cursor to point at last place in the first row, in the main loop constantly check for paused and tick flags to determine the running status of program.

# Enable autoscroll to the left direction
lcd.autoscroll()
# Set cursor to the last place in first row
lcd.setCursor(16, 0)

# Character index
i = 0
while True:
# Check if scrolling is paused and if timer triggered
if not paused:
if tick:
# Reset tick flag
tick = False
# Print next character
lcd.print(sentence[i])
# Move to the next character
i += 1
# Check if end of sentance has been reached
if i >= len(sentence):
# Reset index
i = 0
# Clear screen
lcd.clear()
lcd.setCursor(16, 0)
# Small delay to avoid busy loop
time.sleep_ms(10)

Full Example

4.2_Autoscroll_Example.py