Amateurfunkgeräte fernsteuern             
CI-V-QSY-Box                 

von Ralf Beesner, DK5BU              
Elektronik-Labor   Projekte   AVR              




Hat einen der Mikrocontroller-Virus so richtig gepackt, wird nicht nur die Umsetzung zum Problem, sondern schon die Idee, was man denn bloß mal bauen könnte. Da fallen einem dann nicht unbedingt neuartige Dinge ein, sondern Lösungen, die vor Jahren mal ein "cooles Gadget" waren und die man damals nur passiv konsumieren konnte, die man aber heute dank BASCOM selbst bauen kann.

In diese Kategorie fällt der "QSYer". Fast alle Amateurfunkgeräte weisen einen seriellen Eingang auf, über den man einige Funktionen des Geräts fernsteuern kann. Da nur wenige Geräte eine Zifferntastatur zur komfortablen Direkteingabe von Frequenzen aufweisen, brachte eine Firma vor vielen Jahren ein kleines Gerät mit 16er-Tastatur heraus, das die Fernsteuerdialekte einiger Funkgeräte beherrschte.

Damit konnte man Frequenzen per Direkteingabe aufrufen statt mit Bandschalter und Drehknopf mühsam dorthin zu kurbeln; bei einigen Geräten waren auch weitergehende Funktionen (z.B. Abruf der Memorykanäle des Funkgeräts) möglich.

Da ich nur zwei Geräte der Firma ICOM besitze (einen Transceiver IC 703 und einen Empfänger IC R8500), habe ich ein solches Gerät für ICOM-Funkgeräte entwickelt.


Das ICOM-CI-V-System

Die älteren Yaesu-Transceiver (z.B. FT757, FT747) hatten kein einheitliches Design ihrer "CAT-Schnittstelle". Neuere Yaesu Geräte (oder Geräte anderer Hersteller) kenne ich nicht näher.

Bei ICOM setzte man recht früh auf ein halbwegs konsistentes Gesamtsystem: einen seriellen Bus, mit dem man nicht nur mit einem PC mehrere Funkgeräte bedienen konnte, sondern auch Geräte untereinander vernetzen konnte, um sie z.B. im Frequenz Gleichlauf zu betreiben.

Neben der Arbeitsfrequenz lassen sich weitere Parameter wie z.B. Schrittweite, Modulationsart, Eingangsabschwächer und dergleichen fernsteuern. Man kann über die Schnittstelle auch die Speicherkänäle auslesen und beschreiben.

Die Vernetzung erfolgt über eine Zweidrahtleitung. RxD und TxD sind zu einer gemeinsamen  Leitung zusammengeführt (Pegel 0V/5V); die Übertragung erfolgt als asynchrones serielles  Signal mit 8 bit (8N1) wie zu den Zeiten, als man noch mit Telefonmodems und Mailboxen hantierte.

Um selektiv ansprechbar zu sein, weisen die ICOM Geräte unterschiedliche Hexbyte Geräteadressen auf. Die Adresse (und die Übertragungsgeschwindigkeit) lassen sich meist im Einstellmenü des Gerätes verändern.

Der PC (bzw. hier die externe QSY-Tastatur) bekommt die Adresse &HE0.


Struktur der Datentelegramme 


Die Telegramme beginnen mit zwei Synchronisationsbytes &HFE, dann kommt die Geräteadresse, es folgt die PC-(bzw. Tastatur-) Adresse. Danach kommt das Steuerkommando für direkten Frequenzwechsel und anschließend die in 5 Bytes umgeschlüsselte Frequenz (den Aufbau der Frequenzbytes erkennt man am besten an dem ersten Beispiel 1.234.567,890 kHz). Den Abschluss des Telegramms bildet das Byte &HFD.


Hardware

Das Programm entstand zwar ursprünglich auf einem AtMega8 Board; die Aufgabe passt aber besser zu einem ATtiny 2313, da nur etwa 1,6 kB Flash und 14 IOs benötigt werden. Der AtTiny 2313 hat eine Hardware UART und im Gegensatz zum AtMega8 sogar PinChange-Interrupts.



