Programmierung von RFM12b mit RN-MikroFunk

RN-MikroFunk und Funkmodul RFM12b

Im letzten Beitrag haben wir das Projekt RN-MikroFunk vorgestellt: Eine Bauanleitung zu einem programmierbaren AVR Mikrocontroller-Board mit dem Funkmodul RFM12b sowie einem ATMega-Mikrocontroller. Wie das Ganze im Hinblick auf das Funkmodul programmiert werden kann und welche Befehle das Funkmodul RFM12 bzw. RFM12b versteht, dass wird in diesem Beitrag anhand einiger Beispiele demonstriert.

Funkmodul RFM12b bzw. RFM12

RFM12b Universelles FunkmodulRM-MikroFunk lässt sich auf der Unterseite mit einem Funkmodul vom Typ RFM12b oder RFM12 bestücken. Dieses Funkmodul ist recht weit verbreitet und im Internet gibt es jede Menge Informationen und Programme die Sie verwenden können. Auch die Programme unseres Schwestermoduls RN-AvrUniversal können fast ohne Änderung übernommen werden. Zudem ist RN-AVR Universal dann auch funkkompatibel zu RN-MikroFunk.

Beachten Sie, dass es das Funkmodul RFM12(b) auch für verschiedenen Frequenzbereichen gibt, einmal für den 868 Mhz und einmal für den 433 Mhz Bereich.

Achtung: Für diese Funkbereiche gibt es genaue Vorschriften wie stark die Sendeleistung sein darf und welche Kanäle wie stark belegt werden dürfen. Bitte beachten Sie unbedingt dass beim Betrieb des Funkmodules diese gesetzlichen Bestimmungen eingehalten werden.

Der Betrieb darf nur in freigegebenen Frequenzbereichen mit der maximal erlaubten Sendeleistung und Sendedauer erfolgen. Bitte entnehmen Sie diese Informationen bei der jeweils zuständigen Behörde. Für Deutschland finden Sie diese Informationen unter http://www.bundesnetzagentur.de/ .

RN-MikroFunk Unterseite der leiterplatte mit Funkmodul

RN-MikroFunk Unterseite der leiterplatte mit Funkmodul

Wir empfehlen Ihnen die 433 Mhz Module, nur diese wurden von uns ausgiebig getestet. Dieser Frequenzbereich hat den Vorteil, dass die Kanalnutzung wesentlich freizügiger geregelt ist, als bei dem 868 Mhz Bereich. Mit diesen Modulen ist es somit einfacher sich an die rechtlichen Vorgaben zu halten.
Im Bild rechts erkennen Sie wie das Funkmodul auf der Unterseite von RN-MikroFunk aufgelötet wird.

Durch das Bestücken eines Funkmoduls können sich quasi mehrere Boards untereinander verständigen bzw. ein Board könnte die Daten auch an einen PC weitergeben welcher wiederum die Daten weitergibt oder auch darauf reagiert.

Die Anwendungen sind vielfältig, insbesondere da RN-MikroFunk trotz Controller und Funkmodul noch so klein und stromsparend ist!

So wären Alarmanlagen denkbar wo RN-MikroFunk praktisch mit Bewegungssensoren, Fenster- oder Türkontakten usw. ausgerüstet wird und den Alarm per Funk an eine Zentrale (vielleicht ebenfalls RN-MikroFunk oder RN-AVR Universal) meldet. Oder aber Haussteuerungen mit Überwachungen von Zimmertemperaturen , Heizung usw. Oder einfache Fernbedienung von fahrbaren Modellfahrzeugen oder Robotern. Vieles ist denkbar, mit RN-MikroFunk können Sie vieles erproben.

Die Funkmodule RFM12 und RFM12b sind weitgehend identisch. Der wesentliche Unterschied besteht darin, dass das neuere Modul  RFM12b nur noch bis 3,3V betrieben werden darf, das Modul RFM12 dagegen war für den 5V Betrieb ausgelegt.

Erstes RN-MikroFunk Testprogramm für RFM12b

Das Beispielprogramm „Funkmodul RFM12 Test.bas“ demonstriert die Programmierung des Funkmoduls. Laden Sie dieses Programm in zwei Funkmodule. Nach der Übertragung senden und empfangen beide Boards im Wechsel 10 Bytes und geben diese über die serielle Schnittstelle (angeschlossene USB-Modul) aus. Über ein Terminal-Programm können Sie den Datenaustausch beobachten.

Wenn Sie nun ein Board ausschalten, dann erscheint bei dem anderen „Kein Datenempfang“.

„Kein Datenempfang“ kann bei diesem Beispiel jedoch auch auftreten wenn beide Funkmodule an sind. Der Zeitintervall in dem die Funkmodule im Wechsel senden (genauer das Timeout) wird hier per Zufall gewählt, dadurch kann es passieren dass die Module zeitweise, insbesondere beim Start, gleichzeitig senden und sich so nicht empfangen können. Man sollte sich hier ein geeignetes Übertragungsprotokoll einfallen lassen damit gleichzeitiges Senden möglichst vermieden wird. Zum Beispiel könnte ein Funkmodul senden, und dann solange auf Empfang gehen bis bestimmte Daten kommen und erst dann wieder senden. Es gibt viele Möglichkeiten.

Das Programm soll nur ein schnellen Test der Funkmodule gewährleisten. Laden Sie es einfach unverändert in zwei RN-MikroFunk Module und verbinden Sie eines über die RS232 (oder über ein USB-Modul) mit dem PC.

Als Antenne reicht ein kleines Stück Draht. Die normale Drahtlänge sollte bei 433 Mhz 17 cm sein. Um andere Empfänger, vielleicht in der Nachbarschaft, nicht zu stören, können Sie aber die Reichweite durch das komplette Weglassen der Antenne auch auf ein paar Meter beschränken. Das sollten Sie solange tun, bis Sie sich mit dem Funkmodul und den Vorschriften vertraut gemacht haben.

Das Programm ist wieder in Bascom verfasst, natürlich lässt sich das auch leicht auf C umschreiben falls man C vorzieht. Weiter unten auf dieser Seite finden Sie alle Beispiele zum Herunterladen als Download-Link.

'##############################################################
'Funkmodul RFM12 Test.bas
'
'Ein Testprogramm für die Universalplatine RN-MikroFunk
'
'Das Programm demonstriert wie sich Daten per Funk austauschen lassen
'Laden Sie das Programm unverändert in zwei RN-MikroFunk Module
'die mit einem Funkmodul ausgestattet sind.
'Nach dem Start senden und empfangen die Module abwechselnd
'Werden Daten empfangen werden die über die RS232/USBmodul ausgegeben
'Werden keine Daten empfangen, wird "Kein Datenempfang" ausgegeben.
'Dies ist nur ein Beispielprogramm das für eigene Zwecke beliebig
'angepasst werden kann
'
'Weitere Beispiele auf www.mikrocontroller-elektronik.de
'######################################################################

$programmer = 12 'Bascom USB Programmer (Zeile weglassen wenn anderer Programmer)
$PROG &HFF,&HFF,&HD9,&HFF 'Diese Anweisung stellt Fusebits ein
$regfile = "m328pdef.dat"

$framesize = 32
$swstack = 32
$hwstack = 64
$crystal = 8000000 'Quarzfrequenz
$baud = 9800 'Baudrate (Übertragungsgeschwindigkeit)
Baud = 9800

Declare Sub Rfm12_init
Declare Sub Rfm12_setfrequenz
Declare Sub Rfm12_empfange
Declare Sub Rfm12_senden
Declare Function Spitransfer(byval Dout As Word) As Word

Config Pind.2 = Input 'Int0
Portd.2 = 1 'Pullup
Config Int0 = Falling
Enable Interrupts
Enable Int0
On Int0 Funkirq

Ss Alias Portb.2
Mosi Alias Portb.3
Miso Alias Pinb.4
Sck Alias Portb.5

Config Ss = Output
Config Mosi = Output
Config Sck = Output

Dim Datenbytes As Byte
Dim D As Word
Dim Eingangsdaten(20) As Byte
Dim Ausgabedaten(20) As Byte
Dim N As Byte
Dim Timeout As Word
Dim T As Word
Dim Tt As Word
Dim Frequenz As Single

Ss = 1
Sck = 0
Rfm12_init
Frequenz = 434.150
Rfm12_setfrequenz

Do
 For N = 1 To 10 'Datenbytes mit beliebigen Werten füllen
  Ausgabedaten(n) = N
 Next N

 Rfm12_senden
 Waitms 500
 Timeout = 400 + Rnd(1000)
 Rfm12_empfange

 If Datenbytes = 0 Then
  Print "Kein Datenempfang"
 Else
  Print
  Print "Datenbytes:" ; Datenbytes
  For N = 1 To Datenbytes
   Print Eingangsdaten(n);
   Print " ";
  Next N
 End If

 Waitms 700
 Loop


' ************ Hilfsfunktionen zur Kommunikation mit Funkmodul **************
' (nähere Infos im Datenblatt des Funkmoduls)

' Initialisiere Funkmodul

Sub Rfm12_init
 D = Spitransfer(&H80d7) '433 MHz
 'D = spitransfer(&H80e7) '868 MHz
 D = Spitransfer(&H82d9)
 D = Spitransfer(&Ha67c) '434,15 MHz / 868,3 MHz
 D = Spitransfer(&Hc647) '4.8kbps
 D = Spitransfer(&H94a4)
 D = Spitransfer(&Hc2ac)
 D = Spitransfer(&Hca81)
 D = Spitransfer(&Hc483)
 D = Spitransfer(&H9850)
 D = Spitransfer(&He000)
 D = Spitransfer(&Hc800)
 D = Spitransfer(&Hc000)

 D = Spitransfer(&H0000)
 Waitms 200
End Sub

Sub Rfm12_setfrequenz
 If Frequenz < 800 Then Frequenz = Frequenz * 2
 Frequenz = Frequenz - 860
 D = Frequenz / 0.0050
 If D < 96 Then D = 96
 If D > 3903 Then D = 3903
 D = D + &HA000
 D = Spitransfer(d)
End Sub

Sub Rfm12_empfange
 Tt = Timeout * 10
 D = Spitransfer(&H82c8)
 D = Spitransfer(&Hca83)
 Datenbytes = 0
 For N = 1 To 10
  Ss = 0
  T = 0
  Do
   T = T + 1
   Waitus 100
   If T > Tt Then Goto Nosignal
  Loop Until Miso = 1
  D = Spitransfer(&Hb000)
  Eingangsdaten(n) = D
  Datenbytes = Datenbytes + 1 'Anzahl der empfangenen Bytes merken
 Next N

Nosignal:
 D = Spitransfer(&H8208)

End Sub

Sub Rfm12_senden
 D = Spitransfer(&H8238)
 Gosub Rfm12_warte
 D = Spitransfer(&Hb8aa)
 Gosub Rfm12_warte
 D = Spitransfer(&Hb8aa)
 Gosub Rfm12_warte
 D = Spitransfer(&Hb8aa)
 Gosub Rfm12_warte
 D = Spitransfer(&Hb82d)
 Gosub Rfm12_warte
 D = Spitransfer(&Hb8d4)
 For N = 1 To 10
  Gosub Rfm12_warte
  D = &HB800 + Ausgabedaten(n)
  D = Spitransfer(d)
 Next N
 Gosub Rfm12_warte
 D = Spitransfer(&Hb8aa)
 Gosub Rfm12_warte
 D = Spitransfer(&Hb8aa)

 Gosub Rfm12_warte
 D = Spitransfer(&H8208)

End Sub

Function Spitransfer(byval Dout As Word) As Word
Local Nspi As Integer
Local Dspi As Integer
Local Dmiso As Word
 Ss = 0
 Dmiso = 0
 For Nspi = 1 To 16
  Dspi = Dout And &H8000
  If Dspi = 0 Then
  Mosi = 0
 Else
  Mosi = 1
 End If

 Dout = Dout * 2
 Dmiso = Dmiso * 2
 Dmiso = Dmiso + Miso
 Sck = 1
 Waitus 5
 Sck = 0
 Next Nspi
 Ss = 1

 Spitransfer = Dmiso
End Function

Rfm12_warte:
 Ss = 0
 Do
 Loop Until Miso = 1
Return


