Introduction: U-Disp - the Digg (tm) Display (Open Source)

About: Swedish expat living now living in Malaysia after spending some years working in Dubai.

Ever wanted to know how many diggs your latest digg submission is getting? Or how many unread mails you got? Or the current load of your server? How many hits your homepage is getting? The exchange rate, gold price or your portfolio value?

And you you want this on a display that's easy to read across the room and can be chained to several display for showing multiple values without scrolling or changing?

Then U-Disp is something for you.

U-DIsp is a eight character seven-segment display that you connect to your computer by USB. The display is controlled by a Windows Service (background) that are pulling information from a multitude of sources and can be configured to display in on one or several displays.
This video shows two chained displays being plugged into my laptop and starting up showing their built in "attract mode" for a while.

When I start the software on the laptop the attract mode ends and the upper display then displays the number of Diggs of two stories on Digg.com, and the lower display shows the current time, my number of unread mails and the CPU load.


Step 1: Open Source Software & Hardware

All parts of this project are open source. Licensed with the BSD license which allows you to do pretty much anything with it as long as you keep the copyrights and the attributions in the source as well as the products.

Both the firmware in the microcontroller on the board itself as well as the software running as a service on the PC are open source and can by freely modified and redistributed.

The hardware is also open with the schematics and the board layout in Eagleformat plus complete Gerber files.

You are free to build, modify, improve, use, sell and distribute all of this as long as the original copyrights are left intact in the code.

Since I've only got the Non-Profit -version of Eagle I'm not allowed to make any money of any projects created with the software, but I'm allowed to sell boards at my cost-price with no markup. So I can sell some of my spare empty PCB's to anyone that's interested.

Here's the BSD license,

Copyright (c) 2007, Mats Engstrom
All rights reserved.

Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

  • Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
  • Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
  • The names of its contributors may not be used to endorse or promote products derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

Step 2: What You Need

The displays are populated differently depending on if it's the first display or one of the following in a chain of displays.

For the first display you need the following items:
  • (1) ATtiny2313 - Microcontroller
  • (1) FT232R - USB-to-Serial converter
  • (1) U-disp PCB
  • (4) Dual digit CA Seven Segment displays
  • (8) BC547 - Small signal NPN transistors
  • (9) 82 ohm resistors
  • (1) 10 K resistor
  • (2) 100 nF capacitors
  • (1) 100 uF electrolyte capacitor
  • (1) USB-A connector

For the following displays you need the following items:
  • (1) ATtiny2313 - Microcontroller
  • (1) 6 MHz crystal
  • (1) U-disp PCB
  • (4) Dual digit CA Seven Segment displays
  • (8) BC547 - Small signal NPN transistors
  • (9) 82 ohm resistors
  • (1) 10 K resistor
  • (2) 20 pF capacitors
  • (2) 100 nF capacitors
  • (1) 100 uF electrolyte capacitor
  • (1) 2x3 pole Molex connector

The complete BOM (bill of materials) with Mouser product numbers are available on the www.u-disp.com project site.

Step 3: The Prototype

I'll start with briefly describing the prototype for the u-disp and the steps taken.

Timeline
Sep 01 - Started thinking about making an USB display
Sep 06 - Bought the domain name u-disp.com
Oct 07 - Started planning the pc software
Oct 10 - Wrote the display emulator
Oct 11 - Started writing the pc software
Nov 05 - Made schematics & preliminary layout in Eagle
Nov 12 - Ordered components from Mouser.
Nov 18 - Got the components.
Started building prototype. Displays with driver transistors freeformed, uC on proto board.
Charlieplexing firmware for testing display.
Nov 22 - Finalized layout for PCB
Nov 23 - Ordered PCB from Gold Phoenix
Nov 30 - PCB shipped from China
Dec 05 - PCBs arrives
Built the first real display
Dec 06 - Built a second display and chained them

As you can see from the the timeline above it took quite a while to finish this project. And to be honest - it's still not really finished. There's a lot of things that needs to be fixed and improved in the PC software, but it kinda works at least...

From November 5 to December 6 - that's one month. Most of the time was just waiting and more waiting. If I lived in the US instead of Middle East I'd probably been done in under 10 days. But I'm really not in a rush here, it's just a hobby.

Step 4: Prototype - Displays & Drivers

I started by building a "self contained" Charlieplexed (read more about Charlieplexinghere) seven segment display unit with drivers and current limiting resistors. This little unit can be reused in other projects.

