Moving a Project from a PIC  Microcontroller
to an Arduino IDE Programmed ATTiny85

revised 12-03-2020   d. bodnar

I have enjoyed programming various Arduino microcontrollers over the last few years.  They work well, are inexpensive and have an extensive support network on the Internet.

The only problem that I find is that even the smallest Arduino is much larger than many of the PIC chips that I also use.  If space is an issue I usually go for the PIC family of microprocessors.

Recently I was working on a project where I wanted to make a small circuit to flash a bright LED beacon to help follow a drone in flight.  I designed and built the circuit using a small, surface mount 8 pin PIC chip and wondered if I could make an equally small circuit using an Arduino.

A few years ago I had experimented with an 8 pin ATTiny85 chip that could be programmed using the Arduino IDE (programming environment).  I decided to revisit that chip and to see if I could translate the program that I wrote in PIC BASIC PRO to the Arduino compiler's "C" so that I could use it with the ATTiny85.  I also discovered that there is a surface mount version of the ATTiny85 that had the potential to give me a circuit that was as small as the PIC based unit.

The Circuit
The schematic is very similar to the one from the PIC 12F683.  The main difference is to the programming wiring to the header labeled "programming".  There is also a connection to pin 3 (PB4) that can be used to see the serial output as the unit blinks or progresses from one mode to another.

 

The Circuit Board
The two boards are shown here.  The PIC version is on the right in red and the ATTiny85 version is on the left in blue.