Die Tastatur besteht aus einer 3*4 Matrix. Oben links liegt die "1", in der unteren Reihe liegen die Tasten "*", "0" und "#".

Man kann sie wie ich aus DIP Tastern selbst bauen, es gibt aber im Versandhandel (z.B. bei Conrad) schönere Tastaturen (man muss aber darauf achten, dass die Tasten in einer Matrix verdrahtet sind; es gibt auch Versionen, deren Tasten einzeln herausgeführt werden).

Eine solche Tastatur lässt sich sehr einfach mit dem BASCOM Befehl "getkbd" abfragen; er setzt einen 8 bit breiten Port voraus, der voll belegt wird. Die unteren 4 IOs liegen an den Spalten der Tastaturmatrix (der 4. IO bleibt bei einer 12er Tastatur unbeschaltet), die oberen 4 IOs liegen an den Zeilen der Tastaturmatrix.

Die Tastatur liegt an Port B des AtTiny 2313. PD1 ist der UART Ausgang, an PD2 bis PD5 liegt ein "Mäuseklavier". Ein Buzzer für Quittungstöne ist an PD6 angeschaltet.

Der Mikrocontroller läuft mit dem internen RC Taktoszillator. Er ist ausreichend stabil für den Betrieb der seriellen Schnittstelle mit 19200 bit/s; allerdings nur, wenn der Takt nicht auf 1 MHz (dem Auslieferungszustand) belassen wird, sondern auf 8 MHz hochgesetzt wird.

Er muss jedoch nicht umgefust werden; die Änderung der Taktrate von 1 MHz auf 8 MHz erfolgt zur Laufzeit des Programmes.

Da die Funkgeräte TTL Pegel erwarten, kann man den seriellen Ausgang des AtTiny 2313 über einen Vorwiderstand mit dem CI-V Anschluss des Funkgerätes verbinden. Bei meinen Geräten durfte er maximal 12 kOhm betragen. Zwei Dioden sorgen für die Ableitung von Überspannungen. 



Software


Die Software besteht aus folgenden Blöcken:

Im Initialisierungsblock wird das "Mäuseklavier" abgefragt; der wichtigste Parameter, der hier eingestellt werden kann, ist die Geräteadresse des zu steuernden Funkgerätes bzw. Receivers. Daneben lässt sich noch eine abweichende Baudrate einstellen und in einen 4-Byte Modus für die Frequenzbytes umschalten; dem Manual des R8500 entnahm ich, dass zumindest der IC735 nur 4 Frequenzbytes nutzt.

Die Mainloop liest erst mal die Geräteadresse aus dem EEPROM. Dann wird in das Unterprogramm "read_kbd" verzweigt. Hier wird zunächst auf einen Tastendruck gewartet (GETKBD liefert "16"  zurück, wenn keine Taste gedrückt ist), die gedrückte Taste ermittelt und gewartet, bis die Taste losgelassen wurde (GETKBD liefert dann wieder "16" zurück). Der Wert wird in das Array "Puffer" geschrieben und ein Quittungston ausgegeben.

Ist der Quittungston nicht hoch und kurz, sondern tief und lang, wurden zu viele Zeichen eingegeben. Wurde die Taste "#" gedrückt, ist die Frequenzeingabe abgeschlossen; der Quittungston ist dann hoch und lang. Der GETKBD Wert für "#" (12) wird durch 0 ersetzt. Danach geht es dann wieder in die Mainloop. Die eingegebenen Zeichen stehen nun im Array "`Puffer"'.

Damit man nicht alle Frequenzen 10-stellig eingeben muss, wurde die Taste "*" als Trennzeichen zwischen MHz und kHz definiert. Die Lage dieses Trenners im Array "Puffer" wird daher zunächst gesucht. Anschließend werden die Ziffern in das 10-stellige Array "Freq" umsortiert. In dem Array stehen zunächst Nullen, und ausgehend von dem Trenner "*" werden die eingegebenen Ziffern so ins Array "Freq" kopiert, dass das unterste Element Freq(0) die GHz-Stelle enthält und das oberste die Hz-Stelle (sofern für die Stelle keine Ziffer eingegeben wurde, enthält das Byte eine "0").