I decided to not waste any veroboard or labboard so I hot glued four dual-displays together and tacked on eight NPN transistors on them and then connected it all together using 0.1 mm (AWG 38) polyurethane coated wire. This wire is great to work with since you can solder right thru the insulation without stripping it first. I crank up my old Weller to 400C wrap the wire an turn or two on the component pin and the heat and apply solder. It's extremely time saving, but the solder joint looks like crap quite often due to the melted plastic.

After soldering it together and connecting it to a ten-pin header via nine current limiting resistors I manually checked it by applying VCC and GND on all pins in combinations and wrote the resulting lights on a grid I discovered that I had one bad solder joint and that I cross connected the wires to the first and last driver transistors. That was easy to fix and probably saved me hours of frustrating debugging the software for a non existing problem.

I connected the wires to a nine-pole molex header and reinforced the solder joints on it by applying hot glue to it. By putting the molex header on a cold harddrive and then applying the glue it was easy to get a nice glue-reinforcement.

Step 5: Prototype - Microcontroller

Then I wired up a TINY2313 on the solderless proto board and connected the display and the ISP cable to it for testing the updated firmware for Charlieplexing that I had used on a previous project.

After flashing the software it didn't work at all and I couldn't flash any new software into the chip. Being used to AVR's I realized that I had the wrong fuse settings so the crystal oscillator didn't work. That's easy to fix by installing an external clock source to it and flash the fuses to the correct values so I just connected a 10 MHz oscillator module to the XTAL1-pin and flashed it. Now everything was working just fine. I'd like the display to be a bit brighter though, but is is clearly visible even if I shine a 40W halogene light straight on the display so I will not bother to add additional drivers.

To be able to communicate with the microcontroller I needed a more stable timing source than the internal RC-oscillator in the microcontroller, so I added a 6 MHz crystal and two capacitors.

Step 6: Prototype - USB

The display and CPU part is running, so it was time for the USB part. The FT232R is a SOIC28 chip where the pins are at 0.68 mm CC (0.026 inch) and I didn't have an adapter board for it. Manually soldering wires to the pins is possible is you have the right soldering tip, a good soldering flux and a really good magnifying glass, but I didn't have anything is these so I decided to do it another way.

I bent every other pin up and the others down on the chip. This way I increased the spacing between the individual pins I had to solder to something like 1 mm - and that I could handle.

By soldering wire-wrap wires on the pins and then soldering them to a standard IC socket I had my adapter. A quick optical inspection didn't reveal any short circuits, but with such small dimensions and tight tolerances I could easily miss a few bridges.

I inserted the socket into the proto board, connected the capacitor for the internal 3.3 volt generator in the chip and applied power to it. I measured 3.4 volt over the capacitor so the chip was at least partly alive.

After connecting the D+ and D- from an USB cable to it the computer told me that an "Unknown USB device had been connected to it.". This is bad news since XP already got the drivers for the FTDI-chip it it. Hmmm... Maybe I just connected the D+ and D- wires the wrong way around even if I had checked it before I connected them. And yes, that was it. After I reversed them the computer identified the chip and a new serial port.

I looped the TXD and RXD pins together and I got the text I wrote in hyperterminal echoed back to me. Hooray! It's working....

I used an utility from FTDI to set the CBUS1-pin to output 6 MHz to drive the ATTiny2313 with. And then a downloaded a serial port testing program so I could manually toggle RTS and DTR on the chip so I could check that those outputs was working. I also tested the inputs like CTS, RI and CD.

I'm really amazed that it all worked, but I think that I need to dip the entire thing in hot glue in order to not getting it destroyed by just looking at it. It looks really ugly and fragile.

Step 7: Prototype -. Finale

When I knew that both the display-module and the ugly USB-hack worked I went crazy with the glue gun and really secured those two modules. They now look really strange and disgusting but they'll hold for at least a few more projects without breaking.

Step 8: Schematics & Layout

The testing of the prototype is finished so I could start finalizing the layout of the boards..

After making some minor changes to the schematics I tried a couple of variants of the placements of the parts between the USB-connector and the displays.

When I settled on a variant I printed the layout on a piece of paper and stuck the components thru the paper to get a better visual image of how dense the layout was. It seemed to be OK so I double checked the schematics against my prototype to see if there were any discrepancies.

