Fehlerbehebung bei IR-Emittern mit einem Arduino

Ich versuche schon seit einiger Zeit, ein Arduino dazu zu bringen, das Fernsignal meiner Klimaanlage zu replizieren, und ich gebe fast auf, nur weil diese Aufgabe so nervig ist. Das wichtigste zuerst:

  • Der Arduino, den ich verwende, ist der Mega 2560 , der den Mega2560 AVR-Chip verwendet , und der IR-Empfänger ist der VS1838b (logischer Pegel niedrig).

  • Die IR-Trägerfrequenz beträgt 38 KHz (13 uS-Timerzyklen), und die maximale Geschwindigkeit, mit der ich zuverlässige Messwerte aus dem Arduino erhalten konnte, liegt bei etwa 250 KHz (4 uS-Timerzyklen). IR-Signale werden über die Länge eines durch ein 38-kHz-Trägersignal verfälschten Signals dekodiert, aber der VS1838b gibt nur die Länge des Signals zurück (ohne den 38-kHz-Anteil).

  • Der Mega hat 8192 Byte Speicher, was bedeutet, dass ich sehr effizient sein muss. Seriendrucke kommen nicht in Frage, da sie dem Programm eine erhebliche Verzögerung hinzufügen, die das Lesen beeinträchtigen würde. Ich habe ein Array von Bytes verwendet und die Informationen sequentiell von links nach rechts gespeichert, aber das bedeutet, dass ich maximal 64.000 Samples haben kann.

  • Die IR-LED, die ich verwende, ist voll funktionsfähig, und die Lese-/Schreibgeschwindigkeit von Arduino ist ausreichend, da ich in der Lage war, eine AC-Fernbedienung zu öffnen, ein Kabel an einen der IR-Anschlüsse der Fernbedienung zu löten, es an ein Arduino und ein Relais anzuschließen das Ergebnis zu meiner IR-LED.

  • So wird der Timer konfiguriert:

void setup()
{
//  Serial.begin (115200);
  pinMode(8, INPUT);
  pinMode(4, OUTPUT);

  TCCR1A = B00000000;
  TCCR1B = B00001001; // CTC mode with 1:1 prescaler
  TIMSK1 = B00000010; // Enables Timer 1 A compare interrupt
  OCR1A = 0x003E; // 3E = 4us, 7F = 8us, 9F = 10us, CF = 13us, 19F = 26us
}

Ich dachte, es wäre eine einfache Implementierung. Alles, was ich tun musste, war, das Signal genau so zu kopieren, wie es gelesen wurde (direkt von der AC-Fernbedienung), und es würde gut funktionieren (abgesehen davon, dass es bei der Speicherung ineffizient ist). Ich habe das Signal in 4-US-Zyklen kopiert, etwa so:

ISR (TIMER1_COMPA_vect)
{
  temp = temp << 1;

  if (PINH == 32)
    temp++;

  j++;
  if (j == 8)
  {
    store[k] = temp;
    k++;
    j = 0;
    temp = 0;
  }

  if (k == len)
  {
    k = 0;
    j = 0;
    flag = 1;
    StopTimer();
  }
}

Wobei PINH == 32 der Empfangs-Pin für die AC-Fernbedienung ist (32, weil ich direkt aus dem Register lese). Dann habe ich mit demselben Timer-Interrupt das Signal geschrieben, als es mit dem Lesen fertig war:

ISR (TIMER1_COMPA_vect)
{
  if (k == len)
  {
    StopTimer();
    CLR(5);
    k = 0;
    flag = 1;
  }
  
  if (bitRead(store[k], j) == 1)
  {
    SET(5);
  }
  else
  {
    CLR(5);
  }

  j--;

  if (j == -1)
  {
    k++;
    j = 7;
  }
}

Aber das funktionierte nicht und ich hatte keine Ahnung warum. Ich habe dann versucht, den VS1838b zu verwenden und ihn mit einer festen PWM-Frequenz von 38 kHz über den Timer zu koppeln und den Timer abhängig von den Messwerten des Sensors zu aktivieren / deaktivieren.

  • Zusammenfassung: Arduino liest VS1838b ständig und aktiviert / deaktiviert den Timer je nach Ergebnis. Es hat nicht funktioniert.

Ich dachte mir, dass die PWM-Frequenz vielleicht irgendwie vom Programm beeinflusst wird, also habe ich einen anderen Arduino verwendet, um die PWM-Frequenz zu schreiben, und einen anderen, um den VS1838b zu lesen. Ich habe dann das feste 38-kHz-PWM-Schreiben an die Basis eines TIP41C-Transistors angeschlossen, den Arduino-Steuerstift an den Kollektor.

  • Zusammenfassung: Zwei Arduinos, einer gibt eine PWM-Frequenz von 38 KHz an die Basis eines Transistors aus und der andere gibt das NOT- Ergebnis des VS1838b an den Kollektor aus. Es hat nicht funktioniert.

