Manuel Jasch

Alles rund um Internet & Technik

Kurzanleitung zum Programmieren eines ATtiny 85

Dez 312019

Diese Kurzanleitung soll erklären wie man den ATTiny 85 mit Hilfe des großen Bruders, dem Arduino Uno, über die Arduino Software programmiert. Hierfür benötigen wir:

  • Arduino Uno,
  • ATTiny 85,
  • Arduino Software (hier 1.8.9),
  • Kondensator 10 uF,
  • Jumper Kabel
  • und Breadboard.

Folgende Schritte sind notwendig um den Bootloader und das erste Programm zu schreiben:

  • Zuerst wird der Arduino Uno als ISP programmiert. Dafür die Arduino IDE öffnen und unter "Datei->Beispiele->ArduinoISP" das Programm auswählen. Im Anschluss unter "Werkzeuge->Board" den "Arduino Uno" wählen und "Hochladen" klicken.
  • Im nächsten Schritt wird die Schaltung aufgebaut sodass der ATtiny mit dem Arduino kommunizieren kann.undefined
  • Unter "Werkzeuge->Board" den ATtiny 85 mit 8 MHz Takt wählen. Die restlichen Optionen können so bleiben wie vorausgewählt. Wenn der Port nicht angezeigt wird dann passt noch etwas an der Schaltung nicht. Achte hierbei auf die korrekte Ausrichtung des ATTiny's.
    Anschließend unter "Werkzeuge->Programmer" "Arduino as ISP" wählen und "Bootloader brennen" klicken.
  • Wenn bis hierhin alles geklappt hat, kann das erste Programm geflasht werden. Unter "Sketch->Hochladen mit Programmer" wird das aktuelle Programm auf den ATtiny hochgeladen.

 

Hinweise:
Falls der ATtiny nicht auswählbar ist muss zuerst über den Boardmanager unter "Werkzeuge->Board->Boardverwalter.." der ATtinyCore installiert werden.

Wenn der ATtiny nicht aufgelistet wird im Boardverwalter dann fehlt der Arduino Umgebung der richtige Suchpfad. Dafür unter den Voreinstellungen von Arduino unter "Zusätzliche Boardverwalter URL's" folgende URL eingegeben werden: http://drazzy.com/package_drazzy.com_index.json

Falls das ArduinoISP nicht hochgeladen werden kann, entferne bitte den Kondensator aus der Schaltung und probiere es erneut.

  • Permalink
  • Kommentare

Teaboy "James" geht in die zweite Runde

Dez 312019

  undefined

Der Tea-Boy namens James geht in die nächste Runde. Er bekommt ein update was die Stabilität und den Aufbau angeht. Die Unterschiede zu dem vorherigen James sind folgende:

  • Neue Platine
  • Mechanischer An-/Aus Schalter
  • Halterungen für die Füße und Arme
  • Halterung für den Servo 

Bei der Schaltung hat sich nur wenig geändert. der zweite Taster ist durch einen mechanischen Schlater ersetzt worden um die Stromlaufzeit zu erhöhen.undefined

Daraus ist dann direkt eine Platine entstanden, welche gleichzeitig mechanische Funktionen übernimmt. Die Platine dient als Rumpf des James und bietet Befestigungsmöglichkeiten für die Beine, Arme, Servo und Potentiometer. Hier ist das Layout zu sehen:undefined

Die Halskrause ist gleichzeitig die Auswahl der Minuten. Die zusätzliche Schaltung, welche hier abgebildet ist, dient dazu die Platine voll zu machen, um kosten zu sparen.

Das Programm wurde ebenso überarbeitet. Im Folgenden ist ein Ausschnitt der Main Loop zu sehen.

void pulse_led();
void blink_led(uint8_t num, uint16_t frequency);
void finish_sequence();
uint32_t get_set_time();
uint32_t get_state_time();
void reset_state_time();

