Projects

Keeping Time

ATtiny General Purpose Timer

Peter Stewart

Issue 53, December 2021

This article includes additional downloadable resources.
Please log in to access.

Log in

An ATtiny85-based general purpose timer with buzzer.

A note from the editor:

We welcome contributor, Peter Stewart, this month. Peter is a retired engineer who originally graduated from Queensland University of Technology with a Bachelor of Engineering (Electronics and Communications).

Peter cut his teeth with Marconi Avionics in the UK, designing with state of the art 16-bit processors for Helicopter Systems. He then moved back to Australia to work for Plessey Australia, who seconded him back to the UK to work on Tactical Military and Strategic Military Communication Systems. He returned to Australia to help deploy the Strategic Military Communications System.

He then became the Engineering Manager for a RAAF project which updated much of the RAAF Airbases communication radios and systems around Australia. He then returned to his home town of Brisbane, with his wife and children, where he was employed by Boeing Defence Systems to work on several projects, which included the communications infrastructure for an Australia wide HF System.

Peter ended his career as the Design Authority for the Internal and External Communications on the Collins Class Submarines.

He is now enjoying his hobbies, which include electronics (especially IoT and all that is WiFi). He is also an enthusiastic Supercars and F1 watcher.

Up here in Queensland, some years ago, we had water restrictions and it was suggested that we take short showers to conserve water. To help Queenslanders, we were supplied with little hourglass sand timers, which would give you a four minute timer.

I used this in my shower for years until it fell off my shower screen and broke. I did have a spare, but I am a retired engineer and thought there must be a better way or at least something a bit more interesting.

My hobby, since I started University studying Electrical Engineering (Electronics and Communications), has been electronics of all sorts. So, when I retired three and a half years ago, I wanted to get back to grassroots electronics. A lot of things have changed since my University days. I discovered the Internet of Things (IoT). This has been an eye opener and led to many exciting discoveries. So here was another opportunity to put what I have learned to work.

I wanted a Shower Timer, but wait. Why not produce a timer that can be used for many things! My wife sometimes needs a timer in the kitchen. When I wash my dog, the medicated shampoo is to remain on for ten minutes. There are many other applications for timers. So what I needed was a General Purpose Timer. I decided it only had to time minutes, not seconds. This was more useful to me.

Note: My design could be easily adapted to time in seconds if desired.

Being a retired engineer, I had to decide on what my requirements were. This is usually resolved by consulting all the stakeholders. Well, that was my wife, me and my dog. So most of the input came from me. My requirements were as follows:

  1. It had to be simple (well relatively – engineers always like to complicate things).
  2. It needed to be small, but not too small as I decided the Timer did not have to be in the shower as it would then have to be waterproof.
  3. Visual and an audible indicator so I could see or hear when the timer progressed and timed out.
  4. Portable, so it had to be battery powered.
  5. Low power consumption so that the batteries would last a long time.
  6. When not in use, it should consume next to no power.
  7. The controls had to be minimal, two buttons, one for ON and one for START.
  8. The build components had to be readily available, preferably in my parts box.

The Design

I had some little boxes I bought some time ago (64Dmm x 88Wmm x 34Hmm), which I decided to use.

You could most probably use a Jiffy Box or 3D print one (I have just acquired a 3D Printer – very exciting!). The box I used had some mounting pillars in the middle of the base, which I removed using my Dremel Router, as I needed the space for the batteries. So everything had to fit in this box.

I use the Veroboard Type Strip Board (See Jaycar HP9544) for all my prototypes and often for my one off designs (which most are nowadays). I cut it to size to suit my project. All components are soldered to this board – more pictures later. So I have now made a few fundamental design decisions. Now for the components.

ATtiny85 Microcontroller

I decided to use an ATtiny85 microcontroller, as it has five usable Input/Output (I/O) pins. This would allow me to interface to two buttons, a LED (visual indicator), a buzzer (audible indicator) and one other pin to turn off the power. The ATtiny85 is an eight pin microcontroller in an eight pin Plastic Dual Inline Package (PDIP). It has timers, Input/Output pins, low power mode, operates from 2.7 to 5.5 Volts DC (it can operate up to 6 Volts DC – see Data Sheet), and an internal oscillator. Luckily, I had several in my parts box. I also had ATtiny84, ATtiny4313 and ATmega328 microcontrollers in my parts box. These I felt were in excess to my requirements, especially the ATmega328. As I have also built my own programmer (see article at the end of this one) to work with the Arduino IDE, programming would be easy.