'Wird hier eigentlich nicht benötigt - arbeitet ohne IRQ
Funkirq:
Return

 

Erläuterungen zum Funkmodul RFM12b

RFM12b Universelles FunkmodulDas Funkmodul RFM12 bzw. RFM12b (neuere Version für 3,3V Spannung) das bei RN-MikroFunk bestückt werden kann, stammt von der Firma Hope-RF und wird u.a. über Ebay oft sehr preiswert angeboten (Marktpreis deutlich unter 10 Euro, oft ca. 5 Euro).

Unter den Downloads (weiter unten auf dieser Seite) finden Sie Datenblätter zu diesem Funkmodulen, dort werden die Features, Pinbelegung und die Register zur Programmierung genau beschrieben. Mehr ist eigentlich nicht notwendig um damit arbeiten zu können. Es gibt auch im Internet noch viele weitere Webseiten wo die Module beschrieben und Projekte zu finden sind, einige Links finden Sie ebenfalls am Ende dieses Beitrags.

Um ihnen den Einstieg etwas zu erleichtern, möchte ich jedoch noch ein paar grundsätzliche Dinge zu den Funkmodulen beschreiben.

Zunächst die Pinbelegung von RFM12 bzw. RFM12b

Die Module RFM12 / RFM12b sind Pin-kompatibel, der wesentliche Unterschied ist das RFM12 wohl für 5V Logikspannung und das neuere RFM12b für 3,3V Betrieb konzipiert ist. Auch der Befehlssatz ist fast identisch, die meisten Programme können ohne Änderungen für beide Module genutzt werden.

Funkmodul Pinbelegung RFM12b und RFM12Insgesamt hat das Modul 14 Anschlüsse, wobei jedoch für die Verwendung nicht alle Anschlüsse benötigt werden. Bei RN-MikroFunk sind natürlich alle notwendigen Anschlüsse bereits über die Platine mit dem Controller ATMega328P verbunden, Das wären die SPI Pins SDO, SCK, SDI, nSEL sowie die Betriebsspannung VDD und GND. Zusätzlich ist auch nIRQ mit einem IRQ Eingang vom Controller verbunden, das erlaubt zum Beispiel auch den Interrupt gesteuerten Empfang. NRES ist mit Reset verbunden und der Antennenanschluss ist über die Stiftleiste bei RN-MikroFunk herausgeführt. Alle anderen Pin´s werden nicht benötigt. In der nachfolgenden Tabelle beschreiben wir dennoch alle Pin´s.

Pin von RFM12bBei Projekt RN-MikroFunk verbunden mit Port ...Erläuterung
Alle Angaben ohne Gewähr - gültig ist alleine das Original Datenblatt des Herstellers!
SDOMISO / PB4SPI-Bus:Signal Master In Slave out
Über diesen Pin schickt das Modul Daten an den Controller
SDIMOSI / PB3SPI-Bus:Signal Master out Slave in
Über diesen Pin schickt der Controller Daten an RFM12b
SCKSCK / PB5SPI-BUS: Taktrate für Datenübertragung
nSELSS / PB2SPI-BUS: Select Slave
Wenn dieses Pin auf Low gezogen wird, dann wird das Modul RFM12b selektiert um Daten oder Befehle zu übertragen
nRESRESET / PC6Wenn dieser bin auf LOW gezogen wird, dann wird das Funkmodul als auch der Controller zurückgesetzt
nIRQINT0 / PD2Dieser Pin ist für die Verwendung nicht unbedingt notwendig, aber er ist hilfreich wenn man per Interrupt über neue Datenbytes, schwache Batterie etc. vom Funkmodul unterrichtet werden will. Je nach Initialisierung des Funkmoduls unterschiedliche Dinge melden.
VDD+3,3VDie Betriebsspannung
GNDGNDGND / Masse
FSK/DATA/nFFSÜber 1KOhm mit +3,3V verbundenDieser Pin kann genutzt werden um Daten ohne den FIFO (2 Byte Zwischenspeicher) zu empfangen oder auch zu senden. Bequemer ist es jedoch Daten mit eingeschalteten FIFO zu senden bzw. zu empfangen, daher wird dieser Pin bei uns dauerhaft auf High gelegt.
DCLK/CFIL/FFIT- nicht benötigt -Auch dieser Pin kann je nach Initialisierung verschiedene Aufgaben übernehmen.
DCLK – Taktrate wenn Daten ohne FIFO empfangen oder gesendet werden
CFIL – Wenn man hohe Taktraten von 256k und analogen Filter nutzt, soll hier ein Kondensator angeschlossen werden. In der Regel wird jedoch ein digitaler Filter bei der Initialisierung gewählt, dadurch ist dies nicht nötig.
FFIT – Je nach Initialisierung kann über diesen Pin nach ein Interrupt ausgelöst werden, wenn eine bestimmte Anzahl von Bits im FIFO sind.
CLK- nicht benötigt -RFM12b kann hier einen quarzstabiler Takt für den Mikrocontroller liefern. Wir nutzen diesen nicht, da RN-MikroFunk einen eigenen Resonator besetzt und auch ohne Funkmodul arbeiten soll.
nINT/VDI- nicht benötigt -Dieser Pin kann als Eingang (nINT) oder Ausgang VDI konfiguriert werden. Über nINT könnte der Controller das Modul bei seiner aktuellen Aufgabe unterbrechen. Über VDI kann das Modul signalisieren wenn gültige Daten empfangen werden.
Wir benötigen dieses Signal nicht.
ANTAuf Pin1 geführtAntennenanschluss / bei 433 Mhz Modulen reicht oft ein 17cm Draht

Die Features des Funkmoduls RFM12b

Trotz des geringen Preises bietet dieses Modul eine ganze Reihe von hervorragenden Eigenschaften, oft wird es noch unterschätzt. Hier möchte ich nur einige Features nennen:

  • sehr preiswert
  • PLL Technologie
  • kleine PLL Frequenzschritte 2,5 kHz
  • hohe Datenraten bis zu 256khz
  • niedrige Betriebsspannung: 2,2 bis 3,8V
  • automatische Antennenanpassung
  • Programmierbare Empfängerbandbreite von 67 kHz bis 400 kHz
  • Frequenmodulation mit programmierbarem Hub – 15 kHz bis 240 kHz
  • Automatisches Frequenzcontrol (AFC)
  • Datenqualitätsermittlung (DQD)
  • eingebaute Filter
  • automatisch Synchronbytes intern definierbar
  • Standard SPI-Bus (16 Bit)
  • Clock und Reset Signal für externen Microcontroller
  • 16 Bit RX Data FIFO
  • zwei 8 Bit TX Datenregister
  • Standard 10 Mhz Quarztakt
  • Wakeup-Timer zum Wecken eines Mikrocontrollers
  • Geringster Strombedarf – je nach Frequenbereich und Betriebszustand unterschiedlich, im Schnitt ca. 11 bis 25 mA
  • Standby Modi mit nur 0,3uA Verbrauch

 

Die Programmierung des Funkmoduls RFM12b

Wie Sie sicher schon aus der Pinbelegung ersehen konnten, wird das Funkmodul über den SPI-Bus angesteuert. Also genau das gleiche Interface, das auch zum Programmieren verwendet wird.

Aber keine Sorge, das ISP Programmierinterface von RN-MikroFunk kann normal genutzt werden, auch wenn das Funkmodul in Betrieb ist. Das liegt daran, dass beim Programmieren der sSel (Slave Select) Pin über einen Widerstand auf High gezogen wird, und dadurch ist das Modul beim Programmieren quasi passiv und beeinflusst nicht die Ports. In der Praxis gab es manchmal beim Sendebetrieb Konflikte, so dass die Daten nur versendet wurden wenn der ISP Programmer entfernt wurde. Sollte es also Sendeprobleme geben, dann ziehen Sie den ISP Stecker einfach nach dem Programmieren heraus!

Der SPI-Bus, für die Kommunikation mit dem Funkmodul, wird immer im 16 Bit Betrieb genutzt. Das heißt das Funkmodul erwartet bei jeder Übertragung, egal ob Befehl oder Daten immer 16 Bit.

Da das Funkmodul jede Menge programmierbare Einstellungen besitzt, müssen diese natürlich irgendwie programmiert werden.

Dies funktioniert grundsätzlich so:

Die oberen 8 Bit bestimmen grundsätzlich die Aufgabe, die erledigt werden soll. Die unteren 8 Bits verändern verschiedene Einstellungen, die Art der Einstellungen sind je nach Aufgabe (High-Byte) ganz unterschiedlich. Sie müssen also stets zuerst auf das High-Byte schauen, um zu wissen was die unteren 8 Bits verändern. Auch beim Senden von Daten bleibt dieses Prinzip erhalten. So bedeutet beispielsweise ein Wert von Hex B8 im High Byte, das in den unteren 8 Bit ein beliebiges Datenbyte steckt das gesendet werden soll.
Möchten Sie als die zahlen 1, 2 und 3 versenden, so müssten Sie diese drei 16 Bit Werte übertragen Hex B801, B802, B803

Ähnlich funktioniert es mit dem Empfang. Bei einem SPI-Bus ist es ja grundsätzlich so, dass für jedes gesendete Bit auch gleichzeitig ein Bit zurückgegeben wird. Wenn Sie also einen 16 Bit Wert an das Funkmodul senden, so erhalten Sie auch einen 16 Bit Wert zurück. Wenn Sie also ein empfangenes Datenbyte aus dem FIFO (2 Byte Zwischenspeicher im Funkmodul) holen wollen, dann müssen Sie stets den Hex Wert B000 an das Modul senden. Wenn Sie zwei Byte lesen wollen, dann müssten Sie also zweimal Hex B000 an das Modul senden.

Das Ganze hört sich erst mal kompliziert an, ist aber ganz einfach und lässt sich gut in eine Funktion packen damit es einfach handhabbar ist.

Bevor aber das alles funktioniert, muss das Modul immer erst nach dem Start von RN-MikroFunk initialisiert werden. Das heißt es müssen gewisse Grundeinstellungen vorgenommen werden. Schließlich muss das Modul ja erst mal wissen ob es senden oder empfangen soll, beides gleichzeitig geht nicht. Wenn man nach dem Empfang senden will, dann muss der Empfänger aus und der Sender eingeschaltet werden. Aber auch die Frequenz, Frequenzhub, die Bandbreite, die Art der Filterung und vieles mehr muss erst einmal festgelegt werden. Alles das funktioniert wie eben erläutert durch die Übertragung von 16 Bit Werten, wobei die Aufgabe im High Byte steckt. Welche Bedeutung nun die unteren 8 Bit bei welchem High-Byte haben das können Sie sehr genau dem Datenblatt entnehmen. Aber auch unsere Beispielprogramm verraten hier schon sehr viel. Es gibt auch eine Art Online Konfigurierungsprogramm für RFM12b im Internet, dazu aber später mehr bei den Links.

Unsere Bascom Funktionen zur leichteren Programmierung

In welcher Sprache Sie RN-MikroFunk programmieren ist natürlich grundsätzlich egal. Wir verwenden sehr gerne Bascom Basic weil es sehr übersichtlich und produktiv ist. Der Quelltext wird in der Regel wesentlich kürzer als in C Programmen und das erhöht die Übersichtlichkeit und reduziert die Zeit für die Programmierung. Daher verwenden wir in dieser Anleitung nur Bascom Beispiele, natürlich ginge alles in C oder Assembler auf die gleiche Weise.

Wie übertragen wir nun unsere 16 Bit Werte an das Funkmodul?

RN-MikroFunk und das Funkmodul sind so verschaltet, dass wir die Möglichkeit haben sowohl den Hardware SPI-Bus des Mega328P Controllers zu verwenden oder einfach per Software die SPI-Funktion zu realisieren. Wir haben uns zur Software-Lösung entschieden, zum einen weil diese übersichtlicher und verständlicher ist und zum anderen weil wir die gleiche Funktion durch Portanpassung auf jeden AVR-Microcontroller verwenden können, selbst wenn dieser keine Hardware SPI-Unterstützung bietet.

Daher verwenden alle unsere Beispiele grundsätzlich nachfolgende Funktion um die 16 Bit Kommandos an das Funkmodul zu senden.

