Radiosender bauen mit Raspi, Arduino oder ESP32

Seite 3: Eigenbau

Inhaltsverzeichnis

Im einfachsten Fall kann jeder moderne Mikrocontroller bereits durch das schnelle Schalten eines Ausgangs-Pins zwischen 0 und 3,3 beziehungsweise 5V ein Hochfrequenzsignal erzeugen, das sich über ein längeres Stück Draht abstrahlen lässt. Je schneller der Prozessor getaktet wird, desto höher die erreichbare Frequenz am Pin.

Ein Arduino kann beispielsweise Frequenzen erzeugen, die im Mittelwellenband liegen, ein Raspberry Pi schafft locker Frequenzen im UKW-Bereich. Mit einem einfachen Trägersignal allein lässt sich jedoch noch nicht viel erreichen; was fehlt, ist die Modulation durch Musik.

Der Wert des sinusförmigen Verlaufs (grün) kann durch den Vergleich mit dem Register OCR2B in Timer2 in ein unten in rosa dargestelltes PWM-Signal umgewandelt werden.

(Bild: CYrilB, Commonswiki, CC BY-SA 3.0)

Bedingt durch den erreichbaren Frequenzbereich erfordert ein Arduino-Sender eine Amplitudenmodulation, ein Pi-Sender muss sein Signal frequenzmodulieren.

Das erste Arduino-Beispiel ist in Bild 1 zu sehen. Es wurde vom Bastler Markus Gritsch veröffentlicht und benötigt im einfachsten Fall nur zwei Widerstände und einen Elko, um beispielsweise den Kopfhörerausgang eines Smartphones an den AD-Wandler-Eingang des Arduino anzuschließen. Eine Antenne – also ein längerer Draht – schließt man an Pin D3 an. Das Radio stellt man auf eine Frequenz zwischen 730 und 740kHz ein.

Bild 1: Je länger die Antenne (Pin 3) am Arduino, desto besser.

Spielt man nun auf dem Smartphone Musik beispielsweise von Spotify oder anderen Diensten ab, so kann man sie im Radio hören – allerdings meist nur in eher schlechter Qualität. Als Proof-of-Concept und Grundlage für Verbesserungen reicht es aber allemal.

Für erste Tests legt man die Antenne sehr nah an das Radio. Später kann man probieren, welche Entfernungen sich überbrücken lassen. Grundsätzlich gilt: Je länger die Antenne, desto besser.

Die Software für den Arduino nutzt Funktionen des auf dem Board arbeitenden ATmega328, die die Arduino-IDE eher vor den Augen von Einsteigern versteckt. Konkret bedeutet das, dass der Takt des internen, fest eingestellten Taktgenerators (16MHz) über Frequenzteilung reduziert wird und einen Timer respektive Zähler (Counter) antreibt.

Im Prinzip ist das ein Register (genau heißt es TCNT für Timer/Counter Register), das von 0 bis 255 zählt und mit jedem Takt seinen Inhalt um 1 erhöht. Nach 255 fängt es wieder bei 0 an. Das Timer-Register lässt sich auslesen und sein Inhalt mit zwei weiteren Registern vergleichen, den sogenannten Output-Compare-Registern (OCR). Sofern TCNT und das jeweilige OCR gleich sind, kann eine interne Logik unterschiedliche Ereignisse anstoßen, beispielsweise einen Ausgangs-Pin OCn ändern.

Im Bild 2 ist nun zu sehen, dass zwei OCR-Register mit unterschiedlichen Werten PWM-Signale erzeugen können. Mit OCRnA (das n steht für Timer 0, 1 oder 2) lässt sich die Frequenz des PWM-Signals festlegen (hier 734kHz), während sich am Ausgang OCnB mit dem Wert in Register OCRnB das Tastverhältnis einstellen lässt. Unterschiedliche Tastverhältnisse resultieren in unterschiedlichen effektiven Spannungen am PWM-Ausgang. Mit OCRnB lässt sich also das Ausgangssignal amplitudenmodulieren. Und OCRn wiederum wird über das am Analog-Digital-Wandler anliegende Musiksignal bestimmt.

Bild 2: Die Register OCR bestimmen, wann die OC-Pins des Arduino geschaltet werden.

Der Code ist in Listing 1 zu sehen, der ohne Studium des ATmega-Datenblatts und Kenntnisse der internen Register leider für Einsteiger nicht zu verstehen ist. Zum Ausprobieren müssen Sie den Sketch nur in die Arduino-IDE laden, übersetzen und hochladen. Zum Verständnis nur so viel: In der Funktion loop werden die Timer Control Register für Timer 2 gesetzt, die Funktion setup() liest den AD-Wandler-Wert in einer Endlosschleife ein, skaliert ihn und schreibt ihn in das Register OCR2B, welches das Tastverhältnis bestimmt. Unterschiedliche Werte führen zu unterschiedlichen Tastverhältnissen, was zu unterschiedlich hohen Spannungen der Trägerfrequenz führt.

#define INPUT_PIN  0 // ADC-Eingang
#define TIMER_PIN  3 // PWM Ausgang, OC2B (PD3)
#define DEBUG_PIN  2 // 
#define LED_PIN   13 // 

#define SHIFT_BY   3 // 2 ... 7 Abschw�chung 
#define TIMER_TOP 20 // Faktor Tr�gerfrequenz
#define A_MAX TIMER_TOP / 4

void setup() {
    pinMode( DEBUG_PIN, OUTPUT );
    pinMode( TIMER_PIN, OUTPUT );
    pinMode( LED_PIN, OUTPUT );

    // ADC Vorteiler (0b100)
    ADCSRA = ( ADCSRA | _BV( ADPS2 ) ) & ~( _BV( ADPS1 ) | _BV( ADPS0 ) );

    // FAST PWM ohne Teiler
    TCCR2A = 0b10100011; // COM2A1 COM2A0 COM2B1 COM2B0 - - WGM21 WGM20
    TCCR2B = 0b00001001; // FOC2A FOC2B - - WGM22 CS22 CS21 CS20

    // 16E6 / ( OCR2A + 1 ) = 762 kHz @ TIMER_TOP = 20
    OCR2A = TIMER_TOP; //   = 727 kHz @ TIMER_TOP = 21
    OCR2B = TIMER_TOP / 2; // Amplitude der TF bei 50% Tastverh�ltnis
}

void loop() {
    // 34 kHz Sampling-Frequenz 
    digitalWrite( DEBUG_PIN, HIGH );
    int8_t value = ( analogRead( INPUT_PIN ) >> SHIFT_BY ) -
                   ( 1 << ( 9 - SHIFT_BY ) );
    digitalWrite( DEBUG_PIN, LOW );

    // clipping
    if ( value < -A_MAX ) {
        value = -A_MAX;
        digitalWrite( LED_PIN, HIGH );
    } else if ( value > A_MAX ) {
        value = A_MAX;
        digitalWrite( LED_PIN, HIGH );
    } else {
        digitalWrite( LED_PIN, LOW );
    }

    OCR2B = A_MAX + value;
}

Zwar kommt aus dem Arduino ein PWM mit Rechtecksignalen in verschiedenen Tastverhältnissen heraus, letztlich resultiert dies aber in einem amplitudenmodulierten Trägersignal.