Forum: Compiler & IDEs Sonys IR-Code (SIRCS)


von Sven S. (schwerminator)


Lesenswert?

Hallo,
ich bin zur Zeit am Nachbilden des Sony SIRCS-Codes. Ich habe die IR-LED 
mit Timer0 per Hardware gepulst (40kHz). Das Signal erzeuge ich nun 
einfach durch ein- und ausschalten des Timers. Das klappt manuell auch 
wunderbar. Mit manuell meine ich folgendes:
1
IR_LED_ON(); _delay_ms(2.4); IR_LED_OFF(); _delay_ms(0.6);
2
3
IR_LED_ON(); _delay_ms(1.2); IR_LED_OFF(); _delay_ms(0.6);
4
IR_LED_ON(); _delay_ms(1.2); IR_LED_OFF(); _delay_ms(0.6);
5
IR_LED_ON(); _delay_ms(0.6); IR_LED_OFF(); _delay_ms(0.6);
6
IR_LED_ON(); _delay_ms(0.6); IR_LED_OFF(); _delay_ms(0.6);
7
IR_LED_ON(); _delay_ms(1.2); IR_LED_OFF(); _delay_ms(0.6);
8
IR_LED_ON(); _delay_ms(0.6); IR_LED_OFF(); _delay_ms(0.6);
9
IR_LED_ON(); _delay_ms(0.6); IR_LED_OFF(); _delay_ms(0.6);
10
11
IR_LED_ON(); _delay_ms(1.2); IR_LED_OFF(); _delay_ms(0.6);
12
IR_LED_ON(); _delay_ms(0.6); IR_LED_OFF(); _delay_ms(0.6);
13
IR_LED_ON(); _delay_ms(0.6); IR_LED_OFF(); _delay_ms(0.6);
14
IR_LED_ON(); _delay_ms(0.6); IR_LED_OFF(); _delay_ms(0.6);
15
IR_LED_ON(); _delay_ms(0.6); IR_LED_OFF(); _delay_ms(0.6);

Der Fernseher reagierte wie erwünscht mit dem verringern der Lautstärke. 
Der obige Abschnitt wurde mit Timer1 alle 45ms (=22,222Hz) wiederholt. 
Nun gibt es zwei Punkte, die mich zum erstellen einer Funktion bewegt 
haben:
1. Ich will nur einen Timer (0) verwenden
2. Ich möchte einfach Adresse und Kommando an die Funktion übergeben 
können, alles andere macht die Funktion

Hier mal die Funktion:
1
void SIRCS(uint8_t command, uint8_t address){
2
  float x = 0.0;
3
  
4
  for(uint8_t i=0; i<5; i++){
5
    //Start
6
    IR_LED_ON();
7
    _delay_ms(2.4);
8
    IR_LED_OFF();
9
    _delay_ms(0.6);
10
    
11
    //Command
12
    for(uint8_t j=0; j<7; j++){
13
      IR_LED_ON();
14
      _delay_ms(0.6);
15
      
16
      if(command & j){
17
        _delay_ms(0.6);
18
        x += 0.6;
19
      }
20
      
21
      IR_LED_OFF();
22
      _delay_ms(0.6);
23
    }
24
    
25
    //Address
26
    for(uint8_t j=0; j<5; j++){
27
      IR_LED_ON();
28
      _delay_ms(0.6);
29
      
30
      if(address & j){
31
        _delay_ms(0.6);
32
        x += 0.6;
33
      }
34
      
35
      IR_LED_OFF();
36
      _delay_ms(0.6);      
37
    }
38
    
39
    _delay_ms(27.6-x);
40
  }
41
}

Hier eine kleine Funktionsbeschreibng:
Da der Code je nach Anzahl der 0en und 1en unterschiedlich lang ist, 
wird die 45ms Wiederholzeit mit der Variable x dynamisch errechnet.
Die erste for-Schleife wiederholt den Code 5mal. In ihr wird erst der 
Startblock gesendet, dann das Kommando und die Adresse. Unsicher bin ich 
mir bei den Abschnitten "if(command & j)" bzw. "if(address & j)", kann 
man so überprüfen, ob das j'te Bit gesetzt ist? Naja der Rest sollte 
klar sein. Mein Problem ist jetzt, dass das Ganze nicht funktioniert. 
Kann es sein, dass durch die ifs und fors das Timing durcheinander 
gerät? Wo könnte noch der Fehler liegen?

Hier die Infos über das Protokoll: 
http://www.sbprojects.com/knowledge/ir/sirc.htm