Function Spitransfer(byval Dout As Word) As Word
Local Nspi As Integer
Local Dspi As Integer
Local Dmiso As Word
 Ss = 0
 Dmiso = 0
 For Nspi = 1 To 16
  Dspi = Dout And &H8000
  If Dspi = 0 Then
  Mosi = 0
 Else
  Mosi = 1
 End If
 Dout = Dout * 2
 Dmiso = Dmiso * 2
 Dmiso = Dmiso + Miso
 Sck = 1
 Waitus 5
 Sck = 0
 Next Nspi

 Ss = 1
 Spitransfer = Dmiso
End Function

Rfm12_warte:
Ss = 0
Do
Loop Until Miso = 1
Return

 

Die Handhabung ist einfach, die Funktion wird mit folgender Syntax aufgerufen:

y=Spitransfer(x)

X wäre in dem Beispiel der zu übertragende 16 Bit Wert, also zum Beispiel ein Kommando mit Einstellungen. Y wäre der Rückgabewert, beispielsweise wenn das Kommando ein Byte aus dem FIFO lesen soll.

Die Initialisierung des Funkmoduls

Kommen wir jetzt zur Initialisierung des Funkmoduls. Also die Werte die wir beispielsweise nach dem Start von RN-MikroFunk dem Funkmodul mitteilen müssen damit es bereit für weitere Aufgaben ist.

Für diesen Zweck verwenden wir in dem Beispiel folgende Funktion und Werte:

' Initialisiere Funkmodul

Sub Rfm12_init
Local Wert As Word
Local X As Word
Local d As Word

 X = 0
 Restore Datainit3 'Initialisierungsfolge
 Do
  Read Wert
  D = Spitransfer(wert)
  Incr X
 Loop Until Wert = 0
 Waitms 200
End Sub

'Funkmodul Initialisierungsdaten mit 9600 Baud

Datainit3:
Data &H80D7% ' Enable: 433 Mhz;XTAL cap=12pf; TX-Register; RX-Fifo
Data &H82D9% ' Enable: Receiver; Crystal Osc; Base Band Block; Synthesizer
             ' Disable Low-bat Detector; Transmitter; Wake-Up-Timer; Clock output Pin
Data &HA67C% ' &Ha67c=frequenz 434,15 Mhz oder z.B. &HA538 für 433,34 Mhz
Data &HC623% ' &Hc647=Datenrate '4.8kbps; C623=9600kbps; C611 =19200
Data &H90C0% ' LNA Gain=MAX; Pin=nInt; RX Bandwidth=67 khz; VDI=Fast; DRSSI=-103 dB
Data &HC2AC% ' Fiter=Digital; Recover Mode=Auto; Quality Threshold=4; 
             ' Recovery Speed=Slow
Data &HCA80% ' FIFO INT Level=8; Sync on=2;Fifo Fill Start=Sync; Reset
             ' Sensitivity=High;
             ' Disable:FIFO Fill Enabled
Data &HC483% ' Enable: AFC Mode; AFC; Frequency Offset Register
             ' Disable: High Accuracy; Strobe
Data &H9820% ' Frequenz Shift=POS; Power Out=0 dB; Deviation=45 khz
Data &HE000% ' WakeUp-Timer=0ms
Data &HC800% ' Duty Cycle = Infinity % OFF
Data &HC000% ' Low batterie=2,2V; Clock Pin=1 Mhz
Data &HCED4% ' Synchron Pattern
Data &HCC57% ' PLL Settings
Data &H0000% ' Status lesen irqs zurückstellen
Data 0%      ' ende initialisierung

Der einmalige Aufruf der Funktion RFM12_init sorgt also dafür, dass diese Funktion die unteren 16 Bit Werte in den Data-Zeilen liest und nacheinander an das Funkmodul sendet. Als Kommentar ist angefügt was im einzelnen die Werte machen, natürlich wird dies im Datenblatt ausführlicher erläutert. In diesem Beispiel wird das Modul beispielsweise auf den 433 Mhz-Bereich gestellt, der FIFO aktiviert, der Empfänger aktiviert also der Sender deaktiviert, die Frequenz auf 435,15 Mhz gestellt, die Übertragungsrate auf 9600 KBaud festgelegt, die Bandbreite auf 67 khz eingestellt, AFC eingeschaltet , der Wake-Up-Timer abgeschaltet, die Sendeleistung maximiert, das Synchronbyte aktiviert usw. usw.

Die Initialisierung und Einstellungen müssen natürlich nicht unbedingt so lauten, das ist nur ein funktionsfähiges Grundgerüst für unsere Beispielprogramme. Sie können vieles Ihren gewünschten Vorstellungen anpassen, Sie sollten jedoch genau wissen was Sie tun denn sie müssen die schon mehrfach erwähnten rechtlichen Bestimmungen genau einhalten.

Gehen Sie also das Datenblatt genau durch und vergewissern Sie sich ob Sie alle Einstellungen korrekt vorgenommen haben bevor Sie das Modul mit Antenne im Einsatz haben. Reichweiten von bis zu 300m sind je nach Gegebenheit durchaus denkbar, selbst mit einer einfachen Drahtantenne. Verlassen Sie sich auch nicht auf die Beispielvorgaben in irgendwelchen Beispielen sondern erkundigen Sie sich vorher auf welcher Frequenz sie wie lange bzw. oft sie senden dürfen (www.bundesnetzagentur.de).

Wenn Sie die Befehle im Datenblatt studiert haben, so werden Sie erkennen, dass viele Anweisungen immer nur einige Bits des Low Byte im Kommando belegen und somit quasi immer gleich mehrere Einstellungen pro 16 Bit Wert vorgenommen werden. Das ist zwar einfach zu verstehen, aber die Bitrechnerei ist doch oft ganz schön nervig. Hier gibt es eine gute Hilfe im Internet. Schauen Sie mal auf folgender Webseite vorbei:

Online Konfigurator für RFM12

Dort finden Sie ein tolles Online Tool. Sie können dort die gewünschten Einstellungen bequem per Checkbox, Auswahlbox etc. festlegen und das Tool zeigt ihnen sofort das passend Kommando (16 Bit Wert) an. Sie müssen dann diese Werte nur noch in Ihr Programm übernehmen. So sieht das Tool im Internet aus:

Online Konfiguration von RFM12 und RFM12b

Beachten Sie aber auch hier, dass Sie die richtigen Einstellungen, insbesondere Band und Frequenzbereich, verwenden.

Daten per Funk empfangen

Nachdem die Initialisierung abgeschlossen ist, kann das Modul wahlweise auf Sende- oder Empfangsbetrieb gehen. Wir wollen jetzt zunächst den Empfangsbetrieb demonstrieren.

Dazu verwenden wir folgende Funktion:

Sub Rfm12_empfange(byval anzahl as word)
Local d As Word

 D = Spitransfer(&H82c8)
 D = Spitransfer(&Hca83)
 For N = 1 To anzahl
  Ss = 0
  Do
   Waitus 100
  Loop Until Miso = 1
  D = Spitransfer(&Hb000)
  Eingangsdaten(n) = D
 Next N
 D = Spitransfer(&H8208)
End Sub

Mehr ist nicht nötig. Diese Funktion kann direkt nach der Initialisierung aufgerufen werden.

Das Kommando Hex 82C8 sorgt dafür, dass der Empfänger, Basis Band und Quarzoszillator einschaltet. Gleichzeitig schaltet die Anweisung den Batteriededektor, Sender, Wake up-Timer, Synthesizer und den Clock-Ausgang aus.

Das Kommando Hex CA83 schaltet den FIFO ein, legt fest, dass bei 8 Bit im FIFO ein Interrupt ausgelöst wird, dass als Synchronbytes die beiden Bytes 2DD4 festgelegt werden und gibt den FIFO frei.

Danach selektiert die Funktion das Funkmodul nochmal indem es über den Port SS den Pin nSEL des Funkmodules auf Low legt. Das Funkmodul hat nämlich die Eigenschaft dass es den Port MISO dann so lange auf Low läßt, bis ein Byte im FIFO bereitsteht, dann geht es kurz auf High. Ein Interrupt wird dadurch praktisch nicht gebraucht, da sich dieser durch diese Schleife auch ermitteln lässt.

Da wir vorhin über den Befehl CA83 die Synchronbytes 2D D4 aktiviert haben, meldet das Funkmodul ein Byte erst dann, wenn diese beiden Bytes hintereinander empfangen wurden. Der Sender muss also immer dafür sorgen, dass als erstes die Werte Hex 2D D4 gesendet werden, dadurch kann der Empfänger den Anfang einer Sendung (Anfang eines Datenpaketes) automatisch feststellen.

Sobald MISO das erste mal auf auf High geht wurde also 2D D4 und das erste Datenbyte empfangen. Danach holen wir das empfangene Datenbyte ab indem das Kommando Hex B0000 gesendet wird. Der Low-Wert des zurückgegebenen 16 Bit-Wertes ist das empfangene Datenbyte. Danach geht die Schleife von vorne los und es wird auf das nächste Byte gewartet.

Die Schleife könnte nun beliebig lange wiederholt werden, denn es werden ständig weitere Bytes empfangen, selbst dann wenn der Sender beispielsweise nur 12 abgeschickt hat. Das Funkmodul kann also selbstständig nicht erkennen wann die Bytefolge zu Ende ist und interpretiert nach den korrekten 12 Bytes das Rauschen in dem Frequenzbereich auch als Daten. Daher wird unsere Empfangsroutine beim Aufruf die Anzahl der zu empfangenden Bytes übergeben.

Wenn also unsere Funktion wie folgt aufgerufen wird

Rfm12_empfange(12)

dann werden immer nur 12 Bytes empfangen. Das heißt der Empfänger muss vorher wissen wie viele Bytes gesendet werden. Die Funktion ist also für eine feste Paketlänge ausgelegt. Viele Kommunikationsprotokolle arbeiten mit solchen festen Paketlängen, in der Praxis lässt sich das am einfachsten und schnellsten programmieren, daher ist unsere Empfangsfunktion auch so kurz. Für viele Aufgaben reicht das aber, denn in der Bytefolge könnten Portzustände, Temperaturwerte, andere Sensorwerte oder Richtungswerte u.v.m. untergebracht werden. Unzählige Aufgaben wären damit realisierbar.

Wenn man lieber eine flexible Anzahl von Bytes senden möchte, beispielsweise verschieden lange Wörter oder Sätze, dann muss man sich selbst um ein entsprechendes Protokoll kümmern. Das heißt Sender und Empfänger müssen gewisse Vereinbarungen treffen. Beispielsweise könnte man vereinbaren, dass man in jedem ersten Byte das übertragen wird, die Anzahl der nachfolgenden Bytes steht. Der Empfangsroutine müsste dann die Anzahl der Bytes nicht mehr übergeben werden, sie könnte diese selbst aus dem ersten Byte lesen. Sie sehen, auch das wäre relativ einfach!

Ein weiterer Nachteil dieser einfachen Empfangsfunktion ist, dass das Programm quasi so lange in der Schleife fest hängt, bis Daten kommen. Das hat zwar den Vorteil, dass nie etwas verpasst wird, aber den Nachteil dass der Controller in dieser Zeit nichts anderes machen kann. In manchen Fällen muss ein Controller ja auch nicht mehr machen als beispielsweise einen Verbraucher ein- und ausschalten, in der restlichen Zeit kann der Controller auf die Daten der Fernbedienung warten. In so einem Fall wäre unsere Funktion völlig ok. Wenn aber noch andere Aufgaben wie Tastenabfrage, Sensorabfragen etc. nebenher erfolgen sollen, dann müsste man die Empfangsroutine ändern.

Eine Möglichkeit wäre ein Timeout einzuführen. Das bedeutet in der Schleife wird ein Zähler hochgezählt oder die Zeit gemessen. Wird eine Weile nichts empfangen könnte die Funktion kurz verlassen werden und eine andere Aufgabe erfüllt werden. Danach kehrt das Programm gleich wieder in die Empfangsschleife. Nachteil wäre dass bei längeren Unterbrechungen es passieren könnte dass Datensendungen nicht registriert werden.

Eine andere Möglichkeit wäre das Daten per Interrupt empfangen werden, also quasi neben den anderen Aufgaben im Hintergrund. Erst wenn ein Datenpaket vollständig ist, muss es verarbeitet werden. Dies ist die komfortabelste Funktion die wir später noch in dieser Dokumentation demonstrieren. Wir bleiben aber jetzt erst einmal bei dieser vorgestellten Grundfunktion, da sie sehr übersichtlich ist.