void loop() {
  switch(_state) {
    case TEA_BREWING:
      pulse_led(); /* signalize the waiting */
      if (get_state_time() > get_set_time()) /* check if time has expired */
        _state = TEA_FINISHED;
    break;
    case TEA_START_PRESSED:
      reset_state_time();
      blink_led(TEA_START_BLINK, TEA_START_FREQUENCY); /* short delay and blink */
      set_servo(SERVO_MIN, SERVO_POSITIONING_TIME); /* put arm down into the tea */
      _state = TEA_BREWING;
    break;
    case TEA_FINISHED: 
      finish_sequence();
      _state = TEA_POWER_ON;
    break;
    case TEA_POWER_ON:
    default:
      digitalWrite(PIN_LED, HIGH); /* show led that machine is power on */
      if (get_state_time() > WARNING_STILL_ON_AFTER) { /* signalize if the machine is still on */
        play_song(melody, beats, sizeof(melody)/sizeof(melody[0]));
        reset_state_time();
      }
    break;
  }
}

Der vollständige Code und das Eagle Projekt der Platine findet ihr auf Github. Das Programm auf den ATtiny hochladen ist über eine kleine Hilfsschaltung schnell erledigt.

  • Permalink
  • Kommentare

Tea-Boy - James

Dez 202016

undefined

Für ein Weihnachtsgeschenk kam mir die spontane Idee eines Tea Boys. Dieser soll den Tee überwachen, nach abgelaufener Zeit Bescheid geben, ob der Tee fertig ist und den Teebeutel aus der Tasse ziehen.

Über einen Potentiometer soll dabei die Teezeit eingestellt werden und mit einem Taster der Tee-Beutel abgelassen werden. Nach abgelaufener Zeit soll der Beutel wieder aus der Tasse gezogen werden und mit einem Piezo darauf aufmerksam gemacht werden. Eine LED zeigt dabei die Status an.

Was ich für den Tea Boy benötige:

  • ATtiny
  • LED
  • Widerstände: 150 Ohm, 22 kOhm
  • 2 Micro Taster
  • Mini Servo
  • Potentiometer
  • Piezo

Zum Programmieren des ATtiny benötige ich:

  • Kondensator 10 uF, 16 V
  • Arduino Uno Board

Der ATtiny wird mithilfe eines in-system programmer (ISP) und eines Arduino Uno Board programmiert. Dafür wird der ATtiny, wie hier beschrieben, an das Arduino Uno Board angeschlossen. Der Kondensator muss dabei zwischen Masse und Reset gesteckt werden um zu verhindern, dass der Arduino reseted wird. Dann noch ein ISP Programm auf den Arduino installieren, das richtige Board auswählen und schon kann der ATtiny programmiert werden. Über die Entwicklungssoftware von Arduino kann noch die Frequenz des ATtinys ausgewählt werden. Ich habe bei diesem Projekt 8 Mhz gewählt. Nicht vergessen den Bootloader über die Arduino Software zu brennen. Dieser brennt nicht wirklich einen Bootloader sondern dieser setzt die Fuse-Bits, welche den internen Oszillator auf 8 Mhz wählt.

Der nächste Schritt ist die Programmierung. Dabei habe ich mich von dieser Seite inspirieren lassen, um einen Energiesparmodus zu ermöglichen. Der Autor verspricht dabei 0,12 µA im Standby, welcher aber nur durch einen Reset des Mikrocontrollers beendet werden kann. Nachgemessen wurde es nicht. Der Reset Pin wird dafür über einen 22 kOhm Widerstand auf die Versorgungsspannung und gleichzeitig über einen Taster auf Masse gelegt. Nun führt ein Tastendruck zum Reset des Mikrocontrollers.

Der zweite Taster, der den Tee-Vorgang starten soll, wird an A2 und an die Versorgungsspannung gelegt. Ein zusätzlicher Widerstand zieht den Pin auf Masse, falls der Taster nicht gedrückt ist. Der Tastendruck löst einen Interrupt aus, welcher den Potentiometer abfragt, den Servo-Arm herunter fährt und die angegebene Zeit verweilt.

Wenn der Tee fertig ist soll ein Piezo ertönen. Dafür habe ich mich für die hier beschriebene Methode entschieden. Eine andere Melodie ist dabei ohne Probleme möglich und kann in einem Array angegeben werden. Ich entschied mich für eine einfache Tonfolge.

Die Bauteile werden an die folgenden Pins des ATtiny angeschlossen:

undefined

