The holidays are here and now is a great time to dust off the board games for some wholesome family fun. But we have a problem. Where are the dice? Be it a six-sided die for monopoly, or a D20 ready to deliver a critical strike, dice do go missing.
In this tutorial, we will create our own digital dice by learning how to connect an OLED screen, an SSD1306, to a Raspberry Pi Pico via the I2C interface. We will trigger a dice roll by pressing a button and, after a short animation, the roll will display on the screen. To enable this we will install a MicroPython library via the Thonny editor and learn how to use it to write text to the display.
The OLED screen uses the I2C protocol to interface with the Raspberry Pi Pico. Which means that we only require
- A Raspberry Pi Pico running MicroPython
- 6 x Female to Mmale jumper wires
- An I2C, SSD1306 OLED screen 128 x 32
- A push button (momentary switch)
Connect an OLED screen and Button to Raspberry Pi Pico
Use the following wiring diagram to connect the OLED screen and push button to the Raspberry Pi Pico.
1. Connect the GND of the screen to any GND on the Pico (Black wire).
2. Connect VCC to 3V3 on the Pico (Red wire).
3. Connect SCK / SCL to I2C0 SCL (GP1, Physical pin 2, Yellow wire).
4. Connect SDA to I2C0 SDA (GP0, Physical pin 1, Orange wire).
5. Connect the push button to the Breadboard.
6. Connect one leg of the button to any GND (Black Wire), then connect the diagonally opposite leg to GP28 (Physical Pin 34, Purple Wire).
7. Connect your Raspberry Pi Pico to your computer and open the Thonny application.
With the hardware connected and Thonny open, we now need to install a library in order for Python to communicate with the screen.
8. Click on Tools > Manage Packages to open Thonny’s package manager for Python libraries.
9. Type “ssd1306” in the search bar and click “Search on PyPI”.
10. Click on “micropython-ssd1306” in the returned results and then click on Install. This will copy the library to a folder, lib on the Pico.
11. Click Close to return to the main interface.
Programming an OLED Screen on Raspberry Pi Pico
To write a single line of text to the OLED screen we need just six lines of MicroPython.
1. From the machine library, import the Pin and I2C classes. These are used to communicate with the OLED screen, attached to the GPIO of the Pico.
from machine import Pin, I2C
2. Import the OLED screen library.
from ssd1306 import SSD1306_I2C
3. Import randint from the random library. Randint is used to generate random integers (numbers) which will be used for our dice.
from random import randint
4. Import the time library.
5. Create an object, i2c, which stores the I2C channel in use, in this case zero, the SDA and SCL pins that we are connected to, and finally the frequency at which we connect to the OLED screen.
i2c=I2C(0,sda=Pin(0), scl=Pin(1), freq=400000)
6. Create an object, oled, which will be used to communicate with the OLED screen. It has three arguments: the width and height of the screen (128 x 32 pixels) and the I2C connection details. Change the screen height and width to match your screen, we used a 128 x 32 0.96 inch display.
oled = SSD1306_I2C(128, 32, i2c)
7. Create an object, button, to connect the push button to our code. We are connected via GP28, and the pin is an input. We need to pull the pin high,so that, when we press the button, it connects the pin to GND, effectively pulling the pin low and triggering a change of state.
button = Pin(28, Pin.IN, Pin.PULL_UP)
8. Create a loop to constantly run the code.
9. Add a conditional test to check the current status of the button which will roll the dice. If the button is pressed, the state will change from 1 (True) to 0 (False).
if button.value() == 0:
10. Clear the OLED screen of any text.
11. Insert a for loop which will iterate ten times. This loop will display ten randomly chosen numbers, and place them at random positions.
for i in range(10):
12. Write a randomly chosen number, between 1 and 100, at a random position on the screen. Using randomly chosen x (width) position (0, 126) and a random y (height) position (0,24) we create an animated jumble of numbers to dazzle the user and give the impression that the Pico is thinking of many numbers.
13. Add a short delay, then clear the screen. This will give the animation an impression of jumbled numbers appearing across the screen. If we didn’t clear the screen then there is a chance that we wouldn’t see the dice roll clearly.
time.sleep(0.2) oled.fill(0) oled.show()
14. Create a variable called roll and in there store a randomly chosen number between 1 and 6. If you are playing a game which requires a higher value, for example Dungeons and Dragons, then change the 6 to your desired value.
roll = randint(1,6)
15. Write the roll variable to the OLED screen. We need to convert the integer into a string str() so that it can be displayed on the screen. The two values, 64 and 16 are the position (x, y) on the screen. We have set them to be the center of our 128 x 32 screen. For a 128 x 64 screen change these to 64, 32.
oled.text(str(roll), 64, 16) oled.show()
16. Print the value of the roll variable to the Python shell. This is not an essential step, but it is useful for debugging any connection issues with the OLED screen.
17. Add a pause of 10 seconds to keep the dice throw value on the screen. Then clear the screen so it’s ready for the next throw.
time.sleep(0.2) oled.fill(0) oled.show()
18. Create an else condition and add lines to write an instruction to the user onto the OLED screen. We have two lines to write to the screen. The first starts in the top left (0,0) but the second needs to move 16 lines down to remain legible.
else: oled.text("Press to", 0, 0) oled.text("roll dice",0, 16) oled.show()
19. Save the code as dice.py to your Raspberry Pi Pico and click Run to start the code.
Complete Code Listing
from machine import Pin, I2C from ssd1306 import SSD1306_I2C from random import randint import time i2c=I2C(0,sda=Pin(0), scl=Pin(1), freq=400000) oled = SSD1306_I2C(128, 32, i2c) button = Pin(28, Pin.IN, Pin.PULL_UP) while True: if button.value() == 0: oled.fill(0) oled.show() for i in range(10): oled.text(str(randint(1,100)),randint(0,126),randint(0,24)) oled.show() time.sleep(0.2) oled.fill(0) oled.show() roll = randint(1,6) oled.text(str(roll), 64, 16) oled.show() print(roll) time.sleep(10) oled.fill(0) oled.show() else: oled.text("Press to", 0, 0) oled.text("roll dice",0, 16) oled.show()