Monday, January 24, 2011

99-minute timer with dual 7-segment LED display

My objective in this design was to simply it as much as possible parts-wise--to minimize the number of discretes. The original design called for the use of MOSFET transistors exclusively to obviate the need for base resistors but I currently don't have any common cathode LED displays on hand and I need a timer ASAP so I had to use PNPs for the common anode display. There is only one pushbutton and it uses the weak pull-up of the MCU, hence a discrete pull-up resistor is unnecessary.

  • Maximum time/readout = 99 minutes
  • Display is shut down and MCU goes to sleep 10 seconds after readout becomes zero
  • After timing has commenced readout flashes at a frequency of exactly 1Hz and with a duty cycle of 50%. Flashing readout is therefore counting down seconds.
  • The pushbutton has multiple functions depending on status of the timer:
    • when readout is on, pressing it for a fraction of a second increments readout by one. Keeping it depressed for half a second increments readout by 10 and keeps incrementing by 10 while pressed. No further readout change will occur when readout rolls over to zero.  Button must be released and depressed again to increment again.
    • when readout is off (MCU is in sleep mode) button acts to wake up the MCU.
    • when timer has begun countdown but has not yet reached zero, button acts to abort timing.
    • when timer has counted down to zero and buzzer alert is sounding, button acts to stop the buzzer

Detailed description of timer operation and its firmware:

Upon power up, the MCU will be in Standby mode and 2-digit seven-segment LED display will read 0. If PB is momentarily pressed a 7ms beep will sound and the LED display will read 1. Because of the limitations of the display, the maximum number of minutes the system will accommodate is 99 minutes.

After the first keypress (unless it was to awaken the MCU) firmware enters Userinputting mode. Further momentary presses of PB will increment the time by one and a 7ms beep will sound and time will be displayed. Keeping PB depressed for about half a second will increment time by 10 minutes. If time displayed is not a multiple of ten (ie., dividing by ten will result in a remainder), then keeping PB pressed will change time to the next nearest higher multiple of 10. Eg. If current time displayed = 8 then it will be changed to 10. If display = 24 then it will be changed to 30. If PB is kept depressed, increment by 10 will continue until the key is released or until time increments to 0 (there is no 100). A 7ms beep will sound every time heating time is incremented/decremented by 10.

If time displayed is not zero then after no button presses are made for approx 3 seconds from the last button press, countdown will begin and four sets of 50ms beep followed by 50ms silence will sound to indicate that countdown has commenced. Firmware is now in Countingdown mode. The amount of time left will be displayed and display will flash once every second. When time is down to 1 minute, display will change from displaying minutes to seconds. Thus at one minute it will display "60" meaning 60 seconds. Display will cease flashing. Pressing either button while in Countingdown mode will abort countdown and a 7ms beep will sound. Firmware is then returned to Standby mode.

When countdown time has elapsed firmware is changed to Countdownfinished mode. 3 alarm sequences are sounded in succession: 10 sets of 0.1sec beep + 2sec silence, 10 sets of 0.25sec beep + 1.25sec silence, continuous 0.5sec beep + 0.5sec silence. At any time when firmware is in Countdownfinished mode, any button press will terminate the alarm and firmware will be switched back to Standby mode.

When in Standby mode and no button presses are received in approx 10 seconds, LED display is turned off and the MCU goes to sleep. It can be awakened by a button press. The button press that awakes the MCU does not count as time input--the reading is zero when the MCU wakes up. No beep is sounded when a button press wakes up the MCU.

Timer0 is set up to overflow every 8ms. In main() timer0 interrupt flag is continually polled. When it gets set, the input button is checked by the switch debounce routine. This routine determines whether the switch is bouncing or not, and if not whether it is at a high/low level and whether or not a falling/rising edge has occured. A falling edge indicates a valid button press. The routine also keeps track of how long the button has remained pressed and how long it has remained not pressed.

Timer1 is used for countdown timing. Timer1 uses an external 32.768kHz crystal for its clock. With a prescale set to 1:1, TMR1L = 0, and TMR1H set to 192, timer1 overflows every 256 * 64 / 32768 = 0.5sec. Timer1 is turned on only when countdown commences and is stopped after countdown or an aborted countdown.