LED D0 (0)
Servo D1 (1)
Reset Reset
Start A2 (4)
Poti A3 (3)
Piezo A1 (2)

undefined

Und das Programm natürlich:

#include <SoftwareServo.h>
#include <avr/sleep.h>           
#include <avr/interrupt.h>       

#define PIN_POTI  3 //A3
#define PIN_START 4 //A2
#define PIN_SERVO 1 //D1
#define PIN_LED   0 //D0
#define PIN_SPEAKER 2 //A1

#define SERVO_MIN 45
#define SERVO_MAX 135
#define SERVO_POSITIONING_TIME 1600  //in ms

#define MAX_TEA_TIME 780000 // 780 000 = 13 min ; 600 000 ms = 10 min
#define SLEEP_AFTER 20000   //go to sleep after this time (in ms 30 000 ms = 30 s)

#define WAKE_UP_BLINK 2 //wake up or reset
#define WAKE_UP_FREQUENCY 400 //in ms

#define TEA_START_BLINK 3
#define TEA_START_FREQUENCY 300

#define END_BREWING_SHAKING 3 //number of shaking the teabag
#define END_BREWING_SHAKE_DISTANCE 10 //in degree
#define END_BREWING_SHAKE_POSITIONING_TIME 300 //in ms

#define TEA_FINISHED_BLINK 7

#define BODS 7                   //BOD Sleep bit in MCUCR
#define BODSE 2                  //BOD Sleep enable bit in MCUCR

// DEFINITION OF TONES  ==========================================
//       note, period, &  frequency. 
#define  c     3830    // 261 Hz 
#define  d     3400    // 294 Hz 
#define  e     3038    // 329 Hz 
#define  f     2864    // 349 Hz 
#define  g     2550    // 392 Hz 
#define  a     2272    // 440 Hz 
#define  b     2028    // 493 Hz 
#define  C     1912    // 523 Hz 
#define  R     0       // to represent a rest
int melody[] = {  c, R, c, R};
int beats[]  = { 32, 32, 32, 128}; // 32 => 320ms

int MAX_COUNT = sizeof(melody) / 2; // Melody length, for looping. (2 byte)
long tempo = 10000; // Set overall tempo
int pause = 2000; // // Set length of pause between notes
// Loop variable to increase Rest length
int rest_count = 100; //<-BLETCHEROUS HACK; See NOTES
// Initialize core variables
int tone_ = 0;
int beat = 0;
long duration  = 0;

//GLOBAL VARIABLES ==============================================
float tea_time, elapsed_time;
bool start, tea_brewing;
uint32_t start_time; 
uint8_t mcucr1, mcucr2, led_brightness, i;
SoftwareServo servo;

// PLAY TONE  ===================================================
void playTone() {
  long elapsed_time = 0;
  if (tone_ > 0) { // if this isn't a Rest beat, while the tone has 
    //  played less long than 'duration', pulse speaker HIGH and LOW
    while (elapsed_time < duration) {
      digitalWrite(PIN_SPEAKER,HIGH);
      delayMicroseconds(tone_ / 2);
      digitalWrite(PIN_SPEAKER, LOW);
      delayMicroseconds(tone_ / 2);
      // Keep track of how long we pulsed
      elapsed_time += (tone_);
    } 
  }
  else { // Rest beat; loop times delay
    for (int j = 0; j < rest_count; j++) { // See NOTE on rest_count
      delayMicroseconds(duration);  
    }                                
  }                                 
}

// PLAY SONG ===================================================
bool toggle = false;
void playSong() {
  for (int i=0; i<MAX_COUNT; i++) {
    tone_ = melody[i];
    beat = beats[i];
    duration = beat * tempo; // Set up timing
    // Blink LED
    digitalWrite(PIN_LED, toggle);
    toggle = !toggle;
    
    playTone(); 
    delayMicroseconds(pause);
  }
}

