mikrocontroller.net

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


Autor: Sven S. (schwerminator)
Datum:

Bewertung
0 lesenswert
nicht 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:
IR_LED_ON(); _delay_ms(2.4); IR_LED_OFF(); _delay_ms(0.6);

IR_LED_ON(); _delay_ms(1.2); IR_LED_OFF(); _delay_ms(0.6);
IR_LED_ON(); _delay_ms(1.2); IR_LED_OFF(); _delay_ms(0.6);
IR_LED_ON(); _delay_ms(0.6); IR_LED_OFF(); _delay_ms(0.6);
IR_LED_ON(); _delay_ms(0.6); IR_LED_OFF(); _delay_ms(0.6);
IR_LED_ON(); _delay_ms(1.2); IR_LED_OFF(); _delay_ms(0.6);
IR_LED_ON(); _delay_ms(0.6); IR_LED_OFF(); _delay_ms(0.6);
IR_LED_ON(); _delay_ms(0.6); IR_LED_OFF(); _delay_ms(0.6);

IR_LED_ON(); _delay_ms(1.2); IR_LED_OFF(); _delay_ms(0.6);
IR_LED_ON(); _delay_ms(0.6); IR_LED_OFF(); _delay_ms(0.6);
IR_LED_ON(); _delay_ms(0.6); IR_LED_OFF(); _delay_ms(0.6);
IR_LED_ON(); _delay_ms(0.6); IR_LED_OFF(); _delay_ms(0.6);
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:
void SIRCS(uint8_t command, uint8_t address){
  float x = 0.0;
  
  for(uint8_t i=0; i<5; i++){
    //Start
    IR_LED_ON();
    _delay_ms(2.4);
    IR_LED_OFF();
    _delay_ms(0.6);
    
    //Command
    for(uint8_t j=0; j<7; j++){
      IR_LED_ON();
      _delay_ms(0.6);
      
      if(command & j){
        _delay_ms(0.6);
        x += 0.6;
      }
      
      IR_LED_OFF();
      _delay_ms(0.6);
    }
    
    //Address
    for(uint8_t j=0; j<5; j++){
      IR_LED_ON();
      _delay_ms(0.6);
      
      if(address & j){
        _delay_ms(0.6);
        x += 0.6;
      }
      
      IR_LED_OFF();
      _delay_ms(0.6);      
    }
    
    _delay_ms(27.6-x);
  }
}

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

Autor: Christian R. (supachris)
Datum:

Bewertung
0 lesenswert
nicht 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:
float x = 0.0;
...
x += 0.6;
Dann wundert es mich nicht, dass die Zeiten nicht passen....

Autor: Sven S. (schwerminator)
Datum:

Bewertung
0 lesenswert
nicht 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...

Autor: Leser (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.:
void warte(uint16_t zeit)
{
  for(; zeit>0; zeit--) _delay_us(100);
}

int main( void )
{
.
.
.
warte(6);
warte(12);
.
.
.
}

oder hier mal nachsehen:

http://www.mikrocontroller.net/articles/AVR-GCC-Tu...

mfg

Autor: T. H. (pumpkin) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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__...

Autor: nixversteh (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Sven S. (schwerminator)
Datum:

Bewertung
0 lesenswert
nicht 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?

Autor: Martin Schneider (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: nixversteh (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.
if(command & (1<<j))

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

Autor: Sven S. (schwerminator)
Datum:

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

Autor: Sven S. (schwerminator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Halli-Hallo,
eine Frage habe ich noch: Ich schalte ja die gepulste IR-LED mit 
folgenden Makros an und aus:
#define IR_LED_ON()  TCCR2 |= (1<<CS20)
#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?

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.