Go Down

Topic: Port Manipulation Encoder (Read 1 time) previous topic - next topic

Augusto Picciani

Ciao a tutti. Devo controllare un rotary encoder per interfaccia utente e devo modificare il codice in "true C" per velocizzare le letture. Sto usando Arduino Uno (Atmega328).

Il codice di partenza é questo:

Code: [Select]

encoderLast=LOW;
n=LOW;
void setup(){
pinMode(2,INPUT);
pinMode(3,INPUT);
digitalWrite(2,HIGH);
digitalWrite(3,HIGH);
}
void loop(){
encoder();
}
void encoder(){
 n = digitalRead(2);
  if ((encoderLast == LOW) && (n == HIGH)) {
   if (digitalRead(3) == LOW) {
      encoderPos--;
    } else {
      encoderPos++;
    }
  }
  encoderLast = n;
}


Ora dovrei velocizzare la funzione encoder utilizzando la port manipulation:

Code: [Select]

void encoder(){
 n = PIND & _BV(PIND2);
  if ((encoderLast == LOW) && (n == HIGH)) {
   if ((PIND & _BV(PIND3)) == LOW) {
      encoderPos--;//antiorario
    } else {
      encoderPos++;//orario
    }
  }
  encoderLast = n;
}


Il risultato della modifica é che la variabile encoderPos non si incrementa ne si decrementa ed é come se nelle condizioni vi sia qualcosa che non va. Potete aiutarmi? Grazie

PaoloP

Secondo me ti conviene usare un interrupt, così non perdi nessun impulso.
Code fast. Code easy. Codebender --> http://codebender.cc/?referrer=PaoloP

leo72


Secondo me ti conviene usare un interrupt, così non perdi nessun impulso.

Quoto

Augusto Picciani

Purtroppo non posso usare gli interrupt perché mi da problemi con il display.
Inoltre vorrei imparare meglio la port manipulation. Secondo voi il codice é corretto?

sciorty

Code: [Select]
n = PIND & _BV(PIND2);
Se n viene dichiarato come intero 0000100 vale 4, e nel blocco if non viene riconosciuto come HIGH

leo72


Code: [Select]
n = PIND & _BV(PIND2);
Se n viene dichiarato come intero 0000100 vale 4, e nel blocco if non viene riconosciuto come HIGH

Perché HIGH è una costante predefinita che vale 1.
Come LOW è una costante che vale 0.

Augusto Picciani

Grazie, ora funziona!
Ho applicato la stessa funzione ad un encoder Hall di un motore che fa al massimo 80 giri/minuto (rapporto riduzione 131:1), con una risoluzione di 64 cpr, ma di cui utilizzo un solo canale, perché la direzione la prendo da una variabile impostata altrove. (non posso usare gli interrupt)
Dopo alcuni calcoli, ho fatto in modo che ad ogni 25 impulsi letti (solo sul fronte di salita) mi faccio aumentare una variabile per indicarmi i millimetri percorsi. Ora per distanze che vanno da 5mm fino ad 80 mm la precisione é buona. Oltre gli 80 mm inizio ad avere imprecisioni non uniformi.
Tengo a precisare che ho modificato gran parte delle funzioni presenti nel codice con quelle proprie della port manipulation ed ora tutto il funzionamento mi sembra molto piú fluido e senza ritardi.

Cosa posso fare per aumentare la precisione?

BaBBuino

#7
Mar 12, 2013, 07:25 am Last Edit: Mar 12, 2013, 07:27 am by BaBBuino Reason: 1
Io ho appena costruito un oggetto vagamente simile al tuo, con display grafico abbastanza impegativo, e per variate alcuni parametri ho usato un encoder rotativo (a mò di Volume autoradio), usando gli interrupt sui pin 2 e 3.

Mi spieghi che problemi avresti con il display, visto che non usa alcun timer interno (unico motivo per cui un Interrupt ext non dovrebbe funzionare)?

Solo usando gli interrupt puoi avere una "fluidità" di utilizzo soddisfacente.

Tieni sempre a mente che l'ambizione e coronamento finale di un "Power user" di MCU, è quella di non scrivere NULLA nella funzione while(), nel caso di Arduino la funzione loop().

astrobeed


Tieni sempre a mente che l'ambizione e coronamento finale di un "Power user" di MCU, è quella di non scrivere NULLA nella funzione while(), nel caso di Arduino la funzione loop().



