Detect IR: da vicino si, da lontano no..come mai?

Ciao a tutti
se carico sul mio arduino questo sketch preso da internet:

#define IRpin_PIN      PIND
#define IRpin          2
 
// the maximum pulse we'll listen for - 65 milliseconds is a long time
#define MAXPULSE 65000
 
// what our timing resolution should be, larger is better
// as its more 'precise' - but too large and you wont get
// accurate timing
#define RESOLUTION 20 
 
// we will store up to 100 pulse pairs (this is -a lot-)
uint16_t pulses[100][2];  // pair is high and low pulse 
uint8_t currentpulse = 0; // index for pulses we're storing
 
void setup(void) {
  Serial.begin(9600);
  Serial.println("Ready to decode IR!");
}
 
void loop(void) {
  uint16_t highpulse, lowpulse;  // temporary storage timing
  highpulse = lowpulse = 0; // start out with no pulse length
 
 
//  while (digitalRead(IRpin)) { // this is too slow!
    while (IRpin_PIN & (1 << IRpin)) {
     // pin is still HIGH
 
     // count off another few microseconds
     highpulse++;
     delayMicroseconds(RESOLUTION);
 
     // If the pulse is too long, we 'timed out' - either nothing
     // was received or the code is finished, so print what
     // we've grabbed so far, and then reset
     if ((highpulse >= MAXPULSE) && (currentpulse != 0)) {
       printpulses();
       currentpulse=0;
       return;
     }
  }
  // we didn't time out so lets stash the reading
  pulses[currentpulse][0] = highpulse;
 
  // same as above
  while (! (IRpin_PIN & _BV(IRpin))) {
     // pin is still LOW
     lowpulse++;
     delayMicroseconds(RESOLUTION);
     if ((lowpulse >= MAXPULSE)  && (currentpulse != 0)) {
       printpulses();
       currentpulse=0;
       return;
     }
  }
  pulses[currentpulse][1] = lowpulse;
 
  // we read one high-low pulse successfully, continue!
  currentpulse++;
}
 
void printpulses(void) {
  Serial.println("\n\r\n\rReceived: \n\rOFF \tON");
  for (uint8_t i = 0; i < currentpulse; i++) {
    Serial.print(pulses[i][0] * RESOLUTION, DEC);
    Serial.print(" usec, ");
    Serial.print(pulses[i][1] * RESOLUTION, DEC);
    Serial.println(" usec");
  }
 
  // print it in a 'array' format
  Serial.println("int IRsignal[] = {");
  Serial.println("// ON, OFF (in 10's of microseconds)");
  for (uint8_t i = 0; i < currentpulse-1; i++) {
    Serial.print("\t"); // tab
    Serial.print(pulses[i][1] * RESOLUTION / 10, DEC);
    Serial.print(", ");
    Serial.print(pulses[i+1][0] * RESOLUTION / 10, DEC);
    Serial.println(",");
  }
  Serial.print("\t"); // tab
  Serial.print(pulses[currentpulse-1][1] * RESOLUTION / 10, DEC);
  Serial.print(", 0};");
}

e ci collego ovviamente un sensore IR e premo un tasto del telecomando mi escono questi dati:

Received: 
int IRsignal[] = {
// ON, OFF (in 10's of microseconds)
    30, 92,
    26, 110,
    28, 66,
    26, 270,
    26, 122,
    22, 126,
    26, 108,
    26, 82,
    26, 1272,
    26, 94,
    26, 164,
    24, 70,
    28, 68,
    22, 124,
    26, 110,
    26, 68,
    26, 70,
    24, 1498,
    24, 96,
    28, 108,
    22, 72,
    26, 270,
    24, 124,
    22, 126,
    26, 108,
    26, 82,
    28, 1270,
    26, 96,
    24, 270,
    28, 174,
    28, 66,
    26, 122,
    24, 112,
    22, 72,
    26, 68,
    26, 0};

Allora prendo uno sketch e lo adatto in modo che se legge quel treno di impulsi mi dice qualcosa:

#define IRpin_PIN PIND
#define IRpin 2

// the maximum pulse we'll listen for - 65 milliseconds is a long time
#define MAXPULSE 65000