Firmware uses a state machine implemented using switch()/case statement. There are four possible states: Standby, Userinputting, Countingdown, and Countdownfinished. Upon power up state = Standby. After any button press state changes over to Userinputting. Should countdown commence state changes to Countingdown. Should inputting be canceled states changes to Standby. Upon completion of countdown state changes over to Countdownfinished. When a button is pressed to stop alarm state changes to Standby.

The two digits of the seven segment display are multiplexed and each digit is turned on every time timer0 overflows (8ms). Thus, the refresh rate is 62.5Hz. Because of display flickering problem button beep should be less than timer0 overflow period. When longer beeps are required (eg. to indicate countdown has ended) a state machine implementation (employing switch()/case statement) is used within the main state machine.

Watchdog timer is enabled when MCU is awake and disabled when it goes to sleep. PORTA pull up for input button is enabled. Button is debounced in software. When MCU goes to sleep interrupt-on-change is enabled to allow button press to wake up the MCU. Upon waking IOC is disabled.

Wednesday, January 5, 2011

555 propagation delay

Still using the same 555-relay circuit I did a "prequel" and monitored the propagation delay between S(et)-R(eset) inputs and 555 output state change. Channel 1 of oscilloscope was connected to either pin2 or pin6 of the 555, while channel two was connected to pin3. Ground clips were connected to circuit ground. Trigger mode was of course single sweep, rising or falling edge triggered, and triggering on channel 1. Trigger voltage was adjusted accordingly depending on whether rising or falling edge trigger was selected. Each screenshot below is a different, unique acquisition.

The switch used for S and R were simply short lengths of  AWG#22  solid wire. One end was plugged into the breadboard slot for pin2/pin6 and the other end was momentarily plugged into the ground/VCC slot when the 555 was to be triggered. What amazed me--and as you will see in the shots below--was that there was no contact bounce at all with this most primitive method of switching.

A. Channel 1: 555 pin2, falling edge trigger.
Propagation delay, measured @50% of VCC:  ~200ns

B. Channel 1: 555 pin6, rising edge trigger
Propagation delay, measured @50% of VCC:  ~175ns 

Interestingly, there's very noticeable ringing when pin3 goes from high to low. And it begins the moment pin6 goes high. Quite intriguing. Wonder what's happening internally.

All of the tests above were done with the 2N7000 and relay connected. They were disconnected from the circuit and the results were still the same including the observed pin3 ringing.

Tuesday, January 4, 2011

Propagation delay of 555-relay circuit

Given that the relay contact bounce test circuit is still on the breadboard I recorded the time delay between 555 pin3 level change and relay NC/NO contacts state change. Using that very same circuit without any modification, I connected channel 1 probe to 555 pin3 and channel 2 probe to VO. Ground clips of both channels are connected to circuit ground. Channel 1 is set to 2V/div while channel 2 is at 5V/div--so that the two waveforms don't overlap one another on the screen. Trigger is set to single sweep, edge triggering on channel 1. Each screenshot below is a unique acquisition.

A. 555 pin 3 output rising, NO contacts closing. Time delay ~10.5ms (excluding contact bounce, i.e. delay is measured from 555 pin 3 rising edge to the very first falling edge of NO contacts)

B. 555 pin 3 output falling, NO contacts opening. Time delay ~8.6ms

C. 555 pin 3 output rising, NC contacts opening. Time delay ~7.3ms

D. 555 pin 3 output falling, NC contacts closing, Time delay ~12.2ms (excluding contact bounce)

Relay contact bounce test

I haven't really tested the contact bounce characteristics of any mechanical switch so I thought I'd use an oscilloscope to check those of an electromagnetic relay. I picked the Telemecanique RXM2AB2JD mini relay with a 12VDC coil since I like that relay for its smart design and have a couple of them in stock.

Now we can't just use a mechanical switch to directly turn the relay on and off since that switch would itself have contact bounce. We need to switch the relay with a near perfect square wave. To make things simple I opted to use a 555 to perform this switching. I wired the 555 as a simple RS latch (flip flop) thus turning the 555 into a switch debouncer. So now we can use the any mechanical switch and the output of the 555 should, at least theoretically, be a clean, crisp, bounce-free square wave. Here's the debouncing circuit which I assembled on a solderless breadboard:
You will notice that pin2 is normally high while pin6 is normally low. When S(et) is pressed momentarily pin2 goes low and pin3 goes high and stays high. When R(eset) is momentarily pressed pin3 goes low and stays low.