Direi che hai appena scritto una cosa che viola tutte le regole della buona programmazione.
E' esattamente l'opposto di quello che dici, nel main loop, tipicamente una while(1), viene fatto tutto, ovviamente chiamando funzioni esterne scritte appositamente, mentre nelle isr, che devono durare il minimo indispensabile, ci si deve limitare a resettare gli eventuali flag, svolgere solo le operazioni che richiedono attenzione immediata e settare un eventuale flag per informare il main loop che deve eseguire una certa azione.

BaBBuino

Guarda... mi stai mandando in depressione perchè ho giusto litigato la settimana scorsa con un Ingegnere che sosteneva quanto ho detto. Siccome sembrava sapesse il fatto suo, ho abbozzato e fatta mio questa osservazione.

Lui insisteva su una programmazione simil Windows, ovvero programmazione attivata da eventi. Funzioni che partono solo se si è innescato l'evento, un interrup. Naturalmente con una ben studiata gestione delle priorità degli int.

Io invece sostenevo che usare solo interrupt porta a un gran casino, e che una gestione sensata del loop fosse piú funzionale.

Se mi dici bene come sostenere la tesi contro il "tutto fuori", torno a litigarci di corsa!

astrobeed


Lui insisteva su una programmazione simil Windows, ovvero programmazione attivata da eventi


Non è possibile fare paragoni tra un programma scritto per Windows tramite un compilatore ad oggetti, con relativo supporto, e un programma scritto per una mcu 8 bit, sono due cose totalmente diverse come approccio, funzionamento e stile di scrittura.
Il software event driven per Windows si basa sopratutto sugli interrupt software, che sono decisamente diversi da quelli hardware, anche perché il kernel di windows non consente di accedere direttamente all'hardware, poi ci sono i timer che permettono di far partire ogni tot ms (con largo margine di errore) un certo processo, inoltre anche rimanendo sul C++ per Windows non esiste proprio la main(), almeno in apparenza, in realtà c'è anche se non la vedi, più o meno come fa la loop() di Arduino.

Quote

Io invece sostenevo che usare solo interrupt porta a un gran casino, e che una gestione sensata del loop fosse piú funzionale.


L'approccio corretto, parlando di C, è avere un main loop, non importa se si chiama main() o loop(), dentro il quale gestisci il tutto in base ad una serie di flag e/o temporizzazioni.
Un buon modo di gestire il tutto è usare un timer come clock di sistema che ogni tot us, normalmente va bene una volta ogni ms (come fa la millis ) attiva la sua isr al cui interno vengono incrementate delle variabili che sono l'orologio di vari eventi, se ne usa più di una perché spesso fa comodo azzerarle ad ogni ciclo in modo da poter usare variabili al massimo di tipo int e non avere mai problemi di overflow.
Nella main/loop hai una cascata di if, o delle switch, che controllano i flag delle azioni, questi vengono settati all'interno delle isr o come risultanza di operazioni eseguite, in base ai quali vengono chiamate specifiche funzioni, idem con i timer che attivano ad intervalli regolari determinati processi.
Poi ci sarebbero da fare delle considerazioni sulle precedenze di alcuni processi su altri, sopratutto se è richiesto un preciso intervallo temporale di esecuzione con un jitter minimo, però qui stiamo entrando nel campo degli RTOS che è un discorso molto complesso, se serve realmente è meglio usarne uno già fatto e sicuramente funzionante.

astrobeed


ho giusto litigato la settimana scorsa con un Ingegnere che sosteneva quanto ho detto.


Dimenticavo, ingegnere in cosa e che esperienza ha sulla programmazione di micro/mcu ?

BaBBuino

Purtroppo il personaggio è sopra le righe, è stato allievo di un certo Dott. Zener (!) alla Westinghouse e si occupa di robotica industriale (sistemi di azionamento motori brushless bracci robot). Uno di quelli che conosce a memoria ogni bit di Canbus, Modbus, Profibus ecc.
Non è uno di quei ingegneri da 1000 lire al kilo, quindi quando parla ha il suo fascino e ci litigo solo perchè è un caro amico.

Ma se ho modo ci litigo volentieri! :D

astrobeed


Ma se ho modo ci litigo volentieri! :D


Dato che nemmeno io sono da 1000 lire al kg se vuoi ci litigo io per te  :smiley-mr-green:
Però non mi hai ancora detto in cosa è ingegnere, il fatto che si occupa di azionamenti non significa che li progetta lui, anzi è facile che utilizza sistemi che ho progettato io  :D :smiley-mr-green: :D

pablos

Oh perbacco qui la discussione si fa a .... "chi ce l'ha più lungo"  :D :smiley-mr-green: :D :smiley-mr-green:
no comment

Go Up