Printing text on an LCD display using switches

There’s a YouTuber called the 8-Bit Guy who’s made a fantastic project where he gets text on an LCD display just using switches instead of a micro-controller or computer. He made his (video below) in a nice box with chunky switches, and I thought I’d try and make one on a breadboard.

This was a mistake, but I did, just about, get it to work and it makes an interesting project to learn a bit about low level logic, binary maths, data representation and so on with some very simple and inexpensive parts. It’s a good gateway to building a more complex project like a breadboard computer, which I plan to do this winter and it will use a display just like this so it’s all good practice.

Building it

Here’s what I used:

  • a 2 x 16 alphanumeric LCD display (old-fashioned parallel type, not one with an SPI interface)
  • 9 tiny single-pole dual-throw switches
  • a push-button
  • a 0.1uF capacitor to debounce the push-button
  • a variable resistor
  • a 4.7k ohm resistor
  • a breadboard
  • jumper wires
  • a USB lead with one end stripped to provide 5v power

Here’s how I wired it up – I’d be very happy to be corrected on my inevitable mistakes – I am not an electronics expert in any way!

LCD switch wiring diagram

The LCD pin wiring goes like this from left to right:

LCD pin
 1 GND
 2 +5v
 3 variable resistor for contrast
 4 centre pole of register select switch
 5 GND
 6 one side of the enter button
 7 to centre pole of data switch
 8 to centre pole of data switch
 9 to centre pole of data switch
10 to centre pole of data switch
11 to centre pole of data switch
12 to centre pole of data switch
13 to centre pole of data switch
14 to centre pole of data switch
15 +5v for backlight
16 GND for backlight

Using it

Switch the program select switch to the 0v / GND position and enter some control codes. I tried a few different ones but found that this (sometimes) worked to select two line mode. Put the data switches in each position, then press the ‘enter’ button:

0000 1111
0011 0000

Then to enter text, switch the program select switch to the +5v position, alter the switches to the positions of binary representations of ASCII characters, and press the enter button after each one.

H 0100 1000
E 0100 0101
L 0100 1100
L 0100 1100
O 0100 1111
  0010 0000 (space)
W 0101 0111
O 0100 1111
R 0101 0010
L 0100 1100
D 0100 0100

The little breadboard switches are far too fiddly and prone to flying out of the board, so if I were to make this properly I would go the same way as the 8-Bit Guy and use big switches in a proper box.

If you fancy connecting one of these to a BBC micro:bit, check out my previous post: http://www.suppertime.co.uk/blogmywiki/2019/04/lcd-microbit/

Related videos

The 8-Bit Guy video that started me making this:

A Ben Eater video on adding LCDs to a breadboard computer which has very useful stuff on the control codes:

Posted in computers, hardware | Tagged | Leave a comment

micro:bit OLED compass

micro:bit OLED compass

These 128 x 64 pixel OLED displays are inexpensive and provide a great way to augment micro:bit projects. They’re easy to wire up using a breakout board and 4 female-to-female jumper wires. Just connect it like this:

OLED  / micro:bit
----------------
GND  -> GND
VCC  -> 3v
SCL  -> SCL (pin 19)
SDA  -> SDA (pin 20)

There are lots of different ways of driving OLED displays from a micro:bit. I’ll do a round-up of them all soon, but here I experimented with using a MakeCode extension for a 4Tronix robot, the Bitbot, which happens to include some quite nice blocks for writing text and drawing shapes on an OLED display.

This driver can use the full 128 x 64 resolution but I’ve chosen to use the ‘zoom’ mode here to make the text easier to read.

The program keeps taking bearing readings in a ‘Forever’ loop, rounds them to the nearest 10 degrees to stop the display jumping around too much.

As well as showing the compass bearing and current temperatures as numbers, it also draws a line to show which way North is – just like a compass needle!

A bit of maths is called on for this to convert an angle to x,y co-ordinates that can be plotted on a screen. It gets a bit messy because of the offset to the middle of the screen, having to rotate it through 90 degrees and I needed to flip it left-right for some reason but in short it works like this:

x co-ordinate = cos(angle*pi/180) * half width of screen

y co-ordinate = sin(angle*pi/180) * half height of screen

It draws circles for degree symbols and turns the bearing into a string padded with spaces to make sure digits are over-written when it goes from a 3-digit bearing like 350 to a single digit bearing like 0.

Next I may improve this by allowing you to set the bearing that it points to to the current bearing, so you’d have a little gizmo that always points whatever way you want to go.

Posted in microbit | Tagged , , , | Leave a comment