// GO TO DEEP SLEEP ==============================================
void goToSleep(void) {
    // GIMSK |= _BV(INT0);                    //enable INT0
    // MCUCR &= ~(_BV(ISC01) | _BV(ISC00));   //INT0 on low level
    ACSR |= _BV(ACD);                         //disable the analog comparator
    ADCSRA &= ~_BV(ADEN);                     //disable ADC
    set_sleep_mode(SLEEP_MODE_PWR_DOWN);
    sleep_enable();
    //turn off the brown-out detector.
    //must have an ATtiny45 or ATtiny85 rev C or later for software to be able to disable the BOD.
    //current while sleeping will be <0.5uA if BOD is disabled, <25uA if not.
    cli();
    mcucr1 = MCUCR | _BV(BODS) | _BV(BODSE);  //turn off the brown-out detector
    mcucr2 = mcucr1 & ~_BV(BODSE);
    MCUCR = mcucr1;
    MCUCR = mcucr2;
    sei();                         //ensure interrupts enabled so we can wake up again
    sleep_cpu();                   //go to sleep
    cli();                         //wake up here, disable interrupts
    // GIMSK = 0x00;               //disable INT0
    sleep_disable();               
    sei();                         //enable interrupts again (but INT0 is disabled from above)
}

// WRITE SERVO ANGLE  ============================================
int last_angle = 0;
void setServo(uint8_t degree, uint32_t duration) {
  int diff = degree - last_angle;
  diff = abs(diff);
  int w = (float)duration / (float)diff * 0.5 * 1000.0;
  if(last_angle < degree) {
    for (float k = last_angle; k < degree; k+=0.5) {
      servo.write(k); 
      delayMicroseconds(w);
      SoftwareServo::refresh(); 
    }
  } else if (last_angle > degree) {
    for (float k = last_angle; k > degree; k-=0.5) {
      servo.write(k);
      delayMicroseconds(w); 
      SoftwareServo::refresh(); 
    }
  }
  last_angle = degree;
}

// BLINK STATUS LED ==============================================
void blink_led(int num, uint16_t frequency) {
  for(i = 0; i<num; i++){
    digitalWrite(PIN_LED, HIGH);
    delay(frequency);
    digitalWrite(PIN_LED, LOW);
    delay(frequency);
  }
}

// SETUP =========================================================
void setup() {  
  tea_time = 0;
  start = false;
  tea_brewing = false;
  elapsed_time = 0;

  pinMode(PIN_POTI, INPUT);
  pinMode(PIN_START, INPUT);
  pinMode(PIN_SERVO, OUTPUT);
  pinMode(PIN_LED, OUTPUT);
  pinMode(PIN_SPEAKER, OUTPUT);
  
  servo.attach(PIN_SERVO);
  servo.setMaximumPulse(2100);
  servo.setMinimumPulse(550);
  servo.write(SERVO_MAX);              
  for(int i=0; i<600/20; i++) { //stellzeit
    SoftwareServo::refresh();  
    delay(20); 
  }
  last_angle = SERVO_MAX;
  
  start_time = millis();
  blink_led(WAKE_UP_BLINK, WAKE_UP_FREQUENCY);
  digitalWrite(PIN_LED, HIGH);
  //cli(); 
  //General Interrupt Mask Register, External Interrupts: 0b01000000; Pin Change Interrupts: 0b00100000
  GIMSK = 0b00100000;    // turns on pin change interrupts
  //Pin Change Mask Register 
  PCMSK = 0b00010000;    // turn on interrupts on pin PB4
  sei();                 // enables interrupts (bzw. _SEI();)
}

void loop() {
  if (tea_brewing) {
    elapsed_time = millis() - start_time;
    analogWrite(PIN_LED, 60);
    // Check if tea is finished
    if (elapsed_time > tea_time) {
      endRoutine();    
      digitalWrite(PIN_LED, LOW);  
      goToSleep(); 
    }
  } else {
    if (millis() - start_time > SLEEP_AFTER) {
      digitalWrite(PIN_LED, LOW); // TODO auskommentieren? müsste auch ohne aus gehen?! geht nicht aus!
      goToSleep(); 
    }
  }

  if (start) {
    blink_led(TEA_START_BLINK, TEA_START_FREQUENCY);
    startRoutine();
    start = false;
  }
}

//Start the tea procedure
void startRoutine() {
  tea_brewing = true; //set tea making flag
  //get current time value time in ms
  tea_time = (float)MAX_TEA_TIME - (float)MAX_TEA_TIME * analogRead(PIN_POTI) / 1023.0;
  setServo(SERVO_MIN, SERVO_POSITIONING_TIME);
  start_time = millis();  //start time measure
}

