Pages: [1] 2   Go Down
Author Topic: Intercettare change di tutti i PORT PinChangeInt  (Read 954 times)
0 Members and 1 Guest are viewing this topic.
Genova
Offline Offline
Faraday Member
**
Karma: 38
Posts: 3287
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Mi servirebbe che al al programma venisse attirata la sua attenzione quando un qualsiasi pin subisce un cambio di stato che sia IN o OUT, tutti i pin in pratica dal 3 al 49 (anche se in mezzo 0-1-4-10-13-50-51-52-53 sono riservati al sistema), si potrebbe anche sulle analog, ma non è importante adesso.
Non riesco a farlo con il confronto di 2 matrici una istantanea e una hold poichè i tempi sono molto bassi o si perdono alcuni cambi o se ne registrano troppi.
 
Ho letto un po' di argomenti sugli interrupt, quasi tutti fanno riferimenti alla UNO, priorità alta/media/bassa, tutte le parti lette rimandano al datasheet dell'atmel come se fosse facile leggerlo smiley nel mio caso 2560 http://www.atmel.com/Images/doc2549.pdf

Si possono abilitare gli interrupt su molte porte, PORTD PORTE PORTH PORTK PORTG ma non ho capito se su una parte (forse 20) o su tutte e soprattutto trovo documentazione basata sulle porte già abilitate a farlo di default ad esempio pin 2-3 della UNO

ho provato a interpretare queste lib e questi esempi http://code.google.com/p/arduino-pinchangeint/downloads/list , ma l'argomento è in parte a me sconosciuto.
Qualcuno ha provato a fare qualcosa? può indicarmi come farlo via software, non hardware.

Saluti P.  
« Last Edit: December 11, 2012, 09:32:54 am by pablos » Logged

no comment

Global Moderator
Italy
Offline Offline
Brattain Member
*****
Karma: 325
Posts: 22498
Logic is my way
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

I PCINT li puoi attivare su tutti i pin esterni del microcontrollore.
Una volta attivato un PCINT, ad ogni cambiamento di stato viene attivata la corrispondente ISR.

Le ISR sono però "comuni", nel senso che ogni porta ha il suo registro che controlla tutti gli 8 pin collegati. Se viene sollevato un interrupt su un pin viene chiamata la ISR corrispondente al registro che controlla quella porta. Ad esempio, l'Atmega328 ha 3 registri PCINT da 8 bit ciascuno.
Questo vale per tutti i microcontrollori.

Per l'Arduino c'è questa libreria:
http://playground.arduino.cc/Main/PinChangeInt
http://code.google.com/p/arduino-pinchangeint/downloads/list

Per i Tiny c'è quest'altra.
http://code.google.com/p/arduino-tiny/downloads/list

Se hai bisogno di altre info chiedi pure, che io i PCINT li ho usati diverse volte.
Logged


Selvazzano Dentro - Padova
Offline Offline
Edison Member
*
Karma: 37
Posts: 1315
"Chi sa fa, chi non sa insegna"
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Scusa Leo, ho bisogno di un chiarimento.

Sapevo che sulla MEGA esistono 6 External Interrupt collegati ad altrettanti piedini. Se abilitati, in caso di variazione di stato vengono scatenati gli INT da 0 a 5.

I PCINT, invece, come si attivano?

Logged

Global Moderator
Italy
Offline Offline
Brattain Member
*****
Karma: 325
Posts: 22498
Logic is my way
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Scusa Leo, ho bisogno di un chiarimento.

Sapevo che sulla MEGA esistono 6 External Interrupt collegati ad altrettanti piedini. Se abilitati, in caso di variazione di stato vengono scatenati gli INT da 0 a 5.

I PCINT, invece, come si attivano?


