RFM12 Funkmodule

433 MHz Funkmodule an AVR Mikrocontrollern

RFM12 moduleRFM12-Module (Sende-und Empfangsmodul) bzw. RFM01- und RFM02-Module (nur Empfangs-/ nur Sendemodule) bieten eine günstige Möglichkeit Funkverbindungen zwischen Robotern oder anderen mikrocontrollergesteuerten Geräten herzustellen. Die Module senden bei 433 MHz (andere Frequenzen sind auch erhältlich) und werden z.B. bei Pollin angeboten. Für die Programmierung in C nutze ich die RFM12 library von das-labor.org, die bei mir auf Anhieb funktioniert hat. Vielen Dank an dieser Stelle an die Autoren!

Schaltplan & Konfiguration

Die Module werden über die SPI-Schnittstelle angesprochen. Ich verwende die Module mit dem Funk-AVR-Evaluations-Board und dem ATMEL-Evaluations-Board mit Funkmoduladapter von Pollin. In diese Boards können dann AVRs der Typen ATtiny2313, ATmega8, ATmega16 oder ATmega32 eingesteckt werden. Der Vorteil liegt darin, dass man sich um die korrekte Beschaltung der Funkmodule und der Mikrocontroller keine großen Gedanken mehr machen muss. Nachteilig ist, dass die, zu Testzwecken brauchbaren, Taster und LEDs auf dem Funk-AVR-Board dauerhaft Pins der AVRs belegen, sofern man nicht die entsprechenden Leiterbahnen durchtrennt.

 

Selbstverständlich kann man die Funkmodule auch wunderbar außerhalb dieser Boards verwenden, die Beschaltung ist dann folgendermaßen:

Funkmodul Pin Mikrocontroller Pin Funkmodul Pin Mikrocontroller Pin
SDO MISO nSEL SS
nIRQ INT01 SCK SCK
FSK/DATA/nFFS beliebiger IO-Pin SDI MOSI
DCLK/CFIL/FFIT nicht angeschlossen nINT/VDI nicht angeschlossen
CLK nicht angeschlossen GND GND
nRES nicht angeschlossen VDD 5 Volt Betriebsspannung
GND GND ANT Drahtantenne ≈ 16,5cm

1 Auch andere Externe Interrupts sind möglich (INT1, INT2 etc.), muss in der Software definiert werden

Diese Pinbelegung muss dann nachher auch in der Software noch angegeben werden. Doch zuvor zur Einbindung der RFM12 library: Ich arbeite mit dem AVR Studio, die Schritte lassen sich aber sicher auch auf andere Entwicklungsumgebungen übertragen. Ich habe mich einfach an die Dokumentation der RFM12 library gehalten. Die heruntergeladenen Dateien aus dem Ordner “src” werden in einen Unterordner (z.B. “rfm12lib”) im Projektverzeichnis entpackt. Im Projektverzeichnis werden dann zwei Dateien erstellt, RFM12.c und RFM12.h:

RFM12.c:

#include “rfm12_config.h”
#include “rfm12lib/rfm12.c”

RFM12.h:

#include “rfm12_config.h”
#include “rfm12lib/rfm12.h”

In der Entwicklungsumgebung wird die erstellte Datei RFM12.c zu den Quelldateien hinzugefügt (AVR Studio: “Source Files”) und die ebenfalls erstellte Datei RFM12.h wird in der Hauptdatei (z.B. “main.c”) inkludiert. Im Ordner “src” befindet sich eine Datei namens “rfm12_config.h.demo”. Sie wird zu einer Headerdatei umbenannt (“.demo” entfernen) und in das Projektverzeichnis verschoben. In ihr werden nun alle nötigen Konfigurationen vorgenommen.

Bei Verwendung eines ATmega48 sehen die entsprechenden Stellen von rfm12_config.h wie folgt aus (Ausschnitt). Der Rest in der Konfigurationsdatei wurde bei den Standardwerten belassen.

/************************
 * PIN DEFINITIONS
 */

//Pin that the RFM12's slave select is connected to (SS an PB2)
#define DDR_SS DDRB
#define PORT_SS PORTB
#define BIT_SS 2

//SPI port (MOSI an PB3, MISO an PB4, SCK an PB5, SS an PB2)
#define DDR_SPI DDRB
#define PORT_SPI PORTB
#define PIN_SPI PINB
#define BIT_MOSI 3
#define BIT_MISO 4
#define BIT_SCK  5
#define BIT_SPI_SS 2
//this is the hardware SS pin of the AVR - it 
//needs to be set to output for the spi-interface to work 
//correctly, independently of the CS pin used for the RFM12

//    [...]

/************************
 * INTERRUPT VECTOR
 * set the name for the interrupt vector here
 */

//the interrupt vector

//Wenn ein anderer externer Interrupt gewählt wurde (INT1, INT2 etc.) 
//hier entsprechenden Interruptvektor eintragen!
#define RFM12_INT_VECT (INT0_vect) 

