Attiny85 interrupt Timer

Ciao tutti, volevo chiedervi se potreste aiutarmi con questo problema.
Vorrei far eseguire a micro una routine ogni millisecondo o comunque ogni tempo prefissato e pensavo di utilizzare il timer interno che genera un interrupt.
Purtroppo non ho dimestichezza con i registri, e volevo creare qualcosa di flessibile, ovvero che possa modificare senza stravolgere il programma.
Come posso fare?
Chi può aiutarmi?
Grazie.

manolomao:
... Purtroppo non ho dimestichezza con i registri ...
...
... Come posso fare? ...

Usare Google e carcare una libreria di "timer" per Arduino ... ce ne sono un'infinità ...

Guglielmo

Grazie Guglielmo, io usavo la MsTimer2 che però, ovviamente, su Attiny85 non funziona...
Avere la libreria già pronta per Attiny85 sarebbe risolutivo, ma non la trovo...e inoltre mi piacerebbe anche imparare a manovrare i registri così da capire come funziona il sistema...
Puoi darmi qualche link?
Grazie.

Beh ...
... studio del datasheet in primis, poi, c'è una bella utility grafica per Win (che avevo già a suo tempo segnalato) che permette di generare il codice e che si chiama RTM_timercalc non credo generi specificatamente per ATtiny, ma ti fa capire come impostare i timers (su ATtiny, purtoppo, hanno cambiato alcuni nomi, ma il concetto è esattamnete quello), infine c'è il tutorial in pdf che scrisse a suo tempo il nostro caro admin leo72 e che ti allego.

Buono studio.

Guglielmo

Timer.pdf (747 KB)

Grazie Guglielmo, in effetti avevo già provato RTM_timercalc e avevo trovato difficoltà...
La voglio dire tutta...al piccolo Attiny85 vorrei fare tante cose, tre uscite PWM, un uscita per pilotare led neopixel ed un ingresso analogico.....
I tre PWM sono collegati sul pin 5 (0), pin 6 (1) e pin 3 (4) (tre led che variano di intensità), i neopixel al pin 7 (2) e l'ingresso analogico al pin 2, al variare del valore analogico variano gli effetti che voglio ottenere.
Il timer a 1mS mi serve per gestire il timing degli effetti.
Credi sia possibile o sto chiedendo troppo???
Grazie.

