Forum: Mikrocontroller und Digitale Elektronik RFM12 vs nrf24l01


von Lukas K. (Gast)


Lesenswert?

Ich würde gerne zwischen 2 µC eine Funkverbindung aufbauen. Ich habe im 
Internet gesucht und 2 Funkmodule gefunden, die preislich ok wären: Das 
RFM12-433 und das nrf24l01. Welches dieser Funkmodule ist für Anfänger 
besser geeignet?
Wir haben in der Schule einen PIC18F45K22 programmiert, aber nur Timer, 
ADC, Komparatoren, Interrupt aber noch nie SPI oder I²C.

von Verwirrter Anfänger (Gast)


Lesenswert?

Ich hab bisher nur mit den RFM12 und RFM70 gearbeitet, aber ich würde 
dir zum Einstieg die RFM12 Module empfehlen.

Nach kurzem Überfliegen des Datasheets und einiger 
Produktbeschreibungen, scheint mir der nrf24l01 sehr ähnlich zum RFM70 
zu sein. Sehr viel mächtiger als der RFM12, mit Pipelines, ACK, 
retransmit, etc... Das ist alles sehr toll, wenn man es nutzen kann, 
aber das muss auch alles erstmal konfiguriert werden.

Ich denke der RFM12 ist schnell und einfacher zum Laufen zu bringen als 
der nrf24l01, dafür hat der nrf24l01 mehr Features und ist schneller.

von Christoph H. (christoph_b)


Lesenswert?

ansonsten nimm das RFM22B Modul. Ist neuer und stärker.

von Lukas K. (Gast)


Lesenswert?

Gibt es auch etwas in dieser Preisklasse (max. 10€ pro modul) mir UART? 
Die Reichweite sollte min. 20m sein.

von Timmo H. (masterfx)


Lesenswert?

Verwirrter Anfänger schrieb:
> Nach kurzem Überfliegen des Datasheets und einiger
> Produktbeschreibungen, scheint mir der nrf24l01 sehr ähnlich zum RFM70
> zu sein.
Nahezu gleich, nur dass der nRF24L01 nur eine Bank hat und man fast gar 
nichts einstellen muss damit die Kommunikation funktioniert. Beim RFM70 
ist es etwas anders, aber das kann man 1:1 aus dem Beispielcode 
kopieren.

> Sehr viel mächtiger als der RFM12, mit Pipelines, ACK,
> retransmit, etc... Das ist alles sehr toll, wenn man es nutzen kann,
> aber das muss auch alles erstmal konfiguriert werden.

