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
RM-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/ .
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
Das 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.
Insgesamt 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 RFM12b | Bei Projekt RN-MikroFunk verbunden mit Port ... | Erläuterung Alle Angaben ohne Gewähr - gültig ist alleine das Original Datenblatt des Herstellers! |
---|---|---|
SDO | MISO / PB4 | SPI-Bus:Signal Master In Slave out Über diesen Pin schickt das Modul Daten an den Controller |
SDI | MOSI / PB3 | SPI-Bus:Signal Master out Slave in Über diesen Pin schickt der Controller Daten an RFM12b |
SCK | SCK / PB5 | SPI-BUS: Taktrate für Datenübertragung |
nSEL | SS / PB2 | SPI-BUS: Select Slave Wenn dieses Pin auf Low gezogen wird, dann wird das Modul RFM12b selektiert um Daten oder Befehle zu übertragen |
nRES | RESET / PC6 | Wenn dieser bin auf LOW gezogen wird, dann wird das Funkmodul als auch der Controller zurückgesetzt |
nIRQ | INT0 / PD2 | Dieser 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,3V | Die Betriebsspannung |
GND | GND | GND / Masse |
FSK/DATA/nFFS | Über 1KOhm mit +3,3V verbunden | Dieser 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. |
ANT | Auf Pin1 geführt | Antennenanschluss / 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:
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:
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:
'############################################################## '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 https://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
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 https://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-Befehl | Befehl in binärer Schreibweise | Zeit |
---|---|---|
E138 | 1110000100111000 | 100 ms |
E388 | 1110001110001000 | 1 Sekunde |
E5A8 | 1110010110101000 | 5 Sekunden |
E780 | 1110011110000000 | 15 Sekunden |
E8FF | 1110100011111111 | 60 Sekunden |
E9FF | 1110100111111111 | 120 Sekunden |
EAFF | 1110101011111111 | 4 Minuten |
EBFF | 1110101111111111 | 8 Minuten |
ECFF | 1110110011111111 | 16 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 https://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:
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
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
Leiterplatte zum Projekt bestellen
Neu! Die Leiterplatte für dieses Projekt ist direkt über den Shop PlatinenCenter erhältlich. Da die Platinen dort vorgefertigt werden, sind diese sehr preiswert lieferbar.
Individuelle Leiterplatten
Möchtest du keine vorgefertigte Leiterplatte, weil Du vielleicht vorher Änderungen an dem Layout vornehmen möchtest, dann empfehlen ich die Anbieter auf unserer Leiterplatten-Service Seite.
Das Leiterplattenangebot ist ein Service Angebot der jeweiligen Anbieter. Bei Fragen bezüglich Lieferung und Preis bitte dort nachfragen!
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
- Verwendetes Funkmodul RFM12B
- Datenblatt des Herstellers
- Gutes Konfigurationstool für RFM12
- Weiterer Wiki-Artikel zu RFM12
- Forum für Diskussionen
- Bascom
- RN-Mikrofunk Projekt Beschreibung, Schaltplan und Bauanleitung
- RN-AVR Universal – Projekt mit RFM12b Funkmodul und ATmega 644
- Video zu RN-Avr Universal
- Andere Projekte mit RFM12b
- Codeschnippsel im Forum
- Alternative, WLAN Kommunikation mit ESP8266 oder NodeMCU
Bezugsquelle
Letzte Aktualisierung am 2024-12-08 / * Affiliate Links
Weitere Hinweise
Vor dem Aufbau bitte nachfolgende Hinweise lesen:Das Projekt unterliegt einer CC-Lizenz - Lizenzhinweis (zum Aufklappen anklicken)
Falls Dir der Beitrag gefallen oder geholfen hat kannst Du dem Autor aber gerne durch eine kleine Spende Danke sagen!