2-Kanal-Funkschaltinterface

Software

Der Bascom-Quellcode ist eigentlich gut dokumentiert, somit ist zur Software eigentlich nicht viel zu erläutern. Zuerst werden der Prozessortyp, dessen Taktfrequenz und die Stacks definiert:

'2-Kanal-Funk-Schaltinterface für Fernbedienung FS10, AM-Empfänger HFS301 433 MHz
$regfile = "attiny44.dat"
$hwstack = 32
$swstack = 10
$framesize = 40
$crystal = 8000000                                          ' 8 MHz interner Oszillator

Als nächstes werden 4 Portpins als Ausgänge deklariert und mit Aliasnamen versehen. Da Ausgänge beim Programmstart auf Low-Pegel sind und die Leuchtdioden nicht leuchten sollen, werden sie auf High-Pegel geschaltet (Set Ledx).

Config Porta.= Output
Led1 Alias Porta.0                                          ' LED 1
Set Led1                                                    ' LED ausschalten
Config Porta.= Output
K1 Alias Porta.1                                            ' Relais 1
Config Porta.= Output
K2 Alias Porta.2                                            ' Relais 2
Config Porta.= Output
Led2 Alias Porta.3                                          ' LED 2
Set Led2                                                    ' LED ausschalten

Danach definieren wir die Variablen, die wir benötigen. Die Einstellungen für die Tastaturebene und den Hauscode werden im EEPROM des AVR dauerhaft gespeichert (Eram)..

Dim Rxbit As Byte                                           ' empfangenes Bit
Dim Rxready As Byte                                         ' Interrupt fertig
Dim Rxcycle As Byte                                         ' Wellenlänge
Dim Count As Byte                                           ' Zähler
Count = 42                                                  ' 42 Bits empfangen
Dim Praeambel(8) As Byte                                    ' 8 Bit Präambel
Dim Typ(4) As Byte                                          ' 4 Bit Typ
Dim Code(30) As Byte                                        ' 30 Bits Daten
Dim Taste As Byte                                           ' Taste
Dim Ebene_l As Byte                                         ' Tastaturebene low
Dim Ebene_l_k1 As Byte                                      ' eigene Tastaturebene Kanal 1 low
Dim Ebene_l_k1_eram As Eram Byte                            ' EEPROM eigene Tastaturebene Kanal 1 low
Dim Ebene_l_k2 As Byte                                      ' eigene Tastaturebene Kanal 2 low
Dim Ebene_h As Byte                                         ' Tastaturebene high
Dim Ebene_he As Byte                                        ' eigene Tastaturebene high
Dim Ebene_he_eram As Eram Byte                              ' EEPROM eigene Tastaturebene high
Dim Hauscode As Byte                                        ' Hauscode
Dim Hauscode_e As Byte                                      ' eigener Hauscode
Dim Hauscode_e_eram As Eram Byte                            ' EEPROM eigener Hauscode
Dim Check As Byte                                           ' Prüfsumme
Dim Rxpari As Byte                                          ' Paritätsbit empfangen
Dim Erpari As Byte                                          ' Paritätsbit errechnet
Dim Startbit As Byte                                        ' Startbit für Umwandlung Empfangscode
Dim Sekunde As Byte                                         ' Sekundentakt
Dim Setup As Byte                                           ' Einstellung speichern
Dim Temp As Byte                                            ' Code temporär
Dim Tmr1_pre As Word                                        ' Timer Preload
Tmr1_pre = &HC2F7                                           ' 0,5 Sek Takt bei 8 MHz
Dim X As Byte                                               ' temporär

Danach werden die im EEPROM gespeicherten Werte für die Tastaturebene und den Hauscode in den RAM übernommen:

Ebene_l_k1 = Ebene_l_k1_eram                                ' gespeicherte Tastaturebene Kanal 1 low auslesen
Ebene_l_k2 = Ebene_l_k1 + 1                                 ' Tastaturebene Kanal 2 low errechnen
Ebene_he = Ebene_he_eram                                    ' gespeicherte Tastaturebene high auslesen
Hauscode_e = Hauscode_e_eram                                ' gespeicherten Hauscode auslesen

Es werden 2 Timer eingerichtet. Timer 0 ist ist ein 8-bit-Timer und wird verwendet für die Messung der Wellenlänge der Empfangsdaten des 433-MHz-Empfängers. Timer 1, ein 16-bit-Timer, wird verwendet, um die Dauer eines Tastendruckes zu ermitteln bzw. nach Ablauf einer Zeit die Setup-Routine wieder zu verlassen.