micro:bit radio messager with OLED display

What it is

Based on my previous micro:bit keyboard project, this allows you to type a message on a micro:bit using an old PC PS/2 keyboard and send it over radio to another micro:bit.

How to make it

You’ll need a couple of micro:bits, a micro:bit breakout board, a small OLED display, some jumper wires and a breadboard. You’ll also need an old PS/2 keyboard with the plug cut off and you’ll need to identify the 5v VCC, data and GND wires on the PS/2 keyboard cable. See my previous post for more on this.

Connect the keyboard to the micro:bit like this:

KBD | micro:bit
5v VCC -> 3v
data -> pin 1
GND -> GND

Connect the OLED display like this:

OLED | micro:bit
VCC -> 3v
GND -> GND
SCL -> SCL (pin 19)
SDA -> SDA (pin 20)

As well as the Python program at the end of this page, you’ll need to add two Python libraries ssd1306.py and ssd1306_text.py to make the OLED display work. You can do this using the online micro:bit Python editor. Click on the Load/Save button then ‘Show files’ then ‘Add a file’:

adding more files in the Python editor

Flash the 3 files to your micro:bit and you may need to press the reset button on the back of the micro:bit before first use. Your mileage may vary with the Baud rate, and the precise keycodes for each letter.

The receiving micro:bit will need some code on it like this:

from microbit import *
import radio
radio.config(group=23)
radio.on()
storedMessage = ''

while True:
    message = radio.receive()
    if message:
        display.scroll(message)
        storedMessage = message
    if button_a.was_pressed():
        display.scroll(storedMessage)

How to use it

Type your message and it should appear on the OLED display. Backspace will delete any errors. Caps lock key will toggle upper & lower case – the letter A in the bottom right-hand corner shows you which mode it’s in. Pressing enter will send your message by radio and clear the message.

How it works

It works using the principle of brute ignorance. I ignore the proper protocols for PS/2 keyboards and treat it as incoming serial data at 10000 Baud. This worked for me with the old Dell keyboard I found on the street. PS/2 keyboards send 3 codes every time you press a key: a key identifier, a release code when you let go, and it repeats the key identifier. The program looks these up and turns them into the appropriate letters every time 3 codes are received.

Improve it

- Change radio channel on the fly
- Add a Caesar cypher with selectable key – great for group interception / cryptanalysis games!

The main code

Here’s the Python code. You’ll also need those two Python OLED display libraries mentioned above, remember!

from ssd1306 import initialize, clear_oled
from ssd1306_text import add_text
import micropython # to enable disabling of accidental keyboard interrupt
from microbit import *
import radio
radio.config(group=23)

uart.init(baudrate=10000, bits=8, parity=None, stop=1, tx=None, rx=pin1)
micropython.kbd_intr(-1) # disable accidental keyboard interrupt
dataList = []
delay = 1000
capsLock = True
message = ''

keyCodes = {
  139: 'Q', 207: 'W', 210: 'E', 215: 'R', 150: 'T', 219: 'Y', 222: 'U', 161: 'I', 226: 'O', 231: 'P',
  142: 'A', 205: 'S', 145: 'D', 213: 'F', 154: 'G', 217: 'H', 157: 'J', 224: 'K', 224: 'K', 229: 'L',
  140: 'Z', 208: 'X', 209: 'C', 148: 'V', 152: 'B', 153: 'N', 220: 'M', 225: ',', 165: '.', 149: ' ', 164: '?',
  138: '1', 206: '2', 146: '3', 147: '4', 214: '5', 218: '6', 159: '7', 158: '8', 162: '9', 163: '0'
}

initialize()
clear_oled()
add_text(11, 3, 'A')
x = 0
y = 0

while True:
    add_text(x, y, '_') # cursor
    if capsLock:
        add_text(11, 3, 'A')
    else:
        add_text(11, 3, 'a')
    if uart.any():
        data = bytearray(1)
        uart.readinto(data, 1)
        dataList.append(data[0])
        if len(dataList) == 3:
            if dataList[0] in keyCodes:
                if capsLock:
                    letter = keyCodes[dataList[0]]
                else:
                    letter = keyCodes[dataList[0]].lower()
                add_text(x, y, letter)
                x += 1
                if x > 11:
                    x = 0
                    y += 1
                if y > 2:
                    y = 0
                    clear_oled()
                if x < 0:
                    x = 0
                if y < 0:
                    y = 0
                message = message + letter
            elif dataList[0] == 172: # toggle caps lock
                capsLock = not capsLock
            elif dataList[0] == 242: # backspace
                message = message[:-1]
                add_text(x, y, ' ')
                x -= 1
            elif dataList[0] == 131: # press F12 to review message
                display.scroll(message)
            elif dataList[0] == 236: # send message when enter pressed
                radio.on()
                radio.send(message)
                radio.off()
                add_text(0, 3, 'TX')
                message = ''
                x = 0
                y = 0
                sleep(delay)
                clear_oled()
            dataList = []
    display.clear()
