Ansteuerung eines RFM12-Funkmoduls

Beschreibung

Die folgenden Funktionen dienen der Ansteuerung eines RFM12-Funkmoduls zu Versenden und Empfangen von Daten. Ein solches Modul ist für wenig Geld zum Beispiel bei Pollin (Link) erhältlich. Bei der Erstellung der Funktionen kam dieses Modul in der 868 MHz-Version an einem ATmega16 zum Einsatz. Dieses Modul gibt es auch als 433 MHz-Version, hier sind die entsprechenden Registerwerte anzupassen!
Das Modul wird per SPI mit dem Mikrocontroller and dessen SPI-Schnittstelle verbunden. Datenblätter zu dem Modul, dem verbauten Chip und möglichen Antennenformen sind hier zu finden: Die Anbindung des Funkmoduls geschieht auf die in der Abbildung dargestellten Weise:

rfm12_platine.png

Falls auf dem Modul der Chip SI4420 verbaut ist, muss bei Verwendung des FIFOs (in den Funktionen so implementiert) der Pin DATA über einen Pullup-Widerstand auf Vcc gelegt werden.

Quellen

Nutzung der Funktionen

Die Konfiguration der Pins und der SPI-Schnittstelle des ATmega16 (bzw. ATmega32) erfolgt mittels der Funktionen rfm12_pin_init() und rfm12_init(). Bei der Verwendung von anderen AVR-Controllern kann unter Umständen die Initialisierung der SPI-Schnittstelle anders sein.
Zum Versenden von Daten ist die Funktion rfm12_data_io() folgendermaßen aufzurufen:

rfm12_data_io(transmit_buffer, receive_buffer, buffer_length, RFM12_TX_DATA);

Die Funktion versendet dann die durch buffer_length spezifizierte Anzahl von Bytes aus dem Sendepuffer transmit_buffer.

Achtung: Die einzelnen Elemente des Sendepuffers sind 16 Bit breit und enthalten den Befehl Transmitter Register Write Command (0xb8) und die zu übertragenden Datenbytes. Die ersten Datenbytes sollten ein Muster zum Synchronisieren von Sender und Empfänger (empfehlenswert ist 0xaa) enthalten. Danach schließt sich das spezifizierte Synchronisationsmuster (bzw. Erkennungsmuster für den Beginn des Datenpakets) an, mit dessen Hilfe das Empfängermodul den Beginn eines neuen Datenpaketes detektiert. Das Low-Byte des Synchronisationsmusters wird beim SI4421 (verwendet im Modul RFM12B) durch die Definition RFM12_SYNCHRONPATTERN_VALUE in der Datei rfm12_io.h festgelegt.
Im Anschluss daran folgen dann Nutzdaten-Bytes. Am Ende des Transmit-Puffers muss sich mindestens ein "Dummy-Byte" befinden, welches nicht Teil der Nutzdaten ist und ein zu zeitiges Abschalten des Senders verhindert.

Ein Beispiel für das Versenden eines Datenpaketes ist im Folgenden aufgeführt. Das Datenpaket beginnt mit vier Synchronisations-Bytes und dem Synchronisationsmuster 0x2d und 0xd4. Im Anschluss folgen die Nutzdaten, beginnend mit dem 7. Byte bis zum 15. Byte. Am Ende folgen zwei Dummy-Bytes:

  //send message via RFM12 Wireless Module
  checksum = 0;
  transmit_buffer[0] = 0xb8aa; //sync byte
  transmit_buffer[1] = 0xb8aa; //sync byte
  transmit_buffer[2] = 0xb8aa; //sync byte
  transmit_buffer[3] = 0xb8aa; //sync byte
  transmit_buffer[4] = 0xb82d; //sync pattern (high byte)
  transmit_buffer[5] = 0xb8d4; //sync pattern (low byte)
  transmit_buffer[6] = 0xb800 | ((detection_buffer_value >> 24) & 0xff);
  checksum = checksum + ((detection_buffer_value >> 24) & 0xff);
  transmit_buffer[7] = 0xb800 | ((detection_buffer_value >> 16) & 0xff);
  checksum = checksum + ((detection_buffer_value >> 16) & 0xff);
  transmit_buffer[8] = 0xb800 | ((detection_buffer_value >> 8) & 0xff);
  checksum = checksum + ((detection_buffer_value >> 8) & 0xff);
  transmit_buffer[9] = 0xb800 | (detection_buffer_value & 0xff);
  checksum = checksum + (detection_buffer_value & 0xff);
  transmit_buffer[10] = 0xb8ff; //baby detected
  checksum = checksum + 0xff;
  transmit_buffer[11] = 0xb800 | ((checksum >> 24) & 0xff);
  transmit_buffer[12] = 0xb800 | ((checksum >> 16) & 0xff);
  transmit_buffer[13] = 0xb800 | ((checksum >> 8) & 0xff);
  transmit_buffer[14] = 0xb800 | (checksum & 0xff);
  transmit_buffer[15] = 0xb8aa; //sync byte
  transmit_buffer[16] = 0xb8aa; //sync byte
  rfm12_data_io(transmit_buffer, receive_buffer, RFM12_TXBUFFER_LENGTH, RFM12_TX_DATA);


