nRF905 Radio Library for AVR and Arduino

The nRF905 is a radio transceiver IC similar to the well known nRF24L01, but operates at 433/898/915MHz instead of 2.4GHz, has a much longer range and a few extra IO pins. However, the nRF905 data rate is only 50Kbps compared to nRF24L01’s 2Mbps.

This library offers quite a bit of flexibility: Optional use of interrupts, 2 of the connections to the module are optional since their states can also be accessed by the ICs status register, and supports basic collision avoidance.

NOTE: v3.0.0 of the library was released on 12th September 2017, the default CD pin has changed and the AM pin is now used by the library.

ArduinoDocumentation (or use the Arduino library manager, search for “nrf905”)
AVR (non-Arduino)

nRF905 ATmega48/88/168/328 Arduino Uno Description
VCC 3.3V 3.3V Power (3.3V)
CE D7 (13) 7 Standby – High = TX/RX mode, Low = standby
TXE B1 (15) 9 TX or RX mode – High = TX, Low = RX
PWR B0 (14) 8 Power-up – High = on, Low = off
CD D4 (6) 4 Carrier detect – High when a signal is detected, for collision avoidance
AM D2 (4) 2 Address Match – High when receiving a packet that has the same address as the one set for this device, optional since state is stored in register, if interrupts are used (default) then this pin must be connected
DR D3 (5) 3 Data Ready – High when finished transmitting/High when new data received, optional since state is stored in register, if interrupts are used (default) then this pin must be connected
SO B4 (18) 12 SPI MISO (Mega pin 50)
SI B3 (17) 11 SPI MOSI (Mega pin 51)
SCK B5 (19) 13 SPI SCK (Mega pin 52)
CSN B2 (16) 10 SPI SS

Some of the module pin names differ from the IC pin names in the datasheet:

Module IC

The nRF905 is not 5V compatible, so some level conversions will need to be done with the Arduino outputs. A simple voltage divider or resistor and zener diode will do the trick. Only TXE, CE, PWR, SI, SCK and CSN pins need level conversion (not CD, AM, DR and SO).

Divider Zener

The nRF905 has 511 channels ranging 422.4MHz – 473.5MHz in 100KHz steps on the 433MHz band and 844.8MHz – 947MHz in 200KHz steps on the 868/915MHz band (remember to check which frequencies are legal in your country!), but each channel overlaps adjacent channels so there are only a total of 170 usable channels at once.

Searching for nRF905, PTR8000 and PTR8000+ should yield some results for modules on AliExpress, Ebay and DealExtreme. You should be able to get 2 for around £10.

Since v3.0.0 this library uses callbacks which are ran when events occur. If the option to use interrupts is enabled then the callbacks will run from the interrupt routine so be sure that any global variables you use in them are declared ‘volatile’, just as you would when dealing with normal ISRs. These events will wake the microcontroller if it is sleeping.

Event Callback Notes
New packet incoming NRF905_CB_ADDRMATCH  
Valid packet received NRF905_CB_RXCOMPLETE  
Invalid packet received NRF905_CB_RXINVALID  
Packet transmission complete NRF905_CB_TXCOMPLETE This only works if the nextMode is NRF905_NEXTMODE_STANDBY when calling nRF905_TX()

Nitty-gritty radio stuff
The actual air data-rate of nRF905 is 100Kbps, but the data is Manchester encoded which halves the throughput to 50Kbps. The modulation is GFSK with ±50KHz deviation. The radio also adds a few extra bits of data to the address and payload; a preamble and CRC.

Transmitted packet
10 bits
1 or 4 bytes
1 – 32 bytes
0 – 2 bytes

The address is also used as the syncword and should have as many level shifts as possible. 10100110 01100101 00011010 11011010 (2791643866) would be a good address to use, but 00000000 00000000 00000000 0010000 (32) would not be.

The CRC is used to detect errors in the received data. Having a CRC doesn’t eliminate all bad packets, there is always a small chance of a bad packet passing the CRC. Using larger CRCs helps to reduce that chance.
When the CRC is set to 16 bit the radio uses the CRC16-CCITT-FALSE (0xFFFF) algorithm. I’m not sure what it uses for 8 bit CRCs.

Transmission time
The sizes of the address, payload and CRC can be adjusted for a balance between throughput and latency.

Example configurations
Address size Payload size CRC size = Throughput (bps) Latency (ms)
4 32 2 = 36940 6.93
1 4 1 = 17680 1.81
1 1 0 = 6838 1.17

Throughput is how much useful data can be sent (the payload part), assuming no delays for writing and reading the payload.
Latency is how long it takes for the transmission to complete.
Switching from standby mode to receive or transmit mode takes a maximum of 650us and switching between receive and transmit modes takes a maximum of 550us.

Transmission time can be worked out with:

t = tstartup + tpreamble + ((Naddress + Npayload + NCRC) / BR)

tstartup is the time to switch mode as stated above (650us / 550us).
tpreamble is 200us for the 10 bit preamble.
Naddress, Npayload and NCRC are the address, payload and CRC sizes in bits.
BR is the bit rate which is 50,000.

For config 1, switching from standby to transmit:

t = 0.00065 + 0.0002 + ((32 + 256 + 16) / 50000)
t = 0.00693 seconds (6.93ms)

A note to developers: Before v3.0.0 this library would load the address bytes in reverse order, keep that in mind if you’re using an old version of the library to interface with other radio systems!


3 pings