In retrospect I realize that it would have been better to include the locations of the vias on this printout. With the vias visible I probably would have noticed that the USB connector might short circuit some of them.

Step 9: The Final Schematic

Here is the complete schematic.

Depending on if the boards is the first (with USB) or one of the others (without USB but with the crystal instead) the list of components needed will vary a bit.

First card
1pcs 556-ATTINY2313V10PU Atmel Microcontrollers ATTINY2313V-10PU $ @ 1.94
1pcs 895-FT232RL FT232RL USB TO SERIAL @ $3.99
8pcs 512-BC547BTA BC547 Small Signal Transistors NPN 45V 100mA @ $0.02
4pcs 604-DA5611EWA DA5611-EWA Kingbright Dual LED Displays CA @ $1.13
9pcs 299-82-RC 82ohms 1/8W 5% Resistors @ $0.02
1pcs 299-10K-RC 10Kohm 1/8W 5% Resistors @ $0.02
1pcs 140-MLRL10V100-RC Electrolytic Capacitor 6.3X7MM 10V 100uF @ $0.12
2pcs 581-5ZH104ZACJA Ceramic Disc Capacitors 50volt 100nF @ $0.14
1pcs 538-67068-8001 USB TYPE B Connector @ $1.31

Other cards
1pcs 556-ATTINY2313V10PU Atmel Microcontrollers ATTINY2313V-10PU $@ 1.94
1pcs 520-HCU600-SX HC-49/U-S Microprocessor Crystal 6MHz @$0.47
8pcs 512-BC547BTA BC547 Small Signal Transistors NPN 45V 100mA @ $0.02
4pcs 604-DA5611EWA DA5611-EWA Kingbright Dual LED Displays CA @ $1.13
9pcs 299-82-RC 82ohms 1/8W 5% Resistors @ $0.02
1pcs 299-10K-RC 10Kohm 1/8W 5% Resistors @ $0.02
1pcs 140-MLRL10V100-RC Electrolytic Capacitor 6.3X7MM 10V 100uF @ $0.12
2pcs 140-50N5-200J-RC Ceramic Disc Capacitors 50V 20pF @ $0.06
1pcs 581-5ZH104ZACJA Ceramic Disc Capacitors 50volt 100nF @ $0.14
1pcs 538-10-89-7061 Molex VERT BRKAWAY HDR 6P @ $0.26

The numbers in "italics"above are the part numbers from Mouser Electronics.. The prices might be a bit higher on some of the parts since these are the prices that I got when I ordered enough parts for building 10 boards.

Step 10: The Boards

Being more or less confident of that it was correct I made a zip-file of the grerbers of the layout and mailed it to Shane in Canada who is the contact guy for Gold Phoenix in China. I asked him for the 155 sq inch prototype special and within an hour I had a confirmed and payed order on the way for manufacturing in China.

Six days later I got a mail from them with a Fedex tracking number. Another five days passed by before the package arrived at the my office.

The PCBs arrived as 3 panels about the size of a A4-paper. Each panel had 10 of my design on it and they where v-scored so it was easy to break them apart.

I left the office early to go home and start soldering the first display. :-)

Step 11: Building - the Surface Mount

When soldering a PCB you normally start with the smallest devices first so I started with the FT232R USB-to-Serial chip that is a SOIC28-device with the pins as 0.65 mm interval. Thats really tight. But it's not impossible to solder it even with a rather wide tip on your soldering iron.

I started by putting a layer of solder on the pads where the chip would be mounted. I had to use a desoldering wick to remove excess solder from a few of the pads where solderbridges between the pads were.

Then I put the chip on to the pads and carefully adjusted the position of it. I then touched one of the corner pins of the chip with the tip of the soldering iron so that the solder below it melted. I checked that the rest of the pins still were on the pads and had not been skewed and did the same thing with the pin at the opposite corner.

Now the chip were securely fastened I held the tip on each pin (or more likely, two pins at the same time) for a second or two so that all pins got soldered onto the pads.

I checked for unwanted bridges between the pins with a bright light an a magnifying glass and it all looked good straight away.

So I temporary installed the capacitor that handles the 3.3 volt generation for the chip and the USB-connector and plugged it in to the computer.

The computer said Bing-Bong! A new USB device and a new Serial port was detected. So far so good.

