Skip to content

Instantly share code, notes, and snippets.

@tdicola
Created October 22, 2016 00:44
Show Gist options
  • Save tdicola/2c42bfe534838b3c159c1b3cc3e58ac8 to your computer and use it in GitHub Desktop.
Save tdicola/2c42bfe534838b3c159c1b3cc3e58ac8 to your computer and use it in GitHub Desktop.
# SSD1306 Sine Wave Message scroller
# This animates a message scrolling across a SSD1306 display in a sine wave.
# Currently written for SAMD21 MicroPython, but adjust how the I2C bus is
# defined to work with other ports.
# Author: Tony DiCola
# License: Public Domain
import machine
import math
import ssd1306
import time
# Configure message that will scroll.
MESSAGE = 'Hello world this is a fun scroller!'
# Other configuration:
DISPLAY_WIDTH = 128 # Width of display in pixels.
DISPLAY_HEIGHT = 32 # Height of display in pixels.
FONT_WIDTH = 8 # Width of font characters in pixels.
FONT_HEIGHT = 8 # Height of the font characters in pixels.
AMPLITUDE = DISPLAY_HEIGHT - FONT_HEIGHT # Amplitude of sine wave, in pixels.
FREQUENCY = 2 # Sine wave frequency, how often it repeats across screen.
def main(i2c):
# Global state:
oled = ssd1306.SSD1306_I2C(DISPLAY_WIDTH, DISPLAY_HEIGHT, i2c)
pos = DISPLAY_WIDTH # X position of the starting character in the message.
message_len_px = len(MESSAGE) * FONT_WIDTH # Pixel width of the message.
# Build a lookup table of wavy Y positions for each column. This will speed
# up the main loop by not constantly computing Y positions. Remember characters
# can be drawn off screen to the left so increase the lookup table a bit to
# compute their Y positions too.
lookup_y = [0] * (DISPLAY_WIDTH+FONT_WIDTH)
for i in range(len(lookup_y)):
t = i / (DISPLAY_WIDTH-1) # Compute current 'time' as position along
# lookup table in 0 to 1 range.
# Use a sine wave that's offset to the range 0 to AMPLITUDE to compute
# each character Y position at a given X.
lookup_y[i] = int(((AMPLITUDE/2.0) * math.sin(2.0*math.pi*FREQUENCY*t)) + (AMPLITUDE/2.0))
# Main loop:
while True:
# Clear the screen.
oled.fill(0)
# Move left a bit, then check if the entire message has scrolled past
# and start over from far right.
pos -= 1
if pos <= -message_len_px:
pos = DISPLAY_WIDTH
# Go through each character in the message.
for i in range(len(MESSAGE)):
char = MESSAGE[i]
char_x = pos + (i * FONT_WIDTH) # Character's X position on the screen.
if -FONT_WIDTH <= char_x < DISPLAY_WIDTH:
# Character is visible, draw it.
# Look up the Y position in the previously computed lookup table.
# Remember the lookup table spans from all visible pixels and
# an extra FONT_WIDTH number of pixels on the left (so offset
# a bit when indexing into the table).
oled.text(char, char_x, lookup_y[char_x+FONT_WIDTH])
oled.show()
# Run main function but first initialize I2C (with context manager to deinit).
with machine.I2C(machine.Pin('SCL'), machine.Pin('SDA')) as i2c:
main(i2c)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment