Let's put these two things together - drawing pixels + reading pots, to create our knob sketcher toy. We'll start with a minimalistic version called the Tiny Sketcher.

In addition to the ItsyBitsy M4, the Tiny Sketcher uses these parts.

These displays are small, only about 1.3" diagonal, but very readable due to the high contrast of an OLED display. This display is made of 128x64 individual white OLED pixels,...
In Stock
These are our favorite trim pots, perfect for breadboarding and prototyping. They have a long grippy adjustment knob and with 0.1" spacing, they plug into breadboards or...
In Stock
This is a 'full-size' breadboard, 830 tie points. Good for small and medium projects. It's 2.2" x 7" (5.5 cm x 17 cm) with a standard double-strip in the middle...
In Stock


The breadboard setup is shown below. The display has been rotated, but is otherwise wired the same as before. A second pot has been added, but they are both being used in the same way - as variable voltage dividers. The outputs are sent to different analog inputs.

And here is the CircuitPython code to create the sketcher.

import board, busio
import adafruit_ssd1306
from simpleio import map_range
from analogio import AnalogIn
from digitalio import DigitalInOut

# Create the I2C bus
i2c = busio.I2C(board.SCL, board.SDA)

# Define display dimensions and I2C address
WIDTH = 128
ADDR = 0x3d

# Create the digital out used for display reset
rst = DigitalInOut(board.D7)

# Create the display
display = adafruit_ssd1306.SSD1306_I2C(WIDTH, HEIGHT, i2c, addr=ADDR, reset=rst)

# Create the knobs
x_knob = AnalogIn(board.A0)
y_knob = AnalogIn(board.A1)

while True:
    x = map_range(x_knob.value, 0, 65535, WIDTH - 1, 0)
    y = map_range(y_knob.value, 0, 65535, 0, HEIGHT - 1)
    display.pixel(int(x), int(y), 1)
Remember, you can save the code as code.py so it will run automatically.

Most of this code is just setup. All the work to create the sketcher is done in the last 5 lines.

while True:
    x = map_range(x_knob.value, 0, 65535, WIDTH - 1, 0)
    y = map_range(y_knob.value, 0, 65535, 0, HEIGHT - 1)
    display.pixel(int(x), int(y), 1)

We read each of the knob values using the value property. To turn those values into a pixel location, we use the very handy function map_range. This function is so handy, it's a wonder why it wasn't built into the Python core. Instead, it is provided by the simpleio library - more info here. It basically converts one range of values into another range of values. In this case, from the range of analog read values, 0 to 65535, to the range of pixel locations, 0 to WIDTH or HEIGHT. (the - 1 is because of 0 indexing)

Note that the directionality of the knobs can be changed by swapping the order of the last two parameters. If you don't like the direction the pixel moves when you turn the knob, just swap these two and it will reverse it.

Once we have converted the knob values to pixel location, we draw the pixel. The int() is needed since map_range returns a float and pixel() expects integers for the pixel location.

And then we just do that over and over again...forever!

Run the code and turn the knobs. It should be obvious how it works. Sketch away!

Turn the knobs slowly to prevent skipping pixels. This version isn't super fast.

This guide was first published on Dec 30, 2018. It was last updated on Dec 30, 2018.

This page (Tiny Sketcher) was last updated on Jun 16, 2021.

Text editor powered by tinymce.