Power source

Now I had to consider my power options for battery operation. What batteries should I use? Initially, I thought of using two CR2032 batteries. They are small and do not take up much space and dual battery holders are readily available (and I have some in my parts box!). Two fully charged batteries can provide up to 6.6 Volts DC. While they do provide up to 220 mAh of power, which most probably would be adequate, I did flatten these batteries quickly during my prototyping. So I decided I would use two 3000 mAh Li-ion batteries. These would last a lot longer. The use of the Li-ion batteries is quite an overkill, but I did have a lot of these batteries as they do power many of my projects. When I did get my design working, I did some current measurements and the results were as follows:

Current drawn when Buzzer sounds and LED Flashes 12 mA for 125 mS.

Current drawn when Buzzer and LED off, but not in sleep mode 7 mA for 250mS (this is the time between beeps/LED flashes for multiple beeps).

For a five minute timer, my code generates 10 beeps/flashes – one beep/flash per minute while counting down and five beep/flashes at the end. This works out to be 32.5 mA per second consumption or 9.03 x10-3 mAh per use. Let’s say we use it 10 times a day. That is 9.03 x10-2 mAHr per day. To put this in context, a dual CR2032 battery would give 2436 days of use or 6.7 years. My Li-ion battery would give 33223 days of use or 91 years! Yes, my Li-ion batteries are very excessive, but I decided not to change them as I had already managed to get them to fit. I did have another reason for using the Li-ion batteries and that was that they provided 7.4 Volts DC nominally and 8.4 Volts DC when fully charged. This is important as the buzzer I used gave a higher sound output with the higher voltage. I needed it to be as loud as possible to overcome my slight deafness.

Now, you may now see why I used two batteries and not a single battery. A single battery (CR20332 = 3.3 Volts DC max, Li-ion = 4.2 Volts DC max), would not provide enough voltage for the buzzer to sound loudly enough. This is not the only reason. I wanted to use a P-MOSFET switch (see simple configuration diagram) to turn power on and off to the ATtiny85.

The principle here is that Q1 remains switched off while S1 is open, passing no current. R1 keeps the Gate(G) of Q1 at the same voltage as the Source(S). To enable Q1 to pass current, the Gate of Q1 must be taken to a lower voltage, ie. Ground.

Many P-MOSFETS have a Gate Threshold Voltage ( VGS(TH) ) in excess of -4 volts, eg. IRF9540. Therefore, if you used a single battery, there is a good chance the P-MOSFET would not turn on. I have actually used a TP0606 P-MOSFET which has a -2.4 Volt VGS(TH) max. But by using the two batteries, many other P-MOSFETS could be used. My choice of the TP0606 was because of its performance characteristics and that it is in a small TO92 package. The IRF9540 is more commonly available, but is more expensive, overkill on current capability and in the larger TO220 package, but many have them in their parts box.

Initially, I used the circuit shown below for powering the ATtiny85.

When S1 was pressed, Q1 gate would be taken to approximately 0.7 Volts above ground. The HT7350 Voltage regulator would provide 5 Volts DC to the ATtiny85, which in turn would drive R2 with 5 Volts DC, turning Q2 on, thus keeping Q1 passing current. Rather than using a 5 Volt Regulator, you could drop the voltage using a diode if the battery voltage was 6.6 Volts DC. i.e. two by CR2032.

However, I encountered two problems with this approach. The first is that as the battery voltage drops, the voltage to the ATtiny84 drops and can result in unreliable operation.