'8-bit Timer für Wellenlänge 800 µS (0), 1200 µS (1)
Config Timer0 = Timer , Prescale = 64                       ' 8 µS, Overflow 2048.000 µSec
'16-bit Timer für Laufzeitmessungen
Config Timer1 = Timer , Capture Edge = Rising , Prescale = 256       ' 32 µS, Overflow 2097.152 mSec
Enable Timer1
On Timer1 Tmr1_ovfl
Stop Timer1

Pin A.7 wird als Eingang für den Anschluss eines Tasters konfiguriert. Verwendet wird er als Input Capture Pin und löst damit bei jedem Tastendruck einen Interrupt aus. Angesprungen wird dadurch das Label "Tast_icp1". Ein zweiter Eingang wird für den Anschluss des Empfängers verwendet. Hierfür ist unbedingt ein Interrupt notwendig, da sofort auf jedes empfangene Signal reagiert werden muss.

Config Pina.= Input                                       ' Taster, normal low
On Capture1 Tast_icp1                                       ' Interruptaufruf ICP
Enable Capture1                                             ' Interrupt einschalten

Config Pinb.= Input                                       ' RX Input FS10
Config Int0 = Rising                                        ' Interrupt bei steigender Flanke
On Int0 Fs10_int0                                           ' Interruptaufruf
Enable Int0                                                 ' Interrupt einschalten

Um ein wenig Strom zu sparen werden noch unbenötigte Teile des Prozessors abgeschaltet und vor Beginn des Hauptprogrammes die Interrupts global eingeschaltet.

Stop Ac                                                     ' Strom sparen
Stop Adc                                                    ' Strom sparen
Stop Watchdog                                               ' Strom sparen

Enable Interrupts

Im Hauptprogramm erfolgt die Dekodierung der empfangenen Bits. Insgesamt werden 43 Bit pro Befehl übertragen. Der Bitzähler zählt abwärts. Deshalb beginnt die Dekodierung bei Bit 42. Zuerst werden werden 8 Bits mit Wert 0 übertragen. Sollte ein Bit davon 1 sein, wird die Dekodierung abgebrochen, der Bitcounter auf den Startwert 42 gesetzt und zum Start gesprungen. Als nächste 4 Bit folgt der Typ, im Falle der Fernbedienung auch alles Nullen. Auch in dieser Abfrage erfolgt wieder ein Abbruch bei Empfang einer 1. Die Bits 0 bis 30 werden in das Array "Code" übernommen. Nach jedem empfangenen Bit wird der Counter um 1 verringert.

'# # # # # # # # # # # # # # # #   Hauptprogramm Endlosschleife   # # # # # # # # # # # # # # # #
Do
   Start:                                                   ' Beginn Übernahme empfangener Bits
      Config Powermode = Idle                               ' Strom sparen
      Bitwait Rxready , Set                                 ' warten auf gesetztes Bit
      Rxready = 0                                           ' Interrupt fertig zurück setzen
      If Count >= 35 Then                                   ' Bit 42-35 Präambel
         If Rxbit = 1 Then                                  ' Präambel muss 0 sein
            Count = 42                                      ' Zaehler zurück setzen
            Goto Start                                      ' Abfrage neu starten
            Else
               X = Count - 34                               ' Praeambel ermitteln
               Praeambel(x) = Rxbit                         ' Bit in Praeambel übernehmen
         End If
         Elseif Count >= 31 Then                            ' Bit 34-31 Typ
            If Rxbit = 1 Then                               ' Typ muss 0 sein
               Count = 42                                   ' Zaehler zurück setzen
               Goto Start                                   ' Abfrage neu starten
               Else
                  X = Count - 30                            ' Typ ermitteln
                  Typ(x) = Rxbit                            ' Bit in Typ übernehmen
            End If
            Else
               Code(count) = Rxbit                          ' Bit 30-1
      End If                                                ' Ende Übernahme empfangener Bits
      Decr Count                                            ' Zähler verringern

