 A Useful Python Algorithm For Displaying Binary Numbers

2016/06/12

One of the challenges you face teaching introductory coding is binary, base 16, and the relationship between them.

The rationale for binary eventually becomes obvious, but what is the purpose of hexadecimal? When I first encountered it, I just assumed that computer programmers used base 16 arithmetic because they're all a little weird.

Many students will get the rationale for hex and its relationship to binary instantly when you show them binary counting taking place on two groups of four LEDs. Assembling a device to do this makes a nice prototyping and programming exercise on the Raspberry Pi.

It's been a while since I've had to train anybody on it but I still like to use a binary counting or light-chaser program as a sort of "Hello, world!" exercise on a microcontroller.

Doing this in a higher-level language such as Python is a bit different from doing it in assembler. Here's a nice little algorithm to decode a decimal value into eight binary digits.

def decode_decimal(n): rv = [0,0,0,0,0,0,0,0] for i in range(0,8): if (n & 2**i > 0): rv[i] = 1 return rv

This function is called with a decimal number as a parameter, and returns a list with eight elements each of which will be zero or one. At the heart of it is a for loop that populates the list by doing a bitwise logical AND operation with the original decimal number and the value of two raised to each power from 0 through 7.

This works because the AND operation (represented by the & operator in the code) is a "bitwise" operation that takes two numbers and compares them bit-by-bit at the binary level. If the bit being examined is a one in both numbers, then that bit in the result will be a one.

The other sense of an AND operation would be the truth-functional one where we need to do something like:

IF ({out_of_stock} AND {none_on_order}) THEN {order_more}

That's pseudocode, by the way, not Python

The astute reader will notice that the list of 0/1 values returned by this function is backwards to what one would expect. That is, the least-significant bit comes first.

All right, then. Here's the complete code for the binary counter demonstration project I alluded to at the start of this:

#! /usr/bin/python import RPi.GPIO as GPIO import time leds=[4,17,18,27,22,23,24,25] delay = 0.500 count_max = 255 direction = 0 def decode_decimal(n): rv = [0,0,0,0,0,0,0,0] for i in range(0,8): if (n & 2**i > 0): rv[i] = 1 return rv # Main Routine GPIO.setmode(GPIO.BCM) GPIO.setup(leds, GPIO.OUT) GPIO.output(leds, GPIO.LOW) n = 0 try: while True: GPIO.output(leds,decode_decimal(n)) time.sleep(delay) n = n + 1 if n > count_max: n = 0 except KeyboardInterrupt: GPIO.output(leds, GPIO.LOW) GPIO.cleanup() print "counter.py: Done."

If you want to turn your binary counting demonstrator into a simple light-chaser, change:

count_max = 255

...to:

count_max = 128

And change:

n = n + 1

...to:

n = n * 2

I'll leave it to you and your more perspacious students to explain what's going on with that. Something very similar saved an entire project and about four months' work for me a number of years ago.

And finally, here's the breadboard layout for the binary counting demonstrator / light chaser:  