RFM12B Funkmodul direkt am Raspberry Pi betreiben

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

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:

RFM12B-3   RFM12B-2

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.

rfm12b-pins

Achtet darauf richtig zu verkabeln, sonst lauft ihr Gefahr das Modul zu zerstören.

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_breadboard

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.

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

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:

# /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.

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.

# 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.

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 /bootvmlinuz-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

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.

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

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.

#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

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.

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.

cd examples
make

sudo reboot

Nach dem Neustart wechseln wir in das Verzeichnis mit den kompilierten beispiel Programmen und starten dort.

cd rfm12b-linux/examples/bin

Dort können wir nun das ein beispiel Programm aufrufen, ich verwende das Programm rfm12b_read.

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.

rfm12b-direkt-am-raspi

Meine Sender übertragen drei Integer Werte die, um das Komma zu entfernen, mit 100 multipliziert wurden. Das spart Platz im Gegensatz zu einem String.

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)

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

#include <stdio.h>

int main()
{
 int B = 4635 / 256;
 int A = 4635 % 256;

 printf("Byte B %d\n", B);
 printf("Byte A %d\n", A);

 int result = A + 256 * B;
 printf("Int result %d\n", 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).

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.

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.


wallpaper-1019588
[Comic] Seven Sons
wallpaper-1019588
Momentary Lily: Original-Anime angekündigt
wallpaper-1019588
LUCK LIFE: Band feiert Europapremiere auf der Connichi
wallpaper-1019588
Wind Breaker: Deutscher Simuldub bei Crunchyroll gestartet