Second, the voltage drop across a diode is not fixed at 0.7 volts. It varies with current. At very low current, it can be as low as 0.1 volts and at high currents in excess of 1 volt (especially if you use cheap power diodes, eg. 1N4001). So I prefer to use a Voltage Regulator. I chose the HT7350 as it is readily available, has a low Quiescent current (7 µA max) and a low Dropout Voltage (typically 60 mV). Why are these two characteristics important? A low quiescent current is important when using batteries. The lower the quiescent current, the lower the drain on the battery by the voltage regulator. A low dropout voltage, in the case of the HT7350, means it will supply a reliable 5 Volts DC with the input as low as 5.06 Volts. C2 and C4 are required according to the manufacturer’s datasheet to ensure stability. I always add C1 and C3 to provide high frequency bypassing. Being a battery design, you may be able to remove them as the only high frequencies being generated are internal to the ATtiny85. When Q1 was off, I found current consumption was zero.

However, I did encounter some very strange behaviour with this circuit. It was mainly due to C1, C2, C3 and C4. When I tried to turn off Q2 by getting the ATtiny85 to drive the input of R2 to zero volts. There was enough charge in the capacitors C1 and C2 to hold up the HT7350 and it would keep supplying the ATtiny85 with 5 volts and cause it to restart. I then decided to move the HT7350, C1, C2, C3 and C4 between the battery and Q1. This resulted in a stable operation of the ATtiny85. The downside was that the HT7350 would draw some quiescent current from the battery. This was only about 3.5 µA, so not really a problem. This on its own will flatten the CR2032 batteries in 2600 days. Another justification for using the Li-ion batteries?

The Build:

Parts Required:Jaycar
1 x ATtiny85-20UZZ8721
1 x 8 pin Dual In Line (DIL) SocketPI6500
1 x 5 Volt Regulator (HT7350) - See text-
1 x Buzzer (PKM13EPYH4000-A0) 
1 x Buzzer Alternative-
2 x Diodes (1N4148, 1N4004 or equivalent)*ZR1004
1 x P-MOSFET (TP0606) 
1 x P-MOSFET Alternative (IRF9540)ZT2467
1 x N-MOSFET (2N7000)ZT2400
1 x 2N4401 NPN Transistor 
1 x NPN Transistor Alternative (BC337 or equivalent)*ZT2115
1 x Red LED*ZD0150
1 x 1kΩ Resistor*RR0572
2 x 4.7kΩ Resistors*RR0588
1 x 10kΩ Resistor*RR0596
1 x 1MΩ Resistor*RR0644
2 x 100nF Capacitors*RC5490
2 x 10µF Capacitors*RZ6648
2 x Pushbuttons*SP0603
1 x Project CaseHB6075
1 x VeroboardHP9544
4 x M3x15mm Screws*^HP0406
CR2032 POWER OPTION: 
2 x CR2032 Coin Cell BatteriesSB2945
1 x Dual Battery Holder-
18650 POWER OPTION: 
2 x 3.7V 18650 Li-ion BatteriesSB2308
1 x Dual Battery HolderPH9207

* Quantity required, may only be sold in packs. Hook-up wire is also required.

^ Spacers need to 8mm long, with the Altronics part, the 2mm spacers are not required.

I have addressed most of the hardware issues and reasons for selection of most of the components. It is time to put everything together. The final circuit is shown below.

At this point, I would like to make some comments on the components I have used. There are very few components that are critical. For the 5V Voltage Regulator, the HT7350 is one of the best regulators around for battery operation. If you wish to use an alternative regulator, the most important characteristic is the quiescent current. The lower the better, and under 10 µA is ideal. The second most important characteristic is low dropout voltage. I would recommend less than one volt.

The buzzer I have used, manufactured by Murata, is compact and very cheap. The downside is that if you only want one and order it from an online source, postage can be expensive, unless you buy many components at the same time. The alternative from Altronics has a slightly bigger mounting pitch - 0.3” as opposed to 0.2” for the Murata Buzzer. R5 is required for the Murata buzzer and may not be required for the Altronics alternative buzzer.

The diodes are again general purpose, just about anything could be used.The P-MOSFET has been discussed previously, but important characteristics are low Gate Threshold voltage (VGS(TH)) and low on resistance (RDS(on)). The N-MOSFET is a general purpose device with the 2N7000 being readily available. The NPN transistor I used (2N4401) is also a general purpose device. There are many alternatives with one suggested in the above Parts List. You could even use the 2N7000. I just like using bipolar transistors for driving devices like buzzers, relays and LEDs.

