Velocizzare l'IO delle porte digitali

Caspita che hai l'indirce del forum in testa?

Grazie per la dritta.

Comunque, mi pare di aver capito che è impossibile settare per una stessa porta un pin HIGH e l'altro LOW.
Devono essere 2 operazioni differenti.

Sbaglio?

erpomata:
Comunque, mi pare di aver capito che è impossibile settare per una stessa porta un pin HIGH e l'altro LOW.
Devono essere 2 operazioni differenti.

Sbaglio?

Sì.
0=LOW
1=HIGH
Quindi se riprendiamo la porta dell'esempio precedente, PORTD, e facciamo questa assegnazione:

PORTD = 0b10101010;

Hai impostato le porte collegate ai bit dispari su LOW (1-3-5-7) e quelle collegate ai bit pari su HIGH (0-2-4-6).

Si ma se io volessi impostare, ad esempio i bit 0 e 1 rispettivamente a HIGH ed a LOW ma preservando gli altri bit della porta non lo posso fare.

In quella maniera sovrascrivo tutte le impostazioni precedentemente date agli altri pin.

Allora vuol dire che non hai letto il mio post quotato da PaoloP :stuck_out_tongue:

erpomata:
Si ma se io volessi impostare, ad esempio i bit 0 e 1 rispettivamente a HIGH ed a LOW ma preservando gli altri bit della porta non lo posso fare.

Per settare i singoli bit di un port, o un registro, puoi usare le macro SBI(reg,bit) e CBI(reg,bit), usano le omonime istruzioni assembly e richiedo solo due cicli macchina per l'esecuzione.

SBI = Set Bit in I/O Register
CBI = Clear Bit in I/O Register

//SBI e CBI
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))

leo72:
Allora vuol dire che non hai letto il mio post quotato da PaoloP :stuck_out_tongue:
chiarimento su PORTD = B10101000; - #5 by leo72 - Software - Arduino Forum

Certo che l'ho letto ma se per settare a HIGH devo usare una OR e per metterla a LOW devo usare una AND come faccio a combinare la cosa su pin diversi, mantenendo lo stato degli altri pin della porta e facendo l'operazione contemporaneamente su tutta la porta.
Non mi pare di vedere ciò che mi serve in quel post.

Ragazzi mi inserisco anche io nella discussione perché ho un problema con gli input utilizzando "true C". Non so se devo aprire un'altra discussione, nel dubbio posto la domanda...

In pratica devo sostituire il classico DigitalRead(pin) con PINx.
Il codice di test é questo:

int encoder0PinALast=LOW;
int countPulses=0;
int n=LOW;

void setup()
{
  Serial.begin(115200);
  
  pinMode(2,INPUT);
  pinMode(3,INPUT);
  digitalWrite(2,HIGH);
  digitalWrite(3,HIGH);
}

void loop()
{
  
  encoderMotor();
 }

void encoderMotor(){
 // n = digitalRead(2);
 n=PIND & _BV(PCINT2);//<== il mio dubbio é qui. n varrá di volta in volta 1 o 0 ??

   if ((encoder0PinALast == LOW) && (n == HIGH ) ) { 
      if (PIND & _BV(PCINT19) == LOW) {
       countPulses++;
     } else {
       countPulses--;
     }
   } 
   encoder0PinALast = n;
}

Il fatto é che l' if non procede nel modo corretto e non ottengo ne l'incremento ne il decremento della variabile. Potreste chiarirmi il concetto su PINx ? Grazie.

erpomata:

leo72:
Allora vuol dire che non hai letto il mio post quotato da PaoloP :stuck_out_tongue:
chiarimento su PORTD = B10101000; - #5 by leo72 - Software - Arduino Forum

Certo che l'ho letto ma se per settare a HIGH devo usare una OR e per metterla a LOW devo usare una AND come faccio a combinare la cosa su pin diversi, mantenendo lo stato degli altri pin della porta e facendo l'operazione contemporaneamente su tutta la porta.
Non mi pare di vedere ciò che mi serve in quel post.

Scomponi le operazioni in 2 righe, una per l'attivazione con OR ed una per la disattivazione con AND.
Esempio:

PORTD |= ((1<<3) | (1<<5));
PORTD &= ~((1<<4) | (1<<2));
1 Like

PCINTxx indicano gli interrupt di cambio di stato, non i pin.
Inoltre il PCINT2 è agganciato al pin PB2, non PD2.

Per fare la lettura dello stato del pin 2 fai:

if ((PIND & (1<<PB2)) == 1) { ...
}

Ok alla fine si è giunti dove dicevo io:

erpomata:
Comunque, mi pare di aver capito che è impossibile settare per una stessa porta un pin HIGH e l'altro LOW.
Devono essere 2 operazioni differenti.

Sbaglio?

erpomata:
Ok alla fine si è giunti dove dicevo io:

erpomata:
Comunque, mi pare di aver capito che è impossibile settare per una stessa porta un pin HIGH e l'altro LOW.
Devono essere 2 operazioni differenti.

Sbaglio?

