Today I am going to run a 7 segment display off of raspberry pi 4.

The code I ran

#!/usr/bin/env python
import RPi.GPIO as GPIO
import time

pins = [11,12,13,15,16,18,22,7]
dats = [0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71,0x80]

def setup():
 GPIO.setmode(GPIO.BOARD)
 for pin in pins:
  GPIO.setup(pin, GPIO.OUT)   # Set pin mode as output
  GPIO.output(pin, GPIO.LOW)

def writeOneByte(val):
 GPIO.output(11, val & (0x01 << 0))
 GPIO.output(12, val & (0x01 << 1))
 GPIO.output(13, val & (0x01 << 2))
 GPIO.output(15, val & (0x01 << 3))
 GPIO.output(16, val & (0x01 << 4))
 GPIO.output(18, val & (0x01 << 5))
 GPIO.output(22, val & (0x01 << 6))
 GPIO.output(7,  val & (0x01 << 7))

def loop():
 while True:
  for dat in dats:
   writeOneByte(dat)
   time.sleep(0.5)

def destroy():
 for pin in pins:
  GPIO.output(pin, GPIO.LOW)
 GPIO.cleanup()             # Release resource

if __name__ == '__main__':     # Program start from here
 setup()
 try:
  loop()
 except KeyboardInterrupt:  # When 'Ctrl+C' is pressed, the child program destroy() will be executed.
  destroy()

Here is the thing, I just copied this code which was given to me. I don’t know what this means. Specifically, the dats stuff. So let me just run and see if this works. Here is the circuit I made.

Circuit Fritzing

For the snobs

Remark: the 220 $ \Omega $ resistor is connected to power in case that is not clear.

It works 😅 . Let’s carry on and celebrate with a few 📷 .

The connection mess 1

The connection mess 2

The obligatory gif

Now that I have calmed down a little bit, let me look at the mysterious bit of code. From what’s happening I know that the code switches the leds in the 7-segment display so that we loop through 0 to 9 and A to F and then 0 again. The display changes every 0.5 seconds.

Time for google 🔍 . Found it 🙌. Let me rewrite the explanation in my own way.

What Was that Code

The parts that I didn’t understand were 0x3f-like objects and the operation <<.

Let me first understand 0x3f. Upon googling I found this on the wikipedia page of 7-segment display. This is the hexadecimal code for 0b00111111 binary code.

DisplayHexbinary
00x3f0b 00111111
10x060b 00000110
20x5b0b 01011011
30x4f0b 01001111
40x660b 01100110
50x6d0b 01101101
60x7d0b 01111101
70x070b 00000111
80x7f0b 01111111
90x6f0b 01101111
A0x770b 01110111
b0x7c0b 01111100
C0x390b 00111001
d0x5e0b 01011110
E0x790b 01111001
F0x710b 01110001
.0x800b 10000000

When I look at the python documentation x << y is a bitwise operation. And what it does is it returns x with the bits shifted to the left by y units (and new bits on the right-hand-side are zeros). At the same link I saw that x & y is the bitwise and. Each bit of the output is 1 if the corresponding bit of x AND of y is 1, otherwise it’s 0. Let me look at a few examples.

>>> bin(0x01)
'0b1'
>>> bin(0x01 << 0)
'0b1'
>>> bin(0x01 << 1)
'0b10'
>>> bin(0x01 << 2)
'0b100'
>>> bin(0x06)
'0b110'
>>> bin(0x06 << 3)
'0b110000'
>>> bin(0b00111111 & 0b00000001)
'0b1'
>>> bin(0b00111111 & 0b00010001)
'0b10001'
>>> bin(0b10111111 & 0b10010001)
'0b10010001'

I think this makes these operations clear to me. In case of x<<y you add y number of zeros to the binary form of x. x & y looks at the binary form of x and y and performs the and operation on every bit. In case this isn’t clear yet let me write the case of 0b00111111 & 0b00000001 again:

0b00111111
0b00000001
    ||
0b00000001
# which is the same as 0b1

To understand what is happening I have to look at the circuit I have made. I notice that pin 11 (using the raspberry pi board convention) is connected to the pin ?? on the 7-segment display. 7-segment display

Now let’s look at this statement of the code.

def writeOneByte(val):
 GPIO.output(11, val & (0x01 << 0))
 GPIO.output(12, val & (0x01 << 1))
 GPIO.output(13, val & (0x01 << 2))
 GPIO.output(15, val & (0x01 << 3))
 GPIO.output(16, val & (0x01 << 4))
 GPIO.output(18, val & (0x01 << 5))
 GPIO.output(22, val & (0x01 << 6))
 GPIO.output(7,  val & (0x01 << 7))

If I also look at how the loop() function is running, at any moment, val is an element in the list dats. Let’s consider the first case of val = 0x3f. What will be the output of val & (0x01 << 0)? This is the same as 0x3f & (0x01 << 0). I am going to run it in python.

>>> bin(0x3f & (0x01 << 0))
'0b1'