/* ////////////////////////////////////////////////////////////////////////// Bedienung des RFM12 Transceivermoduls *//////////////////////////////////////////////////////////////////////////// byte RF_RXBuf[64+3]; // RF Empfangspuffer byte RF_RXPtr; // Zeiger auf aktuelles Element bit f_RF_NewData; // 1 = Es liegen neue Daten vor bit f_RF_RecInProgress; // 1 = Es läuft eine IRQ Übertragung ab // IRQ Hilfsvariablen für Empfang von Daten enum fifos {RF_RESET, RF_ANZAHL,RF_DATA,RF_CHECK}; // States Receiver byte RF_RecAnzahl; byte RF_FIFO_State; enum brate {b1200,b2400,b4800,b9600,b19200,b38400}; // Prototypen void RF_Init_SPI(); byte SPIRF(byte); void RF_Sleep(); void RF_Wakeup(); void RF_CMD(int16); void RF_Baudrate(brate); void RF_TX_Power(byte); void RFTX_Init(); void RFRX_Init(); void RFTX_Send(byte*, byte); int16 RF_GetStatus(); // Bitmasken #define STATUS_ struct RF_Status { int16 FFIT :1; int16 POR :1; int16 FFOV :1; int16 WKUP :1; int16 EXT :1; int16 LBD :1; int16 FFEM :1; int16 RSSI :1; int16 DQD :1; int16 CRL :1; int16 ATGL :1; int16 SIGN :1; int16 OFFS :4; }; struct RF_Status RFS; bit f_RF_Sleep; // 1=RFM ist abgeschaltet im Power Down Modus // >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> ALLGEMEIN <<<<<<<<<<<<<<<<<<<<<<<<<<<< // >>>> RX TX: Sleep Mode <<<<< void RF_Sleep() { RF_Init_SPI(); RF_CMD(0x8201); // Alles intern abschalten f_RF_Sleep = 1; } // Aufwachen! Danach muss Betriebsart RX oder TX neu gesetzt werden ! void RF_WakeUp() { RF_Init_SPI(); RF_CMD(0x8208); // Nur Osc! delay_ms(5); } // TX RX: Allgemeine Initialisierung des Moduls, keine Festlegung auf Senden/Empfangen void RF_Init() { disable_interrupts(GLOBAL); RF_Init_SPI(); RF_CMD(0x80D7); //EL,EF,12.0pF RF_CMD(0x8208); //!er,!ebb,!ET,ES,EX,!eb,!ew,!DC (in Bereitschaft gehen) RF_CMD(0xC4F7); //AFC: autotune: -10kHz...+7,5kHz,!st,!fi,OE,EN RF_CMD(0xA640); //A140=434MHz RF_CMD(0xC647); //4,8kbps RF_CMD(0x94A0); //VDI,FAST,134kHz,0dBm,-103dBm RF_CMD(0xC2AC); //Data Filter RF_CMD(0xCA81); //FIFO8,SYNC,!ff,DR RF_CMD(0x9850); //!mp,9810=30kHz,MAX OUT RF_CMD(0xE000); //NOT USE RF_CMD(0xC800); //NOT USE RF_CMD(0xC000); //kein WDT, kein Batteriewächter enable_interrupts(GLOBAL); } ///////////////////////////////////////////////////////////////////// /* TX RX : Frequenz einstellen (Kanal wählen) Die Frequenz wird nach der Formel f0 = 10 * (43+F/4000) [Mhz] berechnet und kann mit 12 Bit eingestellt werden mit F = 96..3903 ergibt sich F: 430,24 Mhz < f < 439,75 Mhz in Schritten zu df = 2,5khz Damit sich keine Überschneidungen ergeben wird eine Schrittweite von 250khz (n=100) gewaehlt, daraus ergeben sich 39 wahlfreie Kanaele auf den gesendet und empfangen werden kann. Kanal 0 = 430,25 Mhz Kanal 1 = 430,5 Mhz Kanal 2 = 430,75 Mhz ..... Kanal 38 = 439,75 Mhz */ void RF_SetChannel(byte kanal) { int16 F; RF_Init_SPI(); if (kanal>38) kanal = 38; // Bereichsfehler Fehler abfangen F = 96+((int16)kanal*100); // Berechnung von F aus Kanal RF_CMD (0xA000|F); // Frequenz setzen delay_us(20); // PLL locken lassen } // >>>>>> TX RX: Setze Baudrate <<<<< // 0= 600, 1=1200, 2=2400, 3=4800, 4=9600, 5=19200, 6=38400 // BR = 344827/(R+1)/(1+cs*7) [baud] cs=1 => 8 cs=0 => 1 void RF_Baudrate(brate baudrate) { disable_interrupts(GLOBAL); // 600 => cs=1 R=0x47 (C7) 0 // 1200 => cs=1 R=0x23 (A3) 1 // 2400 => cs=1 R=0x11 (91) 2 // 4800 => cs=0 R=0x47 3 // 9600 => cs=0 R=0x22 4 // 19200 => cs=0 R=0x11 5 // 38400 => cs=0 R=0x05 6 RF_Init_SPI(); switch (baudrate) { case b1200 : RF_CMD(0xC6A3); // 1200 Baud break; case b2400 : RF_CMD(0xC691); // 2400 Baud break; case b4800 : RF_CMD(0xC647); // 4800 Baud break; case b9600 : RF_CMD(0xC622); // 9600 Baud break; case b19200 : RF_CMD(0xC611); // 19200 Baud break; case b38400 : RF_CMD(0xC605); // 38400 Baud break; default : RF_CMD(0xC647); break; } enable_interrupts(GLOBAL); } // >>>>> RXTX: Hole Statusbits in struct hinein int16 RF_GetStatus() { int16 wert; disable_interrupts(GLOBAL); RF_Init_SPI(); ChipSelect(devRFM,1); hibyte(wert) = SPIRF(0x00); lobyte(wert) = SPIRF(0x00); ChipSelect(devRFM,0); RFS = wert; enable_interrupts(GLOBAL); return(wert); } ////////////////////////////////////////////////////////////////////////////// // // >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> SENDEN <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< // ////////////////////////////////////////////////////////////////////////////// void RF_SetTX() { RF_FIFO_State = 0; disable_interrupts(INT_EXT1); // nIRQ auf INT1 (Pin B1) deaktivieren } // >>>> TX: Setze Sendeleistung, Bandbreite beibehalten <<<< // 0(min) - 7 (max) void RF_TX_Power(byte power) { byte val; RF_Init_SPI(); disable_interrupts(GLOBAL); val = 7-power; RF_CMD(0x9850 | val); enable_interrupts(GLOBAL); } // TX: Datenbyte raussenden (1=warten, 0=sofort senden (nur erstes Byte)) void RF_SendByte(byte data) { ChipSelect(devRFM,1); while (RFM12IRQ); SPIRF(0xB8); SPIRF(data); ChipSelect(devRFM,0); } // >>>> TX: Senden einer Bytefolge + Checksumme <<<<< // <2 x 0xAA>, , ... , , < Dummy> #define RF_TX_ON 0x8239 #define RF_TX_OFF 0x8209 #define RF_CHECKPOS 4 void RFTX_Send(byte* data, byte size) { byte check,k,i; disable_interrupts(GLOBAL); RF_Init_SPI(); // RF_GetStatus(); // Notwendig, sonst klappt Senden nicht (seltsam!) RF_CMD(0x8238); // Transmitter EIN for (i=0;i<5;i++) RF_SendByte(0xAA); // Präambel ins Latch, lockt die PLL RF_SendByte(0x2D); // FIFO Schlüssel 2DD4 (öffnet das Tor) RF_SendByte(0xD4); // --- Ab jetzt benutzerdefiniert --- RF_Sendbyte(MASTER_START); RF_Sendbyte(size); // Anzahl folgender Bytes senden (incl Checksumme) // Sendeschleife k = 0; check = 0; for (i=0; i=RF_CHECKPOS) // und zwischendurch immer wieder einfügen { RF_SendByte(check); k=0; } data++; } RF_Sendbyte(check); // Checksumme for (i=0;i<3;i++) // Dummy, nachschieben als Pipelineputzer RF_SendByte(0xAA); RF_CMD(RF_TX_OFF); // TX off enable_interrupts(GLOBAL); } ////////////////////////////////////////////////////////////////////////////// // // >>>>>>>>>>>>>>>>>>>>>>>>>>>>> EMPFANGEN <<<<<<<<<<<<<<<<<<<<<<<<<<<<< // ////////////////////////////////////////////////////////////////////////////// // >>>>> RX: Initialisierung des Empfängerteils <<<< // RF_Init erforderlich void RF_SetRX() { disable_interrupts(GLOBAL); RF_Init_SPI(); RF_CMD(0x80D7); // EL,EF,12.0pF RF_CMD(0x82C8); // Receiver Chain, Power Management EXT_INT_EDGE(1,H_TO_L); // INT1 fallende Flanke INT1IF = 0; // Flag löschen RF_FIFO_State = 0; enable_interrupts(INT_EXT1); // nIRQ auf INT1 (Pin B1) aktivieren enable_interrupts(GLOBAL); RF_CMD(0xCA81); // Fifo Reset RF_CMD(0xCA83); RF_GetStatus(); // !!! Statusbits löschen, sonst klappt es nicht !!! } // Setze DQD Parameter (0..7) void RF_RX_SetDQDFilter(byte dqd) { int16 wert; disable_interrupts(GLOBAL); RF_Init_SPI(); wert = 0xC288; // AL=1, Slow Mode, Digital Filter wert = wert | dqd; RF_CMD(wert); enable_interrupts(GLOBAL); } // Setze LNA Gain, RSSI Threshold und Bandweite /* Bandweite: 1(max) ... 6 (min) LNA Gain : 0(max) ... 3 (min) RSSI : 0(min) ....7 (max) */ void RF_SetRX_LNA(byte bw, byte lna, byte rssi) { int16 wert; disable_interrupts(GLOBAL); RF_Init_SPI(); if (bw>6) bw=6; // Werte prüfen if (lna>3) lna=3; if (rssi>7) rssi=7; wert = 0x9400; // Kommando, VDI, Fast wert = wert | (bw<<5); // BW einmaskieren wert = wert | (lna<<3); // LNA Gain einmaskieren wert = wert | rssi; // RSSI Threshold einmaskieren RF_CMD(wert); enable_interrupts(GLOBAL); } // ============================ INTERRUPT ========================================== // ----- IRQ Routine Nicht aus Hauptprogramm aufufen !!! // Liest 1 Bytes aus dem FIFO aus byte RF_ReadFIFO() { byte data; ChipSelect(devRFM,1); SPIRF(0xB0); data = SPIRF(0x00); ChipSelect(devRFM,0); return(data); } // >>> IRQ: Empfangsroutine, wenn Datenbytes im Fifo eingetroffen sind <<<< // übernimmt immer den ganzen Datensatz, überschreibt alte Daten #INT_EXT1 void nIRQReceive() { static byte RF_Check,k; byte reccheck,data; // Vermutlich sind es gültige Daten... RF_Init_SPI(); f_RF_RecInProgress = 1; // Byte abholen (Master Kennung) if (RF_FIFO_State==RF_RESET) { if(RF_ReadFIFO()!=MASTER_START) goto enderror; RF_FIFO_State=RF_ANZAHL; // Kennung war ok, Buffer füllen RF_RXPtr = 0; goto endirq; } // State 1 (Anzahl Bytes abholen) if (RF_FIFO_State==RF_ANZAHL) { RF_RecAnzahl = RF_ReadFIFO(); if (RF_RecAnzahl>sizeof(RF_RXBuf)) // Passt es? goto enderror; RF_check = 0; RF_FIFO_State = RF_DATA; k=0; goto endirq; } // State 2 (Datensatz abholen) if (RF_FIFO_State==RF_DATA) { data = RF_ReadFIFO(); // Byte abholen if (k++>=4) // Checksumme oder Datum? { if (data!=RF_check) // Passt die Zwischenchecksumme? goto enderror; k=0; } else { RF_RXBuf[RF_RXPtr++] = data; RF_check += data; } if (RF_RXPtr>sizeof(RF_RXBuf)) // Bufferüberlauf droht? goto enderror; if (RF_RXPtr>=RF_RecAnzahl) // Erwartete Anzahl Bytes da? { RF_FIFO_State = RF_CHECK; // dann Checksumme abholen goto endirq; } goto endirq; } // State 3 (Checksumme prüfen) if (RF_FIFO_State==RF_CHECK) { reccheck = RF_ReadFIFO(); if (reccheck!=RF_check) { Errorcounter++; goto enderror; } RF_FIFO_State = RF_RESET; // Alles ok, dann State zurücksetzen f_RF_RecInProgress = FALSE; f_RF_NewData = TRUE; Datensaetze++; // Fifo Reset RF_CMD(0xCA81); RF_CMD(0xCA83); goto endirq; } enderror: // Rausprung mit Fehler RF_CMD(0xCA81); // Fifo Reset RF_CMD(0xCA83); RF_FIFO_State = RF_RESET; // State rücksetzen f_RF_RecInProgress = 0; Errorcounter++; endirq: #asm nop #endasm } ////////////////////////////////////////////////////////////////////////////// // // >>>>>>>>>>>>>>>>>>>>>>>>>>>>> Interne Routinen <<<<<<<<<<<<<<<<<<<<<<<<<<< // Nicht ausserhalb benutzen ! // ////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////// // Konfiguriere die SPI als Master // Speed = 0,1,2 void RF_Init_SPI() { TRISC = TRISC & 0b11010111; // SDO,SCK auf Ausgang TRISC = TRISC | 0b00010000; // SDI Eingang // SPI einrichten SSPCON1 = 0b00000001; // Master Mode, fosc/16 SSPSTAT_SMP = 0; SSPCON1_CKP = 0; // Daten bei fallender Flanke SSPSTAT_CKE = 1; SSPCON1_SSPEN = 1; // SPI bleibt dauerhaft an } // >>> RXTX: Eigene SPI Routine <<<< byte SPIRF(byte data) { byte rec; // Solange SPI beschäftigt ist hämmere ihr die Daten ein bis frei wird LED_AKTIV = 1; do { SSPCON1_WCOL = 0; SSPBUF = data; // Sende Register beschreiben } while (SSPCON1_WCOL); // Datentransfer läuft, jetzt warten bis Byte vom Slave reingekommen while (!SSPSTAT_BF); rec = SSPBUF; LED_AKTIV = 0; return(rec); } // RXTX: >>> Überträgt ein 16Bit Kommando an RFM12 <<<<< void RF_CMD(int16 wort) { ChipSelect(devRFM,1); SPIRF(hibyte(wort)); SPIRF(lobyte(wort)); ChipSelect(devRFM,0); }