The most dramatic difference is that the ATTiny85 version has board space for either a through hole processor or a surface mount processor.  Just be sure not to install both!  The programming header (labeled "program") on the blue board has six pins while the one for the PIC processor only has 4 (labeled "I C S P ).

 

Here the board has been populated with a through hole ATTiny85 (upper left), the USB connector (upper right), button (lower left), Mosfet & resistor (to the right of the switch) and two 3 watt LEDs (center) - there is also a two pin header where the battery can be plugged it (lower right)

The surface mount version of the ATTiny85 is shown here. 

Two headers are at the top of the board.  The six pin header (yellow arrow) is used for programming and the two pin header (white arrow) can be used to monitor the serial output from the processor.  The pin on the left is the serial output and the one on the right is ground.

LED Options
There are a number of options for LEDs.  They have been explored in the earlier web page and can be seen
here:
 http://www.trainelectronics.com/Drone/Beacon/#LED_Options

Most of my test beacons have been wired with 3 watt blue & green LEDs as shown in the image above.

Battery Options
The battery options were also discussed in the earlier web page here:
http://www.trainelectronics.com/Drone/Beacon/#battery
ATTiny85 Programmer
I built a simple programmer for the ATTiny that utilizes an Arduino UNO,  Detailed instructions on building this programmer are here: 
http://www.trainelectronics.com/Drone/ATTinyBeacon/ATTinyProgrammerExample.htm
Simple Programmer Interface
To simplify programming the Drone Beacon I set up the Arduino UNO programmer so that its six pin header (shown below) would plug right into the Drone Beacon board.  Its wiring and construction are shown here: 
http://www.trainelectronics.com/Drone/ATTinyBeacon/ATTinyProgrammerExample.htm

 

 
Modes
The button on the circuit board is used to switch modes and to turn the unit off and on.

The board is programmed to display 5 different blinking modes

  • Mode 1 - 20 very brief flashes followed by a 0.4 second pause - repeats
  • Mode 2 - LED on for 0.02 second, off for 0.02 seconds - repeats
  • Mode 3 - LED on for 0.5 seconds, off for 0.5 seconds - repeats
  • Mode 4 - LED flashes fast on/off (0.02 seconds) three times then once slowly (0.03 seconds), pause 0.25 seconds - repeats
  • Mode 5 - LED flashes on for 0.05 seconds, off for 0.45 seconds - repeats

To change mode press the switch - while it is held down the LED will flash a number of times that represents the mode you will enter when you release the button.  For example, if you are currently in mode 2 and you hold the button down the LED will flash 3 times, pause, flash 3 times and so on. 

This flashing of the new mode number only repeats 5 times - if you hold it so that the mode blinks 5 times the LED will dim till off and the unit will be in sleep mode until the button is pressed again.

When the unit is put to sleep the microcontroller still draws a small amount of current from the battery.  I measured the current consumption at 0.055 ma.  If the battery is good for 1000 ma hours theoretically the sleep mode could last for nearly two years.

 

ATTiny85 Code
The program that was translated from the PIC Basic Pro code is shown below. 

These three libraries are used in the sketch.  I did NOT need to manually add them to my system.

  • avr/sleep.h
  • avr/interrupt.h
  • SoftwareSerial.h
IMPORTANT - Burn Bootloader First
Before you program the ATTiny85 make sure you click on "Burn Bootloader", the last option in the screen shown here.

Once that is done you can program the ATTiny85.

/*  Translation of Drone Beacon from PIC to Arduino
     d. bodnar  11-12-2020
*/
#include <avr/sleep.h>
#include <avr/interrupt.h>
#include <SoftwareSerial.h>
#define RX    3   // *** D3, Pin 2
#define TX    4   // *** D4, Pin 3
int LED = 0;
int dozeCounter = 0;  // hold button for 5 repeats goes to sleep
const int buttonPin = 3;     // the number of the pushbutton pin (physical pin 2)
const int ledPin =  0;      // the number of the LED pin (physical pin 5)
int buttonState = 0;         // variable for reading the pushbutton status
// NOTE: you have to capture serial output via serial converter on pin 3 on ATTINY -
//    used TeraTerm @ 9600
SoftwareSerial Serial(RX, TX);
int counter = 1;
void setup()
{
  Serial.begin(9600);
  pinMode(LED, OUTPUT);
  pinMode(buttonPin, INPUT_PULLUP);
  Serial.println("Drone Beacon on ATTiny85--Ver 3.6.");
}
void loop()
{
  dozeCounter = 0;
  Serial.print (" @ LOOP  "); Serial.print(counter); Serial.print(" Button "); Serial.println(buttonState);
  checkButton();
  switch (counter) {
    case 1:
      fullBrightSlow();
      break;
    case 2:
      fullBrightFast();
      break;
    case 3:
      fivePause();
      break;
    case 4:
      threeTen();
      break;
    case 5:
      another();
      break;
  }
}
// 1 1 1
void fivePause() {
  digitalWrite(LED, HIGH);
  for (int i = 1; i <= 5; i++) {
    checkButton();
    digitalWrite(LED, LOW);
    delay(25);
    digitalWrite(LED, HIGH);
    delay(25);
  }
  checkButton();
  delay(250);
}
// 2 2 2
void fullBrightFast() {
  digitalWrite(LED, LOW);
  delay(60);
  checkButton();
  digitalWrite(LED, HIGH);
  delay(60);
}
// 3 3 3
void fullBrightSlow() {
  digitalWrite(LED, LOW);
  checkButton();
  delay(500);
  checkButton();
  digitalWrite(LED, HIGH);
  checkButton();
  delay(500);
  checkButton();
}
// 4 4 4
void threeTen() {
  for (int xx = 1; xx <= 3; xx++) {
    checkButton();
    for (int i = 1; i <= 10; i++) {
      checkButton();
      digitalWrite(LED, LOW);
      delay(10);
      digitalWrite(LED, HIGH);
      delay(10);
    }
    checkButton();
    delay(50);
  }
  for (int i = 1; i <= 10; i++) {
    checkButton();
    digitalWrite(LED, LOW);
    delay(30);
    digitalWrite(LED, HIGH);
    delay(30);
    checkButton();
  }
  delay (250);
}
//5 5 5
void another() {
  digitalWrite(LED, LOW);
  delay(100);
  checkButton();
  digitalWrite(LED, HIGH);
  delay(25);
}
void checkButton() {
  buttonState = digitalRead(buttonPin);
  if (buttonState == HIGH) {
  } else {
    counter = counter + 1;
    if (counter == 6) {
      counter = 1;
    }
  }
  while (digitalRead(buttonPin) == LOW) { // debounce button
    for (int i = 1; i <= counter; i++) {
      digitalWrite(LED, HIGH);
      delay(100);
      digitalWrite(LED, LOW);
      delay (100);
    }
    dozeCounter = dozeCounter + 1;
    Serial.print("dozeCounter ");  Serial.println(dozeCounter);
    if (dozeCounter >= 5) {
      Serial.println(" @ 5 count");
      for (int xx = 255; xx >= 1; xx = xx - 2) {
        analogWrite(LED, xx);
        delay(10);
      }
      delay(1000);
      sleep();
    }
    delay(500);
  }
}
void sleep() {
  counter = counter - 1;
  if (counter == 0) {
    counter = 5;
  }
  Serial.print(counter); Serial.println(" SLEEPING ");
  GIMSK |= _BV(PCIE);                     // Enable Pin Change Interrupts
  PCMSK |= _BV(PCINT3);                   // Use PB3 as interrupt pin
  ADCSRA &= ~_BV(ADEN);                   // ADC off
  set_sleep_mode(SLEEP_MODE_PWR_DOWN);    // replaces above statement
  sleep_enable();                         // Sets the Sleep Enable bit in the MCUCR Register (SE BIT)
  sei();                                  // Enable interrupts
  sleep_cpu();                            // sleep
  cli();                                  // Disable interrupts
  PCMSK &= ~_BV(PCINT3);                  // Turn off PB3 as interrupt pin
  sleep_disable();                        // Clear SE bit
  ADCSRA |= _BV(ADEN);                    // ADC on
  sei();                                  // Enable interrupts
  Serial.print(counter); Serial.println(" DONE SLEEPING!!!");
  for (int xx = 1; xx <= 255; xx = xx + 2) {
    analogWrite(LED, xx);
    delay(10);
  }
} // sleep