Ich bin ratlos, was möglicherweise die Ursache sein könnte, ich habe das Timer-Datenblatt doppelt überprüft, ich habe den Timer sogar manuell mit micros() -Funktionen kalibriert, aber nichts scheint zu funktionieren. Gibt es etwas, das ich grundlegend falsch mache?

Bearbeiten: Ich habe die Schaltung vereinfacht und Bilder hochgeladen , wie sie aussieht. Grundsätzlich ist D10 ein Eingang zum VS1838b-Sensor, D6 wird vom Timer verwendet, um eine PWM-Frequenz von 38 KHz zu schreiben, und D3 wird verwendet, um das NOT-Ergebnis des Sensors auszugeben. Der Code sieht so aus:

#define CLR(x) (PORTD&=(~(1<<x)))
#define SET(x) (PORTD|=(1<<x))
#define TOGGLE(x) (PORTD^=(1<<x))

void setup()
{
  Serial.begin(2000000);
  pinMode(10, INPUT);
  pinMode(3, OUTPUT);
  pinMode(6, OUTPUT);
  TCCR1A = B00000000;
  TCCR1B = B00001001;
  TIMSK1 = B00000010;
  OCR1A = 0x00CF; // 3E = 4us, 7F = 8us, 9F = 10us, CF = 13us, 19F = 26us
}

void loop()
{

  if ((PINB && B00000100) == 0)
  {
    SET(3);
  }
  else
  {
    CLR(3);
  }

}

ISR (TIMER1_COMPA_vect)
{
  TOGGLE(6);
}

Und es funktioniert immer noch nicht.

" der Arduino-Steuerstift zum Kollektor." Warum? Schaltplan des Treibers anzeigen
Rb = 1 k vom Ausgang mit Träger UND Daten zur Basis, bei Verwendung von 5 V, IR-LED = 1,3 V bei 100 mA benötigt Rc-Serie = 3,5 V / 0,1 = 35 Ohm
@TonyStewartSunnyskyguyEE75 Nun, es stellte sich heraus, dass ich dachte, der TIP41C sei ein N-Typ-MOSFET und verwendete Pulldown-Widerstände. Wird ein IRFZ44n verwenden und die Ergebnisse aktualisieren. Die anderen Versuche ohne Verwendung eines Transistors sollten jedoch funktioniert haben.
Dennoch scheint ein Schema, wie Sie die Dinge verbinden, für unser Verständnis Ihres Systems sehr notwendig zu sein. Gehen Sie nicht davon aus, dass es nur einen möglichen Weg gibt!
@mmmm Beitrag aktualisiert
Ein Mega2560 verwendet einen Mega2560 AVR, keinen Mega328. IR wurde mit Arduino zu Tode gemacht, also warum das Rad neu erfinden? Verwenden Sie zum Erzeugen des 38-kHz-Trägers den CTC-Modus des Timers. Keine Unterbrechungen erforderlich. Verwenden Sie einen 16-Bit-Timer und Code, um die gewünschte Sequenz auszugeben, indem Sie den Träger-Timer ein- und ausschalten.
@Kartman Aber das habe ich getan, aber mit Unterbrechungen. Ist der Interrupt nicht erforderlich, um den Pin ein- und auszuschalten? Es sei denn, Sie meinen so etwas wie die Verwendung des digitalen Pins, der mit dem Timer-Vergleichsmatch verknüpft ist?

Antworten (2)

IR ist so etwas wie AM-Radio, irgendwie. Sie haben ein Signal und einen Träger, aber ein Rechteckwellen-Ding. Sie und das Signal und der Träger zusammen. Um zu übertragen, müssen Sie dies rückwärts tun. Obwohl ich es an einem Punkt geschafft habe, dies mit einem PIC zu schlagen, gehen Sie davon aus, dass Sie dies nicht können, und stören Sie sich nicht. Sie müssen im Grunde einen Träger (38 kHz) erzeugen und ihn zusammen mit Ihrem Signal, ms-Pulsen oder Bruchteilen davon. Angenommen, dies ist innerhalb einer MCU nicht immer möglich, müssen Sie jede MCU bewerten, um zu sehen, ob sie dies in irgendeiner Weise tun kann.

Bei einigen verwenden Sie den Timer, um ein Signal zu erzeugen (Sie verwenden dies nicht für Interrupts zum Bitbang, Sie erzeugen das Signal selbst), und bei einigen können Sie den Ausgang basierend auf einem anderen Timer oder etwas anderem steuern. Einige STM32 haben speziell einen IR-Timer, der im Wesentlichen ein Gate zwischen zwei Timern ist.

Sie könnten es mit einem PWM schaffen, bei dem Sie manchmal ein Tastverhältnis von 50% und manchmal ein Tastverhältnis von 0% erzeugen, wobei Sie jeweils ein Timing durchführen.

