I wanted the serial interface to be both simple to use, but featured enough that I would be able to have many conveniences as well. All the slave display devices (up to 6 slaves, 12 digits total) will be connected in parallel to the master's UART serial bus. So the protocol consists of a one byte command broadcast from the master to all attached slaves. The formatting of the command byte is as follows:
|ADR ||n||DATA |
received byte (msb) 0 0 0 0 0 0 0 0 (lsb)
The 'ADR' is the slave address that the master wants to send the command to. Each slave has a unique address programmed into eeprom byte at address 0. So it is possible to easily change a slave's address without recompiling and reflashing the entire microprocessor. When a slave receives a byte that begins with its address it will execute the command that is encoded. The 'n' is which of the two digits to affect (digit 0 or 1), and 'DATA' is the value to write.
The default mode on power on is to accept commands encoded in BCD (binary coded decimal). I call this mode number write mode (NWM). This means sending 0b01010011 will display number '3' to 2nd digit of module with address 2. So you can see how easy it would be to send a simple number to any of the up to 12 digits. Additionally sending DATA=0xFF will clear all segments for the selected digit.
But what if you want to control individual segments independently? Well the display has a second display mode that I call independent segment write mode (ISWM) that uses a special command format addressed to 0b111 (7). When the master sends a command to address 7 all attached devices will act on it (think of it like a master high priority global command). To switch between NWM and ISWM just send bytes 0b111x0001 and 0b111x0010, respectively (x is don't care so it can either be 0 or 1).
In ISWM mode, you can set or clear each segment individually for custom display characters. 'DATA' is is now only 3 bits and is encoded such that segment A is 0b000, segment B is 0b001 ... segment G is 0b111. In this case the msb 4th bit of 'DATA' will now control whether you are telling the selected segment to set or clear (1 or 0). 'n' still controls which digit you are controlling and 'ADR' is still the module address. For example, to set segment D of 2nd digit of address 2 simply send 0b01011011, and to clear segment A of 1st digit of address 1 send 0b00100000.
Finally since these electromechanical displays only consume power during changes it made sense to add a command to sleep and wake up the module. Sending a special command of 'DATA' = 0b1111 to 'ADR' 7 (ie. the byte 0b111x1111) will put all attached modules to sleep. To wake them up send any byte to the displays.
In summary here's a little example scenario:
master sends 0b111x0001 -> put into number write mode
master sends 0b00010011 -> write number '3' to 2nd digit of module with address 0
master sends 0b00101111 -> clear just 1st digit of address 1
master sends 0b111x0000 -> clear all attached displays
master sends 0b01101100 -> write hyphen to 1st digit of address 3
master sends 0b111x0010 -> put into independent segment write mode
master sends 0b01011011 -> set segment D of 2nd digit of address 2
master sends 0b01101001 -> set segment B of 1st digit of address 3
master sends 0b00010111 -> clear segment G of 2nd digit of address 0
master sends 0b00100000 -> clear segment A of 1st digit of address 1
master sends 0b111x0001 -> put back into number write mode
master sends 0b111x1111 -> go to sleep
master sends 0b111x0010 -> wake up, put into independent segment write mode
I've written the firmware for the PIC16F886 but as I haven't gotten the parts to build a prototype I have yet to test everything. Once I verify that everything works as expected I'll post the firmware, example code, and eagle board design files so that anyone can use them in their own project. If there is enough demand I can sell modules, but just keep in mind that these displays alone are a good $10-$12 each so complete modules would have to factor in that cost.