Unsere Empfangsfunktion endet damit, dass es Hex 8208 an das Funkmodul sendet. Dies sorgt nur dafür dass auch der Empfänger ausgeschaltet wird.

Ein komplettes Empfangsprogramm für RFM12B

Das komplette Empfangsprogramm für RN-MikroFunk könnte im einfachsten Fall also so aussehen:

'##############################################################
'TestEmpfaengerRNMikroFunk.bas
'
'Ein Testprogramm für die winzige universal Platine RN-MikroFunk
'
'Das Programm demonstriert wie man Daten empfaengt
'Ein anderes Funkmodul sollte Daten mit dem Programmm TestSenderRNMikroFunk
'senden.
'Das Programm ist für das 433Mhz Modul RFM12b gedacht, diese
'muss bei RN-MikroFunk bestückt sein. Ansonsten muss nur Spannung
'bzw. Batterie angeschlossen werden.
'
'Weitere Beispiele auf mikrocontroller-elektronik.de 
'######################################################################

'Portbelegung:
'keine externe Beschaltung nötig

$programmer = 12 'Bascom USB Programmer (Zeile weglassen wenn anderer Programmer)
$PROG &HFF,&HFF,&HD9,&HFF 'Diese Anweisung stellt Fusebits ein

$regfile = "m328pdef.dat"
$framesize = 32
$swstack = 32
$hwstack = 64

$crystal = 8000000 'Quarzfrequenz
$baud = 9800 'Baudrate (Übertragungsgeschwindigkeit)
Baud = 9800

Declare Sub Rfm12_init
Declare Sub Rfm12_empfange (byval anzahl as word)
Declare Function Spitransfer(byval Dout As Word) As Word

Ss Alias Portb.2
Mosi Alias Portb.3
Miso Alias Pinb.4
Sck Alias Portb.5

Config Ss = Output
Config Mosi = Output
Config Sck = Output

Dim Eingangsdaten(200) As Byte
dim eingangsstring as string*199 At Eingangsdaten Overlay
Dim DatenbyteAnzahl As word '

Dim N As Byte

Waitms 100
Ss = 1
Sck = 0
Rfm12_init

'Hauptprogramm
Do
 DatenbyteAnzahl=12
 call Rfm12_empfange (DatenbyteAnzahl) 'gehe auf Empfang und warte
 'auf die 12 erwarteten Datenbytes
 Print
 Print "Datenbytes:" ; DatenbyteAnzahl
 Print "Als Dezimalzahlen: " ;
 For N = 1 To DatenbyteAnzahl
   Print Eingangsdaten(n);
   Print " ";
 Next N
 print
 Print "Als String: " ;left(eingangsstring,DatenbyteAnzahl)
Loop

' ************ Hilfsfunktionen zur Kommunikation mit Funkmodul **************
' (nähere Infos im Datenblatt des Funkmoduls)

' Initialisiere Funkmodul
Sub Rfm12_init
Local Wert As Word
Local X As Word
Local d As Word

 X = 0
 Restore Datainit3 'Initialisierungsfolge
 Do
  Read Wert
  D = Spitransfer(wert)
  Incr X
 Loop Until Wert = 0

 Waitms 200
End Sub

Sub Rfm12_empfange(byval anzahl as word)
Local d As Word

 D = Spitransfer(&H82c8)
 D = Spitransfer(&Hca83)
 For N = 1 To anzahl
  Ss = 0
  Do
   Waitus 100
  Loop Until Miso = 1
  D = Spitransfer(&Hb000)
  Eingangsdaten(n) = D
 Next N
 D = Spitransfer(&H8208)
End Sub

Function Spitransfer(byval Dout As Word) As Word
Local Nspi As Integer
Local Dspi As Integer
Local Dmiso As Word
 Ss = 0
 Dmiso = 0
 For Nspi = 1 To 16
  Dspi = Dout And &H8000
  If Dspi = 0 Then
  Mosi = 0
 Else
  Mosi = 1
 End If
 Dout = Dout * 2
 Dmiso = Dmiso * 2
 Dmiso = Dmiso + Miso
 Sck = 1
 Waitus 5
 Sck = 0
Next Nspi
Ss = 1
Spitransfer = Dmiso

End Function

Rfm12_warte:
Ss = 0
Do
Loop Until Miso = 1
Return

End

'Funkmodul Initialisierungsdaten 9600 Baud
Datainit3:
Data &H80D7% ' Enable: 433 Mhz;XTAL cap=12pf; TX-Register; RX-Fifo
Data &H82D9% ' Enable: Receiver; Crystal Osc; Base Band Block; Synthesizer
             ' Disable Low-bat Detector; Transmitter; Wake-Up-Timer; Clock output Pin
Data &HA67C% ' &Ha67c=frequenz 434,15 Mhz oder z.B. &HA538 für 433,34 Mhz
Data &HC623% ' &Hc647=Datenrate '4.8kbps; C623=9600kbps; C611 =19200
Data &H90C0% ' LNA Gain=MAX; Pin=nInt; RX Bandwidth=67 khz; VDI=Fast; DRSSI=-103 dB
Data &HC2AC% ' Fiter=Digital; Recover Mode=Auto; Quality Threshold=4; 
             ' Recovery Speed=Slow
Data &HCA80% ' FIFO INT Level=8; Sync on=2;Fifo Fill Start=Sync; 
             ' Reset Sensitivity=High;
             ' Disable:FIFO Fill Enabled
Data &HC483% ' Enable: AFC Mode; AFC; Frequency Offset Register
             ' Disable: High Accuracy; Strobe
Data &H9820% ' Frequenz Shift=POS; Power Out=0 dB; Deviation=45 khz
Data &HE000% ' WakeUp-Timer=0ms
Data &HC800% ' Duty Cycle = Infinity % OFF
Data &HC000% ' Low batterie=2,2V; Clock Pin=1 Mhz
Data &HCED4% ' Synchron Pattern
Data &HCC57% ' PLL Settings
Data &H0000% ' Status lesen irqs zurückstellen
Data 0% 'ende initialisierung

Dieses Programm macht folgendes:

Nach dem Start wird das Funkmodul initialisiert. Danach geht es auf Empfang und wartet bis 12 Bytes empfangen werden. Werden diese empfangen, so werden die 12 Bytes als Dezimalzahlen als auch als String über RS232 (oder angeschlossenes USB-Modul) an den PC übertragen. Danach beginnt die Schleife von vorn, es geht wieder auf Empfang.

Wenn wir dieses Programm in RN-MikroFunk übertragen, dann wird es korrekt funktionieren, aber wir werden keine Daten empfangen. Einfach deshalb weil wir noch kein Programm haben, dass die Daten sendet! 🙂
Das Gegenstück folgt aber jetzt!

Daten mit dem Funkmodul senden

Kommen wir nun zum Senden. Wir gehen davon aus, dass wir die gleiche Initialisierung wie im vorherigen Beispiel verwendet habe. In dem Fall könnte einen Sendefunktion wie folgt aussehen:

'Hier werden die zu sendenden Daten abgelegt

Dim Ausgabedaten(200) As Byte
dim ausgabestring as string*199 At Ausgabedaten Overlay

Sub Rfm12_senden(byval Anzahl As Integer)
local n as byte
Local d As Word

 D = Spitransfer(&H8238) 'Sender, Synthesizer und Quarzoszillator einschalten
 Gosub Rfm12_warte
 D = Spitransfer(&Hb8aa)
 Gosub Rfm12_warte
 D = Spitransfer(&Hb8aa)
 Gosub Rfm12_warte
 D = Spitransfer(&Hb8aa)
 Gosub Rfm12_warte
 D = Spitransfer(&Hb82d) 'Das Synchronbyte zum markieren des Datenanfangs senden 
 Gosub Rfm12_warte
 D = Spitransfer(&Hb8d4) 'Das Synchronbyte zum markieren des Datenanfangs senden 
 For N = 1 To Anzahl 'In der Schleife die Daten senden 
  Gosub Rfm12_warte
  D = &HB800 + Ausgabedaten(n)
  D = Spitransfer(d)
 Next N
 Gosub Rfm12_warte
 D = Spitransfer(&Hb8aa)
 Gosub Rfm12_warte
 D = Spitransfer(&Hb8aa)
 Gosub Rfm12_warte
 D = Spitransfer(&H8208) 'Sender und Empfänger abschalten

End Sub

Sie sehen, auch die Senderoutine ist winzig, aber mehr bedarf es nicht! Durch den Aufruf von

Rfm12_senden(x)

werden praktisch die ersten x Bytes aus dem global definierten Array Ausgabedaten gesendet! Man muss also nichts anderes machen als seine Sensordaten, Richtungsangaben, Portstatus oder was auch immer man versenden möchte, vorher in das Array eintragen. Danach die Sendefunktion aufrufen und das war´s.

Im Quelltext wird erläutert was die 16 Bit Kommandos bei dem Funkmodul bewirken. Im Grunde wird nur der Sender, Synthezizer (für FM-Modulation) und Quarzoszillator vor dem Senden eingeschaltet. Danach senden wir grundsätzlich zwei Bytes die nur aus wechselnden 0 und 1 Bits bestehen, also zweimal Hex AA (Binär ist das 10101010).

Diese beiden Bytes sollen den Empfänger helfen sich auf die Daten zu synchronisieren. Da wir ja ein 16 Bit Wort an das Funkmodul übertragen müssen, wird also jedem Datenbyte das High Byte Hex B8 vorangestellt (Befehl zum senden von Daten).

Nach diesen beiden Synchronbytes senden wir die Kennung zum Datenbeginn. Sie erinnern sich, beim Empfänger hatten wir dafür Hex 2D D4 definiert. Also senden wir zuerst 2D und dann D4.

Jetzt sind wir soweit, jetzt können in der Schleife beliebig viele Datenbytes hintereinander gesendet werden. In unserem Beispiel machen wir das mit einer For-Next-Schleife die die ersten x Bytes aus dem Array ausliest, jedem Byte ein Hex B8 voranstellt und alle sendet.

Nach dem Übertragen der Daten senden wir noch zwei zusätzliche Bytes, hier nehmen wir auch wieder Hex AA, einfach nur um zu erreichen das der Sender sich nicht zu schnell ausschaltet und irgend etwas verschluckt wird.

Das war´s! Der letzte Befehl Hex 8208 sorgt dafür das Empfänger und Sender wieder abgeschaltet wird.

Ein komplettes Sendeprogramm für RFM12B

Das nachfolgende Programmen zeigt noch mal das komplette Sendeprogramm, es ist quasi das Gegenstück zum vorherigen Empfangsprogramm.
Wenn Sie es sich genau anschauen, werden Sie feststellen dass es weitgehend identisch ist, lediglich statt der Empfangsfunktion ist hier die Sendefunktion hineingekommen.

Das Hauptprogramm darin sieht so aus:

Do
  ausgabestring="RN-MikroFunk"
  call Rfm12_senden(12)
  wait 5
Loop

Wie Sie sicher selbst ersehen, macht das Programm nichts anderes als den String „RN-MikroFunk“ in das zu übertragende Array einzutragen. Danach wird dieser String (genau 12 Zeichen) gesendet. Dann 5 Sekunden gewartet und das ganze wiederholt.

Laden Sie also einmal dieses Sendeprogramm in ein RN-Mikrofunk und das Empfangsprogramm in ein zweites RN-MikroFunk das sie mit der RS232 (oder über USB-Modul) mit dem PC verbinden. Sie werden sehen, die Daten kommen an, dies sieht dann so aus:

Daten Empfang mit Funkmodul RFM12

 

'##############################################################
'TestSenderRNMikroFunk.bas
'
'Ein Testprogramm für die winzige universal Platine RN-MikroFunk
'
'Das Programm demonstriert wie man Daten an ein anderes Modul sendet
'Die Daten werden in Array oder dem ausgabestring abgelegt und
'mittels Rfm12_senden(x) werden die ersten x Bytes davon gesendet!
'Das Programm ist für das 433Mhz Modul RFM12b gedacht, diese
'muss bei RN-MikroFunk bestückt sein. Ansonsten muss nur Spannung
'bzw. Batterie angeschlossen werden.
'
'Weitere Beispiele auf http://www.mikrocontroller-elektronik.de/
'######################################################################