Das 10 Byte-Array "Freq" muss jedoch noch auf 5 Byte eingedampft werden; die Bytes werden als Halbbytes (Nibbles) in das 5-Byte Array "Freqbyte" umsortiert (gerade Stellen ins untere Halbbyte; ungerade ins obere). Danach wird das komplette Telegramm gesendet: zwei Präambel Bytes, Geräteadresse, Absende Adresse, Befehlsbyte "Frequenzwechsel", 5 (bzw. 4) Frequenzbytes und das Ende Byte. Da der ursprünglich verwendete Befehl "PRINTBYTE freqbyte(n)" sonderbare Sachen machte (es wurde nicht nur das indizierte Byte, sondern das gesamte Array ausgesendet), wurde die umständlichere Variante "Print Chr(freqbyte(n));" verwendet.

Zum Schluss geht der Attiny2313 in den Sleep-Modus. Da bei meiner Bascom Version der Befehl "Powerdown" nicht wie erwartet funktionierte, ist das über direkte Registerbefehle und den Maschinenbefehl "`!Sleep"' gelöst. Mir war nicht so recht klar, ob Pin Change Interrupts bei einer Keyboard Matrix funktionieren, da alle Anschlüsse des Keyboards an IOs des Controllers angeschlossen sind, aber im Test klappte es einwandfrei.   

Die Pin Change Interrupts für Port B werden über die Registerbefehle

PCMSK = 255
GIMSK.5 = 1
SREG.7 = 1

ausgewählt und aktiviert.



Kurz-Bedienungsanleitung

CI-V-QSY-Box an den CI-V Anschluss des Funkgerätes anschalten, Mäuseklavier Schalter "4" auf "On"  stellen, dann die Betriebsspannung (5V aus 3 Mignonzellen oder aus einem Spannungsregler 12V/5V) anlegen.

Die Geräteadresse 4-stellig eingeben und mit "#" abschließen, z.B.  

 Geräteadresse 68 -> 0608#
 Geräteadresse 4A -> 0410#
 Geräteadresse FE -> 1514#

Die CI-V-Box geht dann in Powerdown und verbraucht praktisch keinen Strom.

Bei der Eingabe einer Frequenz werden die MHz Stellen eingegeben, dann ein "*", anschließend die kHz Stellen. Kurzeingaben sind möglich, z.B.

 7*03# -> 7,030 MHz
 7*#   -> 7 MHz
 936#  -> 0,936 MHz


Download: Quelltext, Hexfile und PDF: QSYbox.zip




'Frequenzeinstellung für ICOM-Amateurfunkgeräte

' Keyboardmatrix liegt an PortB
' Spalten von links nach rechts: PB0, PB1, PB2, PB3
' Reihen von oben nach unten: PB4, PB5, PB6, PB7

' Keyboardaufbau
'
' 1 2 3
' 4 5 6
' 7 8 9
' * 0 #

' Befehl GETKBD mappt letzte Zeile um: '
'
' 1 2 3
' 4 5 6
' 7 8 9
' 10 11 12

' Quittungston an PD6
' RxD / TxD PD0 / PD1
' Mäuseklavier an PD 2, 3, 4 , 5: Gerätevorwahl und Geschwindigkeit
' PD5 (Schalter"1") : 4800 bit/s
' PD4 (Schalter"2") : 9600 bit/s
' PD3 (Schalter"3") : 4bit-Modus (IC735)
' PD2 (Schalter"4") : nach Reset wird Geräteadresse abgefragt



' Rechengang:

' Frequenz: 1.234.567.890 Hz

' Tastatureingabe: 1234 * 56789 # -> <*> ist Ende MHz- Eingabe <#> ist <Enter>

' Sendefolge Frequenzbytes: 90 78 56 34 12

'
' Frequenz 4.567.890

' Tastatureingabe: 4 * 56789 #

' Sendefolge Frequenzbytes: 90 78 56 04 00


' Frequenz 567 kHz

' Tastatureingabe: 567 #

' Sendefolge Frequenzbytes: 00 07 56 00 00




' Version 2: Powerdown und Pin Change Interrupts eingebaut; dadurch kein
' Ruhestromverbrauch