In this case, for the LED, I am using the ATtiny85 to drive the LED directly via a resistor (R4). The datasheet for the ATtiny85 indicates the I/O drive capability is 40mA. I have used a LED which requires less than 1 mA to provide sufficient brightness. This reduces the current drain on the battery. However, as the LED is on for relatively short periods, a LED with a higher current requirement could be used. Just adjust R4 to give the required LED brightness.

For R1, R2, R3, R4 and R5. I have used 1% metal oxide resistors. This is not really necessary and the cheaper 5% carbon film types could be used. I prefer metal oxide resistors as they tend to be more stable, i.e. they do not change value as much with temperature and age. Resistor R1 value of 1 MΩ is important. A lower value means the current drawn when Q2 is on would be higher, resulting in wasting current being drawn from the battery. A 1 MΩ results in 5 µA being drawn from the battery. I am always looking to reduce battery power consumption.

Capacitors C1, C2, C3 and C4 are important in that they must be low leakage types. In the past, I have found some of my battery projects suffering from quick battery discharge because the capacitors on the power rails had relatively low DC resistance, causing excess current to be conducted to ground. This is a common problem with old capacitors.

Note the schematic diagram shows a Serial Output. This was used for debugging the software. By using a Software Serial Library (See Arduino IDE code in website resources), I used “Serial.print” statements to help debug my code. I interfaced this to my PC running the Arduino IDE via a FTDI module, only using the Ground and Rx connections. The drawback here was due to the I/O limitations of the ATtiny85, I could not use switch S2.

Finally, let’s build the timer. I like to use Veroboard for building my prototypes and one off projects. It is very easy to use. It can be cut to size from the larger boards you buy from companies like Jaycar and Altronics. The wiring diagram above shows the layout I have used on the Veroboard.

The board is 46 mm (horizontal) x 63 mm (vertical) or 18 holes x 23 holes. The holes are on a 0.1” pitch. The tracks on the back of the board run horizontally (the light grey lines you can see on the diagram). Where you see an “X” on the board, this is where I have cut the track. I use a spot face cutter (Jaycar TD2461) for cutting the track. You can alternatively use a 3mm or 1/8” drill bit. The yellow lines on the diagram are wires. I use a white Teflon wire. Any hookup wire could be used.

Start by cutting the board to size, then cut all the tracks in the required places. It is more difficult to cut tracks after solder has been applied.

Next, drill any mounting holes, four in this case, at 3mm diameter. I have used M3 screws for mounting the board to the case. I then mark up the top of the board where the switches, LED and Buzzer will be located. I use this as a template to mark where the holes need to be drilled/cut/filed in the top of the case.

Solder all the components on the board starting with wires and low profile components (resistors, diodes and IC socket), followed by capacitors, voltage regulator, transistors, switches, LED, and buzzer. You can also solder in the 3-pin header if you plan to use the serial output.

If you are using the Altronics Buzzer, you will have to position the negative pin of the buzzer one track higher. Then there is also no need for the short wire link to the right of the buzzer.

It is good practice to check each solder joint as you go with a multimeter to check the solder joint is good and that there are not any shorts where there should not be. In my experience, many components have been destroyed because of solder shorts.

It is a good idea to do a fit with the top of the case at this point. By putting the four M3 screws into the lid of the case and screwing on the four 8mm spacers (or in my build the four 6mm + 2mm spacers) and attach the board to ensure holes for the switches, buzzer and LED line up. If not, adjust as necessary. Initially, I just drilled many small holes in the lid for the buzzer, to make it look like a speaker grill. Sadly, I was a little off drilling my holes and also the buzzer sound was a bit muffled. I had to cut a bigger hole, about the diameter of the buzzer. This made sure I could hear the beeps!

Concept of Operation

The way I determined that the timer would work was in one of two ways. The first was Setup Mode and the second was Repeat Mode.

In Setup Mode, the “ON” button (S1) is pressed and held. The timer is now powered on and now the LED would flash every second, which would indicate the number of minutes (count) the timer would last.