Einige können Sie mit einem SPI-Controller abziehen, indem Sie den Mosi verwenden, der eine Anzahl von 0x55s und andere Werte sendet, um die richtige Anzahl von Taktzyklen und dann die richtige Anzahl von Nullen zu erzeugen, um die Lücken zu erzeugen. Dies ist wahrscheinlich der einfachere Weg, wenn die MCU ein ausreichend tiefes Fifo oder einen Weg zum DMA hat und Sie über genügend Zyklen und / oder Speicher verfügen, um das Fifo / DMA zu füttern.

Oder Sie könnten einfach ein diskretes Gate außerhalb der MCU platzieren ...

Dann speisen Sie dieses Ausgangssignal wie jede andere LED mit einem Widerstand in die IR-LED ein, um die Spannung über der LED zu begrenzen / zu steuern.

Wenn Sie kein Zielfernrohr haben, werden Sie dies äußerst schwierig finden. Möglicherweise müssen Sie alles verlangsamen, indem Sie Ihre Divisoren anpassen und es dann in ein anderes MCU- oder Himbeer-Pi- oder FPGA-Board oder etwas einspeisen, das als selbstgebauter Logikanalysator verwendet wird, um das Timing zu untersuchen. Gute Oszilloskope sind heutzutage sehr preiswert, daher lohnt es sich, einen Vierkanal zu erwerben, wenn Sie weiterhin MCU-Arbeiten durchführen möchten (dies umfasst uart, spi (zwei Datenleitungen), i2c und eine Reihe anderer Dinge) (lernen Sie, wie man liest die Protokolle, verwenden Sie nicht die Software, die versucht, sie für Sie zu lesen, sie scheitern so sehr, wie sie erfolgreich sind, und machen das Leben viel schlimmer, diese Protokolle sind einfach aus den Rohsignalen zu lesen).

sbprojects.net/knowledge/ir/index.php Dies ist meine Anlaufstelle, wenn ich IR-Arbeit mache. Ich benutze es, um herauszufinden, welche IR-Protokolle ich mir mit einer bestimmten Fernbedienung anschaue ... Ein Oszilloskop hilft beim Empfangen, ist aber nicht notwendig, da es viele Jahre lang ohne ein Oszilloskop dekodiert wurde. Aber für die Übertragung macht es einen großen Unterschied.
Unterbrechungen erschweren das Leben Verwenden Sie sie nur bei Bedarf. habe ich bisher nicht benötigt. Ich habe einen Repeater gemacht, der vielleicht Ihrem ähnlich ist, ich hatte einen alten Fernseher (einer der ersten mit Infrarot), der kein Standardprotokoll verwendete (es war älter als die Standardprotokolle). Ich habe einen Decoder-Repeater gemacht, um einen neueren Code in die älteren Codes zu übersetzen, und konnte eine Universalfernbedienung verwenden, hat super funktioniert. Jetzt, wo ich darüber nachdenke, ist es durchaus möglich, dass ich das auch etwas geschlagen habe, aber viel mehr Speicher und Flash hatte als Sie und im Grunde Nops gemacht und/oder in asm in I/O geschrieben habe. wie in Hunderten. heute würde ich ein irtim in einem stm32 verwenden
oder ein Spi-Controller in fast jeder MCU (sehen Sie sich an, wie sie die WS2812B-LEDs mit Spi ähnlich steuern und Spi in einen zeitgesteuerten Signalgenerator verwandeln)

Ich bin mir nicht sicher, was das Problem war, aber meine anfängliche Logik war richtig.

Um es zu beheben, habe ich Mikrocontroller vom Arduino Nano auf den neuen Arduino Nano Every getauscht, die IR-LED gegen eine neue ausgetauscht (obwohl die alte angeblich funktionierte) und den Code mit dem neuen Arduino neu geschrieben (gleiche Logik, aber mit dem neuen Atmega4809 Timer):

// Macros for easier bit manipulation
#define CLR(x) (VPORTB.OUT&=(~(1<<x)))
#define SET(x) (VPORTB.OUT|=(1<<x))
#define TOGGLE(x) (VPORTB.OUT^=(1<<x))

void setup()
{
  pinMode(5, OUTPUT); // IR LED output
  pinMode(9, INPUT); // VS1838b input sensor

  TCA0.SINGLE.PER = 0x00D2;
  TCA0.SINGLE.CMP1 = 0x00D2;
  TCA0.SINGLE.INTCTRL = B00100000;
  TCA0.SINGLE.CTRLA = B00000001;
}

void loop()
{
}

ISR(TCA0_CMP1_vect) {
    TCA0.SINGLE.INTFLAGS |= B00100000;
    if ((VPORTB.IN & B00000001) == 0)
    {
      TOGGLE(2);
    }
    else
    {
      CLR(2);
    }
}

Das funktioniert jetzt. Vielen Dank an alle für Ihre Hilfe!