'Portbelegung:
'keine externe Beschaltung nötig

$programmer = 12 'Bascom USB-Programmer (Zeile weglassen wenn anderer Programmer)
$PROG &HFF,&HFF,&HD9,&HFF 'Diese Anweisung stellt Fusebits ein
$regfile = "m328pdef.dat"
$framesize = 32
$swstack = 32
$hwstack = 64
$crystal = 8000000 'Quarzfrequenz
$baud = 9800 'Baudrate (Übertragungsgeschwindigkeit)
Baud = 9800

Declare Sub Rfm12_init
Declare Sub Rfm12_senden(byval Anzahl As Integer)
Declare Function Spitransfer(byval Dout As Word) As Word

Ss Alias Portb.2
Mosi Alias Portb.3
Miso Alias Pinb.4
Sck Alias Portb.5

Config Ss = Output
Config Mosi = Output
Config Sck = Output

'Hier werden die zu sendenten Daten abgelegt

Dim Ausgabedaten(200) As Byte
dim ausgabestring as string*199 At Ausgabedaten Overlay

Ss = 1
Sck = 0
Rfm12_init

'Hauptprogramm
Do
 ausgabestring="RN-MikroFunk"
 call Rfm12_senden(12)
 wait 5
Loop

' ************ Hilfsfunktionen zur Kommunikation mit Funkmodul **************
' (nähere Infos im Datenblatt des Funkmoduls und in der Dokumentation von RN-MikroFunk)

' Initialisiere Funkmodul
Sub Rfm12_init
Local Wert As Word
Local X As Word
Local d As Word

 X = 0
 Restore Datainit3 'Initialisierungsfolge
 Do
  Read Wert
  D = Spitransfer(wert)
  Incr X
 Loop Until Wert = 0
 Waitms 200
End Sub

Sub Rfm12_senden(byval Anzahl As Integer)
local n as byte
Local d As Word

 D = Spitransfer(&H8238) 'Enable Transmitter; enable Synthesizer ;enable Crystal Osc
 Gosub Rfm12_warte
 D = Spitransfer(&Hb8aa)
 Gosub Rfm12_warte
 D = Spitransfer(&Hb8aa)
 Gosub Rfm12_warte
 D = Spitransfer(&Hb8aa)
 Gosub Rfm12_warte
 D = Spitransfer(&Hb82d)
 Gosub Rfm12_warte
 D = Spitransfer(&Hb8d4)
 For N = 1 To Anzahl
  Gosub Rfm12_warte
  D = &HB800 + Ausgabedaten(n)
  D = Spitransfer(d)
 Next N
 Gosub Rfm12_warte
 D = Spitransfer(&Hb8aa)
 Gosub Rfm12_warte
 D = Spitransfer(&Hb8aa)
 Gosub Rfm12_warte
 D = Spitransfer(&H8208) 'disable transmitter und receiver
End Sub

Function Spitransfer(byval Dout As Word) As Word
Local Nspi As Integer
Local Dspi As Integer
Local Dmiso As Word
 Ss = 0
 Dmiso = 0
 For Nspi = 1 To 16
  Dspi = Dout And &H8000
  If Dspi = 0 Then
  Mosi = 0
 Else
  Mosi = 1
 End If
 Dout = Dout * 2
 Dmiso = Dmiso * 2
 Dmiso = Dmiso + Miso
 Sck = 1
 Waitus 5
 Sck = 0
Next Nspi
Ss = 1
Spitransfer = Dmiso

End Function



Rfm12_warte:
Ss = 0
Do
Loop Until Miso = 1
Return

End ' programmende


'Funkmodul Initialisierungsdaten mit 9600 Baud
Datainit3:
Data &H80D7% ' Enable: 433 Mhz;XTAL cap=12pf; TX-Register; RX-Fifo
Data &H82D9% ' Enable: Receiver; Crystal Osc; Base Band Block; Synthesizer
             ' Disable Low-bat Detector; Transmitter; Wake-Up-Timer; Clock output Pin
Data &HA67C% ' &Ha67c=frequenz 434,15 Mhz oder z.B. &HA538 für 433,34 Mhz
Data &HC623% ' &Hc647=Datenrate '4.8kbps; C623=9600kbps; C611 =19200
Data &H90C0% ' LNA Gain=MAX; Pin=nInt; RX Bandwidth=67 khz; VDI=Fast; DRSSI=-103 dB
Data &HC2AC% ' Fiter=Digital; Recover Mode=Auto; Quality Threshold=4;
             ' Recovery Speed=Slow
Data &HCA80% ' FIFO INT Level=8; Sync on=2;Fifo Fill Start=Sync;
             ' Reset Sensitivity=High;
             ' Disable:FIFO Fill Enabled
Data &HC483% ' Enable: AFC Mode; AFC; Frequency Offset Register
             ' Disable: High Accuracy; Strobe
Data &H9820% ' Frequenz Shift=POS; Power Out=0 dB; Deviation=45 khz
Data &HE000% ' WakeUp-Timer=0ms
Data &HC800% ' Duty Cycle = Infinity % OFF
Data &HC000% ' Low batterie=2,2V; Clock Pin=1 Mhz
Data &HCED4% ' Synchron Pattern
Data &HCC57% ' PLL Settings
Data &H0000% ' Status lesen irqs zurückstellen
Data 0% 'ende initialisierung

RN-MikroFunk und Funkmodul RFM12b

 

Strom sparend mittels Watchdog senden

In den meisten Fällen wird man wohl RN-MikroFunk mit Batterie betreiben. Daher ist es wichtig, dass man möglichst wenig Energie verbraucht. Insbesondere wenn das Modul im ständigen Einsatz ist, zum Beispiel als Alarmmelder in einer Alarmanlage oder zur Überwachung von Temperaturen wie Heizung oder Zimmertemperatur. Wer will schon gerne wöchentlich die Batterie wechseln?

Aus diesem Grund wurde RN-MikroFunk sehr sparsam konzipiert, alle Bauteile wurden hinsichtlich Strombedarf und möglichen Schlafmodi ausgewählt.

Daher kann man beispielsweise unser letztes Programm durch ein paar zusätzliche Zeilen im Hauptprogramm dazu bringen, dass nach dem Senden der Daten sowohl das Funkmodul als auch der RN-MikroFunk selbst für 8 Sekunden in einen Tiefschlaf geht. In diesen 8 Sekunden werden weniger als 0,01 mA verbraucht! Ein extrem niedriger Wert!

Nach den 8 Sekunden weckt sich RN-MikroFunk selbst und macht an der Stelle weiter wo es aufgehört hat, also es sendet wieder die nächsten Daten und geht wieder schlafen. Das spart natürlich erheblich an Energie ein.

Der geänderte Programmteil sieht nun so aus:

'Hier werden die zu sendenden Daten abgelegt

Dim Ausgabedaten(200) As Byte
dim ausgabestring as string*199 At Ausgabedaten Overlay
dim r as word

Ss = 1
Sck = 0
Rfm12_init
Config Watchdog = 8192
Enable Wdt
Enable Interrupts

'Hauptprogramm
Do
 Reset Watchdog
 r=Spitransfer(&H8201) 'Funkmodul komplett schlafen legen /alles abschalten
 Powerdown
 ausgabestring="RN-MikroFunk"
 call Rfm12_senden(12)
Loop

Wenn die Daten nicht so dringend sind, reicht es oft auch aus wenn man diese nur alle 5 oder 10 Minuten sendet. Das könnte man erreichen indem man einen Zähler einbaut, welcher bei jedem Aufwachen hochgezählt wird. Erst wenn der Zähler einen bestimmten Wert erreicht hat, wird Funkmodul und vielleicht Sensor eingeschaltet und gesendet. Ist der Wert beim Aufwachen noch nicht erreicht, dann legt sich das Modul gleich wieder schlafen.

Bei bestimmten Sensoren oder Aufgaben könnte man sie auch solange schlafen legen bis eine Pegeländerung an einem Port RN-MikroFunk aufweckt.

Und die dritte Möglichkeit wäre, das sich RN-MikroFunk in einer definierbaren konfigurierbaren Zeit vom Funkmodul wecken lässt. Auch der Datenempfang kann zum Aufwecken genutzt werden.

Es gibt also zahlreiche Möglichkeiten, sie sorgen dafür dass eine Batterie je nach Anwendung oft weit über ein oder sogar mehrere Jahre ausreichen kann.

Den Wake-Up timer des Funkmodules RFM12b nutzen

Eine besonders elegante und auch besonders stromsparende Möglichkeit Daten in gewissen Zeitabständen zu senden, ist das Ausnutzen des sogenannten Watch-Up Timers im Funkmodul. Dieser Timer kann nämlich nicht nur das Funkmodul in eine programmierbaren Zeit aufwecken, nein per Interrupt kann es den Mikrocontroller von RN-MikroFunk ebenfalls wecken. Den Watchdog-Timer den wir im letzten Beispiel verwendet haben hat nämlich den Nachteil, dass dieser zumindest alle 8 Sekunden das Board kurz aufwecken muss, längere Zeiten sind dort nicht definierbar.

Der Wake-Up Timer des Funkmodules gestattet sowohl kurze Zeiten im Millisekundenbereich als auch lange Zeiten bis zu mehreren Stunden, Tagen, Wochen ja sogar Jahre sollen möglich sein.

Das ist natürlich fantastisch, denn in dieser Sleeptime (Schlafenszeit) braucht unser Board fast gar keinen Strom mehr, der Wert liegt gewöhnlich unter 0,01mA. Ein fantastischer Wert, damit lassen sich mit entsprechenden Sleeptimes Dinge bis zu mehreren Jahren mit einer Batterie überwachen, insofern die Selbstentladung nicht zu groß ist.

Wo ist der Haken?

Es gibt keinen, außer dass man erst mal herausbekommen wie der Wake-Up Timer funktioniert und zu handhaben ist. So ganz einfach ging das nicht aus dem Datenblatt hervor und im Internet sucht man vergebens nach Erläuterung und Beispielen die wirklich funktionieren. Die wenigen Beispiele die ich gefunden habe, haben nur theoretisch funktioniert, in der Praxis nicht!

Ich habe einen ganzen Tag mit dem experimentieren der Register verbracht um herauszubekommen wie es nun wirklich klappt. Diese Arbeit könnt ihr euch somit jetzt ersparen, denn nachfolgender Quelltext funktioniert definitiv bei RN-MikroFunk:

'##############################################################
'RFM12b_WakeupTimer_SenderRNMikroFunk.bas
'
'Ein Testprogramm für die winzige universal Platine RN-MikroFunk
'
'Dieses Programm demonstriert wie man den Wake-Up Timer des RFM12b
'nutzen kann um Strom zu sparen
'Der Vorteil dieses Timers gegenüber dem Watchdog Timern
'besteht darin das ein wesentlich längere Sleeptime
'definiert werden kann, man ist nicht mehr auf die 8 Sekunden
'des Watchdog beschränkt. Nähere Infos in der Doku zu
'RN-MikroFunk. Man spart also deutlich mehr Strom
'und kann so das Board eventuell über Jahre mit einer Batterie nutzen.
'
'Auch dieses Programm sendet per Funk wieder den String "RN-MikroFunk"
'Danach schaltet es aber das Funkmodul und alle Funktionen bis auf den
'Wake-Up Timer komplett aus und geht auch selbst in den Schalfmodus!
'Dadurch braucht das Board fast keinen Strom, unter 0,01mA !!!
'Nach 5 Sekunden weckt das Funkmodul per Interrupt RF-MikroFunk auf.
'und macht da weiter wo es aufgehört hat. Es sendet also alle 5 Sekunden
'den String aus und schläft zwischendurch!
'
'Alternativ wären auch Minuten, Stunden ja sogar Tage als Sleeptime definierbar
'
'Weitere Beispiele auf http://www.mikrocontroller-elektronik.de/
'######################################################################

'Portbelegung:
'keine externe Beschaltung nötig

$programmer = 12 'Bascom USB Programmer (Zeile weglassen wenn anderer Programmer)
$PROG &HFF,&HFF,&HD9,&HFF 'Diese Anweisung stellt Fusebits ein
$regfile = "m328pdef.dat"
$framesize = 32
$swstack = 32
$hwstack = 64
$crystal = 8000000 'Quarzfrequenz
$baud = 9800 'Baudrate (Übertragungsgeschwindigkeit)
Baud = 9800