Skip to comment form

    • Jasmin on October 8, 2016 at 11:36 am
    • Reply

    is this how i will put it in a while loop? i’ve tried it but the arduino does not read sensor data anymore

    1. Yup. You could see if the ping example works as that has the send in a while() loop, if the example doesn’t work then you might have a wiring issue (probably to do with the CD pin).

        • Jasmin on October 8, 2016 at 11:51 am
        • Reply

        it does not work 🙁 however, i checked the CD pin and it is connected to pin2. all the other pins are also connected correctly.

        1. Did you load ping_client on to one Arduino, and ping_server onto another? There’s definitely a wiring issue if pings don’t work, could you post some picture of your setup?

            • Jasmin on October 8, 2016 at 12:00 pm

            Yes we did. where can i post the pictures? do you need the picture of the connections?

          1. You can upload to Yeah, pictures of all the wires connecting the Arduino to the radio module.

    • Jasmin on October 8, 2016 at 12:13 pm
    • Reply
    here are the pictures.

    • Jasmin on October 8, 2016 at 12:19 pm
    • Reply

    we tried again, it’s not ping time out anymore. but on the other side, it only outputs waiting for ping.

    1. Ah, you’re using a MEGA. Have you changed INTERRUPT_NUM to 5 in nRF905_config.h?

        • Jasmin on October 8, 2016 at 2:38 pm
        • Reply

        oh, i’ve changed it before but now that i have checked it, it went back to 1. ugh. now it is working thank you ^_^ but there are many garbage data, how can we eliminate or lessen those?

        1. Hah alright 😛 Can you post a screen shot showing the bad data?

            • Jasmin on October 11, 2016 at 4:37 pm

            here’s the screen shot 🙂

          1. What does your latest code look like now? (pastebin)

    • Jasmin on October 8, 2016 at 12:22 pm
    • Reply
    here is the print screen of the output from the ping example

    • Brian on October 11, 2016 at 5:17 pm
    • Reply

    Hey I’m having trouble getting these two NRF905 modules talking with two Arduino Uno R3 controllers. I have followed your Arduino Uno connections to the letter and I am using the ping_client, ping_server code provided. I have the digital pins directly connected to the NRF905 pins. When I change the interrupt to 0 (as I’ve read in through the comments) in the config file the client prints out:

    Client started
    Ping time: 0ms
    Data from server:

    and the server:

    Server started
    Waiting for ping…

    Nothing happens in the server side after that. I’m guessing the receiver isn’t working? Would you have any suggestions? I’ve been racking my brain all day. I’ve used recommended below connections: Thank you for your help and time!

    * 7 -> CE
    * 8 -> PWR
    * 9 -> TXE
    * 2 -> CD
    * 3 -> DR
    * 10 -> CSN
    * 12 -> SO
    * 11 -> SI
    * 13 -> SCK

    1. Hi Brian, if the ping time is 0 or 1 then there is a problem with the client side, as it already takes around 6ms just for the radio to transmit the packet. What does the debug example print out?

        • Brian on October 14, 2016 at 5:31 am
        • Reply

        Hey Zak,

        Thanks for the reply! Sorry in the client side it does display 6ms afterwards, but the issue is the receiver I believe. It’s just stays at the “waiting for ping….” print. Are there different pin connections for the receiver side? I have both wired exactly the same according to your tutorial.


        1. 6ms still means there’s an issue on the client side, it should timeout if it doesn’t get a response from the server. The “Data from server” part should print out “test #” where # is a number that increments if everything is ok. Both sides have the same connections, could you post a picture of the client side connections? Upload to

    • Jasmin on October 14, 2016 at 8:39 pm
    • Reply

    Hello Zak! I would like to ask if it is possible to increase the maximum payload in your program from 32 bytes to 64 bytes? If yes, how can we implement it? Thanks!

    1. No, 32 bytes is the limit as that the maximum payload the nRF905 radio can send.

    • Jasmin on October 16, 2016 at 12:28 pm
    • Reply

    Hey 🙂 I have another question. The serial monitor freezes when I send a frame. What can i do to solve this?

    1. What sketch are you running on the Arduino?

        • Jasmin on October 16, 2016 at 9:08 pm
        • Reply here is for the TX here is for the RX

        1. You’ve got a lot going on there, I don’t really have time to go though it all. Though, I’d try to avoid using strings as they tend to eat up a lot of RAM, which the Arduino doesn’t have much of. Instead of strings use byte arrays or char arrays and use numeric values or characters to indicate what type of packet it is. [0] could be the packet type (1 = ENQ, 2 = ACK, 3 = EOT …), [1] could be the message length and the rest are the bytes is the message data. You don’t really need CRC as the radio already does all that stuff, and if the received packet is corrupted then it is automatically discarded.

            • Jasmin on October 17, 2016 at 6:42 am

            I’ve tried using bytes but i can’t put it in an if else condition even if i tried to convert the received bytes into string. What can be the solution to this?

          1. You can do conditionals on individual bytes like this:

            if(myArray[0] == 1)
    • Jasmin on October 25, 2016 at 11:45 am
    • Reply

    hey i tried it but it lags what should i do 🙁

    1. I’m not sure what you mean by it lags?

        • Jasmin on October 25, 2016 at 12:25 pm
        • Reply

        the serial monitor freezes.

        1. The Arduino is probably crashing or getting stuck in a loop, what’s your latest code like?

            • Jasmin on October 25, 2016 at 12:36 pm

   – for the rx
   – for the tx

          1. Looks ok to me, although the transmitter will be spamming out packets since it doesn’t have any delays between transmissions. Put more Serial.print debugging messages around the code, so you can see exactly where it gets to.

    • Jasmin on October 27, 2016 at 4:27 am
    • Reply

    ohhh okay i’ll try. hey, i have another question. can i put pins 2 3 7 and 51 52 53 into another input? im also using an lcd tft and the pins collided.

    1. 2 and 7 can be moved to any pin.
      3 must be connected to an interrupt pin, unless you’ve disabled interrupts with NRF905_INTERRUPTS 0 then it can be any pin.
      Make sure you update the nRF905_config.h file.
      50, 51 and 52 can’t change as they connect to the SPI bus, unless you modify the library to use software SPI then you can move to any pin.
      53 can be moved to any pin.

      SPI pins (50, 51 and 52) can be shared with multiple SPI devices.

    • Michael on January 13, 2017 at 2:24 am
    • Reply

    Hi Zak,

    Thanks for the blog, it’s been a great help to get communication between two Arduino Unos. I don’t have enough pins on the receiver for other sensors, so am trying to set this up with an Arduino Mega 2560. Like a few other respondents to the blog am having difficulty with the Mega, but I think I am very close. I have follow your instructions and set INTERRUPT_NUM to 5 in nRF905_config.h and changed the pins:
    11 -> 51
    12 -> 50
    13 -> 52

    With the INTERRUPT_NUM set to 1 the debug sketch seemed to work OK – see below.

    Raw: 108 12 68 32 32 229 166 76 254 2 Channel: 108
    Freq: 433200KHz
    Auto retransmit: 0 Low power
    RX: 0
    TX Power: 10dBm
    Band: 433MHz
    TX Address width: 4
    RX Address width: 4
    RX Payload size: 32
    TX Payload size: 32
    RX Address [0]: 229
    RX Address [1]: 166
    RX Address [2]: 76
    RX Address [3]: 254
    RX Address: 4266436325
    CRC Mode: 16bit
    Xtal freq: 16MHz
    Clock out freq: Disabled

    But when I set it to 5 it runs with errors – see below.

    All registers read as 0xFF or 0x00! Is the nRF905 connected correctly?
    Raw: 0 0 0 0 0 0 0 0 0 0

    With INTERRUPT_NUM set to 5 and the Mega set up as the ping server I get communication, but the data appear to sometimes scramble – see below.

    On the server ……..
    Data: £+›¡‰�
    Waiting for ping… Got ping
    Sending reply… Reply sent
    On the client ……..
    Ping time 122ms
    Data from the server: £+›¡‰�

    No communication when I set the Mega up as the client

    I have the wirelessSerialLink and my own sketch working with the two Unos, but neither work with the Mega.

    Any suggestions would be much appreciated?


    1. Hey Michael, odd that the debug sketch doesn’t work with INTERRUPT_NUM 5, since it doesn’t use any interrupt stuff to read the config registers. Everything else seems fine. Since the nRF905 is a 3.3V device and the Arduino uses 5V signalling, how are you doing the level conversion? Is the nRF905 the only thing connected to the Mega?

    • ksshin on January 18, 2017 at 5:50 am
    • Reply

    Thank you, this saved me a lot of trouble.
    I had to rename *.c files into *.cpp to get this working (Xubuntu 16.04 + default Arduino package), but maybe it does not happen on other Arduino IDE installations?

    1. Hey, for Arduino you should use the files from the Arduino folder, which are already .cpp and include example code written for Arduino.

    • stevestrong on February 4, 2017 at 5:44 pm
    • Reply

    Hi Zak,

    thank you for this great work.
    I am using your software, actually I rewrote it a bit for my needs, but still works fine.
    I am currently using my module only in receive mode, in 868 MHz range.
    So far so good.

    The only problem I have is the limited Rx range: if the transmitter is closer than 1 meter, all data is received OK.
    But I cannot receive anymore data if i place the transmitter more than 1 m away form the module.

    Could you maybe recommend what can I do in order to improve the Rx performance?

    Thank you in advance.

    1. Hey Steve, nRF905 modules are usually only tuned for 433MHz operation. Using a different frequency band will result in very short range as you’ve found out. I don’t think I’ve came across any modules for 868MHz so you’ll probably have to design the module yourself, the nRF905 datasheet shows what components are needed for each frequency band.

    • Jean on March 2, 2017 at 11:14 am
    • Reply

    Hi there !
    First of all thanks for your work !
    I was able to make this working the client and server examples using an arduino UNO.
    I didn’t use power level conversion and it was still working, is it normal ?

    Then I tried with an arduino mega, changing SO SI and SCK pins as expected.
    I also updated the config.h changing the INTERRUPT_NUM to 5 as requested.
    Everything is compiling great.
    But this time when debugging I have “ing timeout” for the client and “Waiting for ping…” for the server

    Did I miss something ? 🙁

    Jean (France)

      • Jean on March 5, 2017 at 11:11 am
      • Reply

      Hi zak,

      I finally achieved make it working.
      Indeed after having read every comments from the beginning, I found one saying that he solved the same problem as me by uncommenting and modifying these lines :
      #define BIT_EXTERNAL_INT INT5
      #define INT_VECTOR INT5_vect
      #define BIT_EXTERNAL_INT_CTL (_BV(ISC51)|_BV(ISC50))
      Now it’s working even if it’s surprising that I need that knowing that I’ve already changed the INT_NUM to 5.

      Anyway, I would like to ask you a new question :
      I have a TX which send a string every 100ms.
      I have a RX which receive this string and analyse it : I added a TIMEOUT if the RX doesn’t receive anything during 1 second (in order to stop motors running in my specific case).
      To test that I disconnect the TX and it’s working fine (the RX stop).
      But when I connect the TX again, this takes around 5 seconds for the RX to receive again (in the meantime I display “timeout”).
      Does this time to reconnect is normal ? Do you have some advices to imporove that ?

      Thanks for you help

      1. Hey Jean, I’ve just put a fix up on Github for the INTERRUPT_NUM issue, shouldn’t have to use the REG_EXTERNAL_INT stuff anymore. About the slow reconnect, add some Serial.println()s in your code to see where it’s taking its time. It should work straight away since there aren’t any connections being made with the radio modules, they just transmit to everything as fast as they can.

        Without any level conversion you are applying 5V to the IO pins, which are only meant to have 3.3V. This is slowly damaging the chip, and it’ll probably start going weird after a while.

    • Jasmin on June 25, 2017 at 11:17 am
    • Reply

    Hello, Zak 🙂 Our group wants to thank you for all your help in our thesis. We finished it successfully. Thank you very much 🙂

    1. Awesome, glad to hear that!

    • ICG on August 9, 2017 at 7:40 am
    • Reply

    how can i make communication distance longer?
    i succeed to test communication and after it, i tried to get “test” word by getting more distance from server.
    however, after 100m, the connection is lost. i expected it should be at least 200m (there was no obstacle).
    can you tell me somthing about it?

    1. Heya, how close to the ground the modules are (put them high up in the air), the antenna (quarter, half, full length), antenna gain, orientation of the antennas and impedance matching circuits on the module can all cause the range vary. Try different antennas or use a module that has a RF power amplifier built-in.

    • on August 10, 2017 at 9:53 am
    • Reply

    Hi Zak,

    great library – thank you for your work!

    I am using both an UNO and an ATMega Nano.

    I know I have to change the config file, however since I am using the library for both boards, compilation becomes a pain if I am testing different things out on both boards at the same time.

    Is it okay if I “re-publish” the library in my local system as a permanent change for the ATMega board? I do not intend to change any of your credits etc.

    Thanks In Advance,

    1. I’m not really sure what you mean by ‘as a permanent change for the ATMega board’, but I don’t see why not 😛

      It’s possible to edit the config and add a few preprocessor checks to see if it’s building for the Nano or Uno:

      #ifdef ARDUINO_AVR_UNO
      // uno config here
      #elif defined(ARDUINO_AVR_NANO)
      // nano config here
      #error "Unknown board!"

      If you’re using separate sketches for each board then you can also copy the .cpp and .h files from the src folder into the sketch folders, then they’ll each have their own copies of the library.

    • Pilatte on August 29, 2017 at 9:38 pm
    • Reply

    Hello zac. Sorry for my bad language, I’m French.
    Thank you verry much for your library. I make a chronometer wireless with Nrf905 433Mhz, 10 dBm. It works good but how can i make communication distance longer?
    After 25m, the connection is lost. (there was no obstacle). I would like near 100m.
    can you tell me somthing about it?

    My board (modules) works on mega and uno

    Thank you for your help.

    1. Hey Pilatte, you could try different antennas like THIS or use an nRF905 module with a built-in RF amplifier like THIS.

    1. The sketch/library can only adjust the transmit power, which is already set to the max (10dBm). That linked amp might work, however I’m not sure how it will react when the module transmits something.

        • Pilatte on August 30, 2017 at 8:05 pm
        • Reply

        Ok. I will try more options.
        Perhaps it’s not high enough (0.5m)
        Thanks for the advice

    • Roy on August 31, 2017 at 10:43 am
    • Reply

    Thanks for all the work you have put into this blog Zak – it is greatly appreciated.

    I have managed to get an arduino uno to send data to an arduino mega. the data represents the position of a joystick.

    The mega reads the data Ok . My problem is that the mega controls a DC motor and uses a feed back loop. The feedback loop reads an encoder so I need to implement an interrupt. Unfortunately as soon as I add an attachInterrupt statement I get an error when compiling as below.

    WInterrupts.c.o (symbol from plugin): In function `attachInterrupt’:

    (.text+0x0): multiple definition of `__vector_6′

    libraries\nRF905\nRF905.cpp.o (symbol from plugin):(.text+0x0): first defined here

    c:/program files (x86)/arduino/hardware/tools/avr/bin/../lib/gcc/avr/4.9.2/../../../../avr/bin/ld.exe: Disabling relaxation: it will not work with multiple definitions

    collect2.exe: error: ld returned 1 exit status

    exit status 1
    Error compiling for board Arduino/Genuino Mega or Mega 2560.

    It would appear that I am not able to assign interrupts to pins on the mega while I use your library. Is there a solution for this ?

    I would appreciate your help


    1. Hey Roy, this is because the library uses native AVR interrupts instead of Arduinos implementation (I’ll be updating the lib to use Arduino interrupts sometime). The fix is pretty easy, you can see what needs changing here –

      In nRF905.cpp remove the line with ‘REG_EXTERNAL_INT_CTL |= BIT_EXTERNAL_INT_CTL;’ and change ‘ISR(INT_VECTOR)’ to ‘void nRF905_processInterrupt()’, then modify your nRF905.h to match the nRF905.h from the link above (only need to change 3 lines).

    • Roy on September 1, 2017 at 11:42 pm
    • Reply

    Thanks for your quick reply Zak. I made those modifications and reran my sketch and there were no error messages on compiling but the receiver no longer worked. So to make things simple I reran your ping server example. With no modifications to the cpp file the ping client and ping server communicate as expected but once I introduce the mods you suggested the ping server sits on

    server started
    waiting for ping…….

    your advice would be appreciated.

    1. Oops, the detachInterrupt(…) and attachInterrupt(…) lines are the wrong way around, swap them and see what happens.

        • Roy on September 5, 2017 at 12:14 am
        • Reply

        Thanks Zak working now

        • Roy on November 4, 2017 at 10:56 pm
        • Reply

        I have decided to improve my software on this project. After making the mods you suggested a couple of months ago the sketch compiled and down loaded and the device worked.
        However now when I recompile the original software the sketch no longer compiles. I have checked through carefully to make sure that none of the modifications you suggested have been corrupted and have not found any problems.

        The error message I receive is as follows

        :\Users\PETETH~1\AppData\Local\Temp\cc8cZZ5e.ltrans1.ltrans.o: In function `__vector_1′:

        cc8cZZ5e.ltrans1.o:(.text+0x8fc): undefined reference to `nRF905_processInterrupt()’

        cc8cZZ5e.ltrans1.o:(.text+0x8fe): undefined reference to `nRF905_processInterrupt()’

        collect2.exe: error: ld returned 1 exit status

        exit status 1
        Error compiling for board Arduino/Genuino Mega or Mega 2560.

        I would appreciate your help

        1. Hey Roy, I’m guessing you’re trying to use the mods with v3 of the library? A lot has changed so any mods probably won’t work now and probably won’t need anymore. Some function names have changed and it now uses callbacks, so you’ll have to look at the examples and update your program to work with the new library.

    • derp on September 2, 2017 at 2:17 pm
    • Reply

    Thanks for the library.

    The power off seems to be kind of bugged, if I do not periodically disable the clock output its power consumption dies increase to about 300uA. But if I disable the clock output every second (it was never enabled to begin with). it (and the ATmega) are using about 5uA.

    Do you know why this ist?

    1. Is the 300uA including the ATmega? The power down function only changes the state of a pin from HIGH to LOW, it doesn’t touch any register settings.

    • Hans on November 1, 2017 at 10:43 pm
    • Reply

    Hi. Thanks for investing time in this, first of all.
    I’ve built a receiver on an Arduino Ethernet and a WiFi, using this library. I’m sniffing data between commercial home automation devices. Thing is, I seem to be missing [at least] a byte of information. I connected the HA device via USB, and via the Arduino console I can see it’s output, an so see what values it is receiving. I only changed the CSN pin for the Arduino Ethernet, from 10 to 5. I receive info from the HA device, 16 byte buffer, and tried to reverse engineer the values, so I can send them out via mqtt.

    Now, here’s the buffer I receive on the Arduino Ethernet (each byte separated by a dot):
    From the console, I can see that there should be a value of decimal 636 in here. This is hex 27C. The first four bytes are the same for all readings, and seem to indicate some sore of device address. The fifth I don’t know what it is, but also never changes. The sixth seems to be indicating the port that the value is received from, E3 is the one I’m looking for it seems. Now, the 2 is the 2 from the 27C. If the value changes to hex 3??, I see that change into a 3. But, the 7C is nowhere to be found. These readings occur quite often, and the serial monitor displays a different value received each time, but the buffer display from the Arduino Ethernet is often the same value as before. Djeez, I hope this still makes sense.
    Anyway, I believe that the 7C part is sent between HA devices, but doesn’t show up in my buffer. Is this in any way something that sounds familiar?

    1. Hey Hans, there’s no known issue with missing bytes, when nRF905_read() is called it just reads exactly what the nRF905 has received and places it into the provided buffer. How do you know that there should be a 0x7C byte?

        • Hans on November 5, 2017 at 9:59 pm
        • Reply

        Hi Zak, thanks for the reply.

        Yeah, the question was sort of a long shot. The HA receives data like current power consumption. The console output displays what it receives, but not in buffer but interpreted form (so current power usage is 600W). I have other readings (daily kWh for example), that consist of multiple bytes, which are received in reversed order. From those it also seems that the missing data should be in the byte after E3. I thought I might have similar issues as the bit shift issue mentioned in one of the comments. But I have stuff working on a NodeMCU also now, which is 3v, without level shifter, so that’s probably not it.

        Thing is, although I don’t know what I’m doing, I seem to have had some luck. The first three bytes consistently show addresses of slave devices that the HA device is receiving from. When the HA displays it received something, so does the nRF905. I can consistently get 868MhZ thermometer sensor values this way. There’s no garbage received by the nRF905. Since that address data is consistent, the rest probably is also. That makes me assume that I’ve tuned in to the right band and channel. Yet comparing data I receive with the interpreted data the HA is displaying (which means that it IS transmitted from slave to HA), it looks like I’m missing a byte of data for some slave devices.

        Since the HA code is not public domain, I cannot check any radio settings, so it’s hard to figure out what I’m doing wrong. Anyway, I will keep playing with it. Thanks again!

        1. The reversed bytes thing is probably due to the endianness. You could try sniffing the SPI bus inside the devices using a logic analyser which can be brought for around £5 on ebay or aliexpress, and use the software from here –

            • Hans on November 7, 2017 at 12:54 am

            Oh, that would have been cool. But it’s not necessary anymore. I found the configuration (Band, channel, crc and stuff), so I was sure I had my receiver configured correctly. Still missing some data. In the end, I connected the receiver to a laptop, and walked downstairs, away from the HA and close to the slave device that is actually sending the data. Guess what. No more missing data. So it was interference, I might have been reading ACKS instead of the source data, or it was just a distance thing, or maybe a combination of both. Super glad it works though, and was certainly not an issue with the library.
            Again, thanks for helping me out here, sorry to have waisted your time.

            Cheers, Hans.

          1. Hah that’s alright 😛 Though, if CRC is enabled it will detect the missing or corrupt data and report an invalid packet or nothing at all. But with raw radio stuff data doesn’t go missing, it just gets corrupted and the amount of data will stay the same.

    • Srikanth on November 25, 2017 at 12:35 pm
    • Reply

    I have two standalone arduino running at 8 MHz and the ping client- server example works well. My real world sketch however needs to use the timer1 interrupt which gets triggered every 10ms to do some housekeeping. I’m not sure if this is interrupting the NRF transmission but when the same ping code goes into my code , it does not function and says Packet Invalid.
    Will the rapid timer1 firing interrupt the NRF905 transmit code

    1. Hey Srikanth, by default the nRF905 uses 2 interrupt pins (AM and DR) where the timing of when these interrupts fire is important to correctly detect valid and invalid packets. If your interrupt takes a long to time to run then it could cause the library to mess up. You could try disabling the AM interrupt (NRF905_INTERRUPTS_AM 0 in nRF905_config.h), but then the invalid packet and address match callbacks won’t work (invalid packets will just be ignored), though that might be fine for your application if you’re not bothered about those two.

        • Srikanth on November 26, 2017 at 1:38 am
        • Reply

        Thank you Zak for your quick reply. I tried disabling all interrupts (NRF905_INTERRRUPTS 0 and NRF905_INTERRUPTS_AM 0) as I realized (too late) that my circuit uses the AM pin to run a LED matrix. I disconnected the connections to bot AM and DR pins as these are needed to be connected only if interrupts are used. But now the ping client just times out and the ping server waits for ever for reply.
        Are the ping client-server example not made to work without interrupts ?

          • Srikanth on November 26, 2017 at 3:47 am
          • Reply

          Dear Zak,
          I have tried various combinations of removing requirement of AM and DR pins
          As mentioned in config.h, I have set NRF905_INTERRUPTS as 0 and NRF905_DR_SW as 1 and NRF905_INTERRUPT_AM as 0 and NRF905_AM_SW as 1 so apparently both AM and DR can be left connected as checking is done in software though maybe slowly. However the ping client times out every time and the ping server hangs on waiting for ping. Incidentally the pins have been left connected though disabled in config.
          When I change it back to use interrupts everything works as before. Unfortunately my PCB is actually made and I had counted on leaving out AM and DR by using a jumper (without actually checking if it works without interrupts). So I need to get the code to work without interrupts as I have no spare pins to assign to my LED matrix

          1. Ah, to use the library without interrupts the nRF905_SERVICE() function should to be called as often as possible (which none of the examples use at the moment). See if you can get it working by sticking nRF905_SERVICE() in the various while loops of the ping examples.

            • Srikanth on November 26, 2017 at 1:25 pm

            Calling nRF905_SERVICE seemed to work on the client side but server was still unresponsive (dont know how that could happen). I finally found an unused pin (A0) on an unused device on PCB and tried to change the config to use that as AM (as the pins were very close on the PCB) but it still did not work (why ? A0 is an interrupt pin too) . Finally I routed that free pin to the LED matrix and used the original C3 as AM and everything works ! (For your info : The devices I’m making is a network of connected synchronized clocks. One of the devices runs on a DS3231 set by a GPS; the rest run a timer based software clock and are updated every minute by the master device with the GPS clock via teh nRF network. All slaves share the same receive address)
            So I have worked around the problem for now. would have been convenient if the AM had worked on A0 though. Thanks a million Zak for your great library and promptness in your replies. I can see you have been keeping that up for over 4 years ! Regards !

          2. Hah thanks 😛
            A0 is only a pin change interrupt like all pins (PCINTx), but the library only supports using external interrupts (INTx). This is because PCINTx interrupts are shared between multiple pins and Arduino doesn’t have any built-in way of dealing with them, which makes it hard to have two or more libraries using PCINTx stuff. Though it should be pretty easy to modifiy the nRF905 lib to use PCINTx if you wanted to.

            • Srikanth on November 26, 2017 at 1:52 pm

            One more question. Now that I have them synced the receivers usually lag 1 sec behind the master. As the typical ping time is only 16 ms, is there anyway I could get them to sync better than that ? Like say calculate a transmission delay and add that ? I’m very tempted to add 1 sec via software at the receiver and am sure we could not make out the difference but is there a better way of getting say a 100 ms sync ? How do ZigBee’s synchronize time ?

          3. This really depends on how your code works. Does the master send the time at 0 milliseconds, or does it use a seperate timer? Is a millisecond counter on the slaves reset or not when the new time is received? Might be best to post your code to
            I’ve no idea how ZigBees do it.

    • Srikanth on December 9, 2017 at 8:50 am
    • Reply

    Dear Zak,
    I got my NRF905 synchronised clocks to work based on your replies and they are working satisfactorily now.
    The next thing I need to do is that there are 5 -6 such devices one on each floor. I need messages to be passed by anyone to the other. I do not want to assign a separate address to each device as I want the single message to be broadcast to all the other 4. I have checked separately that my messages can reach from one floor to 4 floors away as they are almost in line of sight in the stairway. But as a failsafe, , the plan is that each device has a software device number (say one to 5) . A message is sent by device 1. Devices 2-4 receive it as they have the same receive address (as does device 1). After a latency equal to 2x (message transmission time) x deviceNum the receiving device also broadcasts the message again . The message also contains one byte info about who has initiated it and who is re-transmitting it and a message ID no. So that if the same message ID has been just received within the last 1 sec, it is ignored. That way I can ensure that even the last most distant nRF receives it. That way the same message gets sent 5 times, one by each node so that it is sort of like a rudimentary mesh network.

    My question is if all Rx addresses are the same, will the first device have a problem by its own message echoing back to it or will that not happen as the device will be in transmit mode and hence its own message will not be seen by it ?

    Will this system work for a few nodes ? It is basically a signalling system in a small 4 floor clinic where the device at each floor will be able to transmit different alarm conditions to each floor – like fire, earthquake, cardiac arrest, theft etc, so the entire personnel are immediately alerted.

    I initally thought of doing this as Device one transmits only to 2 and device 2 to 3 but that would be less elegant as for eg if one device fails and is replaced the other devices will also need to be re-programmed


    1. Good stuff 🙂 Transmitting radios cannot receive anything, even their own transmissions, so no need to worry about echoing messages there. It sounds like your mesh idea should work, but even though the radios already have a basic collision avoidance system you might still need to see about the problem of multiple nodes transmitting at the exact same time. I’ve not done mesh networking stuff before, so you’ll have to do some experimenting.

        • Srikanth on December 11, 2017 at 8:07 pm
        • Reply

        Thank you. The problem of collisions due to transmitting at exact same time is unlikely as emergencies happen very rarely in a smaller clinic and even if they did, to have two people simultaneously signalling a different emergency on each floor within a second or two of each other is very unlikely. Yes I’ll expirement and let you know the results. Regards and Thanks once again.

    • Pete on January 9, 2018 at 12:58 am
    • Reply

    I have just begun playing around with Arduino and the nRF905 module. I am using an IDUINO UNO and an IDUINO MEGA, each configured with an nRF905. I’ve loaded the nRF905 library and the lowpwr_client and lowpwr_server sketches and managed to get everything working OK, noting the different pin connections required on the MEGA.

    But I’ve run into trouble trying to change the frequency at which the modules are operating. I’ve added the following lines to each of the sketches, immediately prior to the function call to set the Transmission Power:

    // Set Frequency Band to 915MHz and Channel to 381 (921.4MHz)
    nRF905_setChannel(NRF905_BAND_915, 381);

    but communications fail. I’ve read a lot of posts on similar problems, and figuring it might have been a tuning problem, I switched back to the 433MHz band. If the function call is as follows:

    nRF905_setChannel(NRF905_BAND_433, 381);

    everything’s fine.

    But here’s the bit I really don’t understand. If I change the function call in just one of the sketches (it doesn’t matter which one, changing either gives the same result) to

    nRF905_setChannel(NRF905_BAND_915, 381);

    and leave the other as

    nRF905_setChannel(NRF905_BAND_433, 381);

    communications are OK. But as soon as both function calls specify the 915 Band, communications fail.

    If I just change the Channel (using NRF905_BAND_433 in at least one of the function calls), things only work if both function calls specify the same Channel, as I would expect. But I would also have expected things to break if the Frequency Band settings didn’t match.

    Can you tell my why this would be so?

    I’ve also read that the nRF905 units are usually just tuned to the 433MHz Band, and need to be ‘retuned’ to operate in the 915MHz Band, but I’ve been unable to locate instructions on how to achieve this. Any advice on this front would also be appreciated.


      • Pete on January 9, 2018 at 7:01 am
      • Reply

      Call it a therapeutic wait if you like, but things seem to be working now, after disabling LOW_RX and bumping up the transmission power to 10dBm.

      I still don’t really understand why things worked when different frequency bands were specified on the client and server, so I’d be happy to know why that might have been, and I’d still be interested in knowing how to ‘tune’ the nRF905 module to provide a range of more than 100mm (yes, that’s “millimetres”) when operating in the 915MHz Band… 🙂

      1. Hey Pete, I’ve not sure about this myself, but the modules being able to communicate when set to different frequency bands could be because the receiver is picking up a harmonic of the transmission since channels in the 433MHz band are exactly half the frequency of the same channels in the 868/915MHz band.

        Tuning the radio for different bands requires moving around various capacitors and inductors and adjusting their values, there are schematics at the end of the nRF905 datasheet. Not particularly easy.

        I hope that helps.

    • Nick Cooke on January 10, 2018 at 1:41 pm
    • Reply

    Hi Zak
    I may be on the wrong track here. Double checked pinouts – all wired correctly. I am using 2 NANO boards. Cannot get Client and Server to work. I looked at the pinouts of the UNO vs NANO and one shows the INT0 and INT1 as being different on the two boards. Is this true or can I stick to your wiring as published?

    1. Hey Nick, the pinouts for the Nano and Uno are the same, I’m not sure what diagram you’re looking that says otherwise. Could you post some photos of your wiring? (Upload the images to

    • Nick Cooke on January 16, 2018 at 12:30 pm
    • Reply

    Hi Zak – Many thanks for the response. I have a tacky bit of wiring on some veroboard for each module so probably best not to embarrass myself. I’ll double check everything and see where I am possibly tripping myself up. Any tips on how to carry out a functionality check on each Radio Module? I also understood the Nano and Uno to be the same in terms of pinouts. Just had one diagram that showed Int0 and Int 1 on the Nano as opposite to the Uno.

    Appreciate your willingness to help newbies like me.



    • tore stabell kulo on January 20, 2018 at 9:36 am
    • Reply

    Hello, Zak, and thank you very much for your work on the NRF905 library!
    I have managed to get the wireless serial link example to work, and now I want to send some data from one Arduino to another.
    I have searched everywhere, but cant find a working example where I can send some data in a structure, like

    struct dataStruct {
    int node;
    int alarm;
    double temperature;
    } data;

    All examples I can find using the NRF905 is sending “Hello World” or some text phrase. Can you help me in the right direction? To simplify, I dont want/need the receiver to send anything back to the sender.


    Tore Stabell Kulo,

    1. Hey Tore, you just need to pass a pointer to the struct when calling the nRF905_TX() function to send it:

      data_t myStructData;
      myStructData.alarm = 1;
      nRF905_TX(TXADDR, &myStructData, sizeof(data_t), NRF905_NEXTMODE_STANDBY);

      data_t myStructData;
      nRF905_read(&myStructData, sizeof(data_t));

    • Nick Cooke on January 23, 2018 at 3:54 pm
    • Reply

    Hi Zack. I checked all lines and wiring is good. Used a 4k7 and 3v6 Zener for level changes. Keep getting a Ping Time Out on Client side. Any bright ideas as to how I can do further fault finding?

    1. Hmm, have you tried running the debug example? What does it output?

    • Nick Cooke on January 27, 2018 at 5:50 pm
    • Reply

    Hi Zak – Yip tried the debug example and just got 0’s meaning it broke out the loop – so clearly not reading the registers. Does the same on both boards. Hope they aren’t bricked. I’ll check the Zeners to make sure signal levels are good. Rgds Nick

    1. Hmm, try connecting the module directly to the Arduino IO pins without any of the resistors and zeners, it’ll still work just try not to keep it that way for too long.

    • Cyril on March 3, 2018 at 8:55 am
    • Reply


    Firstly I apologize for my English, I am Belgian.
    A big thank you for your work! Nevertheless, after several tries I do not have to install the library on my arduino.
    When I put “add” the following error appears: the specified folder does not contain a valid library.
    In the commantaires I saw that you made 2 other .cpp and .h files but it still does not work.
    I want to use this library to decode a 868.3 MHZ signal in order to turn on and off the lamp with the arduino.
    Can you help me to solve this problem?

    Thanks in advance ! 🙂


    1. Hi Cyril, I’ve not tried the “Add .ZIP library” thing, so I don’t think that method will work. Follow the install instructions on the GitHub repo page (the old fashioned way). Most nRF905 modules are tuned for 433MHz and don’t work at 868MHz. It’s also very unlikly you’ll get it to communicate with the lamp unless it also contains an nRF905 radio chip. You might want to open up the lamp to see what kind of radio it has first.

        • Cyril on March 4, 2018 at 9:52 am
        • Reply

        Hello Zak !
        Thanks for your quick answer!

        I just installed the library as indicate on github but a new error appears:

        C: \ Program Files (x86) \ Arduino \ libraries \ nRF905 \ src \ nRF905.cpp: 27: 26: fatal error: nRF905_types.h: No such file or directory

        #include “nRF905_types.h”

        compilation terminated.

        exit status 1
        Compilation error for Arduino / Genuino Uno board

        Have you ever encountered this error? If so, how to solve it?
        On the datasheet of the chip nrf905, it is indicated that it can receive and transmit at a frequency of 868mhz, is this a lie? if not, is there any way to impose this listening frequency on the nrf905 chip instead of 433mhz?
        The RF receiver of the lamp is of the brand “Niko”.
        Once the right frequency band is chosen, should not we be able to capture any existing signal in this band?

        Thanks a lot for your help ! Once this frequency obtained, my project of domotic voice command will finally be complete 🙂

        1. I think you may be mixing different versions of the library together. Make sure all the files are from the latest v3.0.0. The nRF905 can operate at 868MHz, but the external components on the modules need to be the correct values for the different frequency bands, there are schematics for each band near the end of the datasheet. To receive packets from the lamp they must be in the same format as described in the “Nitty-gritty radio stuff” section of the blog post. The frequency. modulation, deviation, bit rate, encoding, preamble, sync word/address, payload length and CRC settings must all match, which is very unlikly.

    • Isaac on May 8, 2018 at 9:53 am
    • Reply

    On my transceiver module there is an extra pin labelled “uCK” between CE and AM. What does this pin get connected to?

    1. uCK is a clock output from the nRF905. It doesn’t need to be connected anywhere.

    • Peter on July 31, 2018 at 5:49 am
    • Reply

    Hi Zak,

    It would be nice if the Read routine returned the number of payload bytes read. Other than prefilling the buffer with something that you can test for, there doesn’t seem to be a neat way of doing it. It must be available somewhere because the packet layout has a terminating CRC.

    Thanks for a great library.


    1. Hey Peter, there’s no need for the library to return the number of bytes read as it will always read the requested number of bytes, unless you request more than NRF905_MAX_PAYLOAD (32) in which case it will be capped at NRF905_MAX_PAYLOAD.

        • Peter Hanlon on July 31, 2018 at 8:02 am
        • Reply

        I have potentially a bunch of transmitters with variable length transmissions. So it would be nice to ask for max-payload and ask how many actually came in. Also the received number appear to often have leading nulls in the buffer, but the packet status reports OK.

        I will get a little printout if I can.

        Thanks for the quick response to down under.


        1. The nRF905 only supports fixed length packet transmissions. Even if you specifiy a shorter length when calling nRF905_TX() it will still transmit the fixed payload size (default 32 bytes, the remaining bytes will be garbage).

            • Peter Hanlon on August 2, 2018 at 6:47 am

            Thanks Zak,

            Looks like I will have to pad out to a constant length, and change the payload size to that, or just bugger it and transmit 32.

            On the Rx side, it seems that I might be able to detect a complete package by checking DR (or D3) within a read sequence. It appears to go LOW at end packet.

            The little lady is asking me to clean the shower, so mundane things intervene.

            Thanks Zak,


    • Ash on August 26, 2018 at 4:48 am
    • Reply

    Hi Zac. I’ve downloaded the files from github and got the libraries sorted after a bit of playing around.

    Now, when i launch the arduino IDE and try to open/run one of the example sketches (ie. debug, ping client/server, all of em…) i get heeeaps of error messages when i hit verify.

    C:\Users\user\Documents\Arduino\libraries\nRF905\arduino\nRF905\examples\debug\debug.ino: In function ‘void loop()’:

    C:\Users\user\Documents\Arduino\libraries\nRF905\arduino\nRF905\examples\debug\debug.ino:151:8: warning: deprecated conversion from string constant to ‘char*’ [-Wwrite-strings]

    str = “16bit”;


    In file included from C:\Users\user\Documents\Arduino\libraries\nRF905\nRF905.c:11:0:

    C:\Program Files (x86)\Arduino\hardware\arduino\avr\libraries\SPI\src/SPI.h:72:1: error: unknown type name ‘class’

    class SPISettings {


    These are just some of the errors (from debug).
    I’m a bit noob, I can’t code what I need from start to finish so I need working codes to make a start but i am stumped here as everything is throwing error messages.

    I seen a “pastebin” in the comments so here is the debug error(s) im getting
    And here is the ping client errors

    Any help very much appreciated, thanks!

    1. Hey Ash, it looks like you’re using the non-Arduino version of the library. You need to use the stuff from the arduino folder in the github download.

    • Henry Yong on September 19, 2018 at 3:54 pm
    • Reply

    Hi Zak,
    Great blog. Found it useful and I was able to send and receive packets using your library.

    Just a question, would it be possible to use logic level converter to bring down 5v to 3.3v for TXE, CE, PWR, SI, SCK and CSN?

    Thank you!

    1. Thanks 🙂
      Yes, if the converter can drop the 5V signals down to 3.3V then it should work fine.

        • Henry Yong on September 21, 2018 at 1:32 am
        • Reply

        Much appreciated. 🙂

    • Ash on October 6, 2018 at 4:33 am
    • Reply

    Hello again! I sorted the library problems, cheers for the help.

    I’ve since got the lowpwr_server & lowpwr_client codes running. I’ve put a potentiometer into the LP_Client code, which the LP_servo then reads the pot value in serial monitor.

    My goal is to have one client (with the pot) which transmits to the other two, one with an LCD displaying the value and the other taking the value and writing it to a servo motor which then moves to the appropriate position.

    I’m getting a reading on the lcd but after the first 4 numbers it displays odd characters (i think its an array and the odd characters are empty spaces?). And with the servo I cant get it to read the transmitted pot value.

    I think the problem is the type of data being sent, I’ve tried changing the char to int, int8_t, long etc but to no avail.

    These are the codes:
    LP_client with the pot (line 80ish)
    LP_Server with LCD (line 140ish is the LCD)
    LP_Server with Servo (Line 115ish)

    TL;DR I want the pot value from client to transmit to both servers and that value is 1. displayed to LCD & 2. written to a servo

    Lastly, how do i change one of the server codes address so they don’t clash with each other? (I haven’t tried running all 3 yet, only client to server lcd OR client to server servo.

    Thanks Zak!

    1. The data array has a length of NRF905_MAX_PAYLOAD, which is 32. Since you’re only writing to the first few bytes the remaining bytes will be random, which is what the odd characters are. You need a way of telling the receiving end how many bytes are actual data (usually the first byte stores the length, but since you’re using sprintf the string will be null terminated then you can just use lcd.print(data) instead of write(data, length)). The server code also has a lot of delays where things might be missed, and it doesn’t put the nRF905 back into RX mode after receiving a valid packet. Both servers can have the same address, then they’ll both receive the same transmission. The address can be changed by the #define RXADDR value at the top of the code.

      The servo isn’t working since you’re passing it a pointer to the array containing an ASCII string, but you should be passing it an integer instead. Normally you would store the pot value as a byte (or 2 bytes if you need values over 255) in the array, rather than convert it into a string, then let the server decide what to do with the raw value. data[0] = sensorValue;

      I hope this helps, there’s a lot of things to learn about!

    • Bob on November 3, 2018 at 3:58 pm
    • Reply

    Hi Zak,

    I am working on a project in which I want to replace the outdoor sensors of my weather station (Fine Offset WH1080) with much better ones. I have for instance a professional Thies anemometer that I would like to hook up. Your driver looks like a good piece of software for me to start with.

    My first idea is to see if I can receive the packets from the existing transmitter and use lessons learned at a later stage to replace the transmitter by an ESP32 connected to an nRF905. There is a lot of information on the web on how the WH1080 data packets are build up, but there are also a few things I don’t understand. For instance, how do I determine the exact frequency and device address to listen to? I am also interested to know if your driver uses the ShockBurst mode. It would help me understand the code better. What would be the best sample code to start with, considering what I am trying to make?

    Thanks a lot,

    1. Hey Bob,

      ShockBurst is a marketing term meaning that the RF chip does all the hard RF work instead of having the microcontroller do it (packet assembly, CRC etc), which is something pretty much all RF modules do anyway.

      From what I can tell the WH1080 weather station doesn’t use an nRF905, and since the nRF905 has very few RF related configuration options (modulation, bit rate, packet format etc) makes it impossible to use it for your project since the configuration won’t match the transmission format. It seems a lot of people use an RFM01 or RFM12B module with a Raspberry Pi.

      I would guess that the frequency and address (in the nRF905 the address is just another name for the sync word) are the same for all WH1080 stations, so whatever code you find on the internet should just work. So after all that, the first thing to do would be to not use an nRF905 and instead use an RFM12B and a Raspberry Pi 😛

        • Bob on November 3, 2018 at 7:48 pm
        • Reply

        Hi Zak,

        Thanks for your incredibly fast answer. It’s good to know the nRF905 is a dead end. I will switch to either an RFM01 or a CC1101, which sounds promising too. I happen to have one lying around of each. I already wired up the nRF905, but it’s a hobby so who cares. 😉 I don’t want to use an RPi though, I don’t think it is suited for what I have in mind. It will have to go into the mast on my roof.

        Thanks again,

    • Jörg on December 30, 2018 at 1:44 pm
    • Reply

    Hi Zak

    I have a question about the nRF905 module. I tested your libary for sending a single temperature value. That works very fine. Thanky you for your work and the good tutorial!!
    For my second project I want to replace my old garage transmitter (for a longer range).
    I tried to find out which data the garage transmitter sends by closing the door, but the problem is, that the nRF905 always need a special adress (adress match). Is there s possibility to recieve every data with the configured frequenz channel, to find out on which address my garage opener sends the data?

    One similar question:
    If I want do transmit the same data to 3 or 4 nRF905 modules, how should I configure the TX Module? Is there a kind of public adress (or public broadcast) on which every module recieve data? Or do I have to send each one individually (serial one after the other)?

    Thank you

    1. Hey Jorg, there’s slightly more to radio stuff than just what data is transmitted; modulation, encoding, data rate and deviation are some of the things that need to be known about the transmission.
      The nRF905 is fixed to 2-GFSK modulation, manchester encoding, 50Kbps data rate and +-100KHz deviation. If the transmitter doesn’t use these exact settings then you can’t use an nRF905. Si4463 and CC1101 are some radio ICs with many more customization options. You could also try looking into RTL-SDR, very useful for radio debugging.

      There’s no broadcast address on these modules. If you want multiple modules receiving the same transmission then set the same RX and TX addresses on all of them and filter out the transmissions you don’t want in software by using your own addressing scheme as part of the payload.

      I hope that helps 🙂

        • Jörg on January 2, 2019 at 9:05 pm
        • Reply

        Hello Zak
        thank you for your fast answer!
        That’s what I wanted to know.

    • D-man on February 17, 2019 at 5:26 am
    • Reply

    Hi mate,

    i like the range advantage of a 905 compared to a nrf24 but the code is just crazy, even a lora code is much simpler than this.

    i have a base location with a remote location holding relay units.

    on a nrf24 to send on / off information is as easy as this
    send –
    if digitalRead(x)==HIGH;
    datamsg[0] = 1;

    rec –, 1);
    if (datamsg[0]== 1);
    digitalWrite(Relay1, HIGH);

    you see what i mean, the nrf24 is simple simon, too easy but the range is a joke.
    the lora has kilometres of range i will never need, and the cost and size not right.
    so perfect answer is using the nrf905, IF i can work out a way to simplify the code so it is not a nightmare of packet after packet of garbage just to send an on or off request.

    Could you suggest to me a way to get the nrf905 code so straight forward that it can be run to do what i need with the coding effort i use right now on the nrf24? If you can i will personally see you as my god.

    1. Hey D-man, could you upload the crazy code to I’m guessing the library is just being used wrong. The main difference between this library and most other libraries is that this one uses callbacks which are ran straight from an interrupt, this allows much lower processing latencies and increased throughput, especially if you have a large program.

    • Geoffrey on March 2, 2019 at 11:55 pm
    • Reply

    I see that in the .cpp code you have two callbacks not mentioned – NRF905_CB_AIRWAYBUSY and NRF905_CB_AIRWAYCLEAR. I was trying to use these callbacks just to check if the one NRF905 I have at the moment is working.

    It looks like these callbacks are not implemented as yet. Is that correct ?

    Geoffrey, Papamoa, NZ.

    1. Hi Geoffrey, I think the main reason I didn’t implement those airway callbacks is because the library already uses both interrupts inputs on the Arduino Uno for the DR and AM pins (the callbacks are called from interrupts). A 3rd party library is needed to use other pins as interrupts (theres a few libraries around for this, search for “arduino pin change interrupt”). If you’re using something with more interrupt pins like a Mega then you can use the attachInterrupt() function on that pin which will then be ran when ever the CD (carrier detect/airway busy) pin changes. There’s also the nRF905_airwayBusy() function if you only want to poll the status.

    • Damien on March 14, 2019 at 5:33 pm
    • Reply

    Hi Zak, Is there any method to get the RSSI if i use two nRF 905 transceiver ? Please i need your help

    1. Hey Damien, no the nRF905 does not have any way of getting the signal RSSI.

        • Damien on March 15, 2019 at 3:36 pm
        • Reply

        Ok, thank you, Zak, any idea of another 433 MHz transceivers I can get the RSSI and use it with my Arduino board.

        1. The Si4463 has RSSI support, of which I’ve also written a library for here 😀 –

            • Damien on March 20, 2019 at 7:11 pm

            Thank you Zak, your are the best !

    • roza on May 2, 2019 at 9:34 am
    • Reply

    hey Zak,
    I want to realize a wireless communication between 2 arduino uno with the model nrf905.
    the data I want to send is of type boolean and I do not know how to do it.
    can you help me.

    1. Hey Roza, something like this well send a bool:
      bool myThing = true;
      nRF905_TX(TXADDR, &myThing, 1, NRF905_NEXTMODE_RX);

      and this to receive it:
      bool myThing;
      nRF905_read(&myThing, 1);

    • Tom on May 22, 2019 at 9:59 pm
    • Reply

    Hi everyone,
    I have been having trouble getting the nRF905’s on two identical boards I made transmit and/or receive. They use an STM32F103VCT6 MCU – It is pretty much identical to the one that the STM32 “blue pill” board uses, just with a few extra IO pins, more RAM and flash. I edited the nRF905_config.h file so that it will not use interrupts for DR and AM and I changed the Arduino pin definitions to the correct ones for my board, like it is wired up in the schematic below.
    I am able to write to, and read from the configuration register, and all the values seem correct, but haven’t been able to get a ping from one to the other, or even just transmit a packet. I have an RTL-SDR dongle that I used to detect if they were transmitting anything. I was using the ping-client example. There were no signals at 423.4MHz (ch-10, band-0) which was what it was configured to transmit on – only *very* weak signals at around 863MHz, with the dongle’s antenna right up next to the chip – I assume it’s just EMI from the nRF905’s internal VCO doing stuff…

    I ran the same code on an Arduino Uno (I changed the pin definitions, but all config register values were the same). I connected an nRF905 breakout module to it, and I could see strong signals with a bandwidth of about 100KHz at the correct frequency – 423.4MHz every second or so, lasting about a few milliseconds or thereabout.

    Here is a link to the schematic:
    It seems correctly wired to me, but I might have missed something… I doubt both chips are dead, they both behave exactly the same.

    byte 0: 00000001
    byte 1: 00001100
    byte 2: 01000100
    byte 3: 00100000
    byte 4: 00100000
    byte 5: set in example code
    byte 6: set in example code
    byte 7: set in example code
    byte 8: set in example code
    byte 9: 11011011

    If you know anything that might point me in the right direction, I would really appreciate your response.
    Thanks in advance

    1. Hey Tom, schematics, registers and everything look fine to me! Have you tried tri-stating the MCU pins connecting to the nRF905, then soldering some wires from those pins to an Arduino Uno and controlling the nRF905 from that? If that works then it would be a pin configuration issue with TRX_EN, TX_EN etc pins, otherwise there might be a problem with the RF amp and things.

    • Piero on June 26, 2019 at 5:20 am
    • Reply

    Hi Zak,

    Before buying nRF905 modules. I wonder if it would be useful to turn on and off one switch SESOO (which works through RF at 433MHz) emitting with the module the following value: decimal 2214444 = binary 1000011100101000101100.

    I managed to turn on the switch using ASK/OOK module. But I need a more reliable and long range option. Would it be possible with this one?.

    // Set address of device to send to
    byte addr[] = TXADDR;
    // Set payload data
    int data[NRF905_MAX_PAYLOAD] = {2214444};
    nRF905_setData(data, sizeof(data));
    // Send payload (send fails if other transmissions are going on, keep trying until success)

    Would be correct as shown above?

    Thanks in advance,


    1. Hey Piero, the nRF905 only does GFSK modulation, so it won’t work with ASK/OOK stuff. Though, the Si4463 can be configured for ASK/OOK, but you’re on your own with getting it configured for your stuff, it’s quite a complex device.

    • Tim on July 16, 2019 at 7:47 pm
    • Reply

    Hi Zak,
    a big thank you for this project and the assistance you’ve been providing over the years. I stumbled across your blog as I wa slooking for a way to create a simple telemetry link running at 868MHz and the nRF905 plus your code seemed to fit the bill !

    I’ve built the code with no errors using Atmel Studio 7 to run on a ATmega 328P (actually a Arduino nano running at 16MHz but using the hardware as a vanilla 328p).

    When I feed the rx uart with traffic at 19200 baud the unit transmits – but heres the thing it’s transmitting on 403MHz and low power. The other unit with the same code transmits on 402.5MHz so I suspect the chip is not being initiallized correctly and is being set to it’s lowest possible freq ?

    As far as I can tell I have everything hooked ok and have edited nRF905_config.h to set the desired freq etc.

    Running out of ideas on how to debug this – but luckily I have a spectrum analyser which indicates something no right with the frequency setting.

    I may have a go at with the Ardunio code but I’ve never used that environment before ….

    Many thanks again – Tim

    1. No problem Tim! The minimum frequency of the nRF905 is 422.4MHz and default frequency is 433.2MHz, are you sure you’re not picking up a harmonic? What does the debug example code output?

    • Tim on July 18, 2019 at 11:59 am
    • Reply

    Hi Zak,

    thanks for the reply – since my last post I’ve made some progress. Basically I started over with a brand new environment and built the Version 3 code having edited the config file to transmit on 848.8MHz channel 20 – which is now does.

    However neither of the units want to decode the others transmissions – maybe its an address mis match issue despite both units having the same code ?

    I tried turning off the AM interrupt and rely on the SW reading instead – still no joy.

    Probably something silly as clearly they tx ok on the desired freq. On the tx unit I get a TO as expected due to no response.

    Any ideas ?

    Thanks again Tim

    1. nRF905 modules are usually tuned for 433MHz operation, and don’t really work at 868MHz. Are your modules tuned for 868MHz? Also, DR is the important pin to fiddle with, rather than AM, and the ADDRMATCH and RXINVALID callbacks don’t work if AM is not setup for hardware interrupt mode. Setting the same address for both modules is fine.

    • Tim on July 18, 2019 at 12:00 pm
    • Reply

    should have mentioned – I’m now using Arduino to build the sketch / code.

      • Tim on July 18, 2019 at 10:39 pm
      • Reply

      Hi Zak,

      I plan on changing the balun components to 868MHz values once I have the code working ok – fortunately I’m well equipped for RF optimization matters.

      I’ll probe the DR pin to see what it’s doing, I also plan on injecting a signal on the operating freq to see if the CD pin goes high and what RF level it takes to trigger it. Getting the CD pin to respond to a blocking signal will increase my confidence the rx is working ok.

      Noted about AM, Addrmatch and Rxinvalid.

      Question – I might have missed it, but where do I see the unit address ?

      Many thanks again for your time and assistance.

      Regards Tim

      1. The receive/listen address is set with nRF905_setListenAddress() and the send to address is the first parameter of nRF905_TX(). In the example code they’re set to RXADDR and TXADDR, which are defined near the top of the source code file.

    • Tim on July 19, 2019 at 4:50 pm
    • Reply

    All sorted out now.
    Turns out you were correct, as the units were tuned for 433MHz the performance at 868MHz was severely impaired to the extent they wouldn’t work even over a cm.
    Having checked the performance at 433MHz the rx threshold was -100dBm exactly as per the data sheet and likewise tx power +10dBm.
    Having got everything working at 433 it’s just a matter of re-tuning the balun for 868 and creating a suitable antenn\.
    Many thanks again.

  1. […] are used include the standard SPI library provided in the Arduino IDE.  We will also use the nRF905.h library developed by Zak Kemble.  Zak’s nRF905 library will initialized power, provide the communication addresses, and […]

  2. […] Zak Kemble nRF905 discussion […]

Leave a Reply to Zak Kemble Cancel reply

Your email address will not be published.

Are you human? *