Domanda sugli attiny (o roba simile)

Premetto che fin’ora non li ho mai usati, gli attiny, quindi mi servono informazioni di fattibilita’, al momento … poi in base alle possibilita’ vedro’ cosa usare … ma se e’ il caso, uso direttamente una MCU piu grossa, senza problemi …

Ho la necessita’ di pilotare dei motori in AC a spazzole (no, niente modifiche a macchine o impianti esistenti) tramite dei rele’, la classica configurazione invertitore piu interruttore, collegati come in figura (EDIT: oops, mancava la figura :P)

invers-motore-ac.png

Ma dato che i comandi dovrebbero essere dati da un’operatore (e gli operatori umani non sono famosi per il rispetto dei tempi di ritardo necessari :stuck_out_tongue: :D), mi serve improvvisare una “sicura” che possa impedire le inversioni immediate, da piazzare fra le linee di comando ed i rele’, per evitare botti e contatti fusi …

Nello specifico, vorrei implementare qualcosa di meglio della classica linea di ritardo passiva, ed anche un po piu ottimizzata … ad esempio, se comando “avanti”, se l’invertitore e’ in posizione “avanti”, si accende direttamente l’interruttore, se invece l’invertitore e’ in posizione “indietro” (da una precedente marcia indietro) prima si riporta su “avanti” e poi accende l’interruttore … se sto andando “avanti” e di colpo comando “indietro”, prima si spegne l’interruttore, attende 300mS, porta l’invertitore su “indietro”, attende 300mS, accende l’interruttore … se fermo mentre sto andando “indietro”, l’invertitore NON si riporta su “avanti” da solo (in questo modo se devo dare diversi impulsi “indietro”, il tempo di ritardo diminuisce di molto, lo stesso nel caso debba dare diversi impulsi “avanti” successivi), ma attende di ricevere prima un comando “avanti”, in quel caso prima commuta e poi accende …

In pratica vorrei fare in modo che i ritardi intervengano solo quando e’ necessario, cioe’ quando effettuo delle inversioni senza che fra lo spegnimento e l’accensione invertita sia passato un minimo di ritardo, da definire, ma non quando ad esempio do diversi comandi veloci tutti avanti o tutti indietro, e neppure se passo da avanti a indietro o viceversa ma e’ gia trascorso un minimo di ritardo … inoltre bisognerebbe che le sequenze di inversione dei due rele’ fossero generate dalla MCU, perche’ i comandi che arrivano sono solo due, uno va basso quando comando “avanti”, uno quando comando “indietro”, se vanno bassi entrambi contemporaneamente devono essere ignorati come errore … e fare il tutto a porte logiche e flipflop, anche se possibile, mi porterebbe via parecchio spazio che non ho …

Le domande, per chi ha gia utilizzato gli attiny, o comunque le varie MCU ad 8 pin, sono queste: e’ possibile realizzare un sistema del genere con uno di quei chip ? … hanno sufficente memoria e capacita’ per gestire i rele’ in quel modo ? … se si, quale potrebbe essere il modello migliore, considerando che non dovranno fare nient’altro che quello, ma che dovranno anche garantire la massima affidabilita’ senza possibilmente bloccarsi ?

Come ho scritto in un altro thread, ho usato parecchie volte gli ATtiny85 che, per il tuo scopo, dovrebbero essere anche abbondanti, ma che, data la trascurabile differenza di prezzo e visto che immagino non devi produrre centiania di migliaia di pezzi per cui anche 0.5€ fanno la differenza, ti consiglio di usare senza scendere a modelli con meno memoria, anche perché, notoriamente ... l'appetito vien mangiando :wink:

Guglielmo

Vediamo se ho capito cosa Etemenanki vuole fare:
Ha un commutatore a tre posizioni: Indietro-Spento-Avanti con cui comandare un motore attraverso un interruttore e un invertitore. Il passaggio fra Indietro, Spento e Avanti deve essere comandato da un Attiny85 con dentro un programma di questo tipo:

Stato iniziale
interruttore = aperto
invertitore = avanti
comando = spento