Declare Sub Rfm12_init
Declare Sub Rfm12_senden(byval Anzahl As Integer)
Declare Function Spitransfer(byval Dout As Word) As Word

Ss Alias Portb.2
Mosi Alias Portb.3
Miso Alias Pinb.4
Sck Alias Portb.5

Config Ss = Output
Config Mosi = Output
Config Sck = Output

'Interrupt aktivieren, wird zum aufwecken gebraucht

Config Pind.2 = Input 'Int0
Portd.2 = 1 'Pullup
Config Int0 = Falling
On Int0 RFM_Funkirq
Enable Int0
Enable Interrupts

'Hier werden die zu sendenten Daten abgelegt
Dim Ausgabedaten(200) As Byte
dim ausgabestring as string*199 At Ausgabedaten Overlay
dim r as word

Ss = 1
Sck = 0
Rfm12_init
'r=Spitransfer(&hE488) 'Timerzeit auf ca 2 Sekunden stellen
r=Spitransfer(&hE5A8) 'Timerzeit auf ca 5 Sekunden stellen
'r=Spitransfer(&ECFF ) 'Timerzeit auf ca 16 Minuten stellen

print "Start Programm RFM12b_WakeupTimer_SenderRNMikroFunk.bas"

'Hauptprogramm
Do
 ausgabestring="RN-MikroFunk"
 r = Spitransfer(&H80D7) 'TX Register wieder aktivieren
 call Rfm12_senden(12)
 r = Spitransfer(&H8057) 'Deaktiviert das TX Register um WakeUp Interrupt zuzulassen
 r=Spitransfer(&H0000) 'Staus lesen interrups zurücksetzen
 r=Spitransfer(&H8203) 'Funkmodul schlafen legen /Wakeup an lassen
 Powerdown
Loop


' ************ Hilfsfunktionen zur Kommunikation mit Funkmodul **************
' (nähere Infos im Datenblatt des Funkmoduls und in der Dokumentation von RN-MikroFunk)

' Initialisiere Funkmodul

Sub Rfm12_init
Local Wert As Word
Local X As Word
Local d As Word

 X = 0
 Restore Datainit3 'Initialisierungsfolge
 Do
  Read Wert
  D = Spitransfer(wert)
  Incr X
 Loop Until Wert = 0
 Waitms 200
 r = Spitransfer(&H0000)
End Sub

Sub Rfm12_senden(byval Anzahl As Integer)
local n as byte
Local d As Word

 D = Spitransfer(&H8238) 'Enable Transmitter; enable Synthesizer ;enable Crystal Osc
 Gosub Rfm12_warte
 D = Spitransfer(&Hb8aa)
 Gosub Rfm12_warte
 D = Spitransfer(&Hb8aa)
 Gosub Rfm12_warte
 D = Spitransfer(&Hb8aa)
 Gosub Rfm12_warte
 D = Spitransfer(&Hb82d)
 Gosub Rfm12_warte
 D = Spitransfer(&Hb8d4)
 For N = 1 To Anzahl
  Gosub Rfm12_warte
  D = &HB800 + Ausgabedaten(n)
  D = Spitransfer(d)
 Next N
 Gosub Rfm12_warte
 D = Spitransfer(&Hb8aa)
 Gosub Rfm12_warte
 D = Spitransfer(&Hb8aa)
 Gosub Rfm12_warte
 D = Spitransfer(&H8201) 'disable transmitter und receiver
End Sub

Function Spitransfer(byval Dout As Word) As Word
Local Nspi As Integer
Local Dspi As Integer
Local Dmiso As Word
 Ss = 0
 Dmiso = 0
 For Nspi = 1 To 16
  Dspi = Dout And &H8000
  If Dspi = 0 Then
   Mosi = 0
  Else
   Mosi = 1
  End If
  Dout = Dout * 2
  Dmiso = Dmiso * 2
  Dmiso = Dmiso + Miso
  Sck = 1
  Waitus 5
  Sck = 0
 Next Nspi
 Ss = 1
 Spitransfer = Dmiso
End Function


Rfm12_warte:
Ss = 0
Do
Loop Until Miso = 1
Return

'Wird hier nur zum aufwecken genutzt
RFM_Funkirq:
return

'End ' programmende

'Funkmodul Initialisierungsdaten mit 9600 Baud
Datainit3:
Data &H80D7% ' Enable: 433 Mhz;XTAL cap=12pf; TX-Register; RX-Fifo
Data &H82D9% ' Enable: Receiver; Crystal Osc; Base Band Block; Synthesizer
             ' Disable Low-bat Detector; Transmitter; Wake-Up-Timer; Clock output Pin
Data &HA67C% ' &Ha67c=frequenz 434,15 Mhz oder z.B. &HA538 für 433,34 Mhz
Data &HC623% ' &Hc647=Datenrate '4.8kbps; C623=9600kbps; C611 =19200
Data &H90C0% ' LNA Gain=MAX; Pin=nInt; RX Bandwidth=67 khz; VDI=Fast; DRSSI=-103 dB
Data& HC2AC% ' Fiter=Digital; Recover Mode=Auto; Quality Threshold=4;
             ' Recovery Speed=Slow
Data &HCA80% ' FIFO INT Level=8; Sync on=2;Fifo Fill Start=Sync; Reset
             ' Sensitivity=High;
             ' Disable:FIFO Fill Enabled
Data &HC483% ' Enable: AFC Mode; AFC; Frequency Offset Register
             ' Disable: High Accuracy; Strobe
Data &H9820% ' Frequenz Shift=POS; Power Out=0 dB; Deviation=45 khz
Data &HE000% ' WakeUp-Timer=0ms
Data &HC800% ' Duty Cycle = Infinity % OFF
Data &HC000% ' Low batterie=2,2V; Clock Pin=1 Mhz
Data &HCED4% ' Synchron Pattern
Data &HCC57% ' PLL Settings
Data &H0000% ' Status lesen irqs zurückstellen
Data 0% ' ende initialisierung

Nun unser obiges Programm ist natürlich wieder kompatibel zu allen Empfängerprogrammen in dieser Dokumentation. Es sendet wieder alle 5 Sekunden den String „RN-MikroFunk“ an den Empfänger. Zwischen diesen 5 Sekunden legt es sich und Funkmodul schlafen. Es braucht also die meiste Zeit fast keinen Strom! Statt 5 Sekunden kann man natürlich auch 5 Minuten, 15 Minuten oder stündlich nehmen, je nachdem was überwacht werden soll. Die Sleeptime wird über einen 16 Bit Befehl Hex E000 festgelegt. Bei diesem Befehl legen ausnahmsweise mal nicht die unteren 8 Bit sondern die unteren 13 Bit die Zeit fest. Die Zeit berechnet sich nach einer Formel, siehe Datenblatt oder die Wake-Up Time Tabelle etwas weiter hinten in dieser Dokumentation.

Von der Initialisierung und Senderoutinen ist unser Programm praktisch identisch mit den bisherigen Programmen. Hinzu gekommen ist jetzt wieder die Freigabe des Interrupts und eine Interrupt Funktion. Die Interrupt Funktion muss jedoch nichts machen, sie besteht nur aus einem Return. Die Aufgabe des Interrupts besteht ja auch nur daraus den Controller aus dem Tiefschlaf zu wecken.

Entscheidend ist die Hauptscheife in unserem Programm, hier muss eine gewissen Befehlsreihenfolge genau eingehalten werden sonst tut sich nämlich gar nichts weil kein Interrupt ausgelöst wird.

Zunächst muss erst mal die Zeit definiert werden, also wie lange das Funkmodul schlafen gehen soll. Das machen wir mit dem Befehl:

r=Spitransfer(&hE5A8) ‚Timerzeit auf ca 5 Sekunden stellen

Diese Zeit Definition muss nicht innerhalb der Schleife gemacht werden, es reicht wenn diese Zeit einmal vor der Hauptschleife definiert wird.

Dann kommt die Hauptschleife:

Do
 ausgabestring="RN-MikroFunk"
 r = Spitransfer(&H80D7) 'TX Register wieder aktivieren
 call Rfm12_senden(12)
 r = Spitransfer(&H8057) 'Deaktiviert das TX Register um WakeUp Interrupt zuzulassen
 r=Spitransfer(&H0000) 'Staus lesen interrups zurücksetzen
 r=Spitransfer(&H8203) 'Funkmodul schlafen legen /Wakeup an lassen
 Powerdown
Loop

Das Wichtige was hier beachtet werden muss, ist die Deaktivierung des TX-Registers (TX-FIFO) nach dem Senden der ersten Daten. Wird dies nicht gemacht, dann wird nämlich der Interrupt dauerhaft blockiert. Zudem muss über den Befehl Hex 0000 noch einmal der Status des Funkmodules gelesen werden damit der Interrupt zurückgesetzt wird. Erst danach darf man das Funkmodul mit Hex 8203 schlafen legen und dann den Powerdown Befehl geben.

Beim nächsten Senden darf natürlich nicht vergessen werden dass TX-Register (TX-FIFO) wieder zu aktivieren bevor man sendet. Dann wiederholt sich das ganze. Also im Prinzip ganz einfach, wenn man erst mal heraus bekommen hat wie´s geht 😉

Tabelle mit Wake-Up Zeiten für RFM12b

Damit ihr nicht so viel rechnen müsst, hier ein paar Zeitvorgaben für den Wake-Up Timer des Funkmoduls

Hex-BefehlBefehl in binärer SchreibweiseZeit
E1381110000100111000100 ms
E38811100011100010001 Sekunde
E5A811100101101010005 Sekunden
E780111001111000000015 Sekunden
E8FF111010001111111160 Sekunden
E9FF1110100111111111120 Sekunden
EAFF11101010111111114 Minuten
EBFF11101011111111118 Minuten
ECFF111011001111111116 Minuten
.........

Daten per Interrupt und RFM12b empfangen

Jetzt möchte ich noch einen etwas komfortablere Funktion zeigen. Unser letztes Empfangsprogramm in dieser Dokumentation hatte ja den kleinen Nachteil dass während des Empfangs der Controller nichts anderes machen konnte.

Das ist nun bei dem nachfolgendem Programm anders, hier empfängt RN-MikroFunk die Daten quasi ganz nebenbei im Hintergrund, sprich in einer Interrupt Funktion.

Obwohl das Rfm12b im Internet schon sehr oft dokumentiert und eingesetzt wird, findet man kaum Beispiele die genauer erläutern wie das in Bascom funktioniert. Dem soll dieses Beispiel abhelfen denn im Grunde ist es einfach, es gibt nur ein paar Fallstricke.

Damit das Beispiel kompatibel zu den Sendefunktionen hier in der Dokumentation bleibt, wird also auch unser Interrupt gesteuertes Programm wieder fest auf die Datenlänge von 12 Bytes zugeschnitten. Sie können also wieder als Gegenstück eines unserer Sendebeispiele nutzen und es wird wieder der String „RN-MikroFunk“ übertragen. Natürlich lässt sich das Programm auf beliebige Datenlängen anpassen.

Bevor ich etwas zum Code erläutere, erst mal der komplette Quellcode:

'##############################################################
'IRQ_EmpfaengerRNMikroFunk.bas
'
'Ein Testprogramm für die winzige universal Platine RN-MikroFunk und RFM12b
'
'Das Programm demonstriert wie man Daten per Interrupt empfaengt
'Ein anderes Funkmodul sollte Daten mit dem Programmm TestSenderRNMikroFunk
'senden.
'Das Programm ist für das 433Mhz Modul RFM12b gedacht, diese
'muss bei RN-MikroFunk bestückt sein. Ansonsten muss nur Spannung
'bzw. Batterie angeschlossen werden.
'Weitere Beispiele auf http://www.mikrocontroller-elektronik.de/
'######################################################################

'Portbelegung:
'keine externe Beschaltung nötig

$programmer = 12 'Bascom-USB Programmer (Zeile weglassen wenn anderer Programmer)
$PROG &HFF,&HFF,&HD9,&HFF 'Diese Anweisung stellt Fusebits ein
$regfile = "m328pdef.dat"
$framesize = 32
$swstack = 32
$hwstack = 64
$crystal = 8000000 'Quarzfrequenz
$baud = 9800 'Baudrate (Übertragungsgeschwindigkeit)
Baud = 9800