Per generare interrupt ogni millisecondo (in realta' 1.024mS) con una UNO non e' necessario installare una libreria: bastano due righe di codice.
Non so se funziona anche su Attiny85: prova e facci sapere.

#define TEST 3

void setup()
{
  pinMode(TEST, OUTPUT);          // pin di test
  OCR0A = 0x80;                   // abilita "Timer 0 compare" lontano da millis() e delay()
  TIMSK0 |= _BV(OCIE0A);          //
}

void loop()
{
}

ISR(TIMER0_COMPA_vect)          // servizio interrupt "Timer 0 compare"
{
    digitalWrite (TEST, HIGH);
    digitalWrite (TEST, LOW);
}

Marco

>Sulimarco: l'esempio per Atmega328P già lo aveva ed il programmino che ho indicato, RTM_timercalc, genera tutto il codice per varie MCU AVR, ma NON per gli ATtiny ...

Non che cambi qualche cosa nella logica del programma (a parte che gli ATtiny viaggiano a 8MHz), ma come avevo anticipato a manolomao, tocca STUDIARSI il datasheet e scoprire che ...
... sugli ATtiny, alcuni registri hanno nomi diversi, per cui TIMSK0 non esiste, ma esiste TIMSK :smiley:

Guglielmo

l'esempio per Atmega328P già lo aveva ...

La mia proposta era un approccio un po' diverso e cioe' usare il timer che il core di Arduino usa per "millis" e "delay", abilitandolo a generare interrupt anche su "timer compare".
In questo modo non e' necessario preoccuparsi della velocita' del clock della cpu perche' il timer e' gia' stato configurato dal core di Arduino per andare in overflow ogni mS.

Per fare questo oltre a studiarsi il datasheet (come giustamente sottolinei) bisogna anche studiarsi il core di Arduino.
Ad esempio bisogna sapere qual'e' il timer usato per "millis": sulla UNO e' Timer 0 ma, da quanto leggo nel file "core_build_options.h" di Tiny, risulta che Attiny85 usi timer 1.

#if defined( __AVR_ATtinyX5__ )

/*
  For various reasons, Timer 1 is a better choice for the millis timer on the
  '85 processor.
*/
#define TIMER_TO_USE_FOR_MILLIS   1

Comunque ho postato il mio esempio (che funziona sulla UNO e derivati) soprattutto perche' lo trovo estremamente semplice e potrebbe tornare utile a qualcuno che abbia bisogno di un interrupt ogni mS.

Marco

In questo modo non e' necessario preoccuparsi della velocita' del clock della cpu perche' il timer e' gia' stato configurato dal core di Arduino per andare in overflow ogni mS.

Inoltre non c’è’ bisogno di un timer aggiuntivo, ma solo di quello già’ usato dal core di Arduino.

Marco

... certo, elegante soluzione, ma .... come ho detto e ripetuto fino alla nausea, se uno non si studia il datasheet e NON sa il nome dei registri, ai voglia che tu fai esempi, su Tiny NON compilano perché i nomi sono diversi.

Guglielmo

Totalmente d’accordo ! :slight_smile:

Marco

Grazie Guglielmo e grazie Sulimarco.
Proverò tutto appena ho un po' di tempo...
Alla luce di quello che ho scritto sulla configurazione del circuito, dite che riesco a gestire tutto con l'Attiny85 o devo passare al nano?
Guglielmo, quindi visto che timer1 è usato per i millis, uso timer 0 per il mio interrupt??
Grazie.

Se usi la logica suggerita da Sulimarco NON ti serve alcun altro timer ... :wink:

Guglielmo

Sulimarco, c'è qualcosa che però non capisco....spero mi perdonerai e potrai spiegarmi meglio questi comandi:

OCR0A = 0x80;                   
TIMSK0 |= _BV(OCIE0A);

Perchè sto provando di convertire le tue istruzioni nel core Attiny85, e vorrei capire bene come farlo seguendo le tue istruzioni, soprattutto questa non mi è chiara...

TIMSK0 |= _BV(OCIE0A)

E un altra cosa, nella routine interrupt

    digitalWrite (TEST, HIGH);
    digitalWrite (TEST, LOW);

cosa si può vedere in uscita????

Ad esempio bisogna sapere qual'e' il timer usato per "millis": sulla UNO e' Timer 0 ma, da quanto leggo nel file "core_build_options.h" di Tiny, risulta che Attiny85 usi timer 1.

Questo l'avevo visto installando il package "Digistump" ma installando il package ufficiale di questo non ho trovato traccia: quindi sembra che, per millis, si usi Timer 0 anche per Attiny85.

Venendo alle tue domande:

TIMSK0 |= _BV(OCIE0A);
Setta il bit OCIE0A nel registro TIMSK0.
Questo bit fa si che si generi un interrupt quando il contatore del timer e' uguale al valore caricato nel registro OCR0A
Per Attiny85 bisogna scrivere:
TIMSK |= _BV(OCIE0A);

OCR0A = 0x80;
Carica il registro OCR0A in modo che l'interrupt si generi non in concomitanza all'interrupt usato da millis.
Se questo succedesse funzionerebbe tutto lo stesso perche' i due interrupt verrebbero serviti uno di fila all'altro, ma non e' bello perche' il micro resterebbe in interrupt per un tempo piu' lungo.

digitalWrite (TEST, HIGH);
digitalWrite (TEST, LOW);

Genera un impulso sul pin di test, visibile con un oscilloscopio.
Se non hai un oscilloscopio collega un led al pin di test e fai la seguente modifica.

ISR(TIMER0_COMPA_vect)          // servizio interrupt "Timer 0 compare"
{
  if(Conta++ == 0x00)
  {
    digitalWrite (TEST, !digitalRead(TEST));
  }
}

Ricordati di dichiarare Conta come variabile byte globale.
In questo modo il led collegato al pin di test deve lampeggiare in modo visibile a occhio.

Marco

This topic was automatically closed 120 days after the last reply. New replies are no longer allowed.