I PCINT sono raggruppati ad 8 per 8. Quindi ogni flag controlla l'attivazione dei PCINT di una intera porta.
Datasheet alla mano (versione del 10/2012), vai al cap. 15 (alla pagina 112) per una breve descrizione poi al capitolo 15.2.5 (dalla pagina 115) e seguenti.
Per attivare un PCINT devi:
1) disattivare gli interrupt globali
2) mettere ad 1 il bit corrispondente al gruppo che ti interessa (PCIE0, PCIE1 o PCIE2) nel registro PCICR
3) usare i 3 registri PCMSK0..2 per scegliere il PCINT da attivare.
4) riattivare gli interrupt globali

Ad esempio, se vuoi attivare il PCINT sul pin 20, devi
1) controllare a che gruppo corrisponde, il PCINT20 è del 3°
2) impostare quindi ad 1 il bit PCIE2 in PCICR
3) impostare ad 1 il bit PCINT del registro PCMSK2
4) aggiungere una ISR per il vettore del 3°gruppo di PCINT: ISR(PCINT2_vect)

Attenzione ad una cosa. Se tu imposti 2 PCINT, entrambi di uno stesso gruppo, quando verrà chiamata la corrispondente ISR tu non saprai a priori qual è stato a sollevare l'interrupt. Quindi se ti servono più di un PCINT conviene usarli di gruppi differenti.
Logged


Genova
Offline Offline
Faraday Member
**
Karma: 38
Posts: 3287
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Grazie Leo, non ti ho risposto ieri perchè il forum era lentissimo.

I link che hai messo sono gli stessi che ho messo io smiley in più avevo letto questo di Lesto che tratta il 328
http://arduino.cc/forum/index.php/topic,36241.0.html

questo di un Cinese per il 2560... ho pensato chissà che per una volta un Italiano copia da un Cinese
http://blog.yahoo.com/_ZGD2MIDSBMSKHSUJW23LXRS2EQ/articles/12989

anche questo dove dice che sono 24 i pin che supportano gli interrupt
http://aeroquad.com/archive/index.php/t-75.html

Forse non si può fare su tutti i gruppi A B C D E F G H K J

ciao
Logged

no comment

0
Offline Offline
Shannon Member
****
Karma: 130
Posts: 10449
:(){:|:&};:
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

pablos segui il mio codice, come noterai sono pochi i registri usati e non ci sono rigiri di librerie esterne, se non per le costanti.

Io credo che i registri siano gli stessi, solo che anzichè fermarsi all'INT2 vanno oltre, in oltre devi fare attenzione che a livello di registri devi vedere la numerazione dei PIN da datasheet, e scordarti di quella arduino. Altro particolare: noterai che intercetterai tutti gli interrupt, per esempio quelli della seriale.. occhio a non fare casini, anche se non dovrebbe esserci nulla che un buon reset non possa sistemare smiley

