mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik IR NEC Protokoll einlesen


Autor: Michael (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo zusammen.

Ich bastle schon lange an einer Routine zum einlesen von NEC IR 
Protokoll.

Verwendet wird ein TSOP1738 entsprechend entstört direkt am INT1 eingang 
eines Atmega8. (Signal invertiert).

Nun zu meinem Problem.

Via dem Interrupt INT1 wird auf die entsprechenden Flanken getriggert 
(ISR).

Immer nach einer steigenden Flanke deaktiviere ich den Interrupt Int1 
und aktiviere den Interrupt Zählerüberlauf vom Zähler 2. Der läuft nach 
814us ab und tastet mir das Signal am Eingang INT1 ab. Nach Abtastung 
deaktiviere ich den Interrupt Zählerüberlauf lösche das Flag vom Int1 
und aktiviere den Interrupt INT1 wieder und warte auf die nächste 
Flanke.

Den Sync erkenne ich.

Aber die Bit's kann ich nicht einlesen. Bzw. immer ein HIGH am Eingang.

Zeiten:
Interrupt steigende Flanke bis Zählerüberlauf aktiviert 13us
Bis Abtastung 814us
Abtastung und Interrupt flanke aktiviert 18us


Sonst habe ich alle sonstigen Interrupts deaktiviert. (UART,Timer1)

Anbei der Code:

SIGNAL (SIG_INTERRUPT1) //Interruptroutine Interrupt1
{

if(IR_sperr) //Sperrconter damit Zeit zum auslesen des Codes
{
IR_sperr--;
}

else
{
  GIFR |= 0x80; //Flag rücksetzen

  switch (Sync)
  {

  case 0: //Wenn noch nicht Sync erkannt

  TCNT2 = 0;
  MCUCR |= 0x04;           // on rising edge
  Sync = 1;

  break;

  case 1: //Wenn  Sync erkannt 9ms Puls


      if (((TCNT2 >0x00)) && ((TCNT2 <= 0x08))) //4Tick Toleranz
      //Wenn 16T langer Sync !!!//!Achtung Zähler überläuft funktioiert
      //nur mit 8Bit Zähler 9000us / 34.7us = 258!
      {

      MCUCR &= ~0x04;           // on faling edge
      TCNT2 = 0;
      Sync = 2;
      }
      else
      {
      MCUCR &= ~0x04;           // on faling edge
      Sync = 0;
      shiftreg(0,1); //Lösche Schieberegister
      }
  break;

  case 2: //Wenn 4ms erkannt

      if (((TCNT2 >0x36)) && ((TCNT2 <= 0x44))) //4Tick Toleranz
      //Wenn 4T langer Sync !!!//
      {
      MCUCR |= 0x04;           // on rising  edge
      Sync = 3;
      }
      else
      {
      MCUCR &= ~0x04;           // on faling edge
      Sync = 0;
      shiftreg(0,1); //Lösche Schieberegister
      }
  break;

  case 3: //Im Decodiermodus

      if(!(MCUCR & 0x04))//Wenn  falling  Edge
      {
      MCUCR |= 0x04;           // on rising  edge
      }
      else
      {
      TCNT2 = -24; // in 840us ein Zählerüberlauf
      TIMSK |= 0x40; //Setze Timer Overflow Interrupt
      GICR &= ~0x80;           // ext. Int1 disable
      }




  break;
  }

}
GIFR |= 0x80; //Flag rücksetzen
}
*********************************************************************
SIGNAL (SIG_OVERFLOW2) //Interruptroutine Zählerüberlauf
{
static unsigned char In_Port,stat;

In_Port = IR_PP1; //Lese Wert von Port ein



  if(In_Port == 1) //Wenn Input High
  {
    //Setze Bit auf 1




    TIMSK &= ~0x40; //Lösche Timer Overflow Interrupt
    GICR |= 0x80;           // ext. Int1 enable
    MCUCR &= ~0x04;           // on falling edge



  }
  else
  {
    //Setze Bit auf 0



    TIMSK &= ~0x40; //Lösche Timer Overflow Interrupt
    GICR |= 0x80;           // ext. Int1 enable
    MCUCR |= 0x04;           // on rising edge

  }


  stat = shiftreg(In_Port,0);

  if(stat == 1 ||stat == 2  )
  {

    Sync = 0;
  shiftreg(0,1); //Lösche Schieberegister
    MCUCR &= ~0x04;           // on faling edge
  GICR |= 0x80;           // ext. Int1 enable
  }




GIFR  |= 0x80;           // clear Int0-Flag
}

****************************************************
in .h File

#define IR_PP1  ((PIND & 0x8) >> 3)

********************************************************
//Init des Zählers bzw. vorteiler

TCCR2 = 0x06;           // 0x6 == 1/256 Timer2 auf 28.8kHz --> 34.7us ( 
bei 7.3728Mhz Osz.)
*************************************************************


Was mache ich falsch?

Danke im voraus

Grüsse Michael