// what our timing resolution should be, larger is better
// as its more 'precise' - but too large and you wont get
// accurate timing
#define RESOLUTION 20

// What percent we will allow in variation to match the same code
#define FUZZINESS 20

// we will store up to 100 pulse pairs (this is -a lot-)
uint16_t pulses[100][2]; // pair is high and low pulse
uint8_t currentpulse = 0; // index for pulses we're storing


int ApplePlaySignal[] = {
       30, 92,
    26, 110,
    28, 66,
    26, 270,
    26, 122,
    22, 126,
    26, 108,
    26, 82,
    26, 1272,
    26, 94,
    26, 164,
    24, 70,
    28, 68,
    22, 124,
    26, 110,
    26, 68,
    26, 70,
    24, 1498,
    24, 96,
    28, 108,
    22, 72,
    26, 270,
    24, 124,
    22, 126,
    26, 108,
    26, 82,
    28, 1270,
    26, 96,
    24, 270,
    28, 174,
    28, 66,
    26, 122,
    24, 112,
    22, 72,
    26, 68,
    26, 0};

//int AppleForwardSignal[] = {};
//int AppleRewindSignal[] = {};

void setup(void) {
  Serial.begin(9600);
  Serial.println("Ready to decode IR!");
}

void loop(void) {
  int numberpulses;
  
  numberpulses = listenForIR();
  
  Serial.print("Heard ");
  Serial.print(numberpulses);
  Serial.println("-pulse long IR signal");
  if (IRcompare(20, ApplePlaySignal)) {
    Serial.println("PLAY");
  }
    
}

boolean IRcompare(int numpulses, int Signal[]) {
  
  for (int i=0; i< numpulses-1; i++) {
    int oncode = pulses[i][1] * RESOLUTION / 10;
    int offcode = pulses[i+1][0] * RESOLUTION / 10;
    
    
    // check to make sure the error is less than FUZZINESS percent
    if ( abs(oncode - Signal[i*2 + 0]) <= (Signal[i*2 + 0] * FUZZINESS / 100)) {
      //Serial.print(" (ok)");
    } else {
      //Serial.print(" (x)");
      // we didn't match perfectly, return a false match
      return false;
    }
    
    /*
Serial.print(" \t"); // tab
Serial.print(offcode); // the OFF signal we heard
Serial.print(" - ");
Serial.print(Signal[i*2 + 1]); // the OFF signal we want
*/
    
    if ( abs(offcode - Signal[i*2 + 1]) <= (Signal[i*2 + 1] * FUZZINESS / 100)) {
      //Serial.print(" (ok)");
    } else {
      //Serial.print(" (x)");
      // we didn't match perfectly, return a false match
      return false;
    }
    
    //Serial.println();
  }
  // Everything matched!
  return true;
}

int listenForIR(void) {
  currentpulse = 0;
  
  while (1) {
    uint16_t highpulse, lowpulse; // temporary storage timing
    highpulse = lowpulse = 0; // start out with no pulse length
  
// while (digitalRead(IRpin)) { // this is too slow!
    while (IRpin_PIN & (1 << IRpin)) {
       // pin is still HIGH

       // count off another few microseconds
       highpulse++;
       delayMicroseconds(RESOLUTION);

       // If the pulse is too long, we 'timed out' - either nothing
       // was received or the code is finished, so print what
       // we've grabbed so far, and then reset
       if ((highpulse >= MAXPULSE) && (currentpulse != 0)) {
         return currentpulse;
       }
    }
    // we didn't time out so lets stash the reading
    pulses[currentpulse][0] = highpulse;
  
    // same as above
    while (! (IRpin_PIN & _BV(IRpin))) {
       // pin is still LOW
       lowpulse++;
       delayMicroseconds(RESOLUTION);
       if ((lowpulse >= MAXPULSE) && (currentpulse != 0)) {
         return currentpulse;
       }
    }
    pulses[currentpulse][1] = lowpulse;

    // we read one high-low pulse successfully, continue!
    currentpulse++;
  }
}