The “START” button (S2) is pressed to initiate the timer, and at this time, the “count” is saved in EEPROM, and the LED flashes twice. At the end of each minute, the LED flashes and the buzzer beeps. On timer expiry, there is the last minute beep plus five LED flashes and five beeps to indicate the end. The timer then turns itself off.

In Repeat Mode, the “START” button is first depressed, then the “ON” button is pressed. While still depressing the “START” button, the “ON” button is released (within 60 seconds). This sets up Repeat Mode. The LED will then flash three times. During this flashing, the “START” button is released. Once the “START” button is pressed again, the timer starts again as in the Setup Mode, using the last count stored in EEPROM.

The Software

I have used the Arduino IDE to develop and program the ATtiny85. I used my homemade programmer which interfaces to my PC via a USB cable to program the ATtiny85.

For those who would like to make their own AT Programmer, I attach some details at the end.

Note: DIYODE has also designed a project in Issue 14 to program an ATtiny.

As mentioned, I developed my software using the Arduino IDE. I am currently using version 1.8.15.

Note: when using a fresh ATtiny85, it is a good idea to “Burn Bootloader”. This ensures all the correct fuses are programmed and the ATtiny85 operates at the correct speed. Use the settings as per the Arduino IDE screenshot here, showing the Tools Menu.

The code is available from the resources section of our website. The code is written in the C language which is most common for the Arduino IDE. The code is split into several sections which I will attempt to describe.

The first is the “Include” section. Here are listed all the libraries used by this program. All libraries are built in with the exception of the SendOnlySoftwareSerial.h library. This has to be installed using the Library Manager.

#include <avr/sleep.h>
#include <avr/interrupt.h>
#include <avr/power.h>
#include <avr/wdt.h>
#include <EEPROM.h>
//#include <SendOnlySoftwareSerial.h>

Note: the SendOnlySoftwareSerial.h library is commented out. I only used this when debugging the program. Also, this library was specifically designed to be transmit only. So data is output, but no input is accepted. This makes for minimal code which is necessary as the ATtiny85 only has 8k Bytes of Flash memory.

The second section is the EEPROM, I/O and buzzer defines. I am only storing one variable in EEPROM. That will be stored starting at the first location in EEPROM. The rest “define”s the pins used. “ON” button for input (PB_IN), for powering down (PB_OUT), to drive the LED (LED_OUT), to drive the Buzzer (BUZZ_OUT) and the “START” button (START_PIN). Note START_PIN and TX_OUT are defined on the same pin. TX_OUT is only used for serial output when debugging the program.

BUZZ_FREQ defines in Hertz, the frequency at which the Buzzer is beeped. It is the resonant frequency of the Buzzer. If you use a Buzzer other than the two listed above, you may have to change this “define” to match the resonant frequency of your Buzzer.

// EEPROM Data
#define EE_ADDR 0           
// Start location in EEPROM used for storing Minute Count
// IO and Buzzer defines
#define PB_IN 3     //PB3
#define PB_OUT 4    //PB4
#define LED_OUT 2   //PB2
#define BUZZ_OUT 1  //PB1
#define TX_OUT 0    //PB0
#define START_PIN 0 // PB0
#define BUZZ_FREQ 4000

The next section contains the functions.

void Buzz_Flash(int num) sounds the buzzer and flashes the LED the number of times specified in the parameter “num”.

void Flash_LED(int num) flashes the LED the number of times specified in the parameter “num”.

int GetMinCount(void) determines the number of minutes for the timer.

void SleepNow(int flag, int timeout) function puts the ATtiny85 to sleep. “flag” determines whether the ATtiny85 is woken by the “START” button or by the Watch Dog Timer. “timeout” tells the Watch Dog Timer how long to sleep for before awakening the ATtiny85.

ISR (PCINT0_vect) is an empty function. i.e. it does nothing but is required as an interrupt function to wake the ATtiny85 when a change occurs on an input pin (START_PIN). i.e. pressing the “START” button.

void resetWatchDog(int t_o) function sets the timeout (t_o) for the Watch Dog Timer.

ISR (WDT_vect) function is called when the Watch Dog Timer times out. i.e. decrements to zero. This function disables the ATtiny85 Watch Dog function and increments a counter, which is counting seconds.