As you can see in the picture I had to put a piece of insulating tape due to a minor mistake in the layout of the circuit. I forgot that the USB connector is metallic on its underside and that will short circuit any connections or vias that is beneath it - and I had three vias there. Oh well, the next generation of boards will be better.

Step 12: Building - the Rest

After the tricky part was done the remaining parts was a piece of cake.

I soldered the ten resistors and the two other capacitors. Then the eight drivers transistors and finally the four dual displays.

At this stage I didn't know if the remote programming of the microcontroller via the USB chip was working so I chickened out and used a socket for the microcontroller so I could remove it and (re)program it on my labboard if necessary.

Step 13: Testing - One Display

I inserted the microcontroller that I used for the prototype and plugged in the USB cable to power the board and was greeted by a lot of jumbled digits and flashing things.

Ok, so it does something, but not correctly.... After a bit of headscratching I realized that I had changed the order of the output pins on the microcontroller to make the layout nicer, so I fixed the code of the firmware and downloaded it into the microcontroller and applied power again. This time everything looked perfect.

I started a terminal emulator and sent a few hardcoded commands to the display which dutifully showed it on the displays.

I'm still really amazed that I haven't encountered any major (or even minor) screwups this far...

Step 14: Testing - Two Displays

After the success of the last step I quickly assembled another display to test the chain-functionality.

This board had the crystal, the two extra capacitors and the ISP connector on in instead of the USB-chip and USB-connector.

Here I boldly soldered the microcontroller directly on the PCB since I had the ISP-connector to reprogram it with.

Without the slightly tricky surface mounted USB-chip to handle it didn't take many minutes to solder all parts to the board and then connect the new board together with the old by the four wires between the next- and prev-connectors.

After plugging it in to the USB both displays started up and were receiving commands perfectly.

Using the controlling software in my laptop I now could control both displays as the video in the second step showed.

(In the picture here you can clearly see the unfortunate via-holes in the upper right hand corner of the USB connector, between the words NEXT and X1. Without an insulator of some kind between the connector and the board they will be shorted by the metal in the USB-connctor.)

Step 15: Project Description - Hardware

The hardware is a circuit board sized 1.05" x 6.3" (2.7 cm x 16.0 cm) that can be populated in two different ways depending if it is the first in the chain or not.

Chaining
The displays can be chained together to form a string with up to 16 displays. Each board have two 4-pole connectors in the left upper and lower corners. This connector carries the power and the communication channels between the displays. Just connect the top connector of display #1 to the lower conector of display #2 and so on in a chain. Only the first display needs the USB connector and the USB-to-Serial chip, the rest of the displays should have a crystal in place of the USB-chip.
Power

The display is USB powered and draws about 100 mA from the USB bus so it's possible to connect five units in a chain without exceeding the limit of 500 mA per USB socket. Most PC's can deliver much higher currents though, many 2.5" external hard disks requires up to 700 mA and they work just fine.

There are two ways of overcoming the limitation of five displays. Install another USB-connector on the sixth display and don't jumper the plus-connector between display five and six. The new cable will then feed power to display five and higher. The other options to break the plus-jumper between the first and second display and then connect an external 5 volt power supply with enough power to supply the rest of the up to fifteen displays - like 1.5 Amperes.

The circuit

The circuit is basically separated into three parts.

1. The USB-to-serial converter
2. The microcontroller
3. The displays with anode drivers

Almost all of the parts are very common and hole-mounted for easy assembly, there's really no rocket science here. The only exception is the FT232R chip. It's both surface mounted and is most probably not available from your local mom&pop electronics store. Fortunately they are both easy and rather cheap to get hold of by mail order.

The full schematics, in both PDF and Eagle-formats, as well as premade Gerbers are available in the download section of the project website.

USB-to-serial
This is handled by a FTDI FT232R chip housed which is surface mounted (SOIC28) device. These chips can be a bit hard to solder correctly, but it's not impossible if you've done any soldering before. I plan to sell PCB's with the chip pre-soldered as a service for those who are hesitant to try it themselves.

The FT232R handles both the programming of the microcontroller using its synchronous bitbang mode as well as supplying a stable 6 MHz system clock for the microcontroller removing the need for an external crystal or tuning of the microcontroller internal RC oscillator.

When the USB cable is plugged into a PC it will automatically be detected as a new serial port that can be communicated with in an easy way, I've used Hyperterm to test the hardware with.

Microcontroller
The Atmel ATtiny2313 microcontroller is the heart of the circuit. It listens for comands on its usart and checks the destination of the incoming packets to see if it should act on it or just pass it on to the next display in the chain. It continuously updates the multiplexed signals going to the displays in order to display the requested digits and characters on it in a flicker free way,

Since the display is Charlieplexed only nine signals is going to it, with normal multiplexing sixteen (or with extra hardware - eleven) signals would have been required.

The boards that are not first in the chain doesn't have the FT232R chip installed which means that the system clock source on those boards is not available so a crystal and two capacitors must be installed on them. Also a 6-pole ISP header should be installed in order to allow (re)programming of the firmware.

Displays & Drivers
The displays are a dual-digit CA (Common Anode) model from Kingbright. This is a quite common model of display and it should be easy to find replacements for it if necessary.

As mentioned earlier they are Charlieplexed to reduce the number of requiredIO-lines. The anodes are driven by standard NPN small signal transistors like BC547 or 2N2222. The cathodes are current limited by nine 82 ohm resistors.

Step 16: Project Description - Firmware

The firmware is written in AVR-GCC and used about 60% of the available program space of 2KB in the ATtiny2313.

It is really quite simple piece of software. Basically all it does it to receive command packets on the serial port of the Tiny2313, check if the command is for this display, and if it is decode the command and store the bitpattern into the memory. If the command is for another display it will just pass it on to the next display.
The firmware can be download both as source code and as as precompiled hexfile from the download section of the project web site.

The messages between the Windows Service and the microcontrollers on the displays are formatted in rather compact 10 byte packets. In order to be able to reliably detect the beginning of each packet the most significant bit [MSB] (bit 7 that is) in the first byte is set to zero, the rest of the bytes are set to one.

Since each digit has eight leds (the seven segments plus the decimal point [DP]) that needs to be controlled we can't just map each digit onto a single byte because that would get the MSB set to zero (the start of packet indicator) if the decimal point was turned off. So the DPs gets its own byte, but since we have eight digits, and thus eight DPs the last DP must be put somewhere else or we'll get into the same problem again. The last digits DP is put on the first byte at bit six..

The first byte is is in addition to signaling the packet start and keeping the last digits DP also holds four bits (bit 3 to 0) that indicates which display (unit) this message is for. The first display is numbered 0 the next 1 and the last display is number 15. When the first display in a chain receives a message it checks the unit number and sees if it's 0. If it is the message is processed there. If it's not then the display decrements the value in the unit bits and passes the entire message along to the next display in the chain. That display also checks the bits for zero and acts accordingly.
            Bit no         |  7   6   5   4   3   2   1   0-------+---------------------------------------------Byte 0 |  0  d7p  x   x   u3  u2  u1  u0     1 |  1   G   F   E   D   C   B   A     (digit 0)     2 |  1   G   F   E   D   C   B   A     (digit 1)     3 |  1   G   F   E   D   C   B   A     (digit 2)     4 |  1   G   F   E   D   C   B   A     (digit 3)     5 |  1   G   F   E   D   C   B   A     (digit 4)     6 |  1   G   F   E   D   C   B   A     (digit 5)     7 |  1   G   F   E   D   C   B   A     (digit 6)     8 |  1   G   F   E   D   C   B   A     (digit 7)     9 |  1  d6p d5p d4p d3p d2p d1p d0p  
The table above shows the format of the message.

  • d0p is the Digit 0 decimal Point, d1p is the Digit1 decimal point and so on...
  • u0, u1, u2, u3 are the bits that tells the unit number that the message is intended for.
  • A,B,C,D,E,F,G are the segments of each digit.
  • x is an unused bit for future expansion.

Command receiving
Receiving the data from the PC is done with interrupts. Each incoming character generats an interrupt and gets handled by the function below. It collects ten characters in a buffer, checks if the command is for this display and decodes it and stores it if it is. If the message is for another display it decrements the destination nybble and send the entire message to the next display in the chain in the hope that a display later on will be there to handle the message.
//// This is the interrupt handler for the UART data received.//// Collect all incomming characters in the rxBuf -buffer until// we got all ten charachets of the message// Then check if the message is for this unit.  If it is, decode the// data and put it in the display array.  Othervise pass it on to the// next display in the chain.//ISR(SIG_USART0_RX) {	unsigned char rx;	rx = UDR; 		// Get the incomming data	// If the MSB if the character is not set then it's a start byte	if (rx < 128) {				rxPtr = 0;		// So reset the buffer pointer to zero	}	rxBuf[rxPtr++] = rx;	// Store the character in the buffer	// If we got the entire message then process it.	if (rxPtr == MSG_LENGTH) {		// Check If the message is for us		if ((rxBuf[0] & 0x0F)== 0) {			// Yes, decode and store in memory			for (rx=0; rx<8; rx++) {				digits[rx] = (rxBuf[rx+1] & 0x7F);			}			if (bit_is_set(rxBuf[0],6)) digits[7] |= 0x80; 			for (rx=0; rx<7; rx++) {				if (bit_is_set(rxBuf[MSG_LENGTH-1],rx)) digits[rx] |= 0x80; 			}		 		} else {			// Not for us, so we just pass it on			rxBuf[0]--; 	// Decrement the unit-counter			// Copy the entire message to the transmit buffer			for (int i=0; i				txBuf[i] = rxBuf[i];			}			txPtr = 1;		// The next character to be sent by the ISR			UDR = txBuf[0];	// Send the first character manually to trigger the ISR		}		rxPtr = 0;			// Reset the receive buffer pointer to zero	}	// Make sure that the pointer can't point outside the buffer	if (rxPtr >= MSG_LENGTH) rxPtr = MSG_LENGTH - 1;}

Digit multiplexing
Since the digits are multiplexed (only one of the digits are powered at a time) the firmware continuously lights up digit after digit for a few milliseconds each in so the eye/brain believes that all digits are on at the same time,.

To save I/O-pins on the microcontroller a special multiplexing technique called Charlieplexing is used. It drastically reduces the number of needed pins on the microcontroller but requires a more complex software controlling it.

Timer0 is used to generate interrupts for the digit multiplexing