Und genau das ist beim nRF24L01 sehr einfach.
Hier mal ein Beispiel:
1
void nrf24l01_Initialize()
2
{
3
  uint8_t sta;
4
  
5
   
6
  SPI_Write_Reg(WRITE_REG + CONFIG, MASK_TX_DS | MASK_MAX_RT | 0x0C);
7
  CE_LOW();
8
  _delay_us(50);
9
    SPI_Write_Buf(WRITE_REG + TX_ADDR, RX0_Address, 5);    // Writes TX_Address to nRF24L01
10
    SPI_Write_Buf(WRITE_REG + RX_ADDR_P0, RX0_Address, 5); // RX_Addr0 same as TX_Adr for Auto.Ack
11
    SPI_Write_Reg(WRITE_REG + RX_PW_P0, sizeof(CONTROL_paket_t)); // Select same RX payload width as TX Payload width
12
    
13
    SPI_Write_Reg(WRITE_REG + EN_RXADDR, 0x01);  // Enable Pipe0
14
    
15
    SPI_Write_Reg(WRITE_REG + RF_CH, 40);        // Select RF channel 40
16
    SPI_Write_Reg(WRITE_REG + RF_SETUP, 0x07);   // TX_PWR:0dBm, Datarate:2Mbps, LNA:HCURR
17
  SPI_Write_Reg(FLUSH_RX,0);//flush Tx
18
  SPI_Write_Reg(WRITE_REG + CONFIG, MASK_TX_DS | MASK_MAX_RT | 0x0F);
19
  
20
}
21
22
void SwitchToRxMode()
23
{
24
  CE_HIGH();
25
  _delay_us(150);
26
  SPI_Write_Reg(WRITE_REG + CONFIG, MASK_TX_DS | MASK_MAX_RT | 0x0f);     // Set PWR_UP bit, enable CRC(2 bytes) & Prim:TX. MAX_RT & TX_DS enabled..
27
}
28
29
30
void SwitchToTxMode()
31
{
32
  CE_LOW();
33
  _delay_us(150);
34
  SPI_Write_Reg(WRITE_REG + CONFIG, MASK_TX_DS | MASK_MAX_RT | 0x0e);     // Set PWR_UP bit, enable CRC(2 bytes) & Prim:TX. MAX_RT & TX_DS enabled..
35
}
36
37
void Send_Packet(uint8_t type,uint8_t* pbuf,uint8_t len)
38
{
39
  uint8_t fifo_sta;
40
  
41
42
43
  fifo_sta=SPI_Read_Reg(FIFO_STATUS);  // read register FIFO_STATUS's value
44
  if((fifo_sta&FIFO_STATUS_TX_FULL)==0)//if not full, send data (write buff)
45
  { 
46
    
47
    SPI_Write_Reg(FLUSH_TX,0);
48
    SPI_Write_Buf(type, pbuf, len); // Writes data to buffer
49
    CE_HIGH();
50
    _delay_us(20);
51
    CE_LOW();
52
    
53
  }         
54
}
55
56
uint8_t receive_paket(uint8_t *buffer){
57
  uint8_t sta,len, fifo_sta;
58
  
59
  len = 0;
60
  
61
  if(!nRF_data_available)
62
    return 0;
63
  
64
  nRF_data_available = 0;
65
  
66
  sta=SPI_Read_Reg(STATUS_REG);  // read register STATUS's value
67
68
  if((STATUS_RX_DR&sta) == 0x40)        // if receive data ready (RX_DR) interrupt
69
  {
70
    CE_LOW();
71
    do{
72
      len=SPI_Read_Reg(R_RX_PL_WID_CMD);  // read len
73
      if(len<=MAX_PACKET_LEN){
74
        SPI_Read_Buf(RD_RX_PLOAD,buffer,len);// read receive payload from RX_FIFO buffer
75
      }
76
      else{
77
        SPI_Write_Reg(FLUSH_RX,0);//flush Rx
78
      }
79
      fifo_sta=SPI_Read_Reg(FIFO_STATUS);  // read register FIFO_STATUS's value
80
          
81
    }while((fifo_sta&FIFO_STATUS_RX_EMPTY)==0); //while not empty
82
    
83
    SPI_Write_Reg(WRITE_REG|STATUS_REG,sta);// clear RX_DR or TX_DS or MAX_RT interrupt flag  
84
    //SwitchToRxMode();//switch to RX mode
85
    CE_HIGH();
86
  }  
87
    return len;
88
  
89
}

Mehr braucht es nicht.
Einfach "nrf24l01_Initialize"
und dann je nachdem was man machen will "SwitchToRxMode" oder 
"SwitchToTxMode"
und dann per "Send_Packet" bzw. "Receive_Paket" Senden/Empfangen.

Die Variable "nRF_data_available" in der "Receive_Paket"-Routine wird in 
einer Pin-Interrupt-Routine für den Int-Pin gesetzt.

Das reizt natürlich nicht die ganze Funktionalität aus, aber das ist ein 
Grundgerüst auf das man gut aufbauen kann.

Das RFM ist eigentlich nur bei der Initialisierung etwas komplizierter, 
aber ansonsten gleich. Das RFM70 hat jedoch auch mehr Reichweite als der 
nRF24l01 (5dBm vs 0dBm). Dafür kann der nRF24L01 noch 250 kbaud, was die 
Reichweite auch noch etwas erhöht.

von checksum (Gast)


Lesenswert?

Hallo

Ich habe auch Module mit dem 24L01+ verwendet. Diese sind einfach 
einzustellen und recht verständlich. Wenn ich den Einstellmaraton der 
RFM12 sehe, habe ich mich richtig entschieden

Gruß

von Lukas K. (Gast)


Lesenswert?

Muss ich bei der SPI Schnittstelle zwischen NRF24l01 und µC Pullups 
einbauen?

von Timmo H. (masterfx)


Lesenswert?

Nein

von Lukas K. (Gast)


Lesenswert?

Lukas K. schrieb:
> Gibt es auch etwas in dieser Preisklasse (max. 10€ pro modul) mir UART?

von Lukas (Gast)


Lesenswert?

Schau dir mal die BTM-222 Bluetooth Module an, kosten zwar kanpp über 
10€ aber die haben UART und sogar bis zu 100m Reichweite.

von Lukas K. (Gast)