void printpulses(void) {
  Serial.println("\n\r\n\rReceived: \n\rOFF \tON");
  for (uint8_t i = 0; i < currentpulse; i++) {
    Serial.print(pulses[i][0] * RESOLUTION, DEC);
    Serial.print(" usec, ");
    Serial.print(pulses[i][1] * RESOLUTION, DEC);
    Serial.println(" usec");
  }
  
  // print it in a 'array' format
  Serial.println("int IRsignal[] = {");
  Serial.println("// ON, OFF (in 10's of microseconds)");
  for (uint8_t i = 0; i < currentpulse-1; i++) {
    Serial.print("\t"); // tab
    Serial.print(pulses[i][1] * RESOLUTION / 10, DEC);
    Serial.print(", ");
    Serial.print(pulses[i+1][0] * RESOLUTION / 10, DEC);
    Serial.println(",");
  }
  Serial.print("\t"); // tab
  Serial.print(pulses[currentpulse-1][1] * RESOLUTION / 10, DEC);
  Serial.print(", 0};");
}

E sembra funzionare, se punto il telecomando a circa un metro di distanza. Il problema nasce quando allontano il telecomando di qualche metro, non legge piu niente e i dati in entrata sono questi:

Received: 

int IRsignal[] = {
// ON, OFF (in 10's of microseconds)
    28, 96,
    22, 112,
    22, 70,
    24, 272,
    28, 122,
    24, 124,
    24, 110,
    24, 84,
    24, 1272,
    26, 98,
    20, 166,
    26, 68,
    26, 70,
    24, 124,
    22, 114,
    24, 68,
    26, 72,
    24, 1496,
    24, 96,
    26, 110,
    26, 68,
    26, 270,
    24, 124,
    26, 122,
    26, 108,
    26, 82,
    26, 1272,
    24, 98,
    24, 270,
    26, 176,
    24, 70,
    26, 122,
    26, 110,
    26, 68,
    26, 68,
    26, 0};

quindi si discostano di poco...mi aiutate a sistemare l'ultimo sketch per far si che anche se i dati si discostano di poco li legge lo stesso come quel determinato tasto? (nel mio caso si tratta di telecomando MYSKY, tasto BLU).

Grazie mille!!!

Se da 1-2 mt il treno di impulsi arriva correttamente sempre e da 4 metri no, questo no è un problema di programma, semplicemente il segnale è debole. Va rivista secondo me l'elettronica e la modulazione del segnale, anche una luce solare o una lampada 50hz può introdurre molto rumore. Il fatto che discosta anche di poco, vuol dire che non arriva più corretto.

però il telecomando 'comanda' perfettamente il decoder di Sky anche a 5-6 metri... cosa devo correggere?

smartgatto:
'comanda' perfettamente il decoder di Sky anche a 5-6 metri... cosa devo correggere?

E' un problema puramente hardware, devi rivedere la parte ricevente.

al momento la parte hardware è composta semplicemente da un ricevitore ir tipo tsop e qualcosa collegato al pin 2 per la ricezione dei dati e collegato al pin 5 volts e negativo dell'Arduino.... non saprei però come migliorare....

smartgatto:
al momento la parte hardware è composta semplicemente da un ricevitore ir tipo tsop e qualcosa collegato al pin 2 per la ricezione dei dati e collegato al pin 5 volts e negativo dell'Arduino.... non saprei però come migliorare....