Posted in microbit | Tagged , , , | Leave a comment

Read a PS/2 keyboard on a BBC micro:bit

What you’ll learn

  • That computer keyboards aren’t just switches – they need power to make them work
  • They comprise a matrix of buttons connected in rows and columns
  • Computers don’t read your keypresses directly – the keyboard contains a circuit board that does that
  • The keyboard sends keypresses to the computer as a stream of serial data – in effect numbers
  • Old-fashioned PS/2 keyboards send a code when you press a key and another when you release it
  • PS/2 keyboards aren’t, strictly speaking, just input devices. They also receive data from computers, for example to light the CAPS LOCK light output

Background

This is a testament to the power of ignorance. If you don’t know you can’t do something, sometimes you end up being able to do it.

For years I’ve wanted to connect a normal computer keyboard to a BBC micro:bit to make radio messaging and cryptography easier to use. I’ve seen, and indeed made myself, similar things on an Arduino, using libraries designed to read the subtle data coming from a PS/2 keyboard, frighteningly complex libraries in C++ that unpack every transition of every pulse of every bit of digital data.

Well, that’s not how I roll.

Previously I connected a thermal printer straight to a micro:bit and threw some serial data at it, and it worked first time, printing my message.

I never expected my home-made key-pad matrix, coded in utter ignorance, to work. But it did. First time.

Sometimes it’s helpful not to be fettered by knowledge and precedent, though not, I hasten to add, if you’re flying a plane, performing surgery or indeed running a country.

So I decided to take that approach to my micro:bit PS/2 keyboard problem.

What is a PS/2 keyboard anyway?

PS/2 keyboards are the old-fashioned type that came before USB – they often have round plugs, usually encased in purple plastic. (PS/2 mice tended to have green plugs.) They’re not especially easy to buy, at least not new, but people often throw them out, as we’ll see…

They’re just a matrix of buttons attached to a small controller running at 5 volts that turns key presses into serial data. Ok, the protocol is pretty horrible… an 11-bit word sent at anything between 10 and 16.7 kHz and comprising:

  • 1 start bit (always 0)
  • 8 data bits (least significant bit first)
  • 1 parity bit (odd parity)
  • 1 stop bit (always 1)

So I decided to ignore all that. I was walking the dog one day and found a PS/2 keyboard dumped at the side of the road, helpfully with the plug already cut off, and the plug also by the side of the road.

This was a sign.

The investigation begins

matrix inside a computer keyboard

Inside a computer keyboard

I took it home and opened it up. You can see in the picture above how the keys comprise two layers of plastic film that are pressed together to complete a circuit. The keys are arranged in a matrix, a grid of rows and columns.

In the corner you can see the controller printed circuit board that contains the caps, num and scroll lock LEDs as well as the electronics that convert keypresses into a kind of serial data sent down the cable to the PC.

keyboard LEDs and membrane

keyboard LEDs and membrane

I hoped the controller PCB would helpfully show me what each coloured cable did. (There’s no standard for PS/2 cable colours).

detail of keyboard control PCB

detail of keyboard control PCB

reverse of keyboard control PCB

reverse of keyboard control PCB

A few capacitors, LEDs, and an integrated circuit hidden under a blob on the back, and some labels, but alas nothing to identify the purpose of each wire going out to the plug. Even knowing the manufacturer and model number was no use either. Luckily, I still had the severed plug, so I was able to figure out that for this particular Dell keyboard:

Pink = 5v
Black = GND
White = Data
Brown = clock

5v. Hmm, the micro:bit supplies only 3v. Ignoring that, I connected the black wire to micro:bit GND pin and the pink to the micro:bit 3v pin. The LEDs lit up to show the keyboard was doing its power-on-self-test. The NUM LOCK light even lit (but not caps lock, I discovered that’s done in software by PCs, which send a signal back to the keyboard!)

So you can power a PS/2 keyboard off a micro:bit 3v supply – useful! No external power supply needed.

