Forum: Mikrocontroller und Digitale Elektronik IRMP reagiert langsam


von DerSchatten (Gast)


Angehängte Dateien:

Lesenswert?

Ich habe auf einer Logitech Harmony Touch die Funktionen eines SONY 
K770ES Kassettendecks programmiert.

Das Deck nutzt das Sony SIRCS Protokoll.

Damit wollte ich nun ein Nakamichi Dragon Kassettendeck steuern das nur 
eine Kabelgebundene Fernbedienung zulässt.

Dazu habe ich mir folgendes Programm geschrieben:
1
/* IR Receiver:  TSOP34836            
2
CPU: ATtiny44A-PU @ 8 MHz internal RC        
3
Fuses: l:0xE2 h:0xDB e:0xFF
4
*/
5
6
#include "irmp.h"
7
#include <util/delay.h>
8
#include "avr/eeprom.h"
9
10
#define LED_PORT     PORTB
11
#define LED_DDR      DDRB
12
13
#define OUT_PORT     PORTA
14
#define OUT_DDR      DDRA
15
#define OUT_PIN1      0
16
#define OUT_PIN2     1
17
#define OUT_PIN3      2
18
#define OUT_PIN4     3
19
20
// Schaltmuster
21
// -----------------------------------------------------------------------
22
#define ALL_HI      0xFF
23
#define ALL_LOW      0x00
24
#define LED      0x02
25
26
// Ausgabe
27
// -----------------------------------------------------------------------
28
#define REW      0x01
29
#define REC      0x02
30
#define FREW      0x04
31
#define FFORW      0x08
32
#define FORW      0x10
33
#define PAUSE      0x20
34
#define STOP      0x40
35
36
// EEPROM Variablen definieren
37
// -----------------------------------------------------------------------
38
uint16_t eeprom_speicherstelle EEMEM = 1;
39
uint16_t ir_command;
40
41
void timer_init(void)
42
{
43
  OCR1A = (F_CPU / F_INTERRUPTS) - 1;              // Vergleichswert: 1/15000 der CPU-Frequenz
44
  TCCR1B = (1 << WGM12) | (1 << CS10);            // schalte CTC-Modus ein, setze Vorteiler auf 1
45
  TIMSK1 = 1 << OCIE1A;                    // OCIE1A: Interrupt mittels Timer-Vergleich
46
}
47
48
ISR(TIM1_COMPA_vect)                      // Timer1 aufruf alle 1/15000 sek
49
{
50
  (void) irmp_ISR();                      // irmp ISR aufrufen
51
}
52
53
void led_callback(uint8_t on)
54
{
55
  if(on)
56
  {
57
    LED_PORT |= (LED);
58
  }
59
  else
60
  {
61
    LED_PORT = ALL_LOW;
62
  }
63
}
64
65
void ioinit()
66
{
67
  OUT_DDR = ALL_HI;                      // SCHALTER = Ausgang
68
  OUT_PORT = ALL_LOW;                      // EINSCHALT-ZUSTAND
69
70
  #if IRMP_USE_CALLBACK == 1
71
    LED_DDR |= (LED);                    // SignalLED = Ausgang
72
    LED_PORT = ALL_LOW;                    // EINSCHALT-ZUSTAND
73
    irmp_set_callback_ptr (led_callback);          // Aktivität anzeigen
74
  #endif
75
}
76
77
int main(void)
78
{
79
  IRMP_DATA irmp_data;
80
81
  ioinit();                          // Ein/Ausgänge initialisieren
82
  irmp_init();                        // IRMP initialisieren
83
  timer_init();                        // Timer initialisieren
84
85
  sei ();                            // Interrupts aktivieren
86
87
  for (;;)
88
  {
89
    if (irmp_get_data (&irmp_data) && (irmp_data.protocol == IRMP_SIRCS_PROTOCOL) && (irmp_data.address == 0x0000))
90
    {
91
      // wenn ein IR-Signal erkannt wird, dann...
92
      // irmp_data.protocol ist das protokoll, siehe irmp.h
93
      // irmp_data.address ist die Adresse / Hersteller Code des IR Sender
94
      // irmp_data.command ist der Befehlscode
95
      // irmp_protocol_names[irmp_data.protocol] ist der Protokollname (wenn aktiviert, siehe irmpconfig.h)
96
97
      #if IR_TO_EEPROM == 1                // IR-Code in EEPROM speichern
98
        ir_command = irmp_data.command;
99
        eeprom_write_word(&eeprom_speicherstelle, irmp_data.command);
100
      #endif
101
      
102
      if (irmp_data.flags & IRMP_FLAG_REPETITION)
103
        {
104
        switch (irmp_data.command)
105
        {
106
          case 0x0832: OUT_PORT = FORW;  break;    // Vorlauf
107
          case 0x0837: OUT_PORT = REW;  break;    // Rücklauf
108
          case 0x0834: OUT_PORT = FFORW;  break;    // Vorspulen
109
          case 0x0833: OUT_PORT = FREW;  break;    // Zurückspulen
110
          case 0x0838: OUT_PORT = STOP;  break;    // Stop
111
          case 0x0839: OUT_PORT = PAUSE;  break;    // Pause
112
          case 0x071F: OUT_PORT = REC;  break;    // Aufnahme + Pause
113
        }
114
        _delay_ms(500);
115
        OUT_PORT = ALL_LOW;
116
      }
117
    }
118
  }
119
}