Intanto metti una R da 100 ohm in serie tra 5V ed il pin Vcc del TSOP; sempre tra questo pin e massa metti un C elettrolitico da 100uF (rispettando la polarità, in questo modo stabilizzi notevolmente il funzionamento del TSOP e le cose dovrebbero migliorare parecchio; fai comunque un po' di prove al buio per cercare di capire se qualche fonte luminosa dell'ambiente ti dà problemi.

Intanto grazie per le risposte..appena posso proverò...
posso chiedere come mai la resistenza da 100 ohm?

grazie!

smartgatto:
Intanto grazie per le risposte..appena posso proverò...
posso chiedere come mai la resistenza da 100 ohm?

grazie!

Certo che puoi chiedere :slight_smile:
Serve come limitatore di corrente, comunque questa combinazione R-C la trovi in genere consigliata su tutti i datasheet dei ricevitori della serie TSOP, io l'ho usata con ottimi risultati; non so quale versione hai ma sappi che alcuni modelli vengono dati per 40mt di portata, altro che 5-6! Poi naturalmente interviene la problematica del tx, ma nel tuo caso sta certamente funzionando male il ricevitore, visto che il telecomando a 5-6 mt lavora regolarmente con l'altro apparecchio.

Dunque, sul sensore c'è la sigla V4836, quindi suppongo si tratti (perchè è un pezzo di recupero) di un TSOP4836.
Guardando il datasheet:

dice della resistenza da 100 ohm, però parla di un condensatore da 0.1 microFarad, non da 100..forse intendevi dire 100pF? questo però mi sembra di ricordare che non ha polarità...

in effetti non so perchè se metto come hai detto tu un C da 100uF non mi legge niente..ora cerco di recuperare questo condensatore da 0.1uF e vi so dire..!

smartgatto:
Dunque, sul sensore c'è la sigla V4836, quindi suppongo si tratti (perchè è un pezzo di recupero) di un TSOP4836.
Guardando il datasheet:
TSOP4836 datasheet(1/8 Pages) VISHAY | IR Receiver Modules for Remote Control Systems
dice della resistenza da 100 ohm, però parla di un condensatore da 0.1 microFarad, non da 100..

in effetti non so perchè se metto come hai detto tu un C da 100uF non mi legge niente..ora cerco di recuperare questo condensatore da 0.1uF e vi so dire..!

Dunque, io ho usato un 34838, dove in realtà il C è da 47uF (ricordavo male, scusa), il modello che hai tu è un 36KHz e NON un 38KHz, per cui non vorrei che il tuo ricevitore funzioni male in quanto il tx forse sta lavorando a 38KHz; inoltre mi pare che il datasheet stia dicendo che questo ricevitore arriva a 4-5mt nelle migliori condizioni, usato in accoppiata ad un diodo TSAL6200.

Ok, quasi ci sono...
leggendo su internet ho scoperto che il telecomando di sky ha qualche problema di frequenza, forse opera a 32-36Mhz, per cui ho usato il telecomando per la tv (samsung). E ho partorito, anzi, modificato il solito sketch preso da internet:

#define IRpin_PIN PIND
#define IRpin 2
// the maximum pulse we'll listen for - 65 milliseconds is a long time
#define MAXPULSE 65000
// what our timing resolution should be, larger is better
// as its more 'precise' - but too large and you wont get
// accurate timing
#define RESOLUTION 20
// What percent we will allow in variation to match the same code
#define FUZZINESS 20
// we will store up to 100 pulse pairs (this is -a lot-)
//uint16_t pulses[100][2]; // pair is high and low pulse
uint16_t pulses[100][2]; // pair is high and low pulse
uint8_t currentpulse = 0; // index for pulses we're storing

int SegnaleTV[] = {
       450, 428,
    66, 152,
    66, 152,
    62, 156,
    62, 48,
    64, 44,
    66, 44,
    64, 44,
    66, 44,
    64, 154,
    62, 156,
    62, 156,
    62, 46,
    62, 48,
    62, 46,
    64, 46,
    64, 44,
    64, 154,
    62, 46,
    64, 46,
    62, 46,
    64, 156,
    60, 48,
    62, 48,
    60, 48,
    62, 46,
    66, 154,
    62, 154,
    64, 156,
    62, 46,
    62, 156,
    62, 156,
    62, 156,
    62, 4560};

void setup(void) {
  Serial.begin(9600);
  Serial.println("Pronti!");
  pinMode(13, OUTPUT); 
}

void loop(void) {
  int numberpulses;
  
  numberpulses = listenForIR();
  
  Serial.print("Impulso lungo ");
  Serial.print(numberpulses);
  Serial.println("-bit recepito");
  if (IRcompare(numberpulses, SegnaleTV)) {
    Serial.println("Tasto prescelto premuto!");
    digitalWrite(13, HIGH);   
    delay(5000);              
    digitalWrite(13, LOW);    
   
  }
    
}

boolean IRcompare(int numpulses, int Signal[]) {
  
  for (int i=0; i< numpulses-1; i++) {
    int oncode = pulses[i][1] * RESOLUTION / 10;
    int offcode = pulses[i+1][0] * RESOLUTION / 10;
    if ( abs(oncode - Signal[i*2 + 0]) <= (Signal[i*2 + 0] * FUZZINESS / 100)) {
    } else {
    return false;
    }
    
    if ( abs(offcode - Signal[i*2 + 1]) <= (Signal[i*2 + 1] * FUZZINESS / 100)) {
    } else {
      return false;
    }
  }
  return true;
}

int listenForIR(void) {
  currentpulse = 0;
  
  while (1) {
    uint16_t highpulse, lowpulse; // temporary storage timing
    highpulse = lowpulse = 0; // start out with no pulse length
  
    while (IRpin_PIN & (1 << IRpin)) {
       highpulse++;
       delayMicroseconds(RESOLUTION);

       if ((highpulse >= MAXPULSE) && (currentpulse != 0)) {
         return currentpulse;
         
       }
    }
    pulses[currentpulse][0] = highpulse;
  
    while (! (IRpin_PIN & _BV(IRpin))) {
       
       lowpulse++;
       delayMicroseconds(RESOLUTION);
       if ((lowpulse >= MAXPULSE) && (currentpulse != 0)) {
         return currentpulse;
       }
    }
    pulses[currentpulse][1] = lowpulse;
    currentpulse++;
  }
}

Ora appena premo il tasto da me scelto (il tasto ZERO) sul telecomando, arduino lo intercetta e se corrisponde alla sequenza desiderata (ovvero 0x8877) accende il led posto sul pin 13 per 5 secondi e poi si spegne.
Con questo sketch ora funziona, anche da distanza tipo 4-5 metri.
Il problema che devo risolvere è che il tasto zero lo devo premere per un tempo più o meno preciso, perchè se premuto troppo poco o per troppo tempo arduino non lo interpreta correttamente e allora non fa niente. Il treno di impulsi è lungo 34 bit, ripetuto due volte, ma non riesco a capire come modificare lo sketch per dirgli di interpretare solo i primi 34 bit e gli altri lasciarli perdere...
potete aiutarmi?

grazie!!

è un problema che ho riscontrato anch'io.

il microcontrollore, a quanto ho capito, esegue sempre e solo il solito loop.

bisogna far coincidere l'invio del segnale con l'istruzione di ricezione del segnale (in base al codice la frequenza varia) a causa di funzioni e sopratutto delay.

smartgatto:
Ok, quasi ci sono...
leggendo su internet ho scoperto che il telecomando di sky ha qualche problema di frequenza, forse opera a 32-36Mhz, per cui ho usato il telecomando per la tv (samsung). E ho partorito, anzi, modificato il solito sketch preso da internet:

Ascolta, il tuo ricevitore è SICURAMENTE a 36KHz, quindi forse il telec sky sarà a 32KHz, certamente NON a 32-36, QUASI CERTAMENTE quello Samsung è a 36KHz ecco perché ora raggiungi la distanza prevista. SUlla parte software non riesco ad aiutarti, però cerca sul Forum, questo sistema è stato usato e spiegato svariate volt, trovi certamente la soluzione che cerchi, non stare sempre lì ad aspettare la manna... :wink:

Non é piú semplice usare la libreria Testing the Arduino IR remote library che ti trasforma il segnale che arriva dal ricevitore in un numero?
Ciao Uwe

uwefed:
Non é piú semplice usare la libreria Testing the Arduino IR remote library che ti trasforma il segnale che arriva dal ricevitore in un numero?
Ciao Uwe

Ciao Uwe, il problema è che essendo un tv samsung non utilizza nè protocollo Sony, nè il NEC nè gli altri noti, percui i dati vengono letti come RAW..e quindi non saprei come farglieli interpretare..

ciao,

per decodificare codici SAMSUNG ho impiegato anche io l'ottima libreria di Ken Shirriff, opportunamente modificata. Samsung utilizza una codifica molto simile a quella NEC, ma con un header differente. Per quel poco che so, Samsung utilizza codici a 56bit.

Concordo che, se il circuito funziona solo da vicino, si tratta probabilmente di problemi hardware. Nella mia modestissima esperienza ho notato che un condensatore da 100uF stabilizza notevolmente, annullando il "rumore" del sensore. Ho decodificato con successo telecomandi Philips (RC6), Nilox (NEC), Sony, Samsung e Panasonic anche per dispositivi recenti (TV LCD) solo dopo aver aggiunto resistenze e condensatore come suggerito.