Wie kann ein Arduino eine bestimmte Trägerfrequenz (dh 56 kHz) ausgeben?


9

Ich arbeite an einem Freiraumoptikprojekt, um Daten drahtlos zwischen zwei Punkten zu senden. Um dies zu erreichen, verwende ich eine IR-LED, die an ein Arduino Uno angeschlossen ist, das mit einer Trägerfrequenz von 56 kHz für den Sender und ein zweites Arduino mit einem IR-Detektormodul von 56 kHz für den Empfänger pulsiert.

Ich habe versucht, delayMicroseconds () zwischen Pin High- und Pin Low-Befehlen zu verwenden, um die Trägerfrequenz zu erstellen. Diese Art funktioniert, aber die Frequenz ist nicht immer gleich und zusätzliche Verzögerungen zum Pulsieren des Signals (dh die Zeit, die zum Aufrufen der Funktion und zum Dekrementieren erforderlich ist) können sie ändern.

Beim Lesen des Datenblattes für den ATmega328 scheint es eine Möglichkeit zu geben, mithilfe der Timer des Chips einen genaueren Impuls einzustellen. Ist das möglich und wenn ja, wie erzeugen Sie mit den Timern einen 56-kHz-Impuls?


Welche Genauigkeit benötigen Sie für Ihre 56-kHz-Frequenz? Dh welcher Frequenzbereich ist in Ihrem Projekt akzeptabel? Ich frage, weil die Präzision nur mit Arduino-Timern Einschränkungen hat.
jfpoilpret

55,5 kHz bis 56,5 kHz wären ideal, um ein hohes Maß an Reaktionsfähigkeit im Detektor aufrechtzuerhalten.
jlbnjmn

Antworten:


10

Es ist tatsächlich möglich, mit einem Arduino- Timer ein 56-kHz-Signal zu erzeugen .

Ein Timer kann tatsächlich als ein spezielles Register in der MCU angesehen werden, das einen Wert (beginnend bei 0) enthält, der mit einer Frequenz erhöht wird, die der MCU-Taktfrequenz (16 MHz bei Arduino Uno) entspricht, wobei die Möglichkeit durch einen aufgerufenen Faktor geteilt wird Prescaler . Wenn dieser Wert ein von Ihnen angegebenes Limit namens " Vergleich vergleichen" erreicht, passieren zwei Dinge:

  • Der Timer-Registerwert wird auf 0 zurückgesetzt.
  • Eine ISR- Rückruffunktion (Interrupt Service Routine) wird aufgerufen (Sie können sie so definieren, dass sie auf Ihren eigenen Code verweist).

Die Idee ist, diesen ISR zu verwenden, um die Ausgabe eines logischen Pins bei jedem Aufruf zu ändern ( HIGHdann LOW, dann HIGH...).

Um eine 56-kHz-Rechteckwelle zu erzeugen, muss Ihr ISR nun 56000 * 2mal pro Sekunde aufgerufen werden ( * 2da Sie den Ausgabewert zweimal pro Periode ändern müssen).

Sie können den gewünschten Prescaler-Wert für einen Timer aus der folgenden Liste auswählen:

  • 1 (Taktfrequenz ist nicht geteilt, daher 16 MHz)
  • 8 (Taktfrequenz wird durch 8 geteilt, daher 2 MHz)
  • 64
  • 256
  • 1024

Bei Arduino Uno gibt es zwei Größen von Timern / Zählern (sie werden tatsächlich als Timer / Zähler bezeichnet ): 8 Bit und 16 Bit.

Unter Arduino Uno (ATmega328P) haben Sie insgesamt drei Timer, einige können jedoch von der Arduino-Kernbibliothek oder anderen in Ihren Skizzen verwendeten Bibliotheken verwendet werden (dies müssen Sie selbst überprüfen):

  • timer0 (8-Bit)
  • timer1 (16-bit)
  • timer2 (8-Bit): Dieser hat mehr Vorskalierungsoptionen (1, 8, 32, 64, 128, 256 und 1024).

Jetzt müssen Sie eine 56-kHz-Welle aus 16 MHz erzeugen. Ohne Vorskalierung müssen Sie also zählen bis:

