How to work with the NRF24L01+ Best Wireless Communication for Arduino

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
hey what's up guys so this is going to be a first of many videos in which I discuss a new project I just started working on in making my home smart and what I mean by smart is I'm basically creating a wireless mesh network of sensor nodes here in my house that are all communicated with via a single main host station so the first step of this project was to establish the wireless communication and for this I chose to use the NRF 24 l01 which is a great wireless transceiver it operates at 2.4 gigahertz it's got plenty plenty of bandwidth to do this sort of thing and the best part is it's really really cheap so if you want to add wireless communication to your arduino project that's basically what this entire video is gonna be about and i'm not talking about using any pre-written libraries or anything like that we're going to just go right through the code and how to talk to this via a standard arduino uno so let me show you what i'm talking about here okay so what we have here is two arduino x' both with a NRF 24 l0 1 plus attached these this is really cool code that I've got running here and it might not look like it's really that cool until I explain what's happening here but basically on this Arduino we have a push button connected in an LED connected to standard digital pins on the Arduino and if I push this button in the LED blinks so I mean that would probably take just a few lines of code on this earth we know to make that happen but what's interesting of what we have here is that there is no code running in this loop at all on this Arduino everything is actually controlled by this Arduino so in this Arduino loop we're monitoring this digital input and if we ever see this pin go low because we have the pull ups in abled on this it will then turn or flash this LED over here so that's all controlled by this Arduino this Arduino is handling everything it's grabbing the status of this pin and it's driving that LED pin high and low so what we basically have here transparent control over this arduino z' io so we can control all the pins we want from this we can even set up the pin modes over here so basically what I'm getting at here is that you've set all of your sensor nodes up with the same code and then this host Arduino will go out and configure all of the i/o that you want for the four of these sensors so you know I'm configuring this the push-button pin as a digital input I'm configuring the LED pin as an output so it's all handled by the host so it's really cool stuff and we'll get into all the code and how it all works in a second but even cooler by the way is that these two guys are both running the same exact code the only difference is is that this guy here has nothing in its loop no code running in the loop so this one could actually control this one so they could almost control each other if you wanted to but anyway let's just talk a little bit about the hardware here so this is the NRF 24 l 0 1 plus module so you can buy them with these on these modules which is great and they're really really cheap so they come with a 2 by 4 header which really kind of stinks because you can't use that in any breadboard it doesn't really plug in anywhere on the Arduino so you need to either buy a breakout board for it or you need to just remove the header and solder wires on to the board itself like what I have here and that's exactly the way I did it eventually what I'm gonna do though is make up my own little Arduino board that basically just has an Arduino a 3.3 volt supply and this board so let me leave a comment if you'd be interested in something like that too maybe I'll sell them on my website or something so basically though to hook this up you can see there's nothing special needed at all the only thing that kinda you need is a 3.3 volt supply this board only runs on 3.3 volt supplies so if you're running hour doing on 5 volts unfortunately you need a separate regulator just for this board so anyway you get that we go look right through the pins here so your vc see and ground VCC is 3.3 volts ground it's ground that's pretty easy the nice thing about this board is all the aisle pins on it are 5 volt tolerance so you don't need any level shifters so even though you're powering the board with 3.3 volts you can still output 5 volts to the digital inputs on the board for the communications and this will only output 3.3 volts on the output pins of the board which is just fine for the Arduino since the Arduino spins are 3.3 volt tolerant so if you go right through the pins it's pretty simple you have your you have a chip enable which sets it in to tx/rx mode you have a chip select pin to enable the spy interface for the for the chip you've got your mossy miso master out slave in and master in slave out you've got an interrupt pin so which goes low when new data when an event takes place on the chip the way I'm using it is when new data is present on the chip make the pin the interrupts Pingo low that way I can trigger an interrupt on the Arduino and then go grab the data you also have the spike lock so in total you have 8 pins on that and I think from my code it'll be pretty obvious on which pins are which pins on this are wired to which pins on the Arduino so speaking of the code let's jump over to that right now ok so here's the code and like I said before we're not using any libraries so everything is gonna be written in one single Arduino file so you know feel free to copy and paste anything out of here you want to use if you don't want to use my code at all and you just want to get a better understanding of the chip that's fine I don't care I'll put everything that you see here up on my site so check the the description for a link or something like that so anyway let's just jump right in so first thing here is I define the pin outs of both the the transceiver and the Arduino so you can see here that you know pin 1 on the n RF modules ground ground bcc'd 3 3 C e 2 4 CS n 2 5 and also showing the direction here - so this is an output on the Arduino so this is just kind of helpful and basically I wrote this code it is a first draft at this point so I'm just I'm just using the code right now is a starting point for the project I'll eventually clean all this up and create some kind of library that's a little bit easier to use than this but for what for what I've come up with so far I think it's ready for a video okay so anyway we define the pins here we got the only thing we've got includes the spy library we've got then a definition of all the pins here a few global variables nothing special jumping right into the setup here your serial port is going to be your best friend with this module because you're going to need some debugging and the only way to really truly debug everything out is through the serial port so set that up at 115 - I'm running it at 115 - for a reason because the serial library and the interrupts don't really go hand-in-hand with each other so you might run into issues where you're doing serial dot prints within an interrupt and things just freeze up that's that's going to happen to you so you need to make things happen really fast and you got to really watch your timing so I'll I'll explain that a little bit more as we move through this but anyway alright setting up and then we got a subroutine here NRF initialize I'll drop down to that real quick here the codes really not too bad actually so if we jump down here to NRF initialize if I can find it here again not really too prepared with this video just winging it as usual oh come on where is it it's coming up NRF initialize right here okay so basically we're setting up all the pins you know see pins and Out Boy's CSN's and I'll put mossy pins and output nice opens and input the clock pins an output then we do a print then we've got to set up the spy port and the way this module works you can actually check the datasheet and the data sheet really you really got to rely on this and go to it a lot especially when you're talking about working with the registers what am I doing here I'm just gonna grab show you where this is at here okay yeah so this is where it shows you the the spy timing here so you can see that when the chip select line goes low that's when you start clocking your data and so and you can see that the clock is held low when it's not active and if we look here master out slave in you can see that new data is clocked in on the rising edge of the clock line so you can see you have a rising edge while the data is ready to go here okay so I just wanted to show you that so that is spy mode zero which is rising edge of data and that keeps the clock low now I'm running my spy at 8 megahertz so I'm just dividing it by 2 but you could really run it at anything you want so with the Arduino you're not gonna go too fast for it so I'm running it as fast as I can with your do we know it a 16 megahertz clock dividing that by 2 to give you 8 I think a lot of people are actually dividing that by 4 when working with this module okay so then what we do is we put it in our X mode right away by writing the sieep in high and then we let it sit high the CSN pin needs to always be high when you're not talking to the device so it's an active low chip select and then we kick off the spy the spy interface so spied begin and then the NRF is ready alright that was pretty easy then we jump into setting one of our first register here so this is NRF set our x payload so you need the device needs to agree with the device that's sending data as to how much data is coming along and you've got a 32 byte pipeline I think you have like four or five pipelines I'm just using one pipe so pipe zero and I'm setting it up with three bytes so let's jump down here to where I do that where is that I'll find it here right here okay so we have two things that jump into this subroutine you've got the pipe and then you have the bytes so I'm just doing a three byte message so everything is sent over via just just three bytes and you can see here what I do is I take the I set up this the the address to equal the pipe plus 32 plus 16 plus 1 so this is the register address and I'm just gonna break this down for you real quick here to show you how this all works so if I go over here and I look right here you got to go down to spy commands of the user manual and you'll see it that if you want to write to a register which we do you have to write a 0 0 1 so this is a value of 32 so basically I'm just adding 32 and then the A's here are the actual address of the register so if I go down here now to where all the registers are right here it's starting at 0 and it's all hexadecimal you can see that I'm going down to 16 plus 1 so that should be a 1 0 here well it's actually 16 plus a 1 gives you 11 here in hexadecimal 1 1 and you'll see here that the firt that address is RX p WP 0 so this is number of bytes in rx payload in data pipe 0 so that's basically what I'm doing right here so 16 plus 1 gives me the hexadecimal 1 1 plus the 32 so that I'm writing to it and then that sets up the address so I mean if I went pipe 1 there you know it would actually be this address here this pipe oops ok so moving along here what it does then now you've got the address of the register so then it pulls the chip select line low you pull it low now you're ready to talk to it and when you talk to spy you actually have to there's there's two that it's full duplex like you're sending data and you're receiving data at this time so when you're receiving data you're making it equal here so data in of 0 is equal to spied out transfer this is actually going to send this out the pipe this is what's coming back at the same time ok so you send out first your address this is telling you that you want to write to address 17 then the next byte you send over is the actual information you want to write to the device which is bytes so we're writing a 3 there to address 17 you're setting the RX payload to 3 bytes all right then we just do a little bit of serial printing there for debug just so we know you know that we did write it okay moving along here set the payload and then what I do here is just for some debugging I go and grab the status register so this is NRF get address 7 and the way I have to set up is when you ever use get address the first variable you send down is the actual address number then the second one could be either 0 or 1 0 meaning that you don't want it to print to the serial to your serial monitor window 1 meaning that you do want it to print so in this case yes I do want it to print okay and if I actually if I go and open up my serial monitor since I have active communication you could see all the debug information so this here was actually the address 7 okay let me get out of that and I can show you that real quick here by skimming down to 7 right here so this is the status register and by the way this actually tells you that anytime you write to it the first thing you get back is always going to be the status register so actually if I go down here I'll just show you this once real quick here so when I did this set payload here if I actually looked at what data in 0 was it would be the status register you always get that whenever you start communicating with it because when you're first writing the byte it doesn't know what you're doing so it just spits out the status ok all right so let's just keep moving through this okay get the address so spit that out let's let's jump down there real quick and show you that it's a massive piece of code here so like I said you're getting tooth you're sending down two things you're sending down the address and whether or not you want to print I have a lot a little explanation there of what that means so here what we do is we do a float we pull the chip select low we do a transfer of the address because now when you're just want to read to register what you do you come down the datasheet here when you just want to read something you go here to our register now it's just all zeros so it's just the address so you read the address and that data one here will be what what is in that register okay and then you pull the chip select back hi and then if your info was a one basically goes through and prints out all of the stuff that's in the register so it'll take all those ones and zeros and make sense out of it okay so you can see I have all these conditions here that make it really easy and prints out things so if it sees ones or zeros it'll actually print out what it what what's actually going on on the chip so you don't you don't have to figure that out so it kind of it helps with debugging this whole thing okay get back here okay so now oh boy okay now we have another subroutine here NRF right the bit right I don't know why wrote it like that but basically what this does here is it'll write a single bit of any register in the chip so the first the first variable you send down is the address the second is which bit in that register and then the lastly is what you want to write do you want to write a 1 or a 0 to that location and this is important to do because let's jump down and take a peek at what that guy is doing here ok right here okay so what this is doing is it'll actually first pull out it'll first pull out that register so it pulls it out and now that register is in data in zero or sorry Dart data in one here and then if you want it to write a 1 to it basically what it'll do is do a bit set of that register just pulled out of bit adds so that's right here of the bit address so in bit sets or bit clears it and then it'll actually write it back in so as you can see now we have the 32 plus the address so now it's going to write to that register and it writes in the modified register so it's good because if other things are moving in that register you don't you don't want to affect those other things you only want to write the single bit that you want to change okay so hopefully that makes sense and you can see here I'm writing all kinds of things so the first thing I'm doing here is putting it in our X mode so let me show you that real quick I'll pull up in the datasheet here so you can see first thing I'm doing is I'm throwing this I'm setting this bit to one throwing it in our X mode then I think what I'm doing next here I'll take a look here is I'm putting it in powerup mode so then I'm writing this bit here to a one so now it's powered up it's in rx mode it's powered up and then the next two things I write to are to set up the interrupts so like I said I only want to call and interrupt when new data is ready so the only interrupt I really care about here is these this masks are XDR so to clear these two guys or make them not do anything this TX and Max RT is I just write a 1 to them and you can sort of see here in the datasheet interrupts not reflected on the iron upin so that's why I wrote a 1 to those two guys and that's exactly what I did here okay up next is I flush out the Rx and the TX FIFO the first-in-first-out buffers and if you go up here you'll see where that is given right here flush TX flush rx so I'm basically just pulling the chip select line and shooting that out pipe to the device so flush your rx flush your TX you know just in case there's anything any garbage data that's still sitting in there just dump all that out okay then I call another subroutine here called clear interrupts I'll jump down to that guy real quick here show you what that does okay so here we are and our of clear interrupts and basically all this does is it gets the address the status it grabs the status register so I'll show you that real quick it grabs the status register which is seven right here and it looks at these three interrupt flags so it's status zero is where you set up or I'm sorry in the config register zero is where you set up what you want these interrupts to be do you want them to be reflected on the our cue pin or not and then in this here and the status register is telling you this is telling you whether or not they're active so if the flag has been set and the only way to clear these is to actually write a 1 to clear the flag okay so basically what i'm doing here is grabbing the red grabbing the register the status register and if it's right reads in as a 1 go ahead and clear it by writing a 1 to it and i'm doing that for the RTV TX and the RX interrupts down there okay all right now we're getting into the good stuff finally what we do is attach the interrupt to we attach an interrupt to the interrupts 0 which is digital pin to the irq pin is connected to digital pin 2 of the arduino to call get data which is a subroutine on the falling edge of that pin so this pin will go low when new data arrives on the transceiver okay now what we do is get into the good stuff so this is how we actually control the other Arduino so look at check this out I'm doing an n RF pin mode and the way I set this up is digital pin 3 as you know and then I sent a zero meaning I wanted to be an input okay so digital pin 3 uses zero to claim it as an input and then I can do a right of that pin by the NRF pin right of digital pin 3 and make it a 1 to drive it high and what this will do is enable the internal pull up of that pin okay so I think now we're ready to talk about what how these are all set up here so I'm gonna go through some of these now and show you some of the things you can do in the code but I think just before that let me do I'm gonna set something up here in the loop where does it add here's the loop is right here so now I'm just gonna show you at a high level what's going on here so if you look at the code that's not commented out here you can see that if NRF pin read of 3 is equal to zero then go ahead and make digital pin 7 high then low high below high low this is the code I just demonstrated for you which is all this is being ran on the host microcontroller so you can see when I do an NRF pin read this is not a pin read of the local microcontroller this is actually reading the pin of the second microcontroller so it's kind of cool and if I did I'm trying to see what I have set up here yeah if I'm ready to okay and then if I go I'm actually gonna try to okay I just wanted to try something there so there's another thing you can do here in this code and that is a ping which is very useful for debugging and I think that's where I want to start the explanation here of how this all works is by a simple ping so I'm actually just going to make sure I got the right one I'm actually just gonna do a ping here upload that to the host Arduino here ok it should be done here and it's done open this up okay so basically it sets up and then it's just telling you if the ping was successful if it was a fail and yeah there are a few fails it's not perfect communication but that's why you send multiple bytes to the thing you keep you keep sending your data until you get a successful read back and I'll show you what I mean by that in a second okay so let's just explain this ping thing for a second we'll talk about pin mode and pin right but the most basic thing here is just by sending something over to the Arduino and then getting it back okay so here is that subroutine to ping it and basically what we're doing is grabbing a random byte so if something from 0 to 255 and then we do a transmit here of ping and it starts with 6 and that's a code so on the receiver side when it sees a 6 it knows it's getting pinged and when it gets pinged it knows to send it back with another code and when we get it back we see that code and then we see what we pinged with and then we match those up to see if we had a successful ping and we'll explain that in a second so basically what it does here is it transmits weights a little and then if the data to which is the data that's coming back is equal to my ping then I know I had a successful ping so now let me show you this transmitted so this is how to actually send data out okay we'll go up here to transmits and it's right here okay when you transmit you need 3 bytes going in right now they don't really mean anything I have them labeled as mode pain and value but they really don't mean anything yet okay the first thing I do is I flush out the TX so if there's anything already in there just get rid of it because I'm about to send new data then we pull the chip select low we do a load TX payload which is if I go right up here to this command right up here so load load the TX payload right here so this is where you could load up all your 32 bytes but in my case I'm only loading up three bytes load it up so first we tell that we're gonna load up then we followed by our three bytes pull the chip select pin high alright now it's time to go into TX mode and what it does is it pulls the chip enable pin low add a little bit of a delay in there then we do a bit right of the configuration register 0 bit 0 and write a 0 in there now it's in TX mode put a little another another slight delay in there make sure everything's make sure everything was written and then we write the chips the trip and Abel pin hi and this is where this critical delay is at and I experimented with different values of this delay and what I'm talking about here is the data the delay now from when this chip enable pin has gone high until you have written back to these the configuration register a1 to put it back into RX mode so i've experimented with different values here and if it's too long or too short it doesn't work so i found the sweet spot right now is just with a delay of 1 millisecond and that seems to work pretty good so so you put it now back into RX mode and at this point right here is when the data is flying out of the transceiver back to the the host receiver there okay and then that's it we're done with the transmit then what we do is we just hang out here so if you go back here to the ping you'll see that we do a transmit and then we wait 15 milliseconds now during this 15 milliseconds the data should have arrived on the other end and it should have caught that data and then sent it back so now let me show you what that looks like over here so if I go now to get data so what happened what happened what what should be happening here is we send the data out it gets caught by the other end and on the other end this subroutine is caught is called immediately because the irq pin goes low as soon as data is in the transceiver ok new data so what we do is we simply do we pull the chip select pin low and then we do a command to read the payload so you go back over here and you'll see read the RX payload and then followed by three bytes and this is the actual information that's coming in the three bytes your data in one two and three okay so now we got the data that's all there is to it to get the data out well there's a little bit more to it and I'll show you that in a second but as soon as we get the data then we start figuring out what the data is and there's all these codes in the data so the first byte that I send is what to tell the transceiver what to do so I just showed you that we sent a six so when you when it sees a six now it's saw six and what it does immediately is it just transmitted back actually there should be a little bit of a delay actually in this it doesn't matter but in here you'd want to have a little bit of a delay before you transmit because if the other guy just sent his data it's caught immediately and you send data back it might still be in the transmitted routine so anyway you might want to add a little delay in there but what it does here is it catches the ping and it immediately transmits back but this time starting with a code of three and it transmitted the data it's just saw so two and then three so these are the two pings it got so it gets that back so then on your on the side that's actually sending the data out it then would this would be called again and then you could see here that data in if it's equal to 3 which is the echo back data to here is equal to the data in and data 3 is equal to that data in and then that's when you see down there that we're comparing two so if data 2 is equal to my ping back we have a successful ping so you could see though if we're seeing a lot of fails in there and I just noticed though that there is no delay in here and I really think there should be some might actually give that a try real quick I just noticed that right now in my code so I'm gonna upload that real quick and basically that's how a ping is used now a pinmode a digital right a digital read are all with other codes so if I sent something with a one starting out that means I'm going to set up the pin mode of that Arduino so followed by data 2 which is the pin I want and followed by data 3 which is the actual mode of the pin so if it's a 0 I want that pin to be an input if it's a 1 I want that pin to be an output and then we have the delay in there here and then what we do is echo back that with a transmit of 3 so then we echo back that data which it would be then the pin and the mode back right back if it's a to spin sent that means that I'm doing a digital right and you know if you read through all this I think out all my comments will make sense but if I send out a 2 that means that I'm trying to write to a pin so data 3 is actually what what the value I want to write whether it be a low or high and data 2 is the actual pin and again I Seco that back with the transmit of 3 ok so that's pretty much it on the things I have right now I also have 5 which will probably be 4 analog reads right now everything is digital digital read and writes but eventually I do want to do analog reads as well amongst other dedicated functions like if I had a temperature sensor on each board 7 might be read the temperature something like that so while we're in here and get data if I don't ever if I don't see a mode here anything 1 through 7 right now what I have that means that no mode byte has been identified and then just you know spit out the data that you did receive so like if you just wanted to send like text or something like that maybe you'd actually start that with like a 7 and then the following bytes would actually be the text so if you just wanted to send messages or something like that that's how you would do it so anyway that's that's how I parse all the data out then the last thing I do here is flush the RX FIFO and then the most important thing that I think a lot of people screw up with is that are that irq pain went low to call this subroutine and you were actually the interrupts was flagged in the transceiver so you actually need to go and clear that interrupts and that's exactly what I'm doing here in the status register bit six right a12 it and we'll clear the interrupt and now that irq pin will go back to being high okay so that's pretty much all there is to it now if we get into it you can see that you know all these other functions are pretty much all copies from each other so like pin mode here would be you know the pin and then the mode you know whether you want it to be an input or an output and then what I do here I'll just explain one of these is I basically give it ten tries to set the pin up so what I do is I do a transmit of code one the pin and then the mode I give it 15 milliseconds and then I check the data that came back so if the data two is equal to the pain I sent out and the mode is equal to the mode I sent out then make I equal to 10 which would force me out of the for loop completely and you're done you can move on if not you know repeat that and keep going until you do get this if you get all the way to the end you'll get a naic hwal to equal to nine that means you got to the end no pin was set and then that would be a fail to set the mode and then reset your to compare variables there okay same thing with pin right same exact thing for pin read it's a little different because pin read is actually not a void subroutine it actually returns the value of the pin read you're trying to do so like you know it works just like a digital read of a bit of a pin in the Arduino language so again you're giving it 10 tries and if the data 2 is equal to the pin that you sent out that you want to read then get out and return date of 3 which is actually the read that the the Arduino on the other side read okay and that's pretty much it that's all the code here I mean it's really simple stuff let me show you maybe an example of this here I'll get rid of the paint stuff and I'll upload that Oh actually I said I was going to Stout adding the delay oh look at that I added the delay and you could see that the code isn't much better and you could see that there's fails in there and there's the reason and I just wanted to make one more comment here is that the reason you know that I'm trying 10 times to do this is that there's a trade-off between how fast you want to write and the quality of your data so if I added more delays in there and did more double-checking of everything and made sure that everything lined up then I wouldn't have to do this but that would all take time but as you can see from this that most of the time you're gonna get at the first try so in here if you get it the first try and you get your data back and it was correct then you might as well just use this method because chances are we'd get it the first try if not it would get it on the second try and that's kind of the reason why I've made my code so simple and didn't do all that checking now obviously you could go completely ballistic with all your checking and if you go through all these registers in here you can see all the crazy stuff you can do and like I said too before is this is just my first draft of this protocol eventually I want to get into you know talking to multiple sensors so so giving each sensor node an address you know and have them all talk to each other and talk back to the host or if one of them is out of range but it can talk to another since your node it would pass its information along you know things like that I also want to get into some of these low power modes and how do you you know put the thing to sleep and how do you wake it up things like that so you can go through all these registers and see that there's a lot of stuff you can do so anyway I hope that wasn't too long of a video but you know like I said too before you don't have to use my code you could use a library that somebody's already written and probably have done a much better job with but the way I like to do things is to break it down and and try to figure everything out just using the datasheet so anyhow that is how to work with the NRF 24 l01 thanks for watching
Info
Channel: Kevin Darrah
Views: 193,630
Rating: 4.9043746 out of 5
Keywords: arduino, 24L01+, NRF24L01+, wireless, microcontroller, nordic, transceiver, pic, avr, how to, tutorial
Id: hI4JGDB7WtU
Channel Id: undefined
Length: 37min 19sec (2239 seconds)
Published: Mon Mar 31 2014
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.