Diversion: Larson Scanner

Small proof-of-concept experiment for programming my 4x4x4 led cube. I implemented a Larson scanner on a breadboard with 16 leds and controlled by a Python script.The purpose of this experiment was to familiarize myself with Python, demonstrate that the simple protocol for sending data to my cube will work, get comfortable with using the arduino’s port registers to set pins high and low, and sort out any wierdness before moving on to the cube.  Thankfully, I’ve had some experience working with serial data on the arduino before.  My model rocket launcher uses two serial ports, one to communicate with the digital display on the main panel, and another to communicate with the smartphone app.


So, first, the code for the arduino.  It’s very simple.  It uses an array to store the data indicating which leds to turn on and off.  Essentially just a bit field, so each bit sets the state of a single led.  It listens for data on the serial port, and when it has received 16 bits (2 bytes) it updates the leds.

The funky bitwise operations with the port registers are to preserve the state of pins that aren’t connected to my leds, and to get the bits into the right place, as they do not line up with the registers nicely. The leds are connected to pins 4 through 19 (digital pins 4 – 13 and analog pins 0 – 5). The hardware serial port is on pins 0 and 1, so we don’t want to mess with that, and on the cube pins 2 and 3 control the 3-8 decoder I use to select which ground plane is active.  Additionally, the 2 high bits on PORTB and PORTC do not correspond to IO pins, so I don’t want to change them either.

After that is loaded to the arduino, and leds connected in a row to pins 4 – 19, I can use a simple Python script to simulate a Larson scanner.

As my first experience with Python, I have to say it’s refreshing to be able to do things like open a serial port so simply. My arduino is connected on COM4 in this example, and I’m using the default baud rate of 9600, as it’s more than enough for my needs with these projects. So what this does is start with a single bit set, then move it left and right using multiplication and division by 2. By pausing for a fraction of a second after sending data, it creates the illusion that the light is bouncing back and forth across the leds. In this case, the arduino is expecting 2 bytes to describe the array, so I format the number using struct.pack() as a 16-bit integer, and I force little-endian as that is what the AVR is, and I wrote the arduino code with that assumption.

The only changes necessary for this code to work on the cube were as follows: The cube needs 64 bits to describe the state of all the leds, so I’m using a long long, or “<Q” in Python formatting. I update the cube every cycle, not just when I receive new data, as I have to multiplex the cube to maintain the illusion that all 4 planes are on at once. Therefore I use a buffer to hold the incoming data, and copy it to the array that I update the leds from when I’ve received 64 bits. Finally, to draw the cube, I have to manipulate the port registers 4 times, and I include the states of pins 2 and 3, to select which ground plane is switched by the 3-8 decoder IC.