Der Empfang von Daten läuft bei dem RFM12-Funkmodul bei Nutzung des Empfangs-FIFOs nach folgendem Schema ab:
  1. Aktivieren des Empfangs-FIFOs. Das Funkmodul beginnt mit dem Füllen des FIFOs sobald es ein spezifiziertes Bitmuster (Synchronisationsmuster) empfängt.
  2. Nach Empfang des Synchronisationsmusters und dem Erreichen eines spezifizierten Füllstands des Empfangspuffers signalisiert das Funkmodul dem Mikrocontroller den Empfang von Daten mittels nIRQ-Signal (Low-aktiv).
  3. Abfrage des Statusregisters nach dem Grund für den Interrupt. Abholung aller empfangenen Daten, falls FFIT-Bit im Statusregister gesetzt ist.
  4. Nach dem Abholen des kompletten Datenpaketes bzw. der erwarteten Anzahl von Bytes muss das Empfangs-FIFO erst deaktiviert und dann wieder aktiviert werden, damit es bereit für den Empfang eines neuen Datenpaketes ist.
Der Empfang von Daten sollte mittels Interrupt implementiert werden. Im Folgenden ein Beispiel für eine solche Interrupt-Service-Routine:

  //!/////////////////////////////////////////////
  ///EXTERNAL ISR Receiving (RFM12 IRQ)///////////
  //!/////////////////////////////////////////////

  ISR(INT2_vect) {

    uint16_t dummy;


    ///read status register
    tx_data = RFM12_STATUSREAD_VALUE;
    rfm12_data_io(&tx_data, &receive_buffer[receive_counter], 1, RFM12_REGISTER_DATA);


    ///read RX FIFO if FFIT Bit in Status Register is set
    if ((receive_buffer[receive_counter] & 0x8000) > 0) {

      //read FIFO Buffer
      tx_data = RFM12_FIFOREAD_VALUE;
      rfm12_data_io(&tx_data, &receive_buffer[receive_counter], 1, RFM12_RX_DATA);

      //if complete packet received - disable and re-enable FIFO
      //FIFO will then wait for the next sync pattern
      if (receive_counter < (RFM12_RXPACKET_LENGTH - 1)) {
        receive_counter++;
      } else {
        tx_data = RFM12_NOFIFOMODE_VALUE;
        rfm12_data_io(&tx_data, &dummy, 1, RFM12_REGISTER_DATA);
        tx_data = RFM12_FIFOMODE_VALUE;
        rfm12_data_io(&tx_data, &dummy, 1, RFM12_REGISTER_DATA);
        receive_counter = 0;
        packet_received = TRUE;
      }

    }

  }


In diese Routine wird gesprungen, sobald das nIRQ-Signal auf Low geht. Der erste Schritt besteht in der Abfrage des Statusregisters. Falls das FFIT-Bit im Statusregister gesetzt ist, liest die Funktion ein Byte aus dem Empfangs-FIFO des Funkmoduls, kopiert dieses Byte in einen internen Empfangspuffer (receive_buffer) und inkrementiert den Positionszähler receive_counter des internen Empfangspuffers. Falls mit diesem Byte das Datenpaket vollständig empfangen wurde, setzt die Funktion den Positionszähler zurück und schaltet das Empfangs-FIFO des Funkmoduls aus und wieder an. Damit ist das Funkmodul bereit für den Empfang des nächsten Datenpakets. Anschließend wird die Funktion wieder verlassen. Falls das Datenpaket noch nicht vollständig ist, bleibt das Empfangs-FIFO des Funkmoduls beim Verlassen der Funktion weiter aktiviert.

Fehlerquellen

Falls die Datenübertragung oder die Kommunikation zwischen Mikrocontroller und Funkmodul nicht funktioniert, sollten neben der korrekten Einstellungen der Funkmodule (in rfm12_io.h) folgende Dinge kontrolliert werden:

Lizenz

Alle hier veröffentlichten Quellen stehen unter der LGPLv3.

Versionsinfo

Anregungen oder weitere Informationen

Für Anregungen oder die Beantwortung von Fragen zum Projekt steht ein Forum zur Verfügung.