Skip to content

A Tiny Raspberry Pi Pico's UI Structure for HD44780 compatible character LCDs

License

Notifications You must be signed in to change notification settings

Saranomy/TinyBlue

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

8 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

TinyBlue

This project is built on top of https://github.com/dhylands/python_lcd

UI Structure for 16x2 LCD

scroll

Scroll down on the list of items

toggle

Jump into LED menu and select Toggle 2 times, then go Back

wokwi

Try the simulator on Wokwi here

Problem

Interacting with extensive live data on a 16x2 character LCD can be challenging due to limited display space.

Solution

TinyBlue organizes items (text and buttons), supports multiple screens, and updates live data efficiently.

Features

User Interface

The interface reserves one character on the left to show the cursor position. The cursor indicates the item currently in focus, which can be clickable or a Back button.

Character Description
focus This item cannot be selected
selectable This item can be selected
back This item is a back button
none The cursor is not at this item yet

Item

An Item represents a single line of text displayed on the LCD screen.

from tinyblue import Item, Screen, TinyBlue

# create an item
item_temp = Item('Temp 40C')

To turn an item into a clickable button, set on_click to a callable function:

def on_update():
    print('updating')

# an update button that calls on_update() when clicked
item_update = Item('Update', on_click = on_update)

To create a back button, set is_back_button to True:

# a back button
item_back = Item('Back', is_back_button = True)

Update the text of an item using set_text(text: string). The text updates automatically if the item is currently displayed:

# update the text
item_temp.set_text('Temp 50C')

Screen

A Screen contains a list of Item objects that users can scroll through and interact with.

...
item_sound = Item('Sound: On', on_click = on_click_sound)
item_light = Item('Light: On', on_click_light)

# create a Settings screen
settings_options = Screen([
    Item('Back', is_back_button = True),
    item_sound,
    item_light
])

TinyBlue

Once items and screens are ready. Initialize TinyBlue(lcd, num_lines, num_columns)

  • lcd must be the I2cLcd object
  • num_lines is how many lines vertically on LCD screens
  • num_columns is how many characters per line

For 1602A format, num_lines = 16, num_columns = 2.

...
num_lines = 2
num_columns = 16

i2c = I2C(0, scl = Pin(17), sda = Pin(16), freq = 400000)
lcd = I2cLcd(i2c, i2c.scan()[0], num_lines, num_columns)

# initialize TinyBlue
tb = TinyBlue(lcd, num_lines, num_columns)

Add the screen objects into TinyBlue with a unique path. '/' is the root path.

screen_menu = Screen([
    Item('Hello 1'),
    Item('Hello 2'),
    Item('Hello 3')
])

# add menu as a root screen to TinyBlue
tb.add_screen(path = '/', screen_menu)

Call render() to display the current screen. This will call I2cLcd functions.

# show what is the screen
tb.render()

Input

TinyBlue is designed to navigate through screens using just 2 buttons

  • Scroll down by calling tb.scroll()
  • Select the focused item by calling tb.select()
...
# keyA is a Pin button
if keyA.value() == 0:
    tb.scroll()

# keyB is a Pin button
if keyB.value() == 0:
    tb.select()

You can add 2 more buttons

  • Scroll up by calling tb.scroll(direction = -1)
  • Go back to the previous screen by calling tb.back(). When you set item's is_back_button = True, it will call this tb.back()

Open Screen

Open a screen at a specific path using tb.open_screen(path)

# ====================== add screen a
screen_a = Screen([
    Item('Back', is_back_button = True),
    Item('Hello A')
])
tb.add_screen(path = '/a', screen_a)

# ====================== add screen b
screen_b = Screen([
    Item('Back', is_back_button = True),
    Item('Hello B')
])
tb.add_screen(path = '/a', screen_a)

# ====================== add screen main
def on_click_a():
    tb.open_screen('/a')

def on_click_b():
    tb.open_screen('/b')

screen_main = Screen([
    Item('Open A', on_click = on_click_a),
    Item('Open B', on_click = on_click_b)
])
tb.add_screen(path = '/', screen_main)

Demo

Here is a counter example showing how to implement a counter with a button

...
count = 0

item_count = Item('Count: 0')
def on_click_add():
    global count
    count += 1
    item_count.set_text(f"Count: {count}")

screen_main = Screen([
    item_count,
    Item('Add', on_click = on_click_add)
])
tb.add_screen(path = '/', screen_main)

Get Started

Hardware Requirement

Install

  1. Complete the Get Started guide with the Pi Pico
  2. Open Thonny, and connect to the Pi Pico
  3. Upload lcd_api.py and machine_i2c_lcd.py from this repository
  4. Upload tinyblue.py and example_tinyblue.py
  5. Open example_tinyblue.py on Thonny and check on the pins
...
# setup display and pins
i2c = I2C(0, scl = Pin(17), sda = Pin(16), freq = 400000)
i2c_devices = i2c.scan()
lcd = I2cLcd(i2c, i2c_devices[0], 2, 16)

scroll = Pin(6, Pin.IN, Pin.PULL_UP)
select = Pin(13, Pin.IN, Pin.PULL_UP)
...
  1. Run it

License

The source code for the site is licensed under the MIT license, which you can find in the LICENSE file.

All graphical assets are licensed under the Creative Commons Attribution 4.0 International License.

Releases

No releases published

Packages

No packages published

Languages