(accidenti, ero proprio agli inizi! quello dev'essere stato uno dei miei primi post!)
Logged

sei nuovo? non sai da dove partire? leggi qui: http://playground.arduino.cc/Italiano/Newbie

Genova
Offline Offline
Faraday Member
**
Karma: 38
Posts: 3287
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Diciamo che ho trovato un compromesso tra la mia necessità e quello che è possibile fare senza troppe complicazioni, magari utile anche ad altri.

A me non servono interrupt di microsecondi, velocità  importantissima tra 2 interfaccie dati, i miei change sono provocati dalla mano umana tramite pulsanti o l'attivazione di un pin dal programma stesso, quindi ho tempo a sufficienza per intercettare il cambio.

Perchè mi serve sapere quale pin è stato attivato dal programma quando è lui stesso a sapere il numero?
Perchè non esistono dei pin prestabiliti che facciano da IN o da OUT, solo quando viene letta la eeprom si sa e questi possono cambiare in base a una nuova scrittura di un file INI su SD e un restart di arduino.

con questo sketch trovo in modo eccellente quale gruppo PORT A,B,C ecc  subisce un cambio
Code:
//--------------------timer--------------------------------------------------------
unsigned long previousMillis_e = 0;  
unsigned long interval_e = 100;
//---------------------------------------------------------------------------------
byte Port[] = {0,0,0,0,0,0,0,0,0}; //A,B,C,D,E,G,H,J,L  ... valori hold
byte cont; // contatore per pulsante port 32(test)

void setup()
{
  delay(1000);
  Serial.begin(9600);//debug
  pinMode(32, INPUT);
  DDRL = 255;  // set a OUTPUT i pin 42-43-44-45-46-47-48-49
  PORTL = 0;  // metto a LOW i pin 42-43-44-45-46-47-48-49
}

void loop()
{  
  unsigned long currentMillis_e = millis();
  if(currentMillis_e - previousMillis_e > interval_e)
  {  
        previousMillis_e = currentMillis_e;            
 
    if(Port[2] !=  PINC){
    Port[2] =  PINC;
    Serial.println("CHANGE_C 30-31-32-33-34-35-36-37 >> val byte = " + (String)PINC);//debug      
    }
  
    /*if(Port[3] != PIND){
    Serial.println("CHANGE PORT_D 18-19-20-21-38 >> val byte = " + (String)PIND);//debug
    }*/
  
    if(Port[5] !=  PING){
    Port[5] =  PING;
    Serial.println("CHANGE PORT_G 39-40-41-4  >> val byte = " + (String)PING);//debug
    }
  
    if(Port[8] !=  PINL){
    Port[8] =  PINL;  
    Serial.println("CHANGE PORT_L 42-43-44-45-46-47-48-49  >> val byte = " + (String)PINL);//debug
    }  
    
//-----------test con pulsante passo-passo------------------------      
        if (digitalRead(32)) cont++; else cont=0;
    
        if (digitalRead(42) == 0 && cont == 1){      
          PORTL |= (1<<7); cont++;
        }
        
        if (digitalRead(42) == 1 && cont == 1){        
          PORTL &= ~(1<<7); cont++;
        }      
//------------------------------------------------------------------    
 }
}

Il programmino restituisce un byte .... esempio:
pulsante sul pin 32 PORTC
led sul pin 42 bistabile o passo-passo PORTL

risposta del dubug con una pressione e rilascio del pulsante

CHANGE PORT_C 30-31-32-33-34-35-36-37 >> val byte = 32
CHANGE PORT_L 42-43-44-45-46-47-48-49  >> val byte = 128
CHANGE PORT_C 30-31-32-33-34-35-36-37 >> val byte = 0

una seconda pressione e rilascio

CHANGE_C 30-31-32-33-34-35-36-37 >> val byte = 32
CHANGE PORT_L 42-43-44-45-46-47-48-49  >> val byte = 0
CHANGE_C 30-31-32-33-34-35-36-37 >> val byte = 0


Domanda:
Mi piacerebbe sapere da questo byte con un calcolo veloce quale pin ha scatenato l'evento in base a questa tabella

 B|42|43|44|45|46|47|48|49

    0 byte 1  
    1 byte 2
    2 byte 4
    3 byte 8
    4 byte 16
    5 byte 32
    6 byte 64
    7 byte 128

Grazie
Saluti
« Last Edit: December 13, 2012, 05:58:42 am by pablos » Logged

no comment

0
Offline Offline
Shannon Member
****
Karma: 130
Posts: 10449
:(){:|:&};:
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

occio che PINC non sono i pin cambiati ma lo stato attuale dei PINC, devi fare una xor con lo stati precedente per sapere quali pin sono cambiati

forse non ho capito ben la domanda ma
Code:
byte b = PINC; //valori attuali, invece una varibaile di tipo byte e nome "a" contiene il vechio valore di PINC

byte cambiati = b^a; //trobo la "maschera dei pin cambiati", se è cambiato il bit corrispondente è ad 1

int B[] = {42,43,44,45,46,47,48,49};

for (int i=0; i < 8; i++){
  if ( cambio & (1<<(8-i) ) ){ //controllo lo stato del bit in posizione 8-i
     //il pin B[i] è cambiato!
  }else{
     //il pin B[i] è sempre lo stesso!
  }
}
« Last Edit: December 13, 2012, 06:06:21 am by lesto » Logged

sei nuovo? non sai da dove partire? leggi qui: http://playground.arduino.cc/Italiano/Newbie

Genova
Offline Offline
Faraday Member
**
Karma: 38
Posts: 3287
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset


salvo ogni 100 ms il cambiamento nell'array e leggo di conseguenza ogni 100 ms lo stato precedente, il tutto funziona, chiaramente ho un change generico di quel gruppo in questo caso qualsiasi bit del PINL

----- millis() 100ms------
if(Port[8] !=  PINL)
{
    Port[8] =  PINL; 
---------------------------

Logged

no comment

Genova
Offline Offline
Faraday Member
**
Karma: 38
Posts: 3287
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

La domanda era se ottengo in lettura

128 so che il bit 7 è high
129 so che i bit 0 e 7 sono high
24 so che i bit 3 e 4 sono high
ecc ecc

volevo assegnare i numeri dei pin reali senza una complessa elaborazione che fa perdere tempo al loop, hai risposto alla domanda comunque, ora ci do un occhio
Ho molte lacune nella scrittura di programmi con operatori logici  smiley-roll-blue
grazie
 
« Last Edit: December 13, 2012, 06:26:25 am by pablos » Logged

no comment

Global Moderator
Italy
Offline Offline
Brattain Member
*****
Karma: 325
Posts: 22498
Logic is my way
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

In hardware/arduino/variants/standard/pins_arduino.h ci sono delle macro che puoi usare per recuperare il pin di Arduino dato il bit della porta e la porta stessa.
Sono le stesse funzioni usate dalla digitalWrite/Read e dalla analogWrite/Read.

Vedi si ti possono servire
Logged


Genova
Offline Offline
Faraday Member
**
Karma: 38
Posts: 3287
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Ok la libreria a cui ti riferisci e' questa presente anche nell'IDE
http://roboticsclub.org/redmine/projects/quadrotor/repository/revisions/58d82c77908eee0e1c222f7b38691e6532deb77b/entry/arduino-1.0/hardware/arduino/variants/mega/pins_arduino.h

Se non sbaglio vengono memorizzate tramite progmem tutti i riferimenti PORT + lettera in ordine da 0 a 69, fin qui ok, ma come estraggo da qui avendo il byte la giusta posizione dell'array PGM?

grazie
ciao
Logged

no comment

Global Moderator
Italy
Offline Offline
Brattain Member
*****
Karma: 325
Posts: 22498
Logic is my way
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Se esamini il file wiring_digital.c presente nel  core capisci come fare.
Questo è contenuto nella digitalWrite:

Code:
uint8_t bit = digitalPinToBitMask(pin);
uint8_t port = digitalPinToPort(pin);

Passandogli il numero di pin dell'Arduino le 2 funzioni ti restituiscono la porta in "port" ed il corrispondente bit in "bit".
Credo sia quello che ti serve, giusto?
Logged


Genova
Offline Offline
Faraday Member
**
Karma: 38
Posts: 3287
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Mmmm una cosa così ma inverso

Servirebbe un DigitalPortToPin ovvero so che il PORD bit 2 ha subito un cambiamento >>> restituiscimi il num del Pin corrispondente.
Logged

no comment

Global Moderator
Italy
Offline Offline
Brattain Member
*****
Karma: 325
Posts: 22498
Logic is my way
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Leggendo l'array digital_pin_to_port_PGM (è di tipo progmem) puoi sapere il pin in base alla porta e bit.
Ad esempio, PD2 è il pin 2.
Basta che ti ricordi l'ordine: da 0 a 7 sono per PD0..PD7, poi da 8 a 13 sono PB0..PB5 e da 14 a 19 sono per PC0..PC5.
Guarda il file pins_arduino.h, ci sono tutte le funzioni e gli array per le conversioni per ottenere bit e porte. Non so cosa si possa usare.
Logged


Pages: [1] 2   Go Up
Jump to: