xTimer with 4094

Wichit Sirichote, kswichit@kmitl.ac.th

New design xTimer using CMOS shift register 4094 for driving 7-segment LED directly!

The original version of xTimer used MAX7219 for driving 7-segment. This new design uses a cheap CMOS shift register, 4094 for LED interface. Each 4094 drives a 0.5" 7-segment without the need of limiting resistor. The left-hand LED is timer function with buzzer alarm output. The right-hand is for clock display.

Figure 1: The prototype of xTimer V1.0 using shift register 4094.

Hardware Schematic

Fig. 2 shows a complete hardware schematic. U2 is ATMEL 89C2051 running with 24MHz xtal. The original version uses 11.0592MHz, this version I need the accurate clock, so I chose 24MHz. Since the clock input to timer is 24MHz/12=2MHz. To produce 100Hz timer interrupt, we can then use reload value for timer0 with 65536-20000=45536.

The input keypad for timer setting, key1 to key4 are tied to P3.2 to P3.5 using internal pull-up. P3.0 and P.3.1 drive two buzzers through 7407 buffer gate. The output is active low. Output1 to output4 are open collector. We can use them to drive small +12V relay directly.

Figure 2: Hardware schematic of xTimer V1.0.

U3,U5,U7,U9,U12,U14,U16 and U18 are CMOS shift register 4094 making the 64 bits CMOS output port. Each chip drives the 7-segmant directly. The brightness for 0.5 inches LED shows very well. Notice that the output of CMOS shift register can drive the segment without external current limiting resistors. The VOH will drop when it sources the current. This feature makes the circuit is easy to build. All 64-bit CMOS output is controlled by three signals, i.e. DATA, STROBE and CLK. The signals are generated by software controlled: DATA by P1.6, STROBE by P1.5 and CLK by P1.7.

Figure 3: The 7-segment driver using CMOS shift register 4094.

64-bit data stream is shifted into the U3 pin2 with rising edge of CLK signal. QS is the output bit that ties to the next data input. STROBE and CLK signal are tied to each 4094 chip. When all 64-bit are complete shifted, the trailing edge of STROBE will write them to the output concurrently.


The firmware is timer interrupt driven program. The interrupt rate is 100Hz. The XTAL is 24MHz. Timer0 receives 24MHz/12=2MHz. To produce 100Hz, the reload value then equal 65536-20000=45536 or 0xB1E0. Below is timer0 interrupt service function. All tasks will be executed every 10ms.

void timer_isr(void) interrupt 1 using 1
TH0 |= 0xb1; // reload value with 24MHz Xtal
TL0 |= 0xe0;
clock(); // update realtime clock

I have replaced timer function for timer3 and timer4 with clock. Below shows new layout. Now Key3 and Key4 can adjust current time for HOUR and MIN easily.

The SPI signals: DIN, CLK and STROBE are declared to use P1.6, P1.7 and P1.5. The function that interfaces to the eight 4094 is write_LED( ). The function has a nest loop using variable i and j. i is for inner loop counting, j is outer loop counting. The inner loop shifts 8-bit from buffer variable. Begin with buffer[0] to buffer[7]. Each byte will shift bit 7 first. This is done by ORing with 0x80. If true, then set DIN with "1" else with "0". The bit is shifted with 0-1 transition of CLK signal. The inner loop will do 8 times by outer loop counter using variable j. When 64-bit are shifted, the STROBE signal will make 1-to-0 transition to strobe all bits to the output.

sbit CLK = P1^7;
sbit DIN = P1^6;
sbit strobe = P1^5;

// write 64-bit data to 4094 x 8, COMS shift regsiter
// The output of each register was tied to common chathod 7-segment LED
// data was shifted with rising edge, 0-to-1 CLK signal
// all bits are sent to the output with 1-to-0 STROBE signal

void write_led()
           char i,j;
 for(j=0; j<8; j++)
           for(i=0;i<8; i++)
           if(buffer[j]&0x80) DIN = 1; // set bit data line
           else DIN=0; // clear bit data line
           CLK= 1; // make clock high
           buffer[j] <<=1; // shift 1 bit left
           CLK = 0; // make clock low
           strobe = 1; // make strobe high
           strobe = 0; // then low


Startup file

I have modified the startup file to skip clear the internal RAM after reset. This prevents the clock data to be cleared. User can press RESET to enter standby mode of Timer1 and Timer2 without destroying the clock display. When compile the source code, you must include the startup file to the project file.

Buzzer Alarm

Timer1 and Timer2 have buzzer alarm output. The beep patterns are arranged by two arrays.
unsigned char code busy_pattern[4]= {1,20,0,100}; // on 20ticks, off 100ticks
unsigned char code busy_pattern2[4]= {1,20,0,20}; // on 20ticks, off 20ticks

busy_pattern is for time1 and busy_pattern2 for timer2. The array comprises of code for enable buzzer and duration.

For example {1,20,0,100} for timer1, the meaning is turn buzzer on 20 ticks and off 100 ticks. Click below for sample sound.

Buzzer1 for Timer1
Buzzer1 for Timer2


Schematic xtimer1.pdf
C source code and startup file xtimer1.c startup.a51
Intel-Hex file xtimer1.hex
Datasheet 4094 shift register 4094.pdf
OrCAD 9.1 Layout gerber file xtimer1.zip

1 May 2006

Recovered 18 December 2015