//End tea procedure
void endRoutine() {
  tea_brewing = false;
  setServo(SERVO_MAX, SERVO_POSITIONING_TIME);
  //shake arm
  for (i = 0; i < END_BREWING_SHAKING; i++) {
    setServo(SERVO_MAX, END_BREWING_SHAKE_POSITIONING_TIME);
    setServo(SERVO_MAX - END_BREWING_SHAKE_DISTANCE, END_BREWING_SHAKE_POSITIONING_TIME);
  }
  setServo(SERVO_MAX, END_BREWING_SHAKE_POSITIONING_TIME);
  for(int l = 0; l<TEA_FINISHED_BLINK; l++) {
    playSong();
  }
}

//Interrupt Service Routine
ISR(PCINT0_vect)
{
  if (digitalRead(PIN_START)) {  // is start pressed?
    start = true;
  }
}

Das Programm erfüllt seinen Zweck und ist lange nicht optimiert aber es musste schnell gehen damit das Weihnachtsgeschenk rechtzeitig fertig wird :)

Und so sieht das ganze fertig aus.. mit dem Kopf lässt sich die Minutenzahl einstellen. Dabei habe ich darauf geachtet das bei sechs Minuten die Mittelstellung erreicht ist. Das Video wurde gekürzt um die Wartezeit zu verringern.

Quellen:

Energiesparmodus: http://www.arduino-hausautomation.de/2014/emils-ampel-attiny45-im-tiefschlaf/

ATtiny programmieren: https://www.frag-duino.de/index.php/maker-faq/37-atmel-attiny-85-mit-arduino-arduinoisp-flashen-und-programmieren

Farbcodierung bei Widerständen: http://www.calculino.com/de/elektronik/ohmscher-widerstand_rechner.html

Vorwiderstand LED: http://www.elektronik-kompendium.de/sites/bau/1109111.htm

Piezo Ansteuerung: https://www.arduino.cc/en/Tutorial/PlayMelody

  • Permalink
  • Kommentare

Thailand, Laos und Cambodscha Teil 2

Okt 052015

Weiter ging es zu den 4000 Inseln am Mekong. Die letzten Flussdelfine, Wasserfälle und die atemberaubende Natur bewundert.

undefined

Danach ging es weiter Richtung Cambodscha. Natürlich mussten wir zum Angkor Wat nach Siem Riep. Der beeindruckendste Tempel war derjenige in dem 2001, Lara Croft: Tomb Raider, gedreht wurde. Seit Jahrhunderten sind nun die Tempelanlagen verlassen und gigantische Bäume sind in dieser Zeit gewachsen.

undefined

Nach zwei weiteren Stopps in den Süden von Cambodscha, Sihanoukville und Battambang, sind wir wieder zurück nach Bangkok gekommen. Thai Boxing durfte dann natürlich auch nicht fehlen.

undefined

  • Permalink
  • Kommentare

Thailand, Laos und Cambodscha Teil 1

Okt 052015

Nach gut zwei Monaten sind wir wieder zurück. In Bangkok hat alles gestartet. Von dort ging es in den Norden Thailands wobei wir wunderschöne Momente hatten auf Bootstouren, beim Schnorcheln und beim erklimmen etlicher Aussichtspunkte. Unter anderem waren wir auf den Inseln Koh Samui, Koh Tao, Khao Ping Kan, Koh Phi Phi und viele weitere Inseln.undefined

undefined

Weiter ging es in das Kletterparadies Krabi und von dort mit dem Flugzeug in den Süden nach Chiang Mai.

undefined

Kochkurs und Trekking Tour standen dabei auf dem Programm. In Pai konnte man dagegen relaxen. Weiter ging es Richtung Laos über Chiang Rai mit den etwas anderen Tempeln. Kajaktouren, Tubing sowie Klettern war in Laos geboten. Auch gab es schöne Wasserfälle.

undefined

In Vang Vieng gab es sowohl sehr ruhige Plätzchen wie auch Party.

undefined 

undefined

  • Permalink
  • Kommentare
k
← Ältere Posts