// Define the i/o pins that are connected to the charlieplexed// display.  The suffix B or D makes it easier to keep track// of the PORT the bit belongs to.#define CHARLIE_1_B		PB3#define CHARLIE_2_B		PB1#define CHARLIE_3_D		PD5#define CHARLIE_4_D		PD3#define CHARLIE_5_D		PD4#define CHARLIE_6_B		PB0#define CHARLIE_7_B		PB4#define CHARLIE_8_B		PB2#define CHARLIE_9_D		PD6uint8_t digits[8];            // The array containing the digits to be shown on the display//// This is the Interrupt Service Routine that need to get called // often enough to not show any visible flickering on the displays.//ISR (SIG_OVERFLOW0) {     static uint8_t currentdigit=0;    // Keeps track of the digit to be shown    uint8_t segments;                // The bitpattern of the current digit    TCNT0 = 128;                     // Reset TCNT0 halfway to get a higher freq    // Get the bit pattern of the current digit    segments=digits[currentdigit];    // Set all LED-portpins as inputs so the corresponding    // segments of the displays will be off    DDRB &= ~(            _BV(CHARLIE_1_B) |             _BV(CHARLIE_2_B) |             _BV(CHARLIE_6_B) |             _BV(CHARLIE_7_B) |             _BV(CHARLIE_8_B)         );    DDRD &= ~(            _BV(CHARLIE_3_D) |             _BV(CHARLIE_4_D) |             _BV(CHARLIE_5_D) |            _BV(CHARLIE_9_D)        );    // Set low level on all LED-port pins. This prepares the segments    // to be lit if the pin is changed to output at a later stage. The    // displays ar of common anode-type (common positive) so the segments    // needs to be sunk to ground to be turned on.    PORTB &= ~(            _BV(CHARLIE_1_B) |             _BV(CHARLIE_2_B) |             _BV(CHARLIE_6_B) |             _BV(CHARLIE_7_B) |             _BV(CHARLIE_8_B)         );    PORTD &= ~(            _BV(CHARLIE_9_D) |            _BV(CHARLIE_3_D) |             _BV(CHARLIE_4_D) |             _BV(CHARLIE_5_D)        );    // Set portpins as output for segments to be lit    // We just assume that each segment has it's standard    // place in the connections.  The special case is handled    // in the switch-statement below.    if (bit_is_set(segments,0)) DDRB |= _BV(CHARLIE_1_B);    if (bit_is_set(segments,1)) DDRB |= _BV(CHARLIE_2_B);    if (bit_is_set(segments,2)) DDRD |= _BV(CHARLIE_3_D);    if (bit_is_set(segments,3)) DDRD |= _BV(CHARLIE_4_D);    if (bit_is_set(segments,4)) DDRD |= _BV(CHARLIE_5_D);    if (bit_is_set(segments,5)) DDRB |= _BV(CHARLIE_6_B);    if (bit_is_set(segments,6)) DDRB |= _BV(CHARLIE_7_B);    if (bit_is_set(segments,7)) DDRB |= _BV(CHARLIE_8_B);    // Here we do the bit-fiddling thats neccesary to charlieplex.    // Since one of the segments (each different) of each display     // is moved to the 9'th connection we need to take care of that.    //    // Depending on which digit that are active now we need to handle    // the situation in its own unique way.    //    // The A segment on the first digit is moved from the 1'th line    // to the 9'th line so be basically to the same thing as in the bunch    // of tests above, but only test for the A segment and if it's lit    // we turn on the 9'th line instead of the first line.      // We then need to activate the transistor that handles the common     // anode for the first digit. The transistor for the first display    // is connected to the 1'th line (where the A-segment usualy go).    // so we turn on the output for that pin and set it high.    //    // The next time this routine is called we do the same thing with    // the second digit. But we then check for the B-segment and so on...    switch (currentdigit) {        case 0:            if (segments & 0b00000001) DDRD |= _BV(CHARLIE_9_D);            DDRB |= _BV(CHARLIE_1_B);            PORTB |= _BV(CHARLIE_1_B);            break;        case 1:            if (segments & 0b00000010) DDRD |= _BV(CHARLIE_9_D);            DDRB |= _BV(CHARLIE_2_B);            PORTB |= _BV(CHARLIE_2_B);            break;        case 2:            if (segments & 0b00000100) DDRD |= _BV(CHARLIE_9_D);            DDRD |= _BV(CHARLIE_3_D);            PORTD |= _BV(CHARLIE_3_D);            break;        case 3:            if (segments & 0b00001000) DDRD |= _BV(CHARLIE_9_D);            DDRD |= _BV(CHARLIE_4_D);            PORTD |= _BV(CHARLIE_4_D);            break;        case 4:            if (segments & 0b00010000) DDRD |= _BV(CHARLIE_9_D);            DDRD |= _BV(CHARLIE_5_D);            PORTD |= _BV(CHARLIE_5_D);            break;        case 5:            if (segments & 0b00100000) DDRD |= _BV(CHARLIE_9_D);            DDRB |= _BV(CHARLIE_6_B);            PORTB |= _BV(CHARLIE_6_B);            break;        case 6:            if (segments & 0b01000000) DDRD |= _BV(CHARLIE_9_D);            DDRB |= _BV(CHARLIE_7_B);            PORTB |= _BV(CHARLIE_7_B);            break;        case 7:            if (segments & 0b10000000) DDRD |= _BV(CHARLIE_9_D);            DDRB |= _BV(CHARLIE_8_B);            PORTB |= _BV(CHARLIE_8_B);            break;    }    // Show next digit at the next interrupt. This can't be done    // at the top of the ISR since the digit variable is needed    // in the switch-statement later on.    currentdigit++;    if (currentdigit>7) currentdigit=0;}

Step 17: Project Description - Software

The controlling software runs on a PC and is written in C#.

It is written to run as a Windows Service so that it starts automatically when the PC is booted and runs invisibly in the background.

To change settings there's a web interface that you can access from your browser by going to http://localhost/:4201 . There you can select what information that should be displayed and how and how long it is shown.

There's also a display simulator with four virtual displays that can be used for debugging and testing the software without actually having access to the u-disp hardware.

The software is working, but not completely reliable, so it needs some more work before its really usable. But I keep on working on in...

Step 18: Some Final Words...

There's a website at www.u-disp.com that is the project site for u-disp,

Much of the information here is duplicated there, and there's a forum and a download section on the site where all software and the other stuff are available for download.

A subversion repository for files and a trac issue tracking is being installed.

If any of you are interested I can sell some of the 25 remaining PCB's for $5 each plus postage.

I hope that you liked this project and may want to be a part of the further development of it. I have plans to make a version with more SMD components and maybe use 14-segment displays for prettier characters.

Also, winning a laser cutter would make it easy to cut out and etch nice front panels in plexi for the displays.... Hint... Hint... ;-)