16000000 / (56000 * 2) - 1 = 141.857( - 1weil ein Timer von 0 bis zu diesem Wert zählt und erst zurückgesetzt wird, nachdem er erreicht wurde)

Aus dieser Berechnung können wir zwei Beobachtungen ziehen:

  1. 141.857 ist keine ganze Zahl und daher können Sie keine Welle von genau 56 kHz erzeugen.
  2. Ohne Vorskalierung benötigen Sie einen 16-Bit-Timer, da 285 nicht als vorzeichenlose 8-Bit-Ganzzahl dargestellt werden kann.

Ab sofort haben Sie zwei Möglichkeiten:

  1. Verwenden Sie einen 16-Bit-Timer ( timer1 ), verwenden Sie prescaler = 1 und wählen Sie 142als Compare Match. das gibt Ihnen die folgende Frequenz:16000000 / (2 * (142 + 1)) = 55944 Hz
  2. Verwenden Sie einen 8-Bit-Timer ( timer0 ), verwenden Sie prescaler = 8 und wählen Sie 17als Compare Match. Dies ergibt eine geringere Genauigkeit bei der folgenden Frequenz: 16000000 / (8 * 2 * (17 + 1)) = 55555 HzDiese liegt immer noch im erforderlichen Bereich.

In Bezug auf das Schreiben Ihrer Skizze empfehle ich Ihnen, diese Anleitung zu lesen, die sehr vollständig und sehr interessant zu lesen ist.

Natürlich ist das vollständige Datenblatt des ATmega328P auch wichtig, wenn Sie bis ins kleinste Detail verstehen möchten, was Sie tun.

Einige wichtige Hinweise:

  • Ein ISR wird mit deaktivierten Interrupts ausgeführt und muss daher so kurz wie möglich sein. Insbesondere gibt es mehrere Funktionen aus der Arduino-Bibliothek, die nicht von einem ISR aufgerufen werden sollen.
  • Der Arduino Uno-Takt ist nicht sehr genau (er verwendet einen Keramikresonator anstelle eines Quarzes, was viel genauer gewesen wäre), was bedeutet, dass sich die Ausgangsfrequenz weiter verschiebt.

2
Auch wenn der angegebene Grenzwert erreicht ist, kann die Hardware einen Pin umschalten. Daher müssen ISRs überhaupt nicht verwendet werden. Bei einem ISR tritt immer Jitter auf, da ein Befehl nach dem Start nicht unterbrochen werden kann. Die Hardware schaltet den Pin jedoch immer mit der gewünschten Geschwindigkeit um.
Nick Gammon

Es ist etwas überraschend, dass der Arduino Uno einen Keramikresonator verwendet, aber eine Quelle dafür sind die Arduino UNO-FAQ (in der Nähe von "Verwendet der Uno einen Resonator oder einen Kristall für den Prozessortakt?" ).
Peter Mortensen

3

Ich habe festgestellt, dass es tone()nützlich ist, Hochfrequenzimpulse an jedem Pin zu erzeugen. Es sollte 56 KHz verarbeiten können. (Bearbeiten: Wie von jfpoilpret festgestellt, liegt der nächste Wert, den Sie auf einem 16-MHz-Arduino tatsächlich erreichen können, bei 55,944 kHz.)

Die Schwierigkeit wird offensichtlich darin bestehen, es mit Ihrem Datensignal zu kombinieren. Ich glaube nicht, dass Sie das in Software tun können, ohne auf Code auf niedriger Ebene zurückzugreifen. In der Hardware sollte es allerdings ziemlich einfach sein, da es digital ist.

Alles, was Sie tun müssen, ist, Ihr Datensignal an einem anderen Pin auszugeben und es dann über ein UND-Gatter mit dem Träger zu kombinieren. Das kombinierte Signal kann direkt zu Ihrem IR-Sender geleitet werden.

Wenn Sie kein UND-Gatter zur Hand haben, ist es ganz einfach, mit einem Transistorpaar ein eigenes zu erstellen. Suchen Sie einfach online nach "Transistor und Gate".