Lesenswert?

@Timmo H. (masterfx): Fehlen bei deinem Code nicht noch die ganzen 
Includes, Deklarationen,...
Wenn ja, wäre es möglich, dass du mir diese auch postest?

von Timmo H. (masterfx)


Angehängte Dateien:

Lesenswert?

Lukas K. schrieb:
> @Timmo H. (masterfx): Fehlen bei deinem Code nicht noch die ganzen
> Includes, Deklarationen,...
> Wenn ja, wäre es möglich, dass du mir diese auch postest?
Klar hier meine Sources

von Lukas K. (Gast)


Lesenswert?

Danke!

von Lukas K. (Gast)


Lesenswert?


von Lukas K. (Gast)


Lesenswert?

Hat züfällig jemand einen Code für das RFM12?

von Timmo H. (masterfx)


Lesenswert?

Damit dürftest du freifeld etwa 30-50m kommen. Es gibt aber auch noch 
das nRF24L01 + PA + LNA (20dBm) damit kommst du dann bis ca. 1km. Oder 
das rfm70 das schafft etwa 100m da 5dBm. Oder das rfm70p ebenfalls 20 
dBm und nur etwa 7€.

von Lukas K. (Gast)


Lesenswert?

Oder kennt jemand zufällig eine Seite, wo das initialisieren und das
senden/empfangen mit dem RFM12 oder dem nrf24l01 schritt für schritt
erklärt ist?

von Timmo H. (masterfx)


Lesenswert?

Steht doch in den examples & appnotes des Herstellers, oder glaubst du 
ich hätte mir das alles selbst ausgedacht?!

von Lukas K. (Gast)


Lesenswert?

Ich habe den Code gelesen, studiert und auch mehr oder weniger 
verstanden. Gehe ich richtig in der Annahme, dass die funktion 
SPI_transfer eine in Software realisierte SPI schnittstelle ist.
Könnte ich diese Funktion mit der Funktion SPI_Read ersetzen oder muss 
ich unterscheiden zwischen SPI_Write und SPI_Read?

SPI Bibliothek: 
http://www.mikroe.com/download/eng/documents/compilers/mikroc/pro/pic/help/spi_library.htm#spi1_read

von Lukas K. (Gast)


Lesenswert?

Noch eine kleine Frage: Wozu dienen diese zeilen?
1
#ifndef _nrf24l01_h_
2
  #define _nrf24l01_h_

von Mike J. (emjey)


Lesenswert?

Lukas K. schrieb:
> Welche Reichweite kann ich mit dem nrf24l01 ungefähr erreichen?

Meine Testwerte: 0dbm (1mW Output Power) , 250kbps

Wenn der Sender in der 1. Etage liegt kann ich in einem Haus (ohne Stahl 
in den Wänden) der 1. zur 2. Etage gehen und verliere kein Paket, aber 
in der 3. Etage manchmal und je nach Lag ist das Signal auch weg.

Draußen: 100m waren kein Problem wenn man eine Sichtverbindung hat, mehr 
habe ich nicht getestet.
Wenn dar Empfänger im 100m Abstand dann hinter einem Gebäude verschwand 
war das Signal auch weg.

Meine Boards werden mit 3.0 oder 3.3V betrieben, eins war auch "defekt" 
bei mir angekommen. Nachdem ich das Center-pad (GND) des Chips von der 
Unterseite aus nachgelötet hatte funktionierte es.

http://www.mikrocontroller.net/articles/NRF24L01_Tutorial

http://www.tinkerer.eu/AVRLib/nRF24L01

von Timmo H. (masterfx)


Lesenswert?

Lukas K. schrieb:
> Gehe ich richtig in der Annahme, dass die funktion
> SPI_transfer eine in Software realisierte SPI schnittstelle ist.
Ja.

> Könnte ich diese Funktion mit der Funktion SPI_Read ersetzen oder muss
> ich unterscheiden zwischen SPI_Write und SPI_Read?
Lediglich die SPI_Transfer und SPI_init ist Hardwareabhängig, daher 
brauchst du auch nur die anfassen.

Lukas K. schrieb:
> Noch eine kleine Frage: Wozu dienen diese zeilen?
>
1
#ifndef _nrf24l01_h_
2
>   #define _nrf24l01_h_
Das verhindert dass wenn du das Header-File in mehrere C-Files 
includierst, dass doppelte Definitionen/Deklarationen auftreten.
Das sollte man generell in jedes Header-File machen.
Schau dir mal die Header-Files deiner Toolchain an, du wirst keins 
finden wo diese Direktive nicht drin ist.
Vielleicht solltest du dir noch mal ein C-Buch anschauen bevor du dich 
an dein Projekt wagst.