Wenn alle 43 Bits empfangen wurden, d.h. der Zähler auf 0 steht, erfolgt die Dekodierung der einzelnen Sequenzen. Jedes 5. Bit muss 1 sein. Sollte dies nicht der Fall sein, wird die Auswertung abgebrochen und wieder zum Start gesprungen. Danach erfolgt die Erfassung der Tastaturebene, des Hauscodes und einer Checksumme. Falls diese nicht mit der errechneten Prüfsumme übereinstimmt, wird auch hier wieder abgebrochen und zum Start gesprungen.

      ' Gültigkeit empfangener Bits prüfen
      If Count = 0 Then                                     ' 42 Bit empfangen
         Count = 42                                         ' Zaehler zurück setzen
         If Code(30) = 0 Or Code(25) = 0 Or Code(20) = 0 Or Code(15) = 0 Or Code(5) = 0 Then
            Goto Start                                      ' jedes 5. Bit muss 1 sein
         End If
         Startbit = 26                                      ' Bit 26-28 - Taste
         Gosub Wandeln
         Taste = Temp                                       ' Taste übernehmen
         Startbit = 21                                      ' Bit 21-23 - Ebene low
         Gosub Wandeln
         Ebene_l = Temp                                     ' Ebene low übernehmen
         Startbit = 16                                      ' Bit 16-18 - Ebene high
         Gosub Wandeln
         Ebene_h = Temp                                     ' Ebene high übernehmen
         Startbit = 6                                       ' Bit 6-8 - Hauscode
         Gosub Wandeln
         Hauscode = Temp                                    ' Hauscode übernehmen
         Startbit = 1                                       ' Bit 1-3 - Checksumme
         Gosub Wandeln
         Check = Temp                                       ' Checksumme übernehmen
         X = Taste                                          ' Quersumme errechnen
         X = X + Ebene_l                                    ' Quersumme errechnen
         X = X + Ebene_h                                    ' Quersumme errechnen
         X = X + Hauscode                                   ' Quersumme errechnen
         If X >= 11 Then
            X = 18 - X                                      ' Quersumme + Checksumme = 18
            Else
               X = 10 - X                                   ' Quersumme + Checksumme = 10
         End If
         If X <> Check Then                                 ' Checksumme prüfen
            Goto Start
         End If                                             ' fertig Gültigkeit empfangener Bits prüfen

Falls sich das Programm im Setup-Modus befindet, werden die empfangenen Befehle übernommen, im EEPROM gespeichert, die Kontroll-LED abgeschaltet und die Timer zurück gesetzt.

         ' Einstellungen speichern
         If Setup = 1 Then                                  ' empfangene Codes speichern
            If Ebene_l < 4 Then                             ' Ebene darf nicht 4 sein
               Hauscode_e = Hauscode                        ' empfangenen Hauscode übernehmen
               Ebene_l_k1 = Ebene_l                         ' empfangenen Ebene low Kanal 1 übernehmen
               Ebene_l_k2 = Ebene_l + 1                     ' empfangenen Ebene low Kanal 2 errechnen
               Ebene_he = Ebene_h                           ' empfangenen Ebene high übernehmen
               Hauscode_e_eram = Hauscode                   ' Hauscode im EEPROM speichern
               Ebene_l_k1_eram = Ebene_l                    ' Ebene low im EEPROM speichern
               Ebene_he_eram = Ebene_h                      ' Ebene high im EEPROM speichern
               Setup = 0                                    ' Setup deaktivieren
               Sekunde = 0                                  ' Sekundenzaehler auf 0
               Stop Timer1                                  ' Sekunden-Timer anhalten
               Set Led1                                     ' LED ausschalten
               Tmr1_pre = &HC2F7                            ' 0,5 Sek Takt bei 8 MHz
               Else
                  Tmr1_pre = &HF0BE                         ' schnelles Blinken
            End If
         End If

Sollte der empfangene Hauscode und die Tastaturebene mit den gespeicherten Werten übereinstimmen, wird das dazu gehörige Relais und die LED ein- bzw. ausgeschaltet.

         ' empfangene Codes vergleichen und auswerten
         If Hauscode = Hauscode_e Then                      ' Hauscode vergleichen
            Hauscode = 255                                  ' nur einmal ausführen
            If Ebene_h = Ebene_he Then                      ' Ebene high vergleichen
               If Ebene_l = Ebene_l_k1 Then                 ' Ebene low Kanal 1 vergleichen
                  K1 = Taste.0                              ' K1 Ausgang schalten
                  Led1 = Not K1                             ' LED 1 schalten
               End If
               If Ebene_l = Ebene_l_k2 Then                 ' Ebene low Kanal 2 vergleichen
                  K2 = Taste.0                              ' K2 Ausgang schalten
                  Led2 = Not K2                             ' LED 2 schalten
               End If
            End If
         End If
      End If
Loop
End