Comando spento->avanti
Se invertitore = avanti
interruttore = chiuso
Se invertitore = indietro
pausa 300ms
invertitore = avanti
interruttore = chiuso

Comando avanti->spento
interruttore = aperto

Comando spento->indietro
Se invertitore = indietro
interruttore = chiuso
Se invertitore = avanti
pausa 300ms
invertitore = indietro
interruttore = chiuso

Comando indietro->spento
interruttore = aperto

Ho capito bene?

Ciao,
P.

No, no, altro che centinaia di migliaia, me ne servirebbero 4 ... sono per inserire le protezioni ed i ritardi di commutazione sulle schede che sto riprogettando (di nuovo, accidenti alla mania del miglioramento :P) per i motori del ROV, uno per ogni motore ... per cercare di renderle migliori ed "a prova di incompetente frettoloso" il piu possibile, perche' non sai mai a chi va in mano e come lo tratta ...

Quindi dici di usare l'Attiny85 ? ... avevo dato un'occhiata veloce ai vari datasheet (perche' degli attiny non ne so molto), e mi sembrava addirittura esagerato, ma la minima differenza di prezzo per quei pochi pezzi non e' certo un problema, e se dici che sono meglio, usero' quelli ... fra l'altro ho visto che hanno il clock RC interno, e dato che a me la precisione qui non serve, meglio, ancora meno componenti da piazzare in uno spazio gia ridotto :slight_smile: ... lo posso programmare con un usbasp e l'ide, o serve un'hardware specifico ?

Etemenanki:
Quindi dici di usare l'Attiny85 ? ... avevo dato un'occhiata veloce ai vari datasheet (perche' degli attiny non ne so molto), e mi sembrava addirittura esagerato, ma la minima differenza di prezzo per quei pochi pezzi non e' certo un problema, e se dici che sono meglio, usero' quelli ... fra l'altro ho visto che hanno il clock RC interno, e dato che a me la precisione qui non serve, meglio, ancora meno componenti da piazzare in uno spazio gia ridotto :slight_smile: ... lo posso programmare con un usbasp e l'ide, o serve un'hardware specifico ?

Lo dico perché magari domani ... ci vuoi aggiungere qualche altra cosetta (... ti conosco :smiley:) e così NON hai problemi di memoria (hai ben 8KB :grin: ) !

Si, si programmano tranquillamente con qualsiasi programmatore ISP (io uso AVRISPmkII) con il solito sistema. Se entri nell'IDE e se vai nel Board manager, installati il "core" "ATTinyCore by Spence Konde" :wink:

Guglielmo

pgiagno:
Vediamo se ho capito cosa Etemenanki vuole fare:
...

Aspetta, cerco di spiegarmi meglio ... (a proposito, mi sono appena accorto di aver disegnato lo schema errato, ho scambiato spazzola e statore su K10, ma era solo per dare un'idea)

All'accensione, ovviamente, entrambe le uscite saranno a zero, e devono rimanere a zero finche' entrambi gli ingressi non sono ad 1 (come sicurezza iniziale, per evitare che i motori possano partire a causa di un corto, prima di abilitare qualsiasi operazione voglio fargli controllare che entrambi gli ingressi siano a zero e ci rimangano per almeno un secondo) ... mettero' la solita RC sul reset per assicurarmi che all'accensione il micro parta sempre nella stessa condizione ... quindi ci sara' un minimo ritardo all'accensione che pero' e' del tutto ininfluente ... (sarebbe bello che potessi collegarci un led sul pin che rimane libero per segnalare l'errore sugli ingressi, ma non complichiamoci troppo la vita per adesso, quello al massimo verra', forse, quando tutto il resto funzionera' come si deve :D)

Poi dipende dai segnali che arriveranno sugli ingressi ... sono a logica negata ed attivi a zero, per ogni motore ci sono due segnali, uno va a zero per la marcia avanti, ed uno va a zero per la marcia indietro (questo dipende dal controllo remoto e non puo essere cambiato), se vanno a zero entrambi deve spegnere come se fossero ad uno entrambi, perche' sarebbe una condizione di errore ...

Qui iniziano i controlli che vorrei fargli fare ... se, ad esempio, inizio con un comando avanti (ingresso 1 a zero), non ci sono problemi, puo attivare il rele switch anche senza ritardo ... la stessa cosa se riceve piu comandi velocemente nella stessa direzione (spento-avanti-spento-avanti ... come se dovessi posizionare il mezzo con piu azionamenti consecutivi e veloci dei motori) ... in quei casi, il motore starebbe gia girando, o fermandosi, nello stesso senso di marcia, quindi il ritardo non serve (ed ovviamente lo stesso capita se le stesse manovre ripetute le faccio indietro, niente ritardi) ... anche nel caso che il primo segnale sia indietro non serve il ritardo lungo, perche' il mezzo e' appena stato acceso e basta il ciclo attiva invertitore - attendi 100mS - attiva switch ...

(EDIT: nota: l'invertitore NON si deve staccare ogni volta che spengo, se sto andando indietro, ma cambiare stato solo quando passo da un senso all'altro di rotazione, per ottimizzare i ritardi per le manovre ripetute anche all'indietro)

Se invece passo da avanti ad indietro (o da indietro ad avanti), possono esserci due casi ... primo caso, spengo il motore, ma prima di effettuare l'inversione passa piu di, diciamo, 500mS (cioe', prima di dare la nuova direzione, il motore e' rimasto spento per piu di 500mS), in questo caso e' sufficente attivare lo scambiatore, attendere diciamo 100mS ed attivare lo switch, il motore si mette a girare indietro ... se a questo punto lo fermo, stacco lo switch ma NON l'invertitore (per ottimizzare il caso in cui debba dare piu comandi consecutivi indietro, come nell'esempio di prima con l'avanti per posizionare il mezzo) ... se invece fra lo spegnimento ed il comando indietro e' passato meno di 500mS, prima di azionare l'invertitore e poi lo switch, aspetto 400mS, in modo da consentire al motore di rallentare (i tempi possono essere anche un po piu lunghi, ma considera che e' un motore che aziona un'elica in acqua, la cosa offre una certa resistenza e l'inerzia e' molto minore che in aria) ...

La stessa cosa ovviamente dovrebbe accadere se passo da indietro ad avanti, se il tempo minimo e' trascorso stacco l'invertitore, aspetto i 100mS ed attacco lo switch, se invece non e' trascorso, prima di staccare l'invertitore attendo i 400mS, stacco, attendo 100mS ed attacco lo switch ...

Questo significa che devo anche memorizzare lo stato dell'invertitore, per sapere in che condizione si trova e se gli impulsi ripetuti sono o meno nello stesso senso dei precedenti, ma usando una semplice flag dovrei cavarmela, immagino ...

gpb01:
... (... ti conosco :smiley:) ...

Ebbene si, lo confesso ... gia mentre leggevo mi e' venuta l'idea di usare il pin libero per segnalare con un led un'errore dello stato degli ingressi (magari in futuro) ... pero' niente altro, sarebbero fissi sulle schede dei motori e farebbero solo quel lavoro ... comunque grazie del suggerimento, ne ordino quattro (no, meglio cinque, per esorcizzare il fantasma di Murphy :D), ed appena arrivano provero' a giocarci un po ...

... e se t'avanzano due pin, considera che ci gira bene la SoftwareSerial e che quindi un domani ... potresti prevedere anche comandi/feedback su porta seriale :smiley: :smiley: :smiley:

Guglielmo

gpb01:
... e se t'avanzano due pin, considera che ci gira bene la SoftwareSerial e che quindi un domani ... potresti prevedere anche comandi/feedback su porta seriale :smiley: :smiley: :smiley:
Guglielmo

No, positivo, negativo, due ingressi, due uscite, il reset ... avanza un solo pin ... (e poi non esageriamo, non vorrei rischiare che un domani prendano vita e mi vengano a cercare per vendicarsi di tutto quello che gli faro' passare mentre imparo ad usarli, poveretti ... :smiley: :smiley: :D)

Io li programmo con questo

molto pratico.

In casa al momento ho un usbasp (usbisp, quel cavolo che e’, quelli fatti a chiavetta), un qualcosa che dovrebbe essere un jtag, ma non ne sono sicuro (non lo uso da anni), ed un vecchio pickit3 preso in fiera un po di tempo fa (piu che altro perche’ costava poco :P), … una volta avevo anche un multiprogrammatore, autocostruito, poi un paio di anni fa ho fatto l’errore di prestarlo ad una persona, che me l’ha fritto …

usbasp va benissimo, prevedi il connettore ICSP e via.

Per chi li usa per la prima volta c'e' l'ottima guida fatta da Leo, si riferisce alla ver 1.5 dell'ide, ma e' valida sotto tutti i punti di vista.

Guida Attiny

Grazie, gli do' un'occhiata ... ne ho ordinati 5, appena arrivano ed ho un momento inizio a massacrarne uno fare qualche esperimento (:D) per vedere cosa riesco a tirarci fuori ... in teoria dovrebbe bastare una macchina a stati finiti con una catena di if/else, ma vedro' cosa ne esce ...

Ok alla macchina a stati finiti, ma con un enumeratore+switchcase :wink:

Ciao,
non ti avanzano pin altrimenti avresti potuto variare con dei trimmer i tempi di "stop" che ti occorrono durante le inversioni di marcia...

testato:
Ok alla macchina a stati finiti, ma con un enumeratore+switchcase :wink:

Cioe', vuoi proprio complicarmi la vita, vero ? ... :smiley:

tonid: non mi serve cambiare i tempi, devono solo essere sufficenti ad assicurarsi che il motore non giri piu in un senso (o almeno giri il meno possibile, quindi saranno da rivedere alla fine, ma una volta trovati, restano definitivi) prima di farlo ripartire nell’altro, tanto per evitare il piu possibile rele’ fritti e contatti incollati anche se l’operatore del momento non rispetta i tempi di suo … cosa che probabilmente non fara’ nesuno (bisogna anche considerare l’ambito di utilizzo di un’apparecchio ed i possibili utenti, nel progettarlo … ad esempio un ROV ha un suo operatore, di solito, ma puo succedere che lo usi qualcun’altro, che passi la mano perche’ deve fare qualcos’altro, che non ci sia e lo debba usare il primo che capita … quindi per quanto possibile, devo cercare di progettarlo il piu possibile “a prova di incompetente” … ed anche il piu possibile robusto e facile da riparare, perche’ nonostante tutto gli incidenti succedono)

Etemenanki:
Cioe', vuoi proprio complicarmi la vita, vero ? ... :smiley:

Vedrai che è perfettamente il contrario, diventa tutto più semplice e leggibile.

Ho buttato giu qualche riga con il notepad mentre aspettavo (con gli if :P) ... niente di definitivo, solo per cercare di immaginarmi una sequenza logica che tenesse conto di tutte le possibili combinazioni con il minimo di comandi ... considera che ci sono solo 3 combinazioni valide dei due ingressi ... entrambi alti (motori spenti), in1 basso (marcia avanti), ed in2 basso (marcia indietro) ... se vanno bassi entrambi e' un'errore ... ci vedi un senso ?

EDIT: corretto errore, avevo dimenticato di resettare le flag nel primo if

byte led=5;      /led per segnalare errore ingressi                            
byte in1=2;      /ingresso avanti, logica negata
byte in2=3;      /ingresso indietro, logica negata
byte switch=6;   /uscita rele' marcia
byte inv=7;      /uscita rele' invertitore
byte pwr=LOW;    /flag stato switch
byte dir=LOW;    /flag stato invertitore
unsigned long millis1=0;
unsigned long millis2=0;

void setup() 
{
   pinMode(led, OUTPUT);
   digitalWrite(led, LOW);
   pinMode(in1, INPUT);
   pinMode(in2, INPUT);
   pinMode(switch, OUTPUT);
   digitalWrite(switch, LOW);
   pinMode(inv, OUTPUT);
   digitalWrite(inv, LOW);
   millis1=millis();
   digitalWrite(led, HIGH);    /ciclo di attesa iniziale
   while((millis1-millis()>=1000)&(in1==HIGH)&(in2==HIGH));  /esce se ingressi ok
   digitalWrite(led, LOW);     /inizio loop ok
   millis2=millis();           /resetta millis2
}

void loop()
{
   if((in1==LOW)&(in2==LOW))      /errore stato ingressi
   {
      digitalWrite(switch, LOW);   /spegne marcia
      pwr=LOW;                          /reset flag marcia
      digitalWrite(inv, LOW);        /spegne invertitore
      inv=LOW;                           /reset flag invertitore
      digitalWrite(led, HIGH);       /accende led errore ingressi
      delay(250);                        /per ripetere il controllo ogni 250mS
      millis2=millis();                  /resetta millis2
   }
      else
	  digitalWrite(led, LOW);       /azzera led errore
      {
      if((dir==LOW)&(pwr==LOW)&(in1==LOW))   /in1 basso con inv avanti da spento
      {
         digitalWrite(switch, HIGH);   /accendi marcia
         pwr=HIGH;                     /set flag marcia on
      }
      if((dir==LOW)&(pwr==LOW)&(in2==LOW))   in2 basso con inv avanti da spento
      {
         if(millis2-millis()>=500      /se passati >500ms da ultimo stop
         {
            digitalWrite(inv, HIGH);      /invertitore on
            delay(100);                   /aspetta 100mS
            digitalWrite(switch, HIGH);   /accendi marcia
			pwr=HIGH;                     /set flag marcia on
         }
         else                             /se non passati 500mS
         {
            delay(500);                   /aspetta 500mS
            digitalWrite(inv, HIGH);      /invertitore on
            delay(100);                   /aspetta 100mS
            digitalWrite(switch, HIGH);   /accendi marcia
            pwr=HIGH;                     /set flag marcia on
         }
      }
      if((dir==HIGH)&(pwr==LOW)&(in2==LOW))   /in2 basso con inv indietro da spento
         {
         digitalWrite(switch, HIGH);   /accendi marcia
         pwr=HIGH;                     /set flag marcia on
      }
      if((dir==HIGH)&(pwr==LOW)&(in1==LOW))   /in1 basso con inv indietro da spento
         {
         if(millis2-millis()>=500          /se passati >500ms da ultimo stop
         {
            digitalWrite(inv, LOW);       /invertitore off
            delay(100);                   /aspetta 100mS
            digitalWrite(switch, HIGH);   /accendi marcia
            pwr=HIGH;                     /set flag marcia on
         }
         else
         {
            delay(500);                   /aspetta 500mS
            digitalWrite(inv, LOW);       /invertitore off
            delay(100);                   /aspetta 100mS
            digitalWrite(switch, HIGH);   /accendi marcia
            pwr=HIGH;                     /set flag marcia on
         }
      if((pwr==HIGH)&(in1==HIGH))        /in1 alto mentre e' in marcia
      {
         digitalWrite(switch, LOW);    /spegni marcia
         pwr=LOW;                      /set flag marcia off
         millis2=millis();             /resetta millis2
      }
      if((pwr==HIGH)&(in2==HIGH))        /in2 alto mentre e' in marcia
      {
         digitalWrite(switch, LOW);    /spegni marcia
         pwr=LOW;                      /set flag marcia off
         millis2=millis();             /resetta millis2
      }
   }
}

quanti errori ci vedi ? ... :smiley:

So che il delay rende i ritardi non proporzionati, probabilmente in futuro lo modifichero' con millis (anche se non danno fastidio) ... per ora e' solo un'esercizio teorico nell'attesa che mi arrivino i chip e di trovare il tempo poi di testarlo in pratica ... una sequenza di controllo di questo tipo, autoescludente, sarebbe realizzabile con gli switchcase come dici tu ? ...

Occhio che l'IF per calcolare il tempo passato con millis() è :

if ( millis() - oldMillis > tempoVoluto ) {
  // se è passato il tempo voluto fai qualche cosa
}

... le tue le vedo tutte al contrario ... c'è un motivo preciso ?

Guglielmo