' Version 3: bugfix
' Version 3a: bugfix und CLKPR zur Taktumschaltung 1 MHz -> 8 MHz
'
'--------------------------------------------------------------------



$regfile = "attiny2313.dat"
$crystal = 8000000 ' Der Controller kann auf 1 MHz Takt (Auslieferungszustand) verbleiben
' auf 8 MHz wird weiter unten umgeschaltet
$baud = 19200
$swstack = 32
$hwstack = 8
$framesize = 24


Ddrd = &B0100_0010
Portd = &B1011_1101

Ddrb = &B0000_0000
Portb = &B1111_1111

Porta = &B0000_1111


Dim B As Byte ' Zählvariablen
Dim I As Byte
Dim N As Byte
Dim M As Byte
Dim P As Byte
Dim Q As Byte
Dim Puffer(12) As Byte ' nimmt die eingegebenen Zeichen auf
Dim Str_len As Byte ' Anzahl eingegebener Zeichen
Dim Freq(10) As Byte ' Frequenz auf 10 Stellen normiert
Dim Pos As Byte ' Position "*"
Dim Fillup As Byte ' Zahl führender Nullen bei Formatierung von Freq(n)
Dim Freqbyte(5) As Byte ' 10-stellige Freq wird in 5 Bytes in Sendereihenfolge gewandelt
Dim Max_len As Byte ' Maximale akzeptierte Tastatureingaben
Dim Address As Byte
Dim Num_bytes As Byte

Const Preamble = &HFE ' zwei Bytes, die am Anfang jeden Telegramms stehen müssen
Const Pcaddress = &HE0 ' PC- Adresse
Const Setfrq = &H05 ' CAT- Befehl "Frequenz einlesen"
Const Eom = &HFD ' muss am Ende des Telegramms stehen

Const Biip = 100 ' Laenge Sound
Const Boop = 600
Const Biipfrq = 400 ' kleiner ist höher
Const Boopfrq = 1200


Buzzer Alias Portd.6
Rigsel Alias Pind.2
Fourbyte Alias Pind.3
Speed1 Alias Pind.4
Speed2 Alias Pind.5
Config Kbd = Portb , Debounce = 40 , Delay = 100

Gimsk.5 = 1
Sreg.7 = 1
Pcmsk = 255

Clkpr = 128 ' Taktumschaltung vorbereiten
Clkpr = 0 ' Vorteiler auf Teilerverhältnis 1 setzen
Clkpr = 0 ' zur Sicherheit wiederholen





' erst mal Mäuseklavier abfragen:


If Speed1 = 0 Then
Baud = 9600
End If

If Speed2 = 0 Then
Baud = 4800
End If

Num_bytes = 5

If Fourbyte = 0 Then
Num_bytes = 4 ' IC735- Modus
End If




' wenn Rig- Pin aktiviert, Geräteadresse abfragen:
' (Eingabeformat: die zwei Hexziffern jeweils 2-stellig (also mit führender 0) eingeben
' Hexziffern > 9 als zwei Ziffern (z.B. D -> 13). Abschliessen mit "#"
' Beispiele:
' Geräteadresse 68 -> 0608#
' Geräteadresse 4A -> 0410#
' Geräteadresse FE -> 1514#



If Rigsel = 0 Then

Max_len = 5 ' nach mehr als 5 Zeichen: Fehlermeldung
Gosub Read_kbd

For N = 1 To 4

If Puffer(n) = 0 Then ' wenn weniger als 4 Ziffern eingegeben wurden
Gosub Murks
End If

If Puffer(n) = 11 Then ' Taste "0" liefert "11"; wird hier durch "0" ersetzt
Puffer(n) = 0
End If

Next


Address = Puffer(2) ' zweite eingegebene Ziffer

If Puffer(1) = 1 Then ' ist die erste Ziffer eine "1", 10 addieren
Address = Address + 10
End If

Shift Address , Left , 4 ' Wert ins obere Halbbyte schieben

Address = Address + Puffer(4) ' vierte eingegebene Ziffer addieren