Now, what if I just ignore the clock wire, and pretend that the PS/2 keyboard is just sending serial data? We can read serial data on a micro:bit, I just need to know the Baud rate (the speed at which the data is being sent). That 10 to 16.7 kHz range sounds a bit scary, I tried a few different numbers and found that using 10,000 Baud I managed to get some sensible looking data from this program, with pin 1 connected to the white keyboard data wire and GND connected to the black keyboard ground wire, flashed onto a micro:bit using the online editor.

import micropython
# to enable disabling of accidental keyboard interrupt
from microbit import *

uart.init(baudrate=10000, bits=8, parity=None, stop=1, tx=None, rx=pin1)

micropython.kbd_intr(-1)
# disable accidental keyboard interrupt

while True:
    if uart.any():
        data = bytearray(1)
        uart.readinto(data, 1)
        display.scroll(data[0])

Pressing the letter Q, for example consistently produced 139, 248, 139.

Pressing A produced 142, 248, 142.

I knew from my reading (see, you do need a bit of knowledge) that PS/2 keyboards send a code when you press a key, then send a release code when you let go. So 139, 248, 139 really means ‘Q pressed’ ‘released Q’.

So all I needed to do was sniff the code for every key I was interested in and create a dictionary to look up the codes and turn them into letters. I’ve only bothered with the alphabet, numbers and some very basic punctuation so far, but I have implemented my own caps lock and backspace. (The caps lock light doesn’t come on, but one day…)

Key codes for other keyboards will probably vary, so use the sniffer program to make your own list if needed. You may also need to use a different Baud rate, but 10,000 worked for me with this Dell.

Secret radio message communicator project

Let’s put this new-found ignorance to use by building a super secret agent communicator! No-one will see you lurking in the bushes with a micro:bit and mahoosive Dell PS/2 keyboard you pulled from the trash!

Put this program on the receiving micro:bit:

from microbit import *
import radio
radio.config(group=23)
radio.on()
storedMessage = ''

while True:
    message = radio.receive()
    if message:
        display.scroll(message)
        storedMessage = message
    if button_a.was_pressed():
        display.scroll(storedMessage)

For the transmitter, use the code below. Remember you’ll need to attach pin 1 on the micro:bit to your keyboard’s data wire – mine was white but yours may not be. Also connect your micro:bit 3v pin to the keyboard’s power wire (pink in my case) and micro:bit GND pin to keyboard Ground (black on this Dell).

Type your message quite slowly. Letters will flash on the micro:bit display. The Caps Lock key toggles upper and lower case, but the shift key does nothing. If you make a mistake press backspace and it will delete the last character of your message.

Press button A on the micro:bit to review your message, and press button B to transmit it over radio. This also deletes the message because a good spy covers their tracks, right?

Sometimes it needs a reset when you power it up, so if it’s not working first time, press the reset button on the back of the micro:bit and see if that sorts it.

If you make something with this, please let me know and I’d be thrilled if you could credit me, this blog or my YouTube channel.

Enjoy!

import micropython # to enable disabling of accidental keyboard interrupt
from microbit import *
import radio
radio.config(group=23)

uart.init(baudrate=10000, bits=8, parity=None, stop=1, tx=None, rx=pin1)
micropython.kbd_intr(-1) # disable accidental keyboard interrupt if ctrl-C character received on serial input
dataList = []
delay = 250
capsLock = True
message = ''

keyCodes = {
  139: 'Q', 207: 'W', 210: 'E', 215: 'R', 150: 'T', 219: 'Y', 222: 'U', 161: 'I', 226: 'O', 231: 'P',
  142: 'A', 205: 'S', 145: 'D', 213: 'F', 154: 'G', 217: 'H', 157: 'J', 224: 'K', 224: 'K', 229: 'L',
  140: 'Z', 208: 'X', 209: 'C', 148: 'V', 152: 'B', 153: 'N', 220: 'M', 225: ',', 165: '.', 149: '_', 164: '?',
  138: '1', 206: '2', 146: '3', 147: '4', 214: '5', 218: '6', 159: '7', 158: '8', 162: '9', 163: '0'
}

while True:
    if uart.any():
        data = bytearray(1)
        uart.readinto(data, 1)
        dataList.append(data[0])
        if len(dataList) == 3:
            if dataList[0] in keyCodes:
                if capsLock:
                    letter = keyCodes[dataList[0]]
                else:
                    letter = keyCodes[dataList[0]].lower()
                display.show(letter)
                message = message + letter
            elif dataList[0] == 172: # toggle caps lock
                capsLock = not capsLock
                if capsLock:
                    display.show(Image.ARROW_N)
                else:
                    display.show(Image.ARROW_S)
            elif dataList[0] == 242: # backspace
                display.show(Image.ARROW_W)
                message = message[:-1]
            dataList = []
            sleep(delay)
    if button_a.was_pressed():
        display.scroll(message)
    if button_b.was_pressed():
        radio.on() # I'm in love with Massachusetts
        radio.send(message)
        radio.off()
        display.scroll('TX')
        message = ''
    display.clear()