Autor: hans (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Michael,

schau mal hier:

http://www.sbprojects.com/projects/ircontrol/picir/nec.htm

Zwar mit Pic aber leicht übertragbar.
gruß Hans

Autor: Michael (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Danke Hans

Diesen Link habe ich auch gefunden. Anhand von diesem und anderen Links 
habe ich die Routine geschrieben.

Habe auch schon mit dem AVR Smulator einen ganzen Durchgang 
durchgespielt, also eigentlich sollte es klappen.


Mein Problem liegt vermutlich dort das die Interruptrutine nicht das 
macht was sie soll, oder ein  Fehler beim Porteinlesen.  Also vermutlich 
ein AVR Problem.

Gruss Michael

Autor: Argh (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Vielleicht ist NEC so nett, dir den Programmcode zu überlassen?

http://www.necel.com/en/faq/mi_com/__com_remo.html

Autor: Michael (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo zusammen

Bin mir sicher es ist ein Timingproblem oder ein Problem beim enlesen 
des Port's. Denn ich lese immer High ein

Ist es überhaupt möglich den externen Interrupt sowohl als 
Flankentrigger wie auch als Eingangsport zu nuzen?

Mache ich beim Einlesen einen Fehler?

In_Port = IR_PP1; //Lese Wert von Port ein

#define IR_PP1  ((PIND & 0x8) >> 3)


Gruss und Dank

Michael

Autor: Sebastian Heyn (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Viel zu kompliziert. FÜr die kurze zeit, in der das IR-Signal empfangen 
wird habe ich eine komplett interruptfreie Lösung. Das spart das ganze 
hin-und her konfigurieren des Interrupts. Ein Timer lasse ich mit 8khz 
laufen, und vergleiche dann die vergangene Zeit mit meinen 
Preset-Werten. Läuft sehr stabil.
Habe noch eine art überlauf mit eingebaut, das heisst, falls mal mist 
empfangen wird, und die Übertragung mittendrin aufhört, kann ich sicher 
sein, dass die Routine zuende geführt wird. (die bytes sind dann=ff)

Nimm mal ein Scope und schau dir an, was der TSOP rausgibt, die machen 
manchmal mist, wenn Energiesparlampen oder Sonnenlicht einfallen.

Autor: koohbraa (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Sebastian,
wenn du bereits eine funktionierende Lösung hast, kannst du uns dann 
evtl. den Source zur Vefügung stellen???

MfG

Autor: Sebastian Heyn (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Mein Tip: erstmal ohne interrupts etc, dann kannst du immernoch schauen 
wie du es abänderst

Ist aber Bascom:

der timer ist eingestellt auf 8khz und macht folgendes:

Timer_irq:
Timer0 = Timervorgabe
Incr Count
Return


Do
Loop Until I = 1                                            'normzustand

'Disable Timer0

O1 = 1
Ena = 0

Do
'hier mache ich nen Powerdown oder ähnliches, solange bis ein signal vom 
tsop kommt
Loop Until I = 0

Count = 0

Enable Timer0
Do
Loop Until I = 1
Disable Timer0

If Count > 60 Then

Count = 0
Enable Timer0
Do
Loop Until I = 0 Or Count > 40
Disable Timer0

Byte1 = 0
Byte2 = 0
Byte3 = 0
Byte4 = 0

'byte 1 wird eingelesen
For B = 0 To 7
Count = 0
Do
Loop Until I = 1

Enable Timer0
O1 = 1
Do
Loop Until I = 0 Or Count > 40
Disable Timer0

If Count > 40 Then
byte1=255
Else
If Count > 7 Then Byte1.b = 1
Next

.
.
.
.
.

Autor: hans (Gast)
Datum:
Angehängte Dateien:

Bewertung
1 lesenswert
nicht lesenswert
Hallo Michael,

hier aus einem Projekt rausgeschnitten mein Code.
Wenn Daten empfangen ist ir_daten gesetzt, bei Repeat zusätzlich
ir_repeat.
Läuft mit Int1 und Timer0 (Timer 1 und 2 waren belegt).
Die Daten sind in der Union irdaten als long oder Byteweise
verfügbar.
Einige Einstellungen liegen an restlichen Programmteilen ;).

Gruß Hans

Autor: Michael (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Danke euch beiden.

Habe den Fehler mittlerweile gefunden.

Saublöd sag ich nur.

Hatte nicht daran gedacht das der Zähler ja schon lösläuft und einen 
Overflow INT Flag setzt. Sobald ich den interrupt enable schalte wird 
der Interrupt ausgeführt. Deswegen las er immer eine 1 ein.

Das findet man aber mit dem Simulator erst raus wenn mann den Simulator 
ein bisschen laufen lässt bevor man simuliert.

Na Ja, viel gelernt!

Grüsse Michael

Autor: Seb (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi hans,

unter welcher Lizenz steht dein Code (nec_x.c)?

Ich würde ihn gerne grob modifiziert in ein GPL-Projekt packen, "Public 
Domain" (soweit es das in Deutschland denn gibt) oder GPL wäre gut.

Gruß
Seb

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.