Geführte FSK-Modulation mit Timer1 Caption    

Elektronik-Labor  Lernpakete  Projekte  HF  



Das FSK-Modulationsverfahren hat grundsätzlich funktioniert. Die Modulationsfrequenz wird gemessen und dann zur Grundfrequenz addiert. Das Ergebnis entspricht einer USB-Modulation. Aber die Präzision musste noch gesteigert werden. Dazu sollte die Timer1 Input Capture Unit  zum Einsatz kommen. Bei einer fallenden Flanke am Eingang T1 wird der aktuelle Stand des Timers in das Caption Register ICR1 übernommen. Man erhält dadurch eine zeitliche Präzision in der Größenordnung eines Prozessortakts. Start T1 kann auch der analoge Komparator mit seinen beiden Eingängen AC1 und AC0 verwendet werden. Damit hat man die Möglichkeit, auch kleinere Eingangssignale auszuwerten. Auch diesmal wurde der erste Funktionstest mit Bascom durchgeführt.

Config Timer1 = Timer , Prescale = 1
start Timer1
TCCR1B = &H81 ' Timer1, Vorteiler 1, ICNC1: Input Capture Noise Canceler
ACSR.ACIC = 1 ' Analog Comparator als Input


do
timer1 = 0
while ACSR.ACO =0
if Timer1 > 65000 then exit while
wend
timer1 = 0
while ACSR.ACO=1
if Timer1 > 65000 then exit while
wend
d1 = ICR1
while ACSR.ACO=0
if Timer1 > 65000 then exit while
wend
while ACSR.ACO=1
if Timer1 > 65000 then exit while
wend

if timer1 < 65000 then
Regaddr = 3
Regdata = 6 ' CLK0 an
Call Siout(regaddr , Regdata) 'enable outputs

d2= icr1
d = d2-d1
f= 16000000/d
'print f
dd = f
Gfreq = 7074000+ dd
Clk = 0
Setfreq
else
Regaddr = 3
Regdata = 5 ' CLK1 an
Call Siout(regaddr , Regdata) 'enable outputs
end if
loop


Das Programm nimmt zwei Zählerstände am Anfang und am Ende einer Schwingung auf und speichert sie in d1 und d2.  In der Wartezeit zwischen den Flanken kann in aller Ruhe der Timer selbst ausgelesen werden, um ein Timeout zu erkennen. Der Timer sollte nämlich niemals mehr als 65000 erreichen, außer wenn die Modulation abgeschaltet wurde. Aus der Periodendauer wurde dann die Frequenz f berechnet. Zur Probe wurden Messwerte der Frequenz seriell ausgegeben. Das Ergebnis an einem analogen Sinusgenerator zeigt eine Zuverlässigkeit im Bereich 0,1 Hz, was sogar für WSPR reichen sollte.



Beim Einsatz mit WSJT-X kann man mit Tune eine konstante Frequenz ausgeben und testen, was die Firmware daraus macht. Aber nun zeigten sich plötzlich wesentlich größere Abweichungen von mehr als einem Hertz. Die Vermutung war, dass es sich um Fehler handelt, die in der Soundkarte entstehen. Das Sinussignal wird mit endlicher Auflösung und endlicher Abtastrate erzeugt und dann so gefiltert, dass insgesamt > 20 kHz übertragen werden können. Dabei bleibt wohl die eine oder andere kleine Delle im Signal erhalten, was zu kleinen Abweichungen in der Periodendauermessung führen muss. Mit einem Bandpass- oder Tiefpassfilter müsste man die Situation verbessern können.