von Lukas K. (Gast)


Lesenswert?

Das eintige, was ich noch nicht verstanden habe ist, was ich der 
funktion Send_Packet als type übergeben soll...
1
void Send_Packet(uint8_t type,uint8_t* pbuf,uint8_t len)

von Timmo H. (masterfx)


Lesenswert?

Lukas K. schrieb:
> Das eintige, was ich noch nicht verstanden habe ist, was ich der
> funktion Send_Packet als type übergeben soll...
>
>
1
void Send_Packet(uint8_t type,uint8_t* pbuf,uint8_t len)
Entweder W_TX_PAYLOAD_NOACK_CMD oder W_ACK_PAYLOAD_CMD, je nachdem ob 
AutoACK haben willst oder nicht.
Wie gesagt, lies die Examples, Datenblätter und Appnotes des 
Herstellers. Da steht alles drin. Ich bin nicht dazu da, dir das Denken 
abzunehmen.

von Lukas K (Gast)


Angehängte Dateien:

Lesenswert?

Ich habe erste versuceh mit dem Modul und dem Code von Timmo H. 
(masterfx) gemacht. Ich habe leider keine daten empfangen.
Wo sollte ich bei der fehlersuche anfangen?
Ich habe 2 PIC18F45K22 mit jeweils einem Modul verbunden und folgende 
Quellcodes geschreiben:

Rx:
1
#include "nrf24l01.c"
2
3
void interrupt(void)
4
{
5
  nRF_data_available = 1;
6
  PORTD=0xFF;
7
  INTCON.INT0IF=0;
8
}
9
10
void Interrupt_Init(void);
11
void main()
12
{
13
  char rxbuf[10];
14
  rxbuf[0]=0;
15
16
  ANSELD=0x00;
17
  PORTD=0x00;
18
  TRISD=0x00;
19
20
  ANSELC=0x00;
21
  TRISC=0x00;
22
  PORTC=0x00;
23
24
  ANSELB=0x00;
25
  TRISB=0xFF;
26
27
  Interrupt_Init();
28
  SPI_init();
29
  nrf24l01_Initialize();
30
  
31
  SwitchToRxMode();
32
33
  while(1)
34
  {
35
    Receive_Paket(rxbuf);
36
    PORTD=rxbuf[0];
37
    Delay_ms(1000);
38
  }
39
40
41
}
42
43
void Interrupt_Init(void)
44
{
45
  RCON.IPEN=0;
46
  INTCON.GIE=1;
47
  INTCON.PEIE=1;
48
  INTCON.INT0IE=1;              // Enabel INT0 (RB0)
49
  INTCON2.INTEDG0=0;            // INT0 on falling edge
50
}
Tx:
1
#include "nrf24l01.c"
2
3
void interrupt(void)
4
{
5
  nRF_data_available = 1;
6
  INTCON.INT0IF=0;
7
}
8
9
void Interrupt_Init(void);
10
void main() 
11
{
12
  char tx[10];
13
  tx[0]=0;
14
  
15
  ANSELD=0x00;
16
  TRISD=0x00;
17
18
  ANSELC=0x00;
19
  TRISC=0x00;
20
  PORTC=0x00;
21
  
22
  ANSELB=0x00;
23
  TRISB=0xFF;
24
  
25
  Interrupt_Init();
26
  SPI_init();
27
  nrf24l01_Initialize();
28
  
29
  SwitchToTxMode();
30
  
31
  while(1)
32
  {
33
    Send_Packet(W_ACK_PAYLOAD_CMD,tx,1);
34
    tx[0]++;
35
    Delay_ms(1000);
36
  }
37
  
38
}
39
40
void Interrupt_Init(void)
41
{
42
  RCON.IPEN=0;
43
  INTCON.GIE=1;
44
  INTCON.PEIE=1;
45
  INTCON.INT0IE=1;              // Enabel INT0 (RB0)
46
  INTCON2.INTEDG0=0;            // INT0 on falling edge
47
}

Die bibliothek habe ich ein bisschen an meine PIC angepasst.

von Lukas K (Gast)


Lesenswert?

Hat niemand eine Idee wo der Fehler liegt oder wo sich ihn suchen 
könnte?