Empfänger haben im Allgemeinen häufig aktiv niedrige Ausgänge. Wenn Sie die Oberseite der LED an die 56 kHz und die Unterseite an Ihren Daten-Pin anschließen, erhalten Sie bei einem niedrigen Daten-Pin einen IR-Ausgang, wodurch der Empfänger niedrig wird. Nein und Gate benötigt, nur eine LED und Widerstand. Das einzige Problem besteht darin, sich auf die aktuellen Io-Pins zu beschränken.
EternityForest

2

Die akzeptierte Antwort von jfpoilpret ist sehr gut geschrieben, vollkommen gültig und in 99% der Fälle werde ich genau das tun, was er erklärt. Seine Lösungen liegen gut innerhalb Ihrer definierten Parameter, daher sollten sie sehr gut funktionieren. Aber was ist besser als " sehr gut "? Perfektion! Schließlich geht es darum, einen genauen Wert zu generieren. Wie gesagt, nah genug ist in den meisten Fällen gut (wohl alle), und selbst wenn Sie mit etwas wie einer Uhr arbeiten, wenn 1 Sekunde 1 Sekunde sein muss, müssen Sie immer noch Unvollkommenheiten bei ererbten Teilen erleiden.

Was ich vorschlagen werde, ist nicht immer möglich. In einigen Fällen ist dies möglich, jedoch mit viel mehr Aufwand und Aufwand als in diesem Fall. Ist es wert, von Fall zu Fall abhängig zu sein. Mein Ziel ist es hauptsächlich, eine Alternative für zukünftige Referenzen aufzuzeigen, die in Randfällen besser ist. Dies wurde für unerfahrene Arduino-Benutzer geschrieben, die keine umfassende Erfahrung in der Elektronik haben.

Für fortgeschrittene Leute wird dies wahrscheinlich zu ausführlich und niedergeschlagen aussehen. Aber ich glaube, dass dieselben Leute es wahrscheinlich bereits wissen und diese Antwort nicht brauchen. Dies gilt auch für jeden Mikrocontroller sowie jeden Hersteller und jede Architektur. Bei anderen Mikrocontrollern müssen Sie jedoch das richtige Datenblatt konsultieren, um die richtigen Register sowie Namen und Werte für die Vorskalierung zu ermitteln.

In Ihrem Fall benötigen Sie eine bestimmte Frequenz und das Schöne daran ist, dass genau 56 kHz tatsächlich sehr einfach erreicht werden können (ohne praktische Mängel der Teile). Dies ist also auch ein perfekter Beispielfall.

Das Erzeugen eines Signals hängt von den Zeitgebern und der Taktquelle des Mikrocontrollers ab, wie durch jfpoilpret gut erklärt. Seine Antwort befasst sich nur mit dem Problem einer Sichtweise, und das ist das Spielen mit Timern. Sie können aber auch an der Taktquelle herumspielen oder sogar an Synergieeffekten und hervorragenden Ergebnissen. Durch Ändern der Umgebungsparameter, in diesem Fall Hacken des Systems und Ersetzen der Taktquelle, können wir ein bestimmtes Problem viel, viel einfacher und einfacher lösen.

Um daran zu erinnern, müssen Sie aufgrund des Umschaltens des Pin-Status den ISR zweimal mehr als die Signalfrequenz ausführen. Dies ist 112.000 Mal pro Sekunde. 56.000 und 16.000.000 summieren sich nicht sehr gut, wie bereits erwähnt. Wir müssen entweder die Signalfrequenz oder die Taktfrequenz ändern. Lassen Sie uns zunächst mit einer unveränderlichen Signalfrequenz umgehen und eine bessere Taktrate finden.

Es wäre am einfachsten, einen Takt mit einer Größenordnung größer als 56 kHz (oder 112 kHz, aber praktisch gleich) zu wählen, da Sie nur Nullen hinzufügen und diese Art der Mathematik für die meisten Menschen am einfachsten ist. Leider ist alles auf dieser Welt eine Art Kompromiss mit etwas. Nicht jeder Wert wird funktionieren.

Das erste Beispiel ist eine zu niedrige Taktgeneratorgeschwindigkeit.