That is all the external functions. Those familiar with using the Arduino IDE will know that there are two other mandatory functions – Setup() and Loop(). In Setup() all the initialisation is normally performed and in Loop(), the repetitive processes are performed.

void setup() {
  pinMode(PB_IN, INPUT_PULLUP);
  pinMode(PB_OUT, OUTPUT);
  digitalWrite(PB_OUT, HIGH);  // Ensure power stays on
  pinMode(LED_OUT, OUTPUT);
  digitalWrite(LED_OUT,LOW);  // Ensure LED is off
  pinMode(START_PIN, INPUT_PULLUP);
  // Ensure Watchdog is disabled
  wdt_disable();
  // Get the number minutes for timeout
  count = GetMinCount();
  // for debugging
  // mySerial.begin(115200);
  // mySerial.println("nSerial started");
  // if count = 0, then false powerup again, if so turn off power again
  // else wait for Start button to be pressed
   if(count == 0)
   {
    digitalWrite(PB_OUT, LOW);
   }
   else
   {
     sleepNow(true,0);   // wait for Start                            
                           button to be pressed
   }
}

In the Setup() function, the most important thing it has to initially do is ensure that Q1 remains on. It does this by setting PB_OUT High. This ensures Q2 is turned on keeping Q1 on. Other I/O pins are then initialised. The Watch Dog is then disabled “wdt_disable()” to ensure no false triggering. Next, the program determines the number of minutes the timer is to operate for. Once this has been determined, it waits for the “START” button to be pressed, calling the sleepNow() function.

It is worth looking further at the sleepNow() function. This function is used in preference to using the “delay()” and “millis()” functions. The delay() and millis() functions are very often used in situations where some sort of timing is required. However, the problem with these two functions is that the processor is running at full current consumption (8 mA) as all parts of the processor are enabled i.e. powered up. In situations where battery power is being used, these functions are basically wasting battery power. The sleepNow() function uses the ATtiny85 sleep() function and other power saving techniques to reduce power consumption by the ATtiny85 to less than 10 µA worst case.

void sleepNow(bool flag, int timeout) 
{
  set_sleep_mode(SLEEP_MODE_PWR_DOWN);
  ADCSRA = 0;
  power_all_disable ();
  noInterrupts();
   if(flag)
  {
    GIMSK |= _BV(PCIE); 
    PCMSK |= _BV(PCINT0); 
  }
  else
  {
    resetWatchDog(timeout);
  }
  sleep_enable(); 
  interrupts();
  sleep_cpu(); 
  if(flag) PCMSK &= ~_BV(PCINT0); 
  sleep_disable(); 
  power_all_enable (); 
} // sleep

The first thing this function does is initialise the Sleep mode to be a power down mode. Next the Analog to Digital Convertor (ADC) register “ADCSRA” has all bits reset. This disables the ADC from starting a conversion. The whole ADC function is disabled. Next, we power down the ADC, Timer 0, Timer 1 and the UART function. These are not needed when the ATtiny85 is in sleep mode and can save considerable power consumption. The one issue with this is associated with Timer 0. All the above listed external functions that use delays or timing, with the exception of “Buzz_Flash()” use the “sleepNow()” function. The “Buzz_Flash()” function calls an internal library function called “tone()”. “tone()” generates a Pulse Width Modulation (PWM) signal that is required for the buzzer to generate beeps. Timer 0 is used to generate the PWM signal. Therefore, “delay()” is still used within the “Buzz_Flash()” function. I believe it is possible to not power down Timer 0, to allow PWM to operate during a processor sleep cycle, but I have not investigated this. Maybe a later version of my timer code.

Interrupts are then temporarily disabled to ensure no false triggering. Then the parameter “flag” is examined. If “flag” is set “true” then we want to put the ATtiny85 to sleep and only wake when the “START” button is pressed. If “flag” is “false”, then the Watch Dog Timer function is to be used. The parameter passed in “timeout” determines how long the Watch Dog Timer counts down, before causing an Interrupt. Now the interrupts can be re-enabled and the ATtiny85 put into sleep mode. I measured 3.6 µA when the ATtiny85 was in sleep mode and most of this can be attributed to the HT7350, 5 Volt voltage regulator.