If Puffer(3) = 1 Then
Address = Address + 10 ' ist die dritte Ziffer eine "1", 10 addieren
End If

Writeeeprom Address , 16 ' Byte ins EEProm an Adresse 16 schreiben

End If







Main:


Readeeprom Address , 16 ' Geräteadresse aus EEProm- Adrssse 16 auslesen


Do

Max_len = 11
Gosub Read_kbd



' umsortieren aus Puffer in das 10- Byte Array Freq(n)

N = 0
Pos = 0
Do ' String (bzw. Array) durchsuchen
N = N + 1
If Puffer(n) = 10 Then
Pos = N ' Position suchen, an der Taste "*" steht
End If
Loop Until Puffer(n) = 0 ' letztes eingegebenes Zeichen suchen

Str_len = N - 1 ' Stringlenge ist einer weniger
Fillup = 5 - Pos ' Zahl der führenden Nullen in Freq(n)


If Pos > 0 Then ' es gibt ein Zeichen "*" = 011

Decr Pos
For N = 1 To Pos ' die Zeichen im Puffer vor dem "*" hinter die führenden "0" in Freq(n) schreiben
I = N + Fillup
Freq(i) = Puffer(n)
Next
Pos = Pos + 2 ' auf das Zeichen hinter dem "*" positionieren
End If

If Pos = 0 Then ' wenn es kein "*" gab, bei 1 loslegen
Incr Pos
End If

For N = Pos To Str_len ' die restlichen Zeichen hinter dem "*" in Freq(n) schreiben
I = N + Fillup
Decr I
Freq(i) = Puffer(n)
Next


' die Taste "0" ist noch mit "11" codiert; 11 durch 0 ersetzen

For N = 1 To 10
If Freq(n) = 11 Then
Freq(n) = 0
End If
Next


' aus 10 Byes 5 machen und Reihenfolge umstellen

For M = 1 To 5

Q = 2 * M
P = 11 - Q
Freqbyte(m) = Freq(p) ' ungerade Stellen aus Freq(n) holen
Shift Freqbyte(m) , Left , 4 ' vom unteren Nibble ins obere Nibble schieben
Freqbyte(m) = Freqbyte(m) + Freq(p + 1) ' gerade Stellen aus Freq(n) ins untere Nibble schreiben

Next


' komplettes Telegramm senden :

Print Chr(preamble);
Print Chr(preamble);
Print Chr(address);
Print Chr(pcaddress);
Print Chr(setfrq);
For N = 1 To Num_bytes
Print Chr(freqbyte(n));
Next
Print Chr(eom);

Waitms 500 ' Wartezeit, damit UART- Zeichenpuffer geleert werden kann

Mcucr = &B0111_0000 ' Powerdown
!Sleep
Mcucr = 0 ' Sleep enable aufheben
Loop




Read_kbd:


' Tastatur lesen, mit Lookup umcodieren, Bytes in Array Puffer(n) schreiben

For N = 1 To 12
Puffer(n) = 0
Next
For N = 1 To 10
Freq(n) = 0
Next


N = 1

Do

Restore Matrix

Do
B = Getkbd()
Loop Until B <> 16 ' 16 : keine Taste gedrückt

Puffer(n) = Lookup(b , Matrix)

Do ' Prüfen, ob Taste losgelassen
B = Getkbd()
Loop Until B = 16

If N > Max_len Then ' Zeichenkette zu lang
Gosub Murks
Goto Main ' auf Anfang
End If

Gosub Quittung ' Quittungston

If Puffer(n) = 12 Then ' Taste "Raute" gedrückt
Puffer(n) = 0 ' durch "0" ersetzen
Gosub Enter ' Eingabe fertig; Rückkehr
Return
End If

Incr N

Loop

Return






Quittung:

Sound Buzzer , Biip , Biipfrq

Return


Enter:

Sound Buzzer , Boop , Biipfrq

Return


Murks:

Sound Buzzer , Boop , Boopfrq

Return



End




' Data

Matrix:

Data 1 , 2 , 3 , 255 , 4 , 5 , 6 , 255 , 7 , 8 , 9 , 255 , 10 , 11 , 12 , 12



Elektronik-Labor   Projekte   AVR