Forum: Mikrocontroller und Digitale Elektronik IR NEC Protokoll einlesen


von Michael (Gast)


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

von hans (Gast)


Lesenswert?

Hallo Michael,

schau mal hier:

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

Zwar mit Pic aber leicht übertragbar.
gruß Hans

von Michael (Gast)


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

von Argh (Gast)


Lesenswert?

Vielleicht ist NEC so nett, dir den Programmcode zu überlassen?

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

von Michael (Gast)


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

von Sebastian Heyn (Gast)


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.

von koohbraa (Gast)


Lesenswert?

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

MfG

von Sebastian Heyn (Gast)


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

.
.
.
.
.

von hans (Gast)


Angehängte Dateien:

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

von Michael (Gast)


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

von Seb (Gast)


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

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.