Wenn Sie eine 56.000-Hz-Uhr wählen, können Sie nichts tun, da Sie den ISR in jedem Zyklus aufrufen müssen und nichts anderes tun können. Es ist völlig nutzlos. Wenn Sie eine 10-mal schnellere Geschwindigkeit (560 kHz) wählen, haben Sie 9 (10 Zyklen, damit der Timer seinen Maximalwert erreicht - ein Zyklus, um die ISR-Funktion aufzurufen) Mikrocontroller-Zyklen, um Ihre Arbeit zu erledigen, und dies kann durchaus nicht ausreichen. Sie benötigen einfach oft mehr Rechenleistung.

Wenn Sie andererseits einen viel zu großen Wert als 56 MHz wählen, kann der Mikrocontroller einfach nicht damit arbeiten. Es ist viel zu schnell. Wenn Sie also einfach den größten Wert im Shop auswählen, wird dies auch nicht schaden.

Das Original Arduino Uno R3 verfügt über einen Standardtakt mit 16 MHz, sodass alles, was langsamer ist, garantiert funktioniert. Der nächste Wert, der eine Größenordnung größer als 56 und kleiner als 16 MHz ist, ist 5,6 MHz. Dies führt dazu, dass der ISR alle 50 Zyklen aufgerufen werden kann und die perfekte Timerfrequenz von 112.000 Hz erzeugt wird. Und Ihr Signal wird genau 56 kHz sein. Sie haben 49 MCU-Zyklen, um Ihr Programm zwischen ISR-Aufrufen auszuführen, aber es ist immer noch ungefähr 1/3 der Geschwindigkeit der ursprünglichen Uhr. Man kann 112 als Basis verwenden und einen 11,2-MHz-Takt verwenden, und dies ergibt ungefähr 2/3 des 16-MHz-Resonators. Die ISR-Funktion wird alle 100 Zyklen aufgerufen und erzeugt immer noch ein perfektes 56-kHz-Signal.

Bei diesen Werten bestehen jedoch zwei Hauptprobleme.

  • Das erste Problem hängt stark von Ihren Anforderungen ab: Sie opfern etwa 1/3 (mit 11,2 MHz) Ihrer maximalen Rechenleistung, um die genaue Signalfrequenz zu erhalten, die einen leicht zu findenden Registerwert (OCR iirc ) verwendet. Sie können damit einverstanden sein oder Sie können nicht.

  • Das zweite Problem ist ein harter Showstopper : Es ist sehr einfach, Werte zu finden, aber sehr oft existieren sie einfach nicht als hergestellte Taktquelle. Dies ist Farnells Resonator-Webseite , auf der einfach sowohl 5,6 MHz als auch 11,2 MHz fehlen.

Um dies zu umgehen, können wir uns die verfügbaren Resonatorwerte ansehen und etwas anderes herausfinden, mit dem genau die gewünschten Werte erzeugt werden können. Wenn wir 56 durch 4 teilen, erhalten wir 14 und zum Glück gibt es einen 14-MHz-Resonator. Dies bietet uns eine viel höhere Geschwindigkeit und Leistung sowie einen ebenso leicht zu findenden Registerwert. Um den ISR 112.000 Mal pro Sekunde aufzurufen, müssen wir den Wert der Dezimalzahl 124 oder der Hexadezimalzahl 0x7C in das OCR-Register eingeben. Wenn wir also 124 Zyklen + 1 zählen, um den ISR aufzurufen, erhalten wir unseren gewünschten perfekten Wert.

