Aus meinen Raspberry Pi Pojekt Funksender und Empfänger hatte ich noch ein RFM12B 433Mhz Funkmodul übrig und suchte nach einer Verwendung, da kam mir die Idee das Modul direkt am Raspberry Pi zu betreiben und dem RasPi um mal zu sehen was so um mich herum passiert.
Material & Hardware
Folgende Hardware habe ich für den zusammenbau verwendet
- Raspberry Pi Modell B+ mit 8GB MicroSD Karte und passendem 2A Netzteil
- Ein RFM12B 433MHz + Stiftleisten / PCB-Header + Klingeldraht für die Antenne
- Ein GPIO Breakout Kit mit Breadboard aus dem Sintron Kit
- Diverse Jumper Kabel Male/Male für das Breadboard (auch aus dem Kit)
Der Zusammenbau
Um das RFM12B Modul einfach auf meinem Breadboard verwenden zu können habe ich mir zwei Stiftleisten zurecht geschnitten (je 6 Stifte) und diese direkt an den RFM12B angelötet. Hierbei habe ich auf jeder Seite des RFM12B den vierten Pin ausgelassen da ich diesen nicht verwende.
Da ich den RFM12B auch in anderen Setups verwenden möchte habe ich auch an den PIN für die Antenne einen Stift angelötet. Das ist für den Einsatz auf dem Breadboard nicht optimal für mich aber zweckmäßig. Ihr könnt auch einen Stift mit der langen Seite nach oben anlöten und daran direkt eine Antenne anbringen (165mm Klingeldraht).
Das Ergebnis nach dem Anlöten der Stiftleiste sieht wie folgt aus:
Tipp: Biegt die Stiftleisten mit einer kleinen Zange zurecht und Steckt sie ins Breadboard, dann könnt ihr den RFM12B dazwischen klemmen und ohne Gefummel verlöten.
Die Verkabelung des RFM12B
Die Verkabelung des RFM12B auf dem Breadboard gestalltet sich recht einfach.
Achtet darauf richtig zu verkabeln, sonst lauft ihr Gefahr das Modul zu zerstören.
1 2 3 4 5 6 7 8 9 |
RasPi GPIO | RFM12B ---------------------------------------- P1/Pin17 (+3.3V) | VDD (+3.3V) P1/Pin19 (MOSI) | SDI P1/Pin21 (MISO) | SDO P1/Pin22 (GPIO6) | nIRQ P1/Pin23 (SCLK) | SCK P1/Pin25 (GND) | GND P1/Pin26 (CE1) | nSEL |
Auf meinem Raspberry Pi GPIO Breakout mit Breadboard sieht die fertige Verkabelung so aus, rechts habe ich eine etwas verkürztes Stück Klingeldraht als Antenne ins Breadboard gesteckt.
RFM12B am RasPi einrichten
Zum Glück stellt uns die Einrichtung des RFM12B direkt am Raspberry Pi dank der JeeLib und der Arbeit von gkaindl nicht vor all zu große Hindernisse, es gibt bereits ein passendes Projekt auf GitHub das es uns ermöglicht direkt mit dem Modul zu kommunizieren.
Vorbereitungen
Wie immer aktualisiere ich als erstes meinen Raspberry Pi und führe einen Reboot durch. Ich verwende übrigens das Raspbian Image 2015-02-16-raspbian-wheezy.img.
1 2 |
sudo apt-get -y update && sudo apt-get -y upgrade sudo reboot |
SPI aktivieren
Wir aktivieren zu erst unser SPI um eine Kommunikation zwischen RasPi und dem Modul zu ermöglichen. Dazu müssen wir das passende Kernel Modul laden, die Datei /etc/modules bestimmt welche Module beim Systemstart geladen werden. Wir editieren die Datei mit dem Editor Nano
1 |
sudo nano /etc/modules |
Um die Kernel Modul „spi–bcm2708″ bei jedem Start automatisch zu laden fügen wir entsprechend der Schnittelle folgende Zeilen am Ende der Datei hinzu:
1 2 3 4 5 6 7 8 9 |
# /etc/modules: kernel modules to load at boot time. # # This file contains the names of kernel modules that should be loaded # at boot time, one per line. Lines beginning with "#" are ignored. # Parameters can be specified after the module name. snd-bcm2835 spi-bcm2708 |
Gespeichert wird bei Nano mit STRG+X, Y und Enter.
Danach müssen wir noch die Datei /etc/modprobe.d/raspi-blacklist.conf ändern, diese verhindert noch das die Kernel Module bei jedem Start geladen werden.
1 2 |
sudo nano /etc/modprobe.d/raspi-blacklist.conf |
Ihr könnt die Zeile blacklist spi-bcm2708 aus der Datei löschen oder durch auskommentieren (voranstellen einer # (Raute)) unwirksam machen.
1 2 3 4 5 6 7 |
# blacklist spi and i2c by default (many users don't need them) #blacklist spi-bcm2708 blacklist i2c-bcm2708 blacklist snd-soc-pcm512x blacklist snd-soc-wm8804 |
Speichern wieder mit STRG+X, Y und Enter. Das SPI Kernel Modul wird nun nach jedem Neustart automatisch geladen, um dieses zu aktivieren solltet ihr euren RasPi nun booten.
RFM12B Treiber installieren
Es handelt sich um einen Kernel Treiber der uns das RFM12B Modul als Character Device unter /dev/ am Raspberry Pi zur Verfügung stellt, damit können wir dann recht unproblematisch Daten auslesen aber auch schreiben.
Zunächst benötigen wir einige Sourcen um den Treiber kompilieren zu können. Wir setzen erst mal unsere Timezone richtig und holen dann die sourcen via apt. An der stelle verwende ich die Sourcen von Raspbian, das sind zwar nicht exakt die die von der RasPi Foundation im Image verwendet werden, das stört mich aber nicht, eine andere Möglichkeit den Treiber zum laufen zu bekommen habe ich nicht gefunden.
1 2 3 4 |
echo 'Europe/Berlin' | sudo tee /etc/timezone sudo dpkg-reconfigure -f noninteractice tzdata sudo apt-get -y install linux-image-rpi-rpfv linux-headers-rpi-rpfv |
Wir sehen nun unter /boot „vmlinuz-3.18.0-trunk-rpi“ und „initrd.img-3.18.0-trunk-rpi“ (kann bei euch abweichen) und fügen diese zu unserer /boot/config.txt hinzu um mit diesem Kernel zu booten. Dann führen wir einen Reboot durch. Kontrollieren könnt ihr danach den aktuellen Kernel dann mit sudo uname -r bei mir ist das nun 3.18.0-trunk-rpi
1 2 3 4 |
echo -e "kernel=vmlinuz-3.18.0-trunk-rpi" | sudo tee -a /boot/config.txt echo -e "initramfs initrd.img-3.10-3-rpi followkernel" | sudo tee -a /boot/config.txt sudo reboot |
Nun holen wir uns den Treiber von Git-Hub in unser Home, ersetzen in der Konfiguration rfm12b_config.h die Parameter welche bestimmen das wir den Treiber auf einem Raspberry Pi einsetzen. Falls ihr ein anderes Modul oder Konfiguration verwenden wollt könnt ihr die Datei „rfm12b_config.h“ auch manuell anpassen.
1 2 3 4 5 6 7 8 |
cd ~ git clone https://github.com/gkaindl/rfm12b-linux.git cd rfm12b-linux sed -i rfm12b_config.h -e 's/#define RFM12B_BOARD[[:space:]]*0/#define RFM12B_BOARD 1/g' sed -i rfm12b_config.h -e 's/#define RFM12B_DEFAULT_GROUP_ID[[:space:]]*211/#define RFM12B_DEFAULT_GROUP_ID 210/g' sed -i rfm12b_config.h -e 's/#define RFM12B_DEFAULT_JEE_ID[[:space:]]*0/#define RFM12B_DEFAULT_JEE_ID 1/g' sed -i rfm12b_config.h -e 's/#define RFM12B_DEFAULT_BAND_ID[[:space:]]*2/#define RFM12B_DEFAULT_BAND_ID 1/g' |
Das Makefile hat in der aktuellen Version einen Bug, daher müssen wir es mit Nano editieren
1 |
sudo nano Makefile |
Wir fügen vor die Zeilen 25 & 26 jeweils eine Raute ein um diese auszukommentieren, die beiden Zeilen meiner Makefile sehen dann so aus.
1 2 |
#if [ -f /lib/modules/$(KVERSION)/build/include/generated/uapi/linux/version.h ]; then # INCLUDE += -I/lib/modules/$(KVERSION)/build/include/generated/uapi/ |
Wir speichern die datei mit STRG+X,Y und Enter und starten dann make
1 |
make |
Nachdem der Treiber kompiliert wurde kopieren wir diesen in unser aktuelles Modules Verzeichnis und aktivieren das Modul durch hinzufügen des Namens in die Datei /etc/modules. Mit Depmod regenerieren wir die Abhängigkeiten zwischen den Kernelmodulen.
1 2 3 4 |
sudo cp rfm12b.ko /lib/modules/$(uname -r)/ echo -e "rfm12b" | sudo tee -a /etc/modules sudo depmod -a |
Dann kompilieren wir noch die mitgelieferten Beispiel-Programme, mit diesen testen wir ob die Kommunikation mit dem RFM12B und unserem Raspberry Pi funktioniert. Es ist ein reboot notwendig um den Treiber zu aktivieren.
1 2 3 4 |
cd examples make sudo reboot |
Nach dem Neustart wechseln wir in das Verzeichnis mit den kompilierten beispiel Programmen und starten dort.
1 |
cd rfm12b-linux/examples/bin |
Dort können wir nun das ein beispiel Programm aufrufen, ich verwende das Programm rfm12b_read.
1 |
sudo ./rfm12b_read |
Da ich natürlich wusste das ich hier mehrere 433Mhz Temperatur Sensoren habe die in der Network ID 210 laufen (vor dem kompilieren in der rfm12b_config.h eingestellt) ist die Ausgabe für mich nicht sehr überraschend.
Meine Sender übertragen drei Integer Werte die, um das Komma zu entfernen, mit 100 multipliziert wurden. Das spart Platz im Gegensatz zu einem String.
1 2 3 4 5 |
typedef struct { int humidity; // Humidity reading int supplyV; // Supply voltage int temp; // Temperature reading } Payload; |
Das Umrechnen der Werte hat mir einiges an Kopfzerbrechen bereitet, dabei war es nach etwas Recherche um das Wissen aufzupolieren gar nicht so schwer.
- Zum Beispiel die Temperatur von 46,35 Grad ist multipliziert mit 100 ein Integer Wert von 4635
- Der Integer Wert 4635 ist ein Multi-Byte-Wert der zwei Bytes braucht.
- Der Wert 4635 wird vor dem Übertragen also in zwei Byte Werte so codiert (encoded)
- 4653 / 256 = 18 (Dividiert durch 256)
- 4653 % 256 = 27 (Modulo)
In unserem Paket finden wir die beiden Bytes wieder, allerdings umgekehrt da die Atmel Chips der Sender mit einer umgekehrte Byte Reihenfolge arbeiten (Little-Endian)
1 2 3 |
Wed Feb 25 22:30:23 2015 8 bytes read 53 6 130 25 27 18 204 1 |
Die beiden Werte können wir mit einem kleinen Stückchen C Code zurückrechnen. Also erolgt die Dekodierung (decoding) so: Byte A +256 * Byte B = Integer Wert
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
#include int main() { int B = 4635 / 256; int A = 4635 % 256; printf("Byte B %dn", B); printf("Byte A %dn", A); int result = A + 256 * B; printf("Int result %dn", result); return 0; } |
Wir finden also im hinteren Teil des Pakets die Werte für Luftfeuchte (65,3H),Volt (4,635V) und Temperatur (4,6C).
1 2 |
Paket: 130 25 27 18 204 1 Werte: 6530, 4635, 460 |
Die ersten beiden Bytes sind die Header Informationen aus welchen sich eigentlich die Node ID des Senders ergeben sollte, wie die genau codiert wird konnte ich nicht herausfinden. In diesem Beispiel ist es die Node ID 21.
1 |
53 6 |
Wenn etwas mehr Zeit ist werde ich euch das RFM12B mit direktem Anschluss an den Raspberry Pi noch etwas näher bringen.
Viel Spaß beim Basteln.