Before showing the oscilloscope readings here's a guide to reading the Rigol DS1102E screen display.
I tested the 555 output (pin 3) to make sure that I was getting a nice clean square wave. The following screenshot is a typical of what I got. As can be seen rise time is around 200ns while fall time is some 10x shorter.The oscilloscope was set to display dots (so we can see if sufficient samples were taken during the rise and fall).

I don't want the 555 getting loaded down by the moderately high current draw (~75mA @12VDC) of the relay so I used a 2N7000 MOSFET transistor to switch the relay coil. I checked the rise and fall times of 2N7000 as well just to make sure, so before installing the relay I connected a 10Kohm pull-up resistor to the transistor drain:
Here's the input-output voltage response diagram for the above circuits (555 with and without the 2N7000):
And here are the oscilloscope readings for VO (voltage at transistor drain with respect to ground):

Below are the final test circuits with the relay and its normally open (NO) and normally closed (NC) contacts used for testing relay contact bounce. Star connections were used for VCC and ground to try and isolate the control circuitry from relay coil noise produced during energization/de-energization.
The input-output response diagram:

The following screenshots show the voltage across the relay when it is switched on. Take note of the different time base of each shot. Each of them is a different acquisition (i.e., relay is switched off then turned on again for each screenshot). Ringing is conspicuous.

Below are screenshots showing the voltage across the relay when it is switched off. Again, take note of the different time bases of each shot, each of which is a different acquisition. Note as well that the vertical division is now 5VD/div in order to get all the data points on screen. As with turn-on ringing is evident.

In the following shot I wanted to show more detail of the relay voltage as it de-energizes so I decreased the vertical division to 2V/div. Time base is 100ns/div.

And finally, here are oscilloscope readings for the relay contact bounce.

A. Normally open contacts

1. N.O. contacts closing. For each the three acquisitions the waveform is presented first as a vector and followed by a screenshot showing it as dots. Note the differing time bases.

The following two shots are from the above 20µs acquisition. I merely dialed the time base up to 100µs (and hence we see the waveform is truncated at the right as the scope's sampling memory has been used up).

2. N.O. contacts opening. For each of the two acquisitions the waveform is presented first as a vector followed by a screenshot showing it as dots. Time base for both acquisitions is 20µs.

B. Normally closed contacts

1. N.O. contacts opening. For each of the three acquisitions the waveform is presented first as a vector  followed by a screenshot showing it as dots. Note the differing time bases.

B. NC contacts closing. For each of the three acquisitions the waveform is presented first as a vector  followed by a screenshot showing it as dots. The first three acquisitions have a time base of 500µs/div; the last two 50µs/div.


Contact bounce is clearly evident when the NO and NC contacts are closing, with the contacts closing and opening for many cycles before settling down to a steady closed position. From the readings above NO contact bounce period is from 2 to 2.5ms, while NC bounce is from 3 to 3.25ms. Compared to manual switches which may take tens of milliseconds to settle, contact bounce period of this relay is short.

NC contacts do not exhibit any bounce at all when opening. It's amazingly clean. NO contacts, however, show an interesting characteristic. There seems to be a short period (tens of microseconds to around 200ms) of high resistance--voltage across the contact (with reference to ground) hovers at around 3V. The resistance can be computed using the voltage divider rule for resistances in series.

VS = voltage source = 12V
R1 = 10Kohm resistor
R2 = NO contact resistance
VR2 = voltage across R2

VR2  = R2VS / (R1 + R2)

Solving for R2 we obtain:

R2 = (VR2R1) / (VS - VR2)

Plugging in the values we obtain R2 = 3.3Kohms

One possible reason for the difference in contact opening characteristic between NO and NC contacts is that NO opens under spring force while NC opens upon coil energization--the latter probably applies a much greater force than the spring thus greatly minimizing contact "sticking." Another reason could be arcing across the contacts while they're opening which is relatively slow under spring force. Contact opening characteristics will need to be further examined under higher voltages and currents.