//the interrupt mask register
#define RFM12_INT_MSK EIMSK

//the interrupt bit in the mask register
#define RFM12_INT_BIT (INT0)

//the interrupt flag register
#define RFM12_INT_FLAG EIFR

//the interrupt bit in the flag register
#define RFM12_FLAG_BIT (INTF0)

//setup the interrupt to trigger on negative edge
#define RFM12_INT_SETUP()   EICRA |= (1<<ISC01)

Im Zweifelsfall bei den Registern der Interruptkonfiguration muss man im Datenblatt nachschlagen.

Verwendung

Als Test habe ich ein Pollin-Board als Sender und eines als Empfänger konfiguriert. Am Sender kann mit einem Tastendruck eine LED ein- und ausgeschaltet werden. Dabei wird über Funk ein Zeichen (teststring = “G”) an den Empfänger gesendet und dort wird dadurch eine LED analog zu der LED am Sender ein- und ausgeschaltet. Hier der dazugehörige Code (es muss jeweils der nicht benötigte Sender- oder Empfängercode auskommentiert werden…):

/*-----------------------Erstes erfolgreiches RFM12-Funk-Programm--------------------*
*
*	Jacob Seibert, 11.01.2012
*	RFM12lib (V 1.1.0) von http://www.hansinator.de/rfm12lib/
*
*
*	Als Sender wird das Pollin Evaluations-Board (V2.01) mit einem ATmega48 verwendet. 
*	Über den Extensionport ist ein RFM12-Modul mit Antenne angeschlossen. Ein Tasten-
*	druck (Taster3) sendet das Zeichen 'G' und toggelt eine LED (LED1).
*
*	Der Empfänger (Pollin Funk-AVR-Evaluations-Board V1.2), ebenfalls mit ATmega48 
*	bestückt, wartet auf ein empfangenes Paket, prüft ob es sich bei dem empfangenen 
*	Zeichen um 'G' handelt und toggelt dann seine eigene LED1 synchron.
*	So kann die LED des Empfängers ferngesteuert ein- und ausgeschaltet werden.
*
*------------------------------------------------------------------------------------*/

#include <avr/io.h>
#include <avr/interrupt.h>
#include "RFM12.h"
#include "uart/uart.h"
#include <util/delay.h>

#ifndef F_CPU
#define F_CPU 8000000UL     /* Quarz mit 16 Mhz */
#endif
/* 2400 baud */
#define UART_BAUD_RATE 2400

void toggle_led (void) //Hilfsfunktion
{
  if(PORTD&(1<<PD5))
  {
    PORTD &= ~(1<<PD5);	
  }
  else
  {
    PORTD |= (1<<PD5);
  }
};

int main (void)
{
  uint8_t teststring[] = "G"; //Zu sendender String
  uint8_t packettype = 0xEE;

  DDRD |= (1<<PD5); // LED Ausgang
  DDRD &= ~(1<<PD4); // Taster Eingang

  uart_init(UART_BAUD_SELECT(UART_BAUD_RATE,F_CPU)); //Initialisiert den UART (Debug)

  rfm12_init();  // Initialisiert die RFM12-Library

  sei(); //Interrupts global aktivieren

  uart_puts("Initialisierung!\r\n"); //Debugging

  while (1)
  {
    /* Teil für den Sender: */
    //if(PIND&(1<<PD4)) /* Tastendruck */
    //{
      //toggle_led();

      /* String zum Senden einreihen */
      //rfm12_tx (sizeof(teststring), packettype, teststring); 

      /* Entprellen und gleichzeitig schon senden (rfm12_tick()) */
      //while(PIND&(1<<PD4)) 
      //{
        //_delay_ms(50);
        //rfm12_tick();
      //}
    //}

    /* Teil für den Empfänger: */
    if(rfm12_rx_status() == STATUS_COMPLETE) /* Paket empfangen? */
    {

      for(uint8_t i=0; i < rfm12_rx_len(); i++) //Paket ausgeben (UART)
      {
        uart_putc(rfm12_rx_buffer()[i]);
      }

      //Prüfen ob erstes Zeichen = 'G' -> Tastendruck beim Sender
      if(rfm12_rx_buffer()[0] == 'G') 
      {
        toggle_led();
      }
      rfm12_rx_clear(); // Pakes als gelesen markieren -> frei für Neues
    }

    rfm12_tick();  /* periodic tick function - call that one once in a while */
  }
  return 0;
};

Weitere Tests habe ich bisher noch nicht unternommen, aber mittels der Übertragung von Strings, wie hier im Beispiel, lässt sich schon eine gute Kommunikation zwischen zwei Robotern o.ä. realisieren.

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht.

Bitte beantworte kurz folgende Frage, um zu zeigen, dass du kein Roboter bist: *