Make a Pico LCD true or false quiz game

By Stewart Watkiss. Posted

In this tutorial, we will create an interactive true or false quiz game using a Raspberry Pi Pico and an LCD display. Whilst doing so, you will learn about some of the pitfalls when connecting to devices running at different voltages. You’ll discover ways to increase voltage output using a simple buffer, and how to make a bidirectional level shifter. The level shifter is then used to convert between 3.3 V for the GPIO ports on a Pico to 5 V used by the LCD display. The game is programmed in Python, with a text file for the questions. The game can be installed inside an enclosure for a complete game.

01. LCD character display

This project is based around an LCD display. Our display has 16 characters across two lines and is often referenced as a ‘1602’. These usually contain an HD44780, or equivalent, driver chip that displays the appropriate pixels that make up the characters.

One downside of the display is that the driver chip needs at least six data connections. This uses up GPIO ports, as well as needing lots of wires to the LCD display. A common solution is to have a ‘backpack’ fitted to the rear of the LCD display using a port expander. The example used here is a PCF8574T 8-bit port expander.

Figure 1: Wiring diagram for Raspberry Pi Pico, voltage level shifter, and LCD display

02. Designed for 5 V

The port expanders are available on a PCB backpack pre-soldered onto the back of the LCD PCB. This saves you from having to create your own circuit, but it does come with an issue. These circuits are normally designed for 5 V, whereas a Pico uses 3.3 V for the GPIO ports.

Connecting a 5 V signal to a Pico GPIO port could cause permanent damage to the latter, so this tutorial looks at some of the possible solutions to interfacing between devices designed for different voltages.

03. Move pull-up to 3.3 V

If the 5 V device did not have a pull-up resistor, the I2C bus could work with pull-ups to the 3.3 V supply instead. This is shown in Figure 2. The crossed-out resistors are the pull-ups inside the LCD I2C backpack and the two pull-up resistors on the left are connected to the 3.3 V output on a Pico. Unfortunately, this involves de-soldering surface-mount devices, which can be difficult.

Figure 2: The I2C bus needs pull-up resistors. Having 5 V pull-ups could damage a Pico designed for 3.3 V

04. Unidirectional level shifter

A simple form of level shifter can be used when controlling 5 V devices from a 3.3 V microcontroller or computer. This is often used for controlling NeoPixels from a Pico or a Raspberry Pi. In its simplest form, this is a MOSFET with two resistors (as shown in Figure 3). The gate resistor RG (typically 470 Ω) reduces the in-rush current, and RL is a pull-up resistor (typically 2.2 kΩ to 10k Ω). With no input, the pull-up resistor sets the output high. When a 3.3 V input is provided, the MOSFET turns on pulling the output low. This results in an inverted signal.

Figure 3: A simple MOSFET level shifter. The output is the opposite of the input but higher voltage

The code can be configured to invert the output, or you could add an additional MOSFET to invert it a second time. A two-stage, non-inverting buffer is shown in Figure 4.

Figure 4: A second MOSFET can be used to create a non-inverting buffer

05. Bidirectional level shifter

The LCD is controlled from your Pico, so you may expect the signal would only need to go in one direction. However, due to the use of I2C protocol, signals need to pass in both directions. We need a bidirectional level shifter. These can be made using individual MOSFETS, but using a premade level shifter from Adafruit or SparkFun is more convenient. An example is the Adafruit bidirectional level shifter, which has four level shifters on a convenient PCB. This is shown in Figure 5.

Figure 5: A bidirectional level shifter is available on small PCBs. These can have headers fitted to be used on  a breadboard

The level shifter has just one MOSFET for each channel. This is in an unusual configuration. The circuit can be thought of as two sides, with the left side being for the low voltage and the right for the higher voltage. The MOSFET joins the two together. The schematic diagram is shown in Figure 6.

Figure 6: The bidirectional level shifter uses two MOSFETs. This works well for signals with pull-up resistors like I2C

06. How the level shifter works

If both the low-voltage and high-voltage signals are high, then the MOSFET is off and the signal is high at both sides. If the low-voltage signal (left) drops low, then the MOSFET is in the forward direction and the voltage at the gate will turn the MOSFET on. This will provide a path to ground and so the high-voltage signal (right) will be pulled low. If the high-voltage signal (right) goes low, due to an internal characteristic of the MOSFET a small current is able to flow in the reverse direction. As this happens, the voltage of the source pin dips, causing the MOSFET to turn on. This pulls the voltage down on the low-voltage signal as well.

07. LCD circuit

The level shifter can be inserted onto the breadboard and connected between your Pico and LCD display. Then it’s just a case of adding three buttons for Start, True, and False. These are shown in Figure 1.

The top power rail is used for 3.3 V taken from your Pico’s 3.3 V output, and the bottom power rail is 5 V taken from the VBUS supply from the USB port.

The buttons used are 16 mm push-to-make switches, similar to arcade buttons, but smaller. You can use other push-to-make switches if you prefer.

08. Download the LCD library

The libraries that support the LCD display with backpack are available from GitHub. Upload the files lcd_api.py and pico_i2c_lcd.py to your Pico. You can see a demo using pico_i2c_lcd_test.py. This can be useful for checking your wiring is correct, but you will need to change the pins used for SDA (GPIO 16) and SCL (GPIO 17).

09. Coding the game

The game code (quizgame.py). starts by setting up the three

button
objects, along with
i2c
and
lcd
. It then reads the file quizfile.txt, which contains the questions.

Then it enters a loop which ensures that the game can be played over again.

Within the first few lines of the loop, you can see that it first clears the display, puts a string which starts on the top line, moves to the start of the second line, and then puts another string to that line.

10. Handling button presses

The button presses are handled by having a

while
loop which runs until an appropriate button is pressed. In the case of the Start button, it just looks for that one button, but when waiting for a true and false, it needs to check both the
true_button
and
false_button
to see if either is pressed. It keeps track of the score and then displays the score at the end, pausing for five seconds before restarting the game.

11. The quiz file

The questions are stored in the file quizfile.txt. This has one line per question. Each line should have three entries separated by a semicolon. The first entry is the top line to display, the second is the second line, and the final entry is a letter T or F to indicate whether the correct answer is

True
or
False
.

The file is opened using the

with
statement. Using with means that the file will be automatically closed after the program has finished reading in the entries. The
readlines
method is used to read all the entries into a list.

To separate the text to display from the answers, the

split
method is used. You may notice that it also uses the
strip
method to ignore any whitespaces, such as spaces before the newline character.

The quiz file is created separately and must be uploaded to Pico.

Figure 7: The game can be placed inside an enclosure. If you don’t have a 3D printer, you can use a generic case and cut appropriate holes

12. Improving the game

The game can be placed in an enclosure to make a complete game. You could start with a standard enclosure and cut holes for the display and buttons, or if you have a 3D printer you can download an example from the Penguin Tutor website. One improvement would be to add some error checking. Without error checking, if there is an invalid entry in the quiz file, the program may crash.

Another possible improvement would be to provide a way to add multiple quizzes rather than just limiting them to a single quiz.

Download the full code.


From The MagPi store

Subscribe

Subscribe to the newsletter

Get every issue delivered directly to your inbox and keep up to date with the latest news, offers, events, and more.