Ich hoffe ihr könnt mir weiterhelfen. mfG, Sven

von Christian R. (supachris)


Lesenswert?

Wieso machst du das nicht komplett mit einem Timer? Dann stimmen die 
Zeiten auch. Und wenn ich in einer zeitkritischen Funktion auf einem 
8-Bit Controller folgendes lese:
1
float x = 0.0;
2
...
3
x += 0.6;
Dann wundert es mich nicht, dass die Zeiten nicht passen....

von Sven S. (schwerminator)


Lesenswert?

Hallo Christian,
wie viele CPU-Takte brauchen denn diese Fließkommaoperationen?

Wenn ich das ganze mit nur einem Timer machen wollte, müsste dieser ja 
mit 40kHz aufgerufen werden. In jeder ISR müsste dann überprüft werden, 
ob bereits 600µs vergangen sind, usw. Ich stelle mir das Ganze 
wesentlich komplizierter vor...

von Leser (Gast)


Lesenswert?

Hi,

selbst wenn du es mit der Delayfunktion machen möchtest, dann sollte das 
auch ohne weiteres ohne Float klappen. Musst halt das Delay ein wenig 
anders aufrufen

bsp.:
1
void warte(uint16_t zeit)
2
{
3
  for(; zeit>0; zeit--) _delay_us(100);
4
}
5
6
int main( void )
7
{
8
.
9
.
10
.
11
warte(6);
12
warte(12);
13
.
14
.
15
.
16
}

oder hier mal nachsehen:

http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial#avr-libc_Versionen_kleiner_1.6

mfg

von T. H. (pumpkin) Benutzerseite


Lesenswert?

"In order for these functions to work as intended, compiler 
optimizations must be enabled, and the delay time must be an expression 
that is a known constant at compile-time. If these requirements are not 
met, the resulting delay will be much longer (and basically 
unpredictable), and applications that otherwise do not use 
floating-point calculations will experience severe code bloat by the 
floating-point library routines linked into the application."

  http://www.nongnu.org/avr-libc/user-manual/group__util__delay.html

von nixversteh (Gast)


Lesenswert?

Das zum einen.
Falls Du das weiterhin mit Delay-Loops machen willst (ich würde 'nen 
Timer incl. Interrupt nehmen), dann  würde ich anstatt _delay_ms(0.6) 
eher _delay_us(600) schreiben.

von Sven S. (schwerminator)


Lesenswert?

Hallo, ich habe versucht eure Tips umzusetzen. Es läuft allerdings 
immernoch nicht. Ich verschwende wahrscheinlich zu viel Zeit mit den 
if-Abfragen usw. Mir wird wohl nichts anderes übrig bleiben, als das 
alles mit Timern zu lösen. Habt ihr einen Ansatz, wie man das mit nur 
einem Timer lösen könnte?

von Martin Schneider (Gast)


Lesenswert?

Die Bit-Abfrage (falls das eine ist)

      if(command & j){

funktioniert so nicht, Du müßtest schon sowas schreiben:

      if(command & (1<<j)){


Ahoi, Martin

von nixversteh (Gast)


Lesenswert?

> Unsicher bin ich
> mir bei den Abschnitten "if(command & j)" bzw. "if(address & j)", kann
> man so überprüfen, ob das j'te Bit gesetzt ist?
Nein. Besser so.
1
if(command & (1<<j))

Oder das ganze evtl. so.
1
for(uint8_t j=1; j<=(1<<5); j<<=1){
2
  ...blabla...
3
  if(command & j){
4
  ...

von Sven S. (schwerminator)


Lesenswert?

Moin Martin,
dein Tip war Gold wert! Danke, welch ein dämlicher Fehler ;)

von Sven S. (schwerminator)


Lesenswert?

Halli-Hallo,
eine Frage habe ich noch: Ich schalte ja die gepulste IR-LED mit 
folgenden Makros an und aus:
1
#define IR_LED_ON()  TCCR2 |= (1<<CS20)
2
#define IR_LED_OFF()  TCCR2 &= ~(1<<CS20)

Das klappt auch wunderbar, aber bei "ausgeschalteter" IR-LED ist das 
Potential dennoch HIGH am OC2-Pin. Das bedeutet, dass die IR-LED 
ungepulst leuchtet. Das beeinträchtigt die Funktion zwar nicht, aber da 
ich die IR-LED später mit wesentlich höherem Strom betreiben werde, wird 
diese das nicht ungepulst vertragen. Wie muss ich also meine Makros 
modifizieren, damit das Potential bei ausgeschalteter IR-LED LOW ist?

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.