You may also be interested in my post on making a your own key matrix using push buttons and a breadboard: http://www.suppertime.co.uk/blogmywiki/2020/08/microbit-computing-fundamentals/

Posted in Uncategorized | Tagged , , , , | 1 Comment

How the micro:bit helps you understand fundamentals of computing

I’ve made a few projects recently using 4 x 4 membrane keypads with the BBC micro:bit. I made a calculator, then a wireless communicator and most recently I recreated the 1970s game Mastermind.

I thought it might be interesting to focus on how keypads (and by extension, computer keyboards) work and unpack some more of the learning around this. I think this shows how good the BBC micro:bit is understanding how technology works at a very fundamental level, but at the same time being quite simple and accessible, using block coding thanks to Microsoft MakeCode, and simple components thanks to the design of the micro:bit itself.

There are, for example, many Arduino projects for wiring up keypads but they are difficult to program, using C++ in the Arduino IDE which isn’t very child friendly, and yet at the same time using provided Arduino libraries actually shields you from learning what’s going on at a fundamental level.

Here we’ll see how the micro:bit gives you the best of both worlds: a simple, friendly online code editor, and yet you’ll write your own program to scan and interpret keypresses.

While I was waiting for my ready-made keypads to arrive, curiosity got the better of me. I had a breadboard and a bag of around 100 tiny push-buttons and decided to see if I could make my own. I knew keypads were arranged in a grid or matrix, but I was curious to know exactly how they were wired together.

Looking at a circuit diagram of a keypad you can see that the same side of each button, the left side here, is connected together, row-by-row:

In each column the other side of each switch is connected together:

keyboard matrix wiring diagram columns

This gives you 8 wires for a 4 x 4 keypad. That sounds like a lot, but if you connected each key separately to a computer, calculator or microcontroller you’d have 16 wires plus a ground or earth wire connected to each button as well.

matrix inside a computer keyboard

Inside a computer keyboard

A standard computer keyboard contains around a hundred keys, so inside a keyboard these are usually arranged in a matrix as well, perhaps 6 rows of around 15 keys, meaning it needs just over 20 wires, rather than a hundred.

So a matrix is really a very neat way of arranging keyboard inputs on electronic devices.

micro:bit connected to a home-made keypad matrix

Making my own was fun and quite therapeutic! As every column in a breadboard is connected, and I only wanted to connect one side of each column of buttons together, I decided to stagger the buttons across the board. I used jumper wires to make the connections on each row and column. What you can’t easily see is that there are also jumper wires running underneath each button as well.

So, electrically speaking at least, I had created something that was the same as a real keypad matrix, even if I only had 12 buttons not 16.

But how to make it work?

I didn’t realise at the time that there was already a MakeCode extension for matrix keypads, which was lucky really as I had to invent my own way.

I knew some projects used different values of resistors to read pins using fewer than 8 wires, but I wanted to do it using as few components as possible. Using a breakout board on a micro:bit gives you access to extra pins, and I picked the following pins for rows and columns:

I avoided some pins that are also connected to the micro:bit’s own A and B buttons and elements of the LED display, as I want to able to use them in my projects.

Using digital outputs and inputs on micro:bit pins is a simple way of detecting if a circuit has been made, so I created a loop in MakeCode that sends a digital output to each row in turn:

MakeCode blocks to scan one row

If it receives an input on any of the pins connected to the columns, then that means you must have pressed a button and the program responds accordingly, for example by showing a number or letter. The example below shows how the number 3 in my calculator or Mastermind game, or the letters C or Q would be detected in my communicator project:

a keypress is detected

I really didn’t expect this to work – but it did! I didn’t even have to add any code to debounce… it just seems to work!

Whilst making your own keyboard matrix out of buttons is instructive, it is very fiddly and time-consuming, and you can still learn a lot from using a pre-made keypad matrix. All you need to connect one of these to a micro:bit is a breakout board and some male to female jumper wires.

The code is quite simple to understand, and modify to suit whatever project you happen to be making.

What other fundamentals of computing can you expose and teach with the mighty micro:bit?

Posted in microbit | Tagged , | Leave a comment