Declare Sub Rfm12_init
Declare Sub Rfm12_empfange (byval anzahl as word)
Declare Function Spitransfer(byval Dout As Word) As Word

Ss Alias Portb.2
Mosi Alias Portb.3
Miso Alias Pinb.4
Sck Alias Portb.5

Config Ss = Output
Config Mosi = Output
Config Sck = Output


'Interrupt aktivieren
Config Pind.2 = Input 'Int0
Portd.2 = 1 'Pullup
Config Int0 = Falling
On Int0 RFM_Funkirq
Enable Int0
Enable Interrupts

Dim IRQ_Eingangsdaten(13) As Byte
Dim Eingangsdaten(13) As Byte
dim eingangsstring as string*12 At Eingangsdaten Overlay
Dim DatenbyteAnzahl As word
dim daten_sind_da as bit

Dim N As Byte
dim r as word 'wird im Interrupt genutzt

print "RN-MikroControl (c) Roboternetz.de start"
Waitms 100
Ss = 1
Sck = 0
Rfm12_init

DatenbyteAnzahl=0
daten_sind_da=0
'Auf neue Anfangssequenz warten
r = Spitransfer(&H82c8) 'Empfänger aktivieren
r = Spitransfer(&Hca83) 'FIFO einstellen/aktivieren

'Hauptprogramm
Do
 if daten_sind_da=1 then
   Print
   Print "Datenbytes:" ; DatenbyteAnzahl
   Print "Als Dezimalzahlen: " ;
   For N = 1 To 12
    Print Eingangsdaten(n);
    Print " ";
   Next N
   print
   Print "Als String: " ;left(eingangsstring,12)
   daten_sind_da=0
 endif

 'an dieser Stelle könnten beliebige Aufgaben nebenher gemacht werden
 'nur ab und zu muss halt geschaut werden ob die Daten schon da sind
 'das sagt hier das Flag "daten_sind_da" aus
Loop


' ************ Hilfsfunktionen zur Kommunikation mit Funkmodul **************
' (nähere Infos im Datenblatt des Funkmoduls und Doku von RN-MikroFunk)


' Initialisiere Funkmodul
Sub Rfm12_init
Local Wert As Word
Local X As Word
Local d As Word

 X = 0
 Restore Datainit3 'Initialisierungsfolge
 Do
  Read Wert
  D = Spitransfer(wert)
  Incr X
 Loop Until Wert = 0
 Waitms 200
End Sub

Sub Rfm12_empfange(byval anzahl as word)
Local d As Word

 D = Spitransfer(&H82c8)
 D = Spitransfer(&Hca83)
 For N = 1 To anzahl
  Ss = 0
  Do
   Waitus 100
  Loop Until Miso = 1
  D = Spitransfer(&Hb000)
  Eingangsdaten(n) = D
 Next N
 D = Spitransfer(&H8208)
End Sub


Function Spitransfer(byval Dout As Word) As Word
Local Nspi As Integer
Local Dspi As Integer
Local Dmiso As Word
 Ss = 0
 Dmiso = 0
 For Nspi = 1 To 16
  Dspi = Dout And &H8000
  If Dspi = 0 Then
  Mosi = 0
 Else
  Mosi = 1
 End If
 Dout = Dout * 2
 Dmiso = Dmiso * 2
 Dmiso = Dmiso + Miso
 Sck = 1
 Waitus 5
 Sck = 0
 Next Nspi
 Ss = 1
 Spitransfer = Dmiso
End Function


Rfm12_warte:
Ss = 0
Do
Loop Until Miso = 1
Return

'Interrupt vom Funkmodul RFM12b
RFM_Funkirq:
 Incr DatenbyteAnzahl
 r = Spitransfer(&Hb000)
 if DatenbyteAnzahl<=12 then
  IRQ_Eingangsdaten(DatenbyteAnzahl) = r
 else
  r = Memcopy(IRQ_Eingangsdaten(1) , Eingangsdaten(1) , 12)
  daten_sind_da=1
  datenbyteanzahl=0
  r = Spitransfer(&Hca81) 'FIFO FILL zurücksetzen
  r = Spitransfer(&Hca83) 'FIFO FILL aktivieren
  Eifr.intf0 = 1 'Eventuell anstehenden Interrupt loeschen
 endif

return

End

'Funkmodul Initialisierungsdaten 9600 Baud
Datainit3:
Data &H80D7% ' Enable: 433 Mhz;XTAL cap=12pf; TX-Register; RX-Fifo
Data &H82D9% ' Enable: Receiver; Crystal Osc; Base Band Block; Synthesizer
             ' Disable Low-bat Detector; Transmitter; Wake-Up-Timer; Clock output Pin
Data &HA67C% ' &Ha67c=frequenz 434,15 Mhz oder z.B. &HA538 für 433,34 Mhz
Data &HC623% ' &Hc647=Datenrate '4.8kbps; C623=9600kbps; C611 =19200
Data &H90C0% ' LNA Gain=MAX; Pin=nInt; RX Bandwidth=67 khz; VDI=Fast; DRSSI=-103 dB
Data &HC2AC% ' Fiter=Digital; Recover Mode=Auto; Quality Threshold=4;
 ' Recovery Speed=Slow
Data &HCA80% ' FIFO INT Level=8; Sync on=2;Fifo Fill Start=Sync; 
             ' Reset Sensitivity=High;
             ' Disable:FIFO Fill Enabled
Data &HC483% ' Enable: AFC Mode; AFC; Frequency Offset Register
             ' Disable: High Accuracy; Strobe
Data &H9820% ' Frequenz Shift=POS; Power Out=0 dB; Deviation=45 khz
Data &HE000% ' WakeUp-Timer=0ms
Data &HC800% ' Duty Cycle = Infinity % OFF
Data &HC000% ' Low batterie=2,2V; Clock Pin=1 Mhz
Data &HCED4% ' Synchron Pattern
Data &HCC57% ' PLL Settings
Data &H0000% ' Status lesen irqs zurückstellen
Data 0%      ' ende initialisierung

Zunächst was macht das Programm ? Nach außen hin macht es das wie gesagt das gleiche wie unsere anderes Programm. Das heißt wenn Sie ein Terminal-Programm über RS232 (bzw. über das USB-Modul) anschließen, sehen wir auch hier wieder folgendes:

Daten Empfang mit Funkmodul RFM12

 

Die Initialisierung beim Start von RN-MikroFunk ist die gleiche wie in unseren anderen Beispielen. Die Hauptschleife sieht aber diesmal ganz anders aus. Dort hat die Schleife im Prinzip folgenden Aufbau

do
 if daten_sind_da=1 then
   …
 endif 

 'zeit für beliebige Aufgaben
Loop

Das bedeutet unser Hauptprogramm kümmert sich die meiste Zeit überhaupt nicht um den Funkempfang. Erst wenn die Variable daten_sind_da auf 1 gesetzt wurde, dann gibt das Programm den Datenstring komplett über RS232 aus. Abholen muss es dann nichts mehr, denn die 12 Bytes liegen fertig serviert in dem Datenarray bzw. String.

Wer kümmert sich nun um den Empfang? Das macht unsere Interrupt-Funktion:

'Interrupt vom Funkmodul RFM12b

RFM_Funkirq:
 Incr DatenbyteAnzahl
 r = Spitransfer(&Hb000)
 if DatenbyteAnzahl<=12 then
  IRQ_Eingangsdaten(DatenbyteAnzahl) = r
 else
  r = Memcopy(IRQ_Eingangsdaten(1) , Eingangsdaten(1) , 12)
  daten_sind_da=1
  datenbyteanzahl=0
  r = Spitransfer(&Hca81) 'FIFO FILL zurücksetzen
  r = Spitransfer(&Hca83) 'FIFO FILL aktivieren
  Eifr.intf0 = 1 'Eventuell anstehenden Interrupt loeschen
 endif

return

Diese Interrupt Funktion wird quasi bei jedem empfangenen Byte automatisch aufgerufen, ausgelöst durch einen Interrupt des RFM12b über INT0.

Unser Programm braucht also nicht mehr zu machen als das Byte in das Array einzutragen und einen Zähler hoch zuzählen. Da wir ja feste 12 Bytes empfangen wollen, muss die Interrupt Funktion dem Hauptprogramm nur noch mitteilen wann die kompletten 12 Bytes da sind. Das macht die Funktion indem es dann die Variable daten_sind_da auf 1 setzt.

Das war es im Prinzip schon. Aber warum kopiert unser Programm das Datenarray noch einmal wenn die Daten da sind, warum kann die Hauptschleife nicht einfach daraus die Daten lesen? Ganz einfach, weil der Datenempfang ja weiter geht. Es könnte also passieren dass während der Ausgabe der Daten die Daten bereits wieder überschrieben werden. Das umgeht man am besten durch Kopieren des Arrays, so kann sich unser Hauptprogramm mit der Ausgabe und Verarbeitung der Daten mehr Zeit lassen, denn unsere Interrupt Funktion kümmert sich bereits nebenher um die nächsten Daten.

Ein Fallstrick bei der Interrupt Handhabung ist die Tatsache, dass nach dem Empfang der kompletten Daten unbedingt FIFO FILL zurückgesetzt und aktiviert werden muss.
Dafür sorgen in diesem Programm die Zeilen:

r = Spitransfer(&Hca81) ‚FIFO FILL zurücksetzen
r = Spitransfer(&Hca83) ‚FIFO FILL aktivieren

Dies ist notwendig, damit das Funkmodul nach einen neuen Datenanfang sucht und dann wieder Interrupts auslöst. Den gleichen Effekt erreicht man übrigens auch wenn der Empfänger aus und eingeschaltet wird!

Sicherheitshalber soll sollte man auch gespeicherte Interrupts, die während des Interrupts aufgetreten sind, löschen, da das Modul beim Erhalt von 12 Bytes nicht aufhört zu empfangen sondern danach noch Müll (Rauschen) kommt.

Eifr.intf0 = 1 ‚Eventuell anstehenden Interrupt loeschen

Ein weiterer Fallstrick: Nicht vergessen den Empfänger vor der Hauptschleife erst einmal einzuschalten und den FiFO bereitzumachen. Wird das vergessen,werden keine Interrupts ausgelöst und quasi nichts empfangen! Also diese beiden Zeilen voranstellen:

'Auf neue Anfangssequenz warten
r = Spitransfer(&H82c8) 'Empfänger aktivieren
r = Spitransfer(&Hca83) 'FIFO Fill aktivieren

Ich denke der Rest des Programms wird durch die Kommentarzeilen im Quellcode klar und bedarf keiner weiteren Erläuterung. Das Programm soll nur das Beispiel dienen, es kann an beliebige Datenlängen angepasst oder natürlich auch auf flexible Datenlängen umgeschrieben werden.

 

Befehlsübersicht Funkmodul RFM12b

Diese Tabelle aufgrund des Datenblattes und verschiedenen anderen Internet-Quellen erarbeitet. Wir können keine Gewähr für Vollständigkeit und Richtigkeit übernehmen. Die Tabelle soll nur einen Überblick geben, Sie ist kein Ersatz für das Datenblatt. Jeweiligen Befehl anklicken um Bit-Belegung aufzulisten:

Configuration Setting HEX 80 & xx
Bit-Interpretation   10000000 | el | ef | b1 | b0 | x3 | x2 | x1 | x0

el (TX FIFO) Sendepuffer für Datentransfer (1=Ein/0=Aus)
ef (RX FIFO) Empfangspuffer (FIFO)(1=Ein/0=Aus)
b1/b0 Basisfrequenz je nach Funkmodul (00=315MHz/01=433MHz/10=868MHz/11=915MHz)
x1/X0 Interner Kondensator für Taktgenerator auswählen (8,5 bis 16pF)
Power-Managment HEX 82 & xx
Bit-Interpretation   10000010 | er | ebb | et | es | ex | eb | ew | dc