NB

  1. ISR - Interrupt Service Routine (dies ist der Code, der nur bei generierten Interrupts ausgeführt wird)
  2. Wie groß Ihr Programm sein kann, hängt von der Speichergröße ab! Es hat nichts mit der Taktrate zu tun und hat nichts damit zu tun, wie oft Sie den ISR anrufen.
  3. Wenn der Mikrocontroller mit dem Programmbefehl startet, wird ein Zähler erhöht. Wenn ein Interrupt generiert wird, wird der ISR aufgerufen und dieser Wert in einem speziellen Register gespeichert. Wenn der ISR-Code vollständig ist, wird der Wert des Programmzählers aus diesem speziellen Register wiederhergestellt und das Programm wird dort fortgesetzt, wo es unterbrochen wurde, als wäre es nie geschehen.

    Ich werde ein äußerst niedergeschlagenes Beispiel geben. Wenn Sie Purist sind, warne ich Sie: Nasen- und Augenblutungen können auftreten.

    Stellen Sie sich vor, Sie müssen von irgendwo nach irgendwo gehen. Die schrittweisen Routenanweisungen sind Ihr Hauptprogramm und seine Befehle. Wie schnell Sie gehen oder laufen, hängt von Ihrer "Taktrate" ab, jedoch nicht von den Routenanweisungen (30 Schritte vorwärts, 1 Umdrehung 90 Grad links, 10 Schritte vorwärts, 45 Grad rechts usw.). Sie sind immer gleich . Stellen Sie sich jetzt vor, ein kleines Kind oder ein gieriger korrupter Lokalpolitiker lösen ab und zu Ihre Schuhe. Dies ist das Ereignis, das einen Interrupt erzeugt. Dann halten Sie nach Ihrem letzten Schritt an, knien nieder und binden Ihren Schuh erneut. Dies ist Ihr ISR-Programm.

    Dann fahren Sie von der Stelle fort, an der Sie angehalten haben. Sie beginnen nicht von vorne. Wenn Sie ohne Sorge in der Welt und mit der ganzen Zeit gehen, ist es Ihnen egal, auch wenn Sie Ihren Schuh bei jedem zweiten Schritt binden müssen. Wenn Sie dies jedoch mit zeitlichen Einschränkungen tun, z. B. bei den Olympischen Spielen in 100 Metern Entfernung (oder vor einem hungrigen, fleischfressenden Raubtier), kann das Anhalten und Binden Ihrer Schuhe schwerwiegende Folgen haben. Gleiches gilt für Mikrocontroller. Selbst wenn Sie nur eine Codezeile ausführen, wird Ihr Programm fortgesetzt, wenn auch langsam. Wenn Sie sich überhaupt nicht für Geschwindigkeit interessieren, ist dies kein Problem. Wenn Sie einige zeitbezogene Aktionen ausführen müssen, z. B. andere zeitabhängige Aktionen, können Interferenzen sehr unerwünscht und problematisch sein.

  4. Weniger ist mehr! Eine schnellere Uhr ist nicht immer besser. Langsam getaktete Geräte verbrauchen erheblich weniger Strom. Dies kann ein entscheidender Punkt in einem batteriebetriebenen Gerät sein.

  5. Die benötigten Zyklen werden aus folgenden Formeln abgeleitet:
    (Taktrate / (Prescaler-Wert * benötigte ISR-Ruffrequenz)) - 1


TLDR: Entlöten Sie den keramischen 16-MHz-Oszillator und ersetzen Sie ihn durch einen anderen, der genau 56 kHz durch ganzzahlige Division (z. B. 14 MHz und Division durch 250) zulässt .
Peter Mortensen

0

Sie können den Träger einfach ein- und ausschalten, indem Sie den Träger-Pin-Modus zwischen Ausgang und Eingang umschalten. Ich habe dies verwendet, um eine Wärmepumpe über den 37-kHz-Infrarotanschluss (Fernbedienung) zu steuern.


0

Es ist nicht erforderlich, einen ISR zum Erstellen des Trägers zu verwenden. Richten Sie einfach einen Timer ein, um eine PWM-Ausgabe von 50% bei der erforderlichen Trägerfrequenz zu erzeugen. Der ISR ist dann nur dafür verantwortlich, den Träger - typischerweise in Intervallen von 0,5 oder 1 ms - mit einer weitaus bequemeren Rate zu modulieren. Nach meiner Erfahrung wird ein 5% iger Fehler in der Trägerfrequenz von den meisten IR-Empfängern toleriert. Ich habe einen Freetronics EtherMega 2560 verwendet (der viele Timer hat), aber ich bin mir sicher, dass andere CPUs genauso gut funktionieren werden.


Wie genau ist dann die Modulation des Trägers implementiert? Ändern des Modus für den Timer-Ausgangserfassungsstift zwischen Eingang (Träger aus) und Ausgang (Träger ein)?
Peter Mortensen
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.