Also wurde ein einfaches Filter mit einer Grenzfrequenz unter 3 kHz gebaut. Dass die Signalamplitude im oberen Bereich schon deutlich abnimmt, ist unproblematisch, weil der Komparator ohnehin ein Rechteck daraus macht. Und tatsächlich, nun wird auch das Signal aus dem PC mit einer Zuverlässigkeit von ca. 0,1 Hz gemessen. Mein Bascom-Programm steuert auch schon den PLL-Chip an. Damit konnten erfolgreich FT8-Signal übertragen werden. Nur für WSPR reichte es noch nicht, weil die Frequenzaufbereitung nur eine Auflösung von 1 Hz hat. Also wurde die eigentliche Anwendung auch wieder mit Arduino programmiert. Und nun funktioniert sogar WSPR mit seinen FSK-Stufen von nur 1,6 Hz!

 // Modulationsfrequenz messen über Analog Comparator Pin7 = AN1
TCCR1A = 0x00;
TCCR1B = 0x01; // Timer1 Timer 16 MHz, ICNC1: Input Capture Noise Canceler

TCCR1B = 0x81; // Timer1 Timer 16 MHz, ICNC1: Input Capture Noise Canceler
ACSR |= (1<<ACIC); // Analog Comparator Capture Input
pinMode(7, INPUT); //PD7 = AN1 = HiZ, PD6 = AN0 = 0
digitalWrite (7,1);
digitalWrite (6,1);
delay(2);
unsigned int d1,d2;
int FSK = 10;
int FSKtx = 0;
while (FSK>0){
TCNT1 = 0;
while (ACSR &(1<<ACO)){
if (TCNT1>65000) {break;
}
} while ((ACSR &(1<<ACO))==0){
if (TCNT1>65000) {break;}
}
TCNT1 = 0;
while (ACSR &(1<<ACO)){
if (TCNT1>65000) {break;}
}
d1 = ICR1;
while ((ACSR &(1<<ACO))==0){
if (TCNT1>65000) {break;}
}
while (ACSR &(1<<ACO)){
if (TCNT1>65000) {break;}
}
d2 = ICR1;
if (TCNT1 < 65000){
unsigned long codefreq = 1600000000/(d2-d1);
// d1 = codefreq /10;
// Serial.println(d1);
// delay (500);
if (codefreq < 350000){
if (FSKtx == 0){
digitalWrite (txOn,1); //Relais
digitalWrite (keyOut,1); //keyOut
si5351.output_enable(SI5351_CLK2, 1);
si5351.output_enable(SI5351_CLK1, 0); //RX off
}
si5351.set_freq((freqTX * 100 + codefreq), SI5351_CLK2);
FSKtx = 1;
}
}
else{
FSK--;
}
si5351.output_enable(SI5351_CLK2, 0);
si5351.output_enable(SI5351_CLK1, 1); //RX on
digitalWrite (txOn,0); //Relais
digitalWrite (keyOut,0); //keyOut
pinMode(7, OUTPUT); //LCD
digitalWrite (7,0);
digitalWrite (7,0);
FSKtx = 0;
}
}


Ein Problem war noch zu lösen: Wenn ich das SDR-Shield zusammen mit dem LCD-Shield von Elektor verwende, belegt dieses die benötigten Leitungen PD6 und PD7. Die oberen vier Leitungen sind der LCD-Datenbus mit den Leitungen D4 bis D7. Ein Test hat aber gezeigt, dass man sich die Ports leihen kann, wenn gerade keine LCD-Ausgabe ansteht. Allerdings hat das LCD anscheinend selbst interne Pullup-Widerstände, sodass ein offener Eingang hoch liegt. Deshalb musste ich den Vergleichspegel des Komparators in Richtung VCC verlegen. PD6 wird deshalb hochgeschaltet und dient als virtuelle Masse für das Tiefpassfilter.



In der Form habe ich nun den Audioeingang in meinen QRP-Transceiver eingesetzt. Nun kann ich WSPR auf die alte Art und mit der direkten Steuerung über den Mikrofoneingang verwenden, außerdem auch FT8, FT4, JS8 und viele andere Betriebsarten.



Zum Abschluss des Versuchs habe ich den WSPR-Sender, gesteuert von WSPR 2.12, mehrere Stunden lang laufen lassen. Das Ergebnis zeigt: Alles funktioniert bestens.







Elektronik-Labor  Lernpakete  Projekte  HF