er Empfänger Ein/Aus (1=Ein/0=Aus)
ebb Base Band Block (1=Ein/0=Aus)
et Sender Ein/Aus (1=Ein/0=Aus)
es Synthesizer Ein/Aus (1=Ein/0=Aus)
ex Quarz-Oszilator Ein/Aus. (1=Ein/0=Aus)
eb Low-Batterie Erkennung (1=Ein/0=Aus)
ew WakeUpTimer Ein/Aus (1=Ein/0=Aus)
dc = Ausgangstakt am CLK Pin (1=Aus/0=Ein)
Frequenz Setting HEX 0A & xx
Bit-Interpretation  1010 | f11 | f10 | f9 | f8 | f7 | f6 | f5 | f4 | f3 | f2 | f1 | f0

F0 bis f11 Bestimmt den Offsetwert der Frequenz. Als Basis gilt das eingestellte Band.
Data Rate HEX C6 & xx
Bit-Interpretation  11000110 | cs | r6 | r5 | r4 | r3 | r2 | r1 | r0

cs Prescaler (1/8) (1=Ein/0=Aus)
r0 bis r6 Bestimmt Baudrate (Teilerfaktor)
Receiver Control HEX 94 & xx
Bit-Interpretation  10010 | p20 | d1 | d2 | i2 | i1 | i0 | g1 | g0 | r2 | r1 | r0

p20 Bestimmt die Funktion von Pin20 (nINT / VDI) (1=VDI Ausgang / 0 =Interrupt)
d1/d2 Valid Data Indicator - definiert die Geschwindigkeit in der ein korrektes Signal erkannt werden soll (Fast,medium,Slow,immer an)
i0 bis i2 Bestimmt die Bandbreite des Empfängers in KHz (67 bis 400 Khz)
g1/g0 LNA-Gain - Verstärkungsfaktor des Eingangs-Signal-Verstärkers (0db / -6db / -14db / -20db)
r0 bis r2 DRSSI - Digital Received Signal Strength Indication (-103, -97 , -91, -85, -79, -73 db)
Data Filter & Clock Recovery HEX C2 & xx
Bit-Interpretation   11000010 | al | ml | ? | s | ? | f2 | f1 | f0

al Recovery Mode (Manuell/Auto )
ml Recovery Speed (schneller/langsamer Modus)
s = DataFilter (0=DigitalFilter / 1=AnalogFilter)
f0 bis f3 (DQD Threshold) Schwellwert, ab dem ein Signal als Gut empfunden wird (4 bis 7)
? Unbekannt, steht auf 1
FIFO and RESET Mode HEX CA & xx
Bit-Interpretation  11001010 | f3 | f2 | f1 | f0 | si | al | ff | dr

F0 bis f3 FIFO Interrupt Level (0 bis 15)
si Legt fest ob 1 oder 2 Syncronbytes genutzt werden sollen (gibt’s nicht bei RFM12 nur RFM12b)
al = FIFO Fill Start - Legt fest ob erst ab Sycronbytes empfangen werden soll (0=Sync / 1=Ständig)
ff = FIFO Fill Erkennung aktivieren (1=Ein/0=Aus)
dr = Sens Reset Mode – Empfindlichkeit mit der Spannungsschwankungen zu RESET führen (Low/High)
Synchronization Pattern HEX CE & xx
Bit-Interpretation  11001110 | b7 | b6 | b5 | b4 | b3 | b2 | b1 | b0

B0 bis b7 Legt den Wert der beiden bzw. dem Sycronisations Byte fest
Automatic Frequency Control HEX C4 & xx
Bit-Interpretation  11000100 | a1 | a0 | rl1 | rl0 | st | fi | oe | en

A0/a1 AFC Modus (0=Auto, 1=einmalig nach Einschalten,2=Solange VDI Low ist, 3=unabhängig von VDI)
r0/r1 Offset Register Limit (Keine Begrenzung , +15 bis -16, +7 bis -8, +3 bis -4)
st Strobe
fi Genauer Berechnungsmodus aktivieren (1=Ein/0=Aus)
oe AFC Offset aktivieren
en AFC ein/aus (1=Ein/0=Aus)
TX Control HEX 98 & xx
Bit-Interpretation  1001100 | mp | m3 | m2 | m1 | m0 | ? | p2 | p1 | p0

mp Frequency Shift (Positiv oder negativ)
m0 bis m3 Deviation (15 bis 240 khz)
p Bestimmt die relative Ausgangsleistung des Senders anhand des dBm-Wertes 
? Unbekannt, steht auf 0
PLL Settings HEX CC & xx
Bit-Interpretation  110011000 | ob1 | ob0 | lpx | ddy | ddit | bw1 | bw0

lpx Clock Rise (Fast, Medium, Slow )
ddy Enable Phase Detector Delay
ddi Schaltet Dithering aus (0=Ein/1=Aus)
bw0/bw1 PP Band (00=86.2kbps / 01=256kbps
Ob1/Ob0 = ?
Wake-Up Timer HEX E & xxx
Bit-Interpretation  111 | R4|R3|R2|R1|R0 | M7 | M6 | M5 | M4 | M3 | M2 | M1 | M0

R Exponent der Zeit
M Zeit
Low Duty-Cycle HEX C8 & xx
Bit-Interpretation  11001000 d6 | d5 | d4 | d3 | d2 | d1 | d0 | en

D0 bis d6 Einschaltdauer während der zyklischen Einschaltung (Formel DC = (D x 2 + 1) / M x 100% )
en = zyklischen Einschaltung aktivieren
Low Battery Detect and uC Clock HEX C0 & xx
Bit-Interpretation  11000000 | d2 | d1 | d0 | v4 | v3 | v2 | v1 | v0

D Bestimmt Frequenz der Clockausgabe am CLK Pin (1, 1.25, 1.66, 2, 2.5, 3.33, 5, 10 Mhz)
v Minimalspannung, ab der ein Interrupt durchgeführt wird, wenn Low-Batterie Erkennung aktiviert ist
RX Read HEX B0 & xx
Bit-Interpretation  10110000 | d7 | d6 | d5 | d4 | d3 | d2 | d1 | d0

d0-d7 Empfangenes Datenbyte

 

TX Write HEX B8 & xx

 

Bit-Interpretation  10111000 | d7 | d6 | d5 | d4 | d3 | d2 | d1 | d0

d0-d7 Zu sendendes Datenbyte
Status Read HEX 0000
Bit-Interpretation  x0 | x1 | x2 | x3 | x4 | x5 | x6 | x7 | x8 | x9 | x10 | x11 | x12 | x13 | x14 | x15 | x16 | x17 | x18

x0 bis x5 Interrupt Bits
x6 bis x15 Status Bits
x16 bis x18 FIFO

x0 FFIT/RGIT Fifo gefüllt / TX Register ist bereit neue Daten zu senden 
x1 = POR (Power On Reset)
x2 = FFOV / RGUR 
x3 = WKUP
x4 = EXT
x5 = LBD
x6 = FFBM (FIFO Puffer leer)
x7 = RSSI/ATS 
x8 = DQD 
x9 = CRL 
x10 = ATGL
x11 = OFFS_4
x12 = OFFS_3
x13 = OFFS_2
x14 = OFFS_1
x15 = OFFS_0
x16 = FO
x17 = FO+1
x18 = FO+2

 

 

Schaltplan zu dem Projekt RN-MikroFunk

Schaltplan - RN-MikroFunk – Mini AVR Microcontroller Modul mit Funkmodul

Downloads

  Eagle-Dateien (ZIP)
  Eagle-Lib (ZIP)
  Bascom Beispielprogramme (ZIP)
  RFM12B Datenblatt (ZIP)
   Datenblatt zum Atmel AVR Controller ATMega 328
   ELV Datenblatt passendes RX/TX/USB-Modul

Empfohlene Leiterplatten Hersteller
Autor des Projektes danken <Klick hier>

Falls dir das Projekt gefallen hat und du einen Nutzen davon hattest, kannst du den Autor durch einen freiwilligen Beitrag Danke sagen bzw. für weitere Projekte motivieren! Der Betrag geht zu 100% an den Entwickler der Schaltung! Den Betrag bestimmen Sie selbst:




 

Links zum Thema

Bezugsquelle

Funkmodul RFM12B-868-S Sende-/Empfangsmodul
Siehe Preisliste
Das RFM12B ist die neue 3,3 V- Version des kostengünstigen Sende-/Empfangsmoduls. Es arbeitet mit FSK-Modulation im 868 MHz-Band. Über die integrierte SPI-Schnittstelle kann das Modul leicht mit einem Microcontroller programmiert werden. Dadurch kann mit geringem Aufw...
Mehr Infos* >>  |  zum Shop* >>
Delock 88877 ISM SMA Omni Star Antenne mit Standfuß 433 MHz,
EUR 6,29 EUR 7,90
ungerichtet, Schwarz...
Versandfertig in 1 - 2 Werktagen
Mehr Infos* >>  |  zum Shop* >>
10pcs 433MHz Antenne Helical-Antenne Fernbedienung f¨¹r Arduino
EUR 2,00 EUR 2,00
Spring antenna in a cost-effective, can be used for a variety of 433MHz wireless device, such as wireless module CC1100 \ CC1020 \ NRF905 \ NRF903 \ SI4432 and other products, ease of use, performance, and to use soldered directly on the antenna of a wireless module. ...
Versandfertig in 1 - 2 Werktagen
Mehr Infos* >>  |  zum Shop* >>
ANSMANN APS 300 Universal Stecker Netzteil zur Stromversorgung
EUR 7,33
Ansmann APS 300...
Versandfertig in 1 - 2 Werktagen
Mehr Infos* >>  |  zum Shop* >>
Varta 4022 5x Industrial 9V Block Batterie Alkaline
EUR 5,94
VPE 20x1 Stück...
Versandfertig in 4 - 5 Werktagen
Mehr Infos* >>  |  zum Shop* >>

* = Fotos stammen von der Amazon-API (Amazon-Partnerprogramm )/Link ist ein Affiliate-Link zu Amazon

Weitere Hinweise

Vor dem Aufbau bitte nachfolgende Hinweise lesen:

Das Projekt unterliegt einer CC-Lizenz - Lizenzhinweis (zum Aufklappen anklicken)

Um ihnen weitgehende Möglichkeiten zum Nutzen der Schaltung einzuräumen, wurde dieses Projekt jetzt unter die CC-Lizenz gestellt. Sie haben So die Möglichkeit die Schaltung beliebig zu verändern oder weiterzugeben. Lediglich die kommerzielle Weitergaben ist nur mit Genehmigung möglich! Genauere Hinweise finden Sie im Lizenztext.

Bei einer Veröffentlichung oder Weitergabe ist nachfolgender Text sichtbar zu übernehmen:


cc_logo310

Projekt (Schaltung & Projektdateien) von Frank ist lizenziert unter einer Creative Commons Namensnennung - Nicht-kommerziell - Weitergabe unter gleichen Bedingungen 4.0 International Lizenz.
Über diese Lizenz hinausgehende Erlaubnisse können Sie unter http://www.mikrocontroller-elektronik.de/ erhalten.

Lizenziert wurde das Projekt von: 
www.Roboternetz.de & www.Mikrocontroller-Elektronik.de  -  Autor/User Frank

Dieser Name und diese Webseiten sind bei der Weitergabe stets deutlich sichtbar zu nennen!



Achtung: Es kann keinerlei Garantie für die Fehlerfreiheit der Schaltung oder anderer Projektdateien übernommen werden! Der Nachbau und Betrieb geschieht auf eigene Gefahr! Jegliche Haftung für Schäden oder Verletzungen wird ausgeschlossen! Schadensersatzansprüche, gleich aus welchem Rechtsgrund, sind ausgeschlossen.

Sicherheitshinweise und Haftungsausschluss (zum Aufklappen anklicken)

Dieses Projekt dient vornehmlich für Lehrzwecke und zum Experimentieren. Für den Aufbau sollten ausreichend Elektronik Grundkenntnisse und Kenntnisse bezüglich der Sicherheit (Experimentieren mit Strom und Handhabung gängiger Werkzeuge wie Lötkolben etc.) vorhanden sein. Unter dem Menüpunkt Buchvorstellungen als auch auf der Seite RN-Wissen.de empfehle ich diesbezüglich noch interessante Literatur mit der man sich dies erarbeiten kann. Für Fragen bezüglich Elektronik und Mikrocontroller empfehle ich das Forum: Roboternetz.de

Sicherheitshinweise und Haftungsausschluss
×

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.

Top