Das ganze reagiert nur etwas träge, sag ich jetzt mal.
Wenn ich nur kurz eine Taste antippe, sehe ich zwar das gesendet wird, 
die Schaltung reagiert jedoch noch nicht.
Erst wenn ich etwas länger auf der Taste bleibe reagiert sie.

Woran könnte das liegen?

von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

DerSchatten schrieb:
> if (irmp_data.flags & IRMP_FLAG_REPETITION)

Lass da mal das Flag weg. Damit wartest du nämlich darauf, das die FB 
bereits den Wiederholungcode sendet und damit wird das erste Kammando 
verschluckt. Ich mach das so:
1
    if (irmp_get_data (&irmp_data))
2
    {
3
    if ((irmp_data.protocol == IRMP_SIRCS_PROTOCOL) && (irmp_data.address == 0x0000)) 
4
      {
5
      switch (irmp_data.command) {
6
     
7
       case    0x0832  :OUT_PORT = FORW; break;
8
// und so weiter.

von Oliver R. (superberti)


Lesenswert?

Hi,

durch die Zeile
1
if (irmp_data.flags & IRMP_FLAG_REPETITION)
2
...

beachtest Du ja auch nur länger gedrückte Kommandos. Das erste erkannte 
IR-Kommando hat immer das Repetition-Flag NICHT gesetzt, erst die 
nachfolgenden bei dauerhaft gedrückter Taste.

Gruß,
Oliver

von DerSchatten (Gast)


Lesenswert?

Spitze! Danke! So geht's schon viel besser.

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

DerSchatten schrieb:
> if (irmp_data.flags & IRMP_FLAG_REPETITION)

Das ist so nicht richtig.

Du meinst hier wohl eher
1
if (! (irmp_data.flags & IRMP_FLAG_REPETITION))

Damit beachtest Du den ersten Frame und ignorierst die 
Wiederholungsframes bei lang gedrückter Taste. So ist das im 
IRMP-Artikel auch dokumentiert ("Entprellen" von Tasten).

Wenn Du die Wiederholungsframes gar nicht ignorieren willst, dann lass 
das if weg und führe das darunter stehende immer aus. Ist hier aber wohl 
nicht nötig, da Du keinen VOLUME-Befehl nutzt, um die Lautstärke zu 
regeln.

>         _delay_ms(500);

Damit bremst Du den µC eine halbe Sekunde. Du setzt den Pin am Port erst 
eine halbe Sekunde nach dem Empfang des IR-Befehls. Und Du wunderst Dich 
dann, dass das Programm "träge" reagiert? Mach das weg. Gerade dann, 
wenn Wiederholungsframes ignoriert werden sollen, ist das unsinnig.

IRMP kannst Du mit dem Delay-Befehl sowieso nicht daran hindern, 
mindestens einen weiteren Frame im Hintergrund einzusammeln. Korrigiere 
das oben stehende if wie oben angegeben und lösche den Delay-Befehl.

: Bearbeitet durch Moderator
von DerSchatten (Gast)


Lesenswert?

ok, das
1
if (! (irmp_data.flags & IRMP_FLAG_REPETITION))

habe ich jetzt wieder rein gepackt.

Das delay soll den Ausgang nach kurzer Zeit wieder auf HI setzen.
Der Ausgang soll ja nur ein mal kurz geschalten werden. Eben wie bei 
einer Fernbedienung.

Gibt's denn da einen anderen Weg?

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

DerSchatten schrieb:
> Das delay soll den Ausgang nach kurzer Zeit wieder auf HI setzen.

Achso, dann habe ich es jetzt kapiert.

> Gibt's denn da einen anderen Weg?

Wenn Dein µC innerhalb dieser halben Sekunde sowieso auf nichts anderes 
reagieren soll, dann ist es okay.

Sonst könntest Du eine Countdown-Variable auf 500 setzen, in der ISR 
herunterzählen und wenn diese auf 0 gelaufen ist, in der Hauptschleife 
den Port wieder resetten. Dann hätte die Hauptschleife während dieser 
500 msec auch noch Zeit für andere Dinge. Ist aber wohl für Deine 
Aufgabenstellung oversized.

Trotzdem solltest Du das im Hinterkopf behalten, wenn Du mal ein 
anspruchsvolleres Projekt angehen möchtest.

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.