As the maximum time that the Watch Dog Timer can count down for is eight seconds, the Watch Dog Timer has to be actioned several times to count for a minute. I have actually set the timeout to one second and count 60 timeouts for every minute. This is performed in the Loop() function.

void loop() {
  Flash_LED(2);
  EEPROM.put(EE_ADDR, count);  
  timeouts=0;
  for(int i=0; i<count; i++)
  {
    while(timeouts < 60)
    {
//      mySerial.print("timeouts is ");
//      mySerial.println(timeouts);
//      delay(500);
      sleepNow(false,WDTO_1S);  
    }
//    delay(1000);
    Buzz_Flash(1);
    timeouts = 0;  
  }
  Buzz_Flash(5);  
  digitalWrite(PB_OUT, LOW); 
  delay(10000);  
}

When the “Loop()” function is initially entered, the LED is flashed twice (the “START” button has been pressed). Whatever count was determined in the “Setup()” function is saved in EEPROM and the processor enters a double nested loop. The inner loop for the sixty second timeout using the “sleepNow()” function and the outer loop counting the minutes for which the timer is to operate. At the end of each minute, the LED is flashed once and the buzzer beeped once. At the end of the overall timeout, the LED is flashed five times at the same time the buzzer is beeped. Then the ATtiny85 powers itself off by setting PB_OUT “LOW”. This turns off Q2, which in turn turns off Q1, preventing power to flow to the ATtiny85.

3D Printed Case

Originally, my project was built into a commercially available enclosure, and that is how this project has been described.

After sending my text to DIYODE to be laid out, I found some time to design an enclosure using Fusion 360. If you have access to a 3D printer, you can download the .stl files from the DIYODE website to print your own. This comprises of a top cover and a base, which friction fit together.

Where to from here?

Well, that is the end of building and programming the general purpose timer project based on the ATtiny85. While the project is relatively simple. It does showcase a few fundamental concepts, which can be used in many other projects, especially battery power projects.

  • How to use P-MOSFETs as power switches.
  • How to activate and deactivate a P-MOSFET via a processor.
  • How to use the processor sleep function (this is not unique to the ATtiny85, but can be used on most of the AVR family of processors) and wake on external interrupt (eg. a button press) or a Watch Dog Timeout.

ATtiny Programmer

There are several programmers on the market for programming ATtiny microcontrollers, including the ATDev for ATtiny project from Issue 14 that is available from Jaycar and Altronics.

There are also several YouTube videos and web articles on how to program ATtiny microprocessors. After looking at many articles and YouTube videos, I decided it would not be difficult to build my own.

The simplest method I came across was to use an Arduino Uno and attach a shield holding the required extra components. Here is a schematic of my ATtiny programming shield.

I used Veroboard to make my shield. Below is the layout for the Veroboard.

Note: the tracks run horizontally with tracks broken using a spot face cutter (or 3mm/1/8” drill bit) indicated with “X”.JP1, JP2 and JP3 are male header pins which allow the veroboard shield to be plugged into the top of the Arduino Uno board.

Note: for JP1, JP2 and JP3, push the pins through so they are flush with the plastic holder. This ensures maximum pin connection into the female header on the Arduino Uno Board.

Before attaching the veroboard shield, the Arduino needs to be programmed with the ArduinoISP program. This is a standard program provided as an example program for the Arduino IDE. Plug in your Arduino Uno via a USB cable to your PC and download the ArduinoISP program to your Arduino Uno. Don’t forget to set “Port” to the correct COM port.

Once the Arduino Uno is programmed, insert the Veroboard shield. To program an ATtiny85, the link is inserted at the bottom left of Socket 2. The ATtiny85 occupies the top eight socket locations of ZIF socket 2.

Change the settings in the Tools menu, using the same port as before when the Arduino Uno was programmed. You can now download your programs to the ATtiny85.

Note: if it is an unprogrammed/new ATtiny85, it is a good idea to “Burn Bootloader” first. This ensures correct operation as per the settings shown here.

Peter Stewart

Peter Stewart

Retired Engineer