von Timmo H. (masterfx)


Lesenswert?

Kannst du denn überhaupt etwas aus dem Chip-Auslesen (also irgendein 
Register wie Adresse, Stausregister oder so)?

von Lukas K (Gast)


Lesenswert?

Das Stausregister habe ich erfolgreich ausgelesen. Bei der Empfangs 
Platine ist es 0b00001111.

von Timmo H. (masterfx)


Lesenswert?

Vermutlich liegt es daran, dass du "nRF_data_available" nicht als 
volatile deklariert hast.
Schlecht kopiert würde ich sagen :D in meinem Code wars ja drin.

Achja und "#include "nrf24l01.c" solltest du auch nicht machen. Includen 
tut man eigentlich das entsprechende header-file, da stehen ja die 
Funktiosprototypen drin, die du in deiner "main.c" brauchst.

von Lukas K. (Gast)


Lesenswert?

Was ist das Problem, wenn ich "#include "nrf24l01.c"?
Das mit der volatile ist es auch nicht, nicht mal ein Interrupt 
ausgelöst wird. Ich habe auch die Interrupt Leitung mit dem Oszi 
gemessen.

von Mike J. (emjey)


Lesenswert?

Lukas K. schrieb:
> Was ist das Problem, wenn ich "#include "nrf24l01.c"?

Das solltest du mal durcharbeiten, dann brauchst du viel weniger fragen.
http://openbook.galileocomputing.de/c_von_a_bis_z/

von Lukas K. (Gast)


Lesenswert?

Das löst das Problem aber auch nicht.
Hat keiner eine Idee wo der Fehler liegen könnte?

von Mike J. (emjey)


Lesenswert?

Och ... nimm dir einfach einen AVR, dann passt der Code.
Ich habe von Pic's keine Ahnung und will mich wegen dir da auch nicht 
einarbeiten.

von Lukas K. (Gast)


Lesenswert?

Ich habe aber keine ahnung von avr und bis jetz alles mit PICs gemacht.

von daniel (Gast)


Lesenswert?

> etwas in dieser Preisklasse (max. 10€ pro modul) mir UART?
SIM20A - http://wm.sim.com/producten.aspx?id=1030

Gruss daniel

von Lukas K. (Gast)


Lesenswert?

Hast du diese bereits verwendet?
Wo kann ich diese kaufen? Wenn ich mich auf dieser Website registrieren 
will, muss ich Company und Job Title eingeben, bin aber 
Privatkäufer/Student.

von Lukas K. (Gast)


Lesenswert?

Jetzt habe ich mir den ganzen Code selber geschrieben, jetzt 
funktioniert es. Danke für die Hilfe.

von Lukas K. (Gast)


Lesenswert?

Ist es normal, dass die Reichweite im Freien nur ca. 15m beträgt?
Habe ich etwas falsch konfiguriert?
1
void nRF24L01_Init(void)
2
{
3
  SPI_Init();
4
  CSN_HIGH();
5
  CE_LOW();
6
7
  SPI_Write_Reg(WRITE+CONFIG,0b01111000);
8
9
  SPI_Write_Reg(WRITE+RF_CH,125);
10
11
  SPI_Write_Buf(WRITE+TX_ADDR, Adress, 5);
12
13
  SPI_Write_Buf(WRITE+RX_ADDR_P0, Adress, 5);
14
15
  SPI_Write_Reg(WRITE+RX_PW_P0, 5);                   // RX Payload with: 5
16
17
  SPI_Write_Reg(WRITE+EN_RXADDR, 0x01);
18
19
  SPI_Write_Reg(WRITE+RF_SETUP, 0b00101011);
20
21
  SPI_Write_Reg(WRITE+EN_AA, 0b00000001);
22
23
  SPI_Write_Reg(FLUSH_RX,0);
24
25
  SPI_Write_Reg(WRITE+CONFIG,0b01001010);             // TX
26
  //SPI_Write_Reg(WRITE+CONFIG,0b00111011);             // RX
27
}

von Timmo H. (masterfx)


Lesenswert?

Lukas K. schrieb:
> Ist es normal, dass die Reichweite im Freien nur ca. 15m beträgt?
Na wenn man so wie du auf -12 dBm stellt denke ich schon dass es normal 
ist. (Bit 0 hat keine Funktion im RF_SETUP)

von Lukas K. (Gast)


Lesenswert?

Danke, habe beim RF_Setup Register wohl eine Stelle verfehlt.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.