Damit ist die Hauptschleife beendet und es folgt ein Unterprogramme zur Übernahme von jeweils 3 Bit in ein Byte. Das jeweilige 1. Bit ist ein Paritätsbit. Sollte das errechnete Paritätsbit nicht mit dem empfangenen übereinstimmen, wird die Dekodierung abgebrochen.

'##############################   U N T E R P R O G R A M M E   ##############################
Wandeln:
   X = 0
   Erpari = 1                                               ' Parität gerade
   Do
      Temp.= Code(startbit)                               ' Code in temporäres Byte übernehmen
      Erpari = Erpari + Temp.x                              ' Summe von Bit 0 bis 2 ermitteln
      Incr X
      Incr Startbit
   Loop Until X = 3                                         ' 3 Bit übernehmen
   Rxpari = Code(startbit)                                  ' Bit 4 - Paritätsbit übernehmen
   Erpari = Erpari And 1                                    ' Parität errechnen
   If Rxpari <> Erpari Then                                 ' Parität vergleichen
      Goto Start                                            ' abbrechen
   End If
Return

Die erste Interruptroutine wird aufgerufen, wenn ein Tastendruck erkannt wurde. Es erfolgt nur der Start von Timer 1.

'##############################   Interruptroutinen und Timer   ##############################
Tast_icp1:                                                  ' Taste betätigt
   Sekunde = 0                                              ' Sekunden zurück setzen
   Start Timer1                                             ' Timer 1 starten
   Timer1 = Tmr1_pre                                        ' Timer laden
Return

Der zweite Interrupt wird ausgelöst durch einen Pegelwechsel von 0 auf 1 am Eingang, der mit dem Empfänger verbunden ist. Hier wird die Zeit zwischen zwei Interrupts mittels Timer 0 erfasst. Sollte diese kleiner 600 oder größer 1400 Mikrosekunden sein, so wird der Counter wieder auf seinen Startwert zurück gesetzt. Zeiten zwischen 600 bis 1000 Mikrosekunden bedeuten, das eine 0 empfangen wurde und eine 1 bei Zeiten von 1008 bis 1400 Mikrosekunden.

Fs10_int0:                                                  ' Funk-Empfang
   Rxcycle = Timer0                                         ' Dauer übernehmen
   Timer0 = 0                                               ' Timer zurück setzen
   Select Case Rxcycle
      Case Is < 75                                          ' kleiner 600 µs
         Count = 42                                         ' reset bitcounter
      Case 75 To 125                                        ' 600-1000µs, 0-bit
         Rxbit = 0                                          ' empfangenes Bit = 0
         Rxready = 1                                        ' Auswertung fertig
      Case 126 To 175                                       ' 1008-1400 µs, 1-bit
         Rxbit = 1                                          ' empfangenes Bit = 1
         Rxready = 1                                        ' Auswertung fertig
      Case Is >= 176                                        ' größer 1400 µs
         Count = 42                                         ' reset bitcounter
   End Select
Return

Die letzte Interruptroutine wird durch einen Überlauf von Timer 1 aufgerufen. Sollte der Taster betätigt sein, so wird die LED eingeschaltet und nach 5 Sekunden ins Setup gewechselt. Die LED beginnt nach Ablauf dieser Zeit zu blinken. Wenn vor Ablauf dieser Zeit der Taster nicht mehr geschlossen ist, wird die LED ausgeschaltet und der Timer wieder angehalten. Nach einer Minute wird der Setup-Modus wieder abgebrochen.

Tmr1_ovfl:
   Incr Sekunde                                             ' Sekundenzaehler
   Timer1 = Tmr1_pre                                        ' Timer laden
   If Pina.= 1 Then                                       ' wenn Taster betätigt
      If Setup = 0 Then
         Reset Led1                                         ' LED einschalten
      End If
      If Sekunde >= 10 Then                                 ' nach 5 Sekunden
         Setup = 1                                          ' Setup aktivieren
      End If
   End If
   If Pina.= 0 And Setup = 0 Then                         ' Taster nicht betätigt
      Set Led1                                              ' LED ausschalten
      Sekunde = 0
      Stop Timer1                                           ' Sekunden-Timer anhalten
   End If
   If Setup = 1 Then
      Toggle Led1                                           ' LED blinkt
   End If
   If Sekunde >= 120 Then                                   ' nach 60 Sekunden
      Setup = 0                                             ' Setup deaktivieren
      Sekunde = 0                                           ' Sekundenzaehler auf 0
      Stop Timer1                                           ' Sekunden-Timer anhalten
      Set Led1                                              ' LED ausschalten
   End If
Return