I see lots of electromechanical 7 segment flip clocks and such but no easy to use universal controller modules so this is my take on it
Finally finished adding all the features I initially intended so I'll consider this project complete. Well other than I still need to 3d print a stand to keep the display upright.
Once again, super thanks to Alfa-Zeta for providing the EM displays and JLCPCB for the pcbs! I couldn't have done it without their support!
Finally got around to programming a Wemos D1 mini (basically an ESP8266) to act as a master controller to the three slave displays. The program currently uses the Youtube API to grab my channel stats and display them on the EM displays. I also ended up using tzapu's WiFiManager (https://github.com/tzapu/WiFiManager#password-protect-the-configuration-access-point) to allow me to easily reconfigure the wifi login via a smart phone or computer by broadcasting a configuration portal directly from the Wemos. Currently I am limited to counting up to 999,999 subs with six digits but I think that will last me a very long time as I am currently just under 10K (unfortunately cant display views as I have over 1 million). Here's a quick demo of it working (and some stress testing of me seeing just how fast I could push the displays ... I will never tire of the clicky-clacky sounds they make!!!).
Next up is to design a little board for the Wemos that has some buttons, a 12V input, and some LEDs. Look forward to an update wrapping up the physical construction and moving on to improving the software and adding real-time clock functionality!
So after the failure that was prototype 1, I've decided to dispense with trying to be clever and save pins/silicon and just throw an independently controllable h-bridge chip at each of the 14 segments (2 digits per module). After all the L9110S chips I got from ebay were only about $8 with free shipping for 50 chips which ends up to comfortably make three modules with a few chips to spare. The only casualty was the nice pretty routing of the board that I was so proud of in v1.0 is now an absolute mess to squeeze the 14 soic chips in along with a larger micro for the necessary extra I/O.
So this brings me the the second notable upgrade. I was using the diminutive narrow smd PIC16F886 package in v1.0, but for 2.0 I had to upgrade to the PIC16F887. Luckily, basic code-wise nothing really changed as they both have the same core, just the 887 has a ton more I/O. The rest of the lower level code to handle all the extra outputs though had to contend with independently driving each segment, but luckily I decided to wire things such that segments were in logical order so a simple port write can easily correctly set an entire digit in one fell swoop (with a small exception of hardware rx/tx pins which required one of the segment G pins to be tacked onto another port). In terms of the communication/interrupt/higher level architecture nothing else really had to change.
I was pretty nervous firing v2.0 up for the first time when I tried to flash the firmware and my pickit couldn't even see the PIC. Oh crap, I figured I screwed up royally again, but a quick look at the schematic revealed I allocated one of the programming pins double duty with driving an h-bridge and since I only supplied 5V and not the 12V coil drive rail I suspected the pin was being logged down. Powering the 12V rail additionally resulted in my programmer being able to see and program the chip. A small setback having to supply both 5V and 12V to program but I can live with that. So I flash the processor, hold the on board button during power-up to exercise the self-test functionality that flips all segments sequentially and low and behold she's AAAAAALLLLIIIIVVVEEE!!!
The next step was to check the communication functionality and luckily everything seems to be functional with two small caveats. The first I've found is that for some reason devices with address 1 don't seem to respond to commands. Every other address 0-6 work perfectly. I'll have to dig through the code and enable debug print statements through the tx pin to figure out why. But for the meanwhile this can be avoided just by not using address 1. Programming the address is currently only possible through using an icsp programmer to flasht the eeprom (I'll likely add the ability to change the address through serial in the near future).
The second bug is more interesting. I've found that sending two packets to the same address to write to say both digits results in the module locking up and not responding to any more commands. A cheap work around is to just delay sending commands by a second to allow any process to finish. However, this is a bandaid and not a fix. I have a sneaking suspicion I am having a stack overflow. See, I handle receiving and decoding serial commands in an interrupt that calls the display write function to actually twiddle the segments. I stupidly didn't disable interrupts while executing a command. The problem is twiddling the segments takes time and if another valid command arrives before the last command is finished then the interrupt will interrupt the last interrupt which isn't quite done and the processor goes deeper down the stack rabbit hole. The PIC only have a stack depth of 9 so if it happens to exceed this (which is probably easy with all the functionception my code does) the stack will overflow and the program counter return address will point to god knows what. I have a feeling when my processor locks up it is executing some random address in no man's land in the memory...Read more »
A quick video update on the first prototype boards I received from JLCPCB. In a nutshell I made a critically stupid design error in the way I had planned to drive these displays which means that I cannot independently drive segments in this revision. For this to work properly I would really need tristate drivers to ensure there are no unintended current paths for the disabled display's segments. I also overlooked a subtle gotcha in the datasheet for the motor driver chips I use where both outputs can never be high simultaneously (which is an issue when trying to reset segments). Additionally I've noticed these motor driver chips are pretty slow (on/off delay in the order of tens/hundreds of ms), but that shouldn't be much of an issue in a mechanical system like this. Oh well, I'll take this as a learning experience and start designing v2.0 of the board. Hopefully I'll have good news in the form of an update once I've ordered and assembled v2.0.
Received the displays and made is quick unboxing/teardown/test video on them. Super huge thanks again to Alfa-Zeta for donating these beautiful displays for this project!
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...Read more »
I've known of these types of displays for quite awhile but due to their second hand price on sites like ebay and rarity I just wrote off that I would never be able to reasonable get ahold of them. Then I found out a company based in Poland is still making them so I decided to send an email to Alfa Zeta asking if they could potentially donate some of their small 7 segment displays for this project explaining what I had intended to do with them. I want to make a clock (like everyone else does) but additionally the device would double as a wifi connected subscriber counter for my youtube channel. I figured worst case they would just ignore me but to my surprise within a day of sending that email they replied saying they would be happy to help and were interested in seeing the outcome of my project!
So now I have a generous set of 6 displays coming in the near future. But I need to figure out how I am going to drive them. A lot of the implementation I see end up using discrete components to implement the necessary bipolar control these types of displays require. I decided to make each module control two digits with multiple modules able to be chained together. Instead I wanted to use the cheap, widely available L9110, a dual h-bridge chip meant for motor control. This would simplify component area, wiring and control.
Now since with 6 displays I would have far too many segments to control directly, I opted to multiplex the displays so I have devised a way to drive each of the segments with a single common high side h bridge and an individual low side h bridge. The issue is this will work for a single display but for multiple ones you couldn't control one display without messing with the others, so a high side series reed relay will allow the controller to select each display individually. So parts count so far for a two digit module is 5 dual h bridge chips and two relays (plus some transistors to drive said relays).
The module will require 5V for the digital logic bits and 12V for switching the coils (with onboard resistors to set drive current). The current will hopefully be low enough (~300mA according to the display datasheet) that I can use an off the shelf boost converter module to generate the 12V from the 5V.
For the controller I went with the PIC16F886 since a tiny smd package is available, it has plenty of I/O, 8K of flash, internal 8MHz oscillator and I am well versed in its use. The firmware will internally handle all control of all segments for the two displays and will be easily interfaced serially using a simple addressing scheme which I will thoroughly detail in the next log.
Thanks to my youtube channel sponsor JLCPCB for providing the boards for these modules free of charge. Check them out for 10 pcbs for only $2. So while I wait for all the parts to arrive let's get started on that firmware ...