Se vogliamo essere pignoli.... se in fallo :stuck_out_tongue:
Perché puoi comporre il byte da passare alla porta PRIMA.

Riprendendo il mio esempio precedente, possiamo fare così:

byte temp = ((1<<3) | (1<<5));
temp &= ~((1<<4) | (1<<2));
PORTD = temp;

Come vedi, con UNA SOLA operazione sulla porta, cambio i bit che mi interessano. :wink:

erpomata:
come faccio a combinare la cosa su pin diversi, mantenendo lo stato degli altri pin della porta e facendo l'operazione contemporaneamente su tutta la porta.

Ma perché non leggi le risposte, che oltretutto sono la soluzione al tuo problema ?

Scomponi le operazioni in 2 righe, una per l'attivazione con OR ed una per la disattivazione con AND.
Esempio:

PORTD |= ((1<<3) | (1<<5));
PORTD &= ~((1<<4) | (1<<2));

secondo me non è che non legge, non ha spiegato cosa vuole di preciso spiegando in modo pratico passo-passo cosa vuole fare, è vero che le istruzioni qui sopra funzionano, ma in alcuni contesti è difficile utilizzarli, non posso sostituire lo 0 e 1 a piacimento, sono costretto a spostare a destra e sinistra i byte, eseguire delle negazioni sui bit, OR e AND, ma non vado diretto ai bit che mi servono e devo fare dei salti sul programma per attivare con |= o &= ~ per disattivare. Se non ho capito male, lui vuole ricostruire il byte e rispedirlo al PORTn Con questo metodo lo può fare ma diventa parecchio laborioso.

Vabbè, sono esempi. Il codice va scritto in base a quel che deve fare.
Vuole leggere da un pin? Ok. Si può fare.
Vuole impostare diversi pin di una stessa porta in modo diverso? Ok. Si può fare.
Poi sta a lui risolvere i problemi in base alle necessità.

Esatto.

@leo
Ma in quel modo sovrascrivo tutto il valore della porta.

@astrobeed
Ho letto il post ma sempre due operazioni sono.

Ricapitolo.

C'è un modo per impostare contemporaneamente 2 o 3 bit di una porta (PORTB/C/D) lasciando invariati tutti gli altri nello stato in cui sono.
Ciao facendo una cosa del genere.

Stato della porta prima 01010101 vorrei che lo stato della porta sia 01010010 cambiando gli ultimi 3 bit lasciando invariati i primi 5 tutti insieme.

  1. ti leggi la porta e depositi il suo valore in una variabile tampone
  2. esegui le modifiche del caso alla variabile tampone
  3. riscrivi la variabile tampone sulla porta.

In questo modo cambi lo stato solo dei bit/pin che ti interessa alterare.

erpomata:
C'è un modo per impostare contemporaneamente 2 o 3 bit di una porta (PORTB/C/D) lasciando invariati tutti gli altri nello stato in cui sono.

No, almeno non con una singola operazione perché prima devi leggere tutti i bit della porta e poi devi applicare una opportuna mascheratura per lasciare invariati quelli che non devi scrivere.
SBI e CBI usano solo due cicli macchina, anche se ne usi otto in fila in totale fanno 16 cicli macchina che è sempre meno di quelli che dovresti usare con qualunque altro sistema, rammento che CBI e SBI sono istruzioni assemby specifiche per modificare un singolo bit di un registro, meglio di queste non esiste nulla.

astrobeed:

erpomata:
C'è un modo per impostare contemporaneamente 2 o 3 bit di una porta (PORTB/C/D) lasciando invariati tutti gli altri nello stato in cui sono.

No, almeno non con una singola operazione perché prima devi leggere tutti i bit della porta e poi devi applicare una opportuna mascheratura per lasciare invariati quelli che non devi scrivere.
SBI e CBI usano solo due cicli macchina, anche se ne usi otto in fila in totale fanno 16 cicli macchina che è sempre meno di quelli che dovresti usare con qualunque altro sistema, rammento che CBI e SBI sono istruzioni assemby specifiche per modificare un singolo bit di un registro, meglio di queste non esiste nulla.

Perchè, in questo modo non stai settando vari bit con una operazione?
Lo scopo dell'OR è proprio quello di non dover leggere perchè lascia gli altri bit inalterati

PaoloP:
Comunque settando la porta puoi settare più pin contemporaneamente.

PORTD |= B10101000; // sets digital pins 7,5,3 HIGH

Stato della porta prima 01010101 vorrei che lo stato della porta sia 01010010 cambiando gli ultimi 3 bit lasciando invariati i primi 5 tutti insieme.

o conosci il byte da mandare al registro in un unica soluzione
01010101 = 85 in dec
01010010 = 82 in dec

PORTD = 82; ecco il tuo comando in un unico colpo!! In realtà riscrive tutto, ma i restanti 5 bit sono gli stessi di prima

o ricostruisci il byte
bitWrite(PORTD, 0, 0); //bit 0
bitWrite(PORTD, 1, 1); //bit 1
bitWrite(PORTD, 2, 0); //bit 2
gli altri bit 3/4/5/6/7 restano invariati

oppure bitset ....