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:
- LEDG und LEDY: Die beiden LEDs signalisieren das Empfangen und Versenden von Daten mit dem Funkmodul und können mit den im Schaltplan als "LED_G Enable" und "LED_Y Enable" bezeichneten Jumpern von den Pins getrennt werden. Bei Nutzung der LEDs sind bei den Jumpern jeweils die Pins 1 und 2 zu überbrücken, bei Nichtverwendung ist eine Brücke zwischen den Pins 2 und 3 notwendig, um undefiniertes Verhalten zu vermeiden. Um eine konstante und in jedem Fall wahrnehmbare Leuchtdauer zu erreichen, erfolgt die Ansteuerung der LEDs mittels NE556-Timer.
- nIRQ: Mit diesem Signal signalisiert das RFM12-Modul, dass die spezifizierte Anzahl von Bytes im Empfangs-FIFO erreicht wurde und der Mikrocontroller diese Daten abholen kann.
- nRES: Signal zum Reset des RFM12-Moduls.
- nSEL: Select-Leitung der SPI-Schnittstelle zum Ansprechen des RFM12-Moduls.
- SDI und SDO: Datenleitungen für den Datentransfer zwischen Mikrocontroller und RFM12-Modul; Teil der SPI-Schnittstelle.
- SCK: Taktsignal für die SPI-Schnittstelle.
- Vcc und GND: Spannungsversorgung für RFM12-Modul; 5 V.
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
- rfm12_io.c - C-Funktionen
- rfm12_io.h - Festlegung von Registerwerten (z. B. Datenrate, Bandbreite, Sendeleistung, Synchronisationsmuster usw.)
- port_definitions.h - Konfiguration der Pinbelegung
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:
- Aktivieren des Empfangs-FIFOs. Das Funkmodul beginnt mit dem Füllen des FIFOs sobald es ein spezifiziertes Bitmuster (Synchronisationsmuster) empfängt.
- 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).
- Abfrage des Statusregisters nach dem Grund für den Interrupt. Abholung aller empfangenen Daten, falls FFIT-Bit im Statusregister gesetzt ist.
- 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:
- Anschlussbelegung am Funkmodul selbst (Verdrahtung) oder in der Datei port_definitions.h fehlerhaft
- fehlende oder falsche Angaben zur Taktfrequenz des Controllers (F_CPU-Definition), die zu einer falschen Berechnung der Delays führen, ebenso wie eine nicht eingeschaltete Optimierungsstufe beim Kompilieren (führt ebenso zu Problemen bei der Berechnung der Delays)
- Probleme durch Mehrfachbelegung der ATmega-Controller-Ports (Beispiele: JTAG-Interface an PortC, USART an PortD)
- Probleme bei der Kommunikation über SPI (Datenrate).
- Fehlende(s) Dummy-Byte(s) am Ende des Sendepuffers.
Lizenz
Alle hier veröffentlichten Quellen stehen unter der
LGPLv3.
Versionsinfo
- Version 0.1, 22.01.2010: erste Version
- Version 0.1, 06.02.2010: Lizenzumstellung auf LGPLv3
- 01.06.2010: Aktualisierung der Schaltung, Änderung der Beschreibung zum Inhalt des Transmit-Puffers, geänderte Datei rfm12_io.h (Kommentar)
- 17.07.2010: Aktualisierung der Schaltung, Änderung der Beschaltung der LEDs (bei Vcc = 3,3 V sollte auch die LED in den Kollektorkreis)
Anregungen oder weitere Informationen
Hier kann ein Kommentar hinterlassen werden: