Maker Pro
Maker Pro

Wireless trigger for LEDs and buzzers

KrisBlueNZ

Sadly passed away in 2015
So if I wanted to transmit I would call it like this:
spi_txrx_byte(txdata);
and if I wanted to receive data I would call it like this?
receive_data = spi_txrx_byte(txdata);
Yes, that's pretty much what I said:
To read a byte: newdata = spi_txrx_byte(0); // write 0x00 and read the simultaneous response
To write a byte: spi_txrx_byte(byte_to_write); // write data; ignore simultaneous response
The difference is that when you receive a byte, you're also transmitting txdata; in my example, while I'm reading a response, I just transmit 0x00. I assume that the nRF ignores the data you send to it while it's sending you a response.
P.44 of the PIC's datasheet clears things up a little I think. It says that any read of a pin reads the entire port
Yes, any read access to PORTB, whether bytewise or bitwise, reads the entire port. I think I've figured out what they mean though. The data sheet says that any read of PORTB will clear the mismatch condition that generates the RBIF status, and therefore will clear RBIF. I think they mean that if you read PORTB when an input has just changed, the read could clear the mismatch before it is able to set RBIF. This is another good reason to poll PORTB instead of polling RBIF to detect a change.
I mean I guess we could just poll that one pin repeatedly to see if the NRF has pulled it low and not worry about an interrupt at all
That's what I said:
How does the nRF drive the IRQ signal? Does it hold it active until it's acknowledged? If so, you don't need the RBIF anyway - just read the PORTB data register instead of polling the interrupt flag.
But as I said, you need to make sure that the nRF holds its IRQ signal active until it has been explicitly acknowledged, e.g. with a message transfer.
 
I was just looking at the function you wrote and in this line:
Code:
PORTAbits.RA3 = (txdata > 127); // Copy bit 7 of txdata to RA3 (MOSI)

I've never seen an argument like this before, wish this was something my professors taught me, very useful. Can you apply this to select out certain bits, like:

Code:
PORTAbits.RA3 = (txdata>1 && txdata<4)

would that give me access to only bit 1?
 
But as I said, you need to make sure that the nRF holds its IRQ signal active until it has been explicitly acknowledged, e.g. with a message transfer.
I found in the NRF datasheet(p.53) it says that the microcontroller needs to write a '1' to the IRQ source bit in the status register in order for the IRQ pin the release control. So it looks like I will need to write to the NRF twice whenever it has data that needs to be processed. Good thing I found this because for some reason I was under the impression that once the RX-FIFO was emptied the IRQ went back high.
 
Okay, I think I've finally finished coding everything for the receiver.

Code:
// THIS CODE IS INTENDED FOR USE WITH A NRF24L01 USED AS A PRIMARY RECEIVER
#include <pic16f627a.h> //needed for MACRO descriptions of config and pins
#include <stdint.h>//needed for uint8_t
#include <xc.h>//this header is needed for delay macro
#define _XTAL_FREQ      4000000//this value is needed for the delay macro
//--------------------------------------------------------------------------------------------------------
//Configure device
#pragma config FOSC = INTOSCIO  // Oscillator Selection bits (INTOSC oscillator: I/O function on RA6/OSC2/CLKOUT pin, I/O function on RA7/OSC1/CLKIN)
#pragma config WDTE = OFF // Watchdog Timer Enable bit (WDT disabled)
#pragma config PWRTE = OFF // Power-up Timer Enable bit (PWRT disabled)
#pragma config MCLRE = OFF // RA5/MCLR/VPP Pin Function Select bit (RA5/MCLR/VPP pin function is digital input, MCLR internally tied to VDD)
#pragma config BOREN = OFF // Brown-out Detect Enable bit (BOD disabled)
#pragma config LVP = OFF // Low-Voltage Programming Enable bit (RB4/PGM pin has PGM function, low-voltage programming enabled)
#pragma config CPD = OFF // Data EE Memory Code Protection bit (Data memory code protection off)
#pragma config CP = OFF // Flash Program Memory Code Protection bit (Code protection off)
//--------------------------------------------------------------------------------------------------------
//internal NRF registers
const uint8_t NRF_Config=0x4F;//forces data that is received to trigger the IRQ pin
const uint8_t NRF_EN_AA=0x00;
const uint8_t NRF_EN_RXADDR=0x01;//enable datapipe zero only (for now)
const uint8_t NRF_RF_CH=0x02;//set up RF channel as 2.402GHz (2.4GHz+2MHz)
const uint8_t NRF_RF_Setup=0x0F;
const uint8_t Clear_Status=0x40;
//------------------------------------------------------------------------------
//buffer variables
uint8_t PICin=0x00;//used as buffer for data leaving NRF
uint8_t NRFin=0x00;//used as buffer for data entering NRF
//--------------------------------------------------------------------------------------------------------
//function prototypes
void init_PIC(void);//configures PIC for operation
void init_NRF(void);//configures NRF for operation
uint8_t spi_txrx_byte(uint8_t);
//--------------------------------------------------------------------------------------------------------

main(void)//main program
{
    init_PIC();//initialize pic
    init_NRF();//initialize NRF
    while(1)
    {
        if (PORTBbits.RB7==0)//poll IRQ pin
        {
            PORTAbits.RA0=0;//bring CE low (disable receiver)
            NRFin=0x27;//load write instruction byte into buffer
            spi_txrx_byte(NRFin);//send buffer data
            spi_txrx_byte(Clear_Status);//clear IRQ interrupt source bit
            NRFin=0x61;//load read rx payload instruction byte into buffer
            PICin=spi_txrx_byte(NRFin);//clk in data and place into PICin
            PORTAbits.RA0=1;//bring CE high (enable receiver)
        }
        else
            PORTB = PICin;//this puts the value of PICin onto PORTB which is connected to a 7 seg LED
    }
}
//--------------------------------------------------------------------------------------------------------
void init_PIC(void)
{
        OPTION_REGbits.T0CS=0;//internal instruction clock
        OPTION_REGbits.PSA=0;   //prescaler assigned to WDT so timer0 increments at a 1:1 ratio
        INTCON=0x00;//disables all interrupts
        CMCON=0x07;//turns comparators off
        PORTA=0x00;//clear PORTA prior to operation
        PORTB=0x00;//clear PORTB prior to operation
        TRISA=0x20;//0010 0000
        TRISB=0x80;//set RB7 as input(interrupt on change) and rest as outputs
        PORTAbits.RA1=1;//set CSN high
        PORTAbits.RA0=1;//set CE high (enable receiver on NRF)
}

void init_NRF(void)
{
//shift in w_register instruction,shift in config data
    PORTAbits.RA1=0;//set CSN low, alerts NRF of incoming SPI
    NRFin=0x00;
    spi_txrx_byte(NRFin);
    spi_txrx_byte(NRF_Config);
    PORTAbits.RA1=1;//set CSN high, tells NRF SPI data is complete
    __delay_us(1);
//--------------------------------------------------------
//shift in w_register instruction,shift in nrf_en_aa
    PORTAbits.RA1=0;
    NRFin=0x01;
    spi_txrx_byte(NRFin);
    spi_txrx_byte(NRF_EN_AA);
    PORTAbits.RA1=1;
    __delay_us(1);
//--------------------------------------------------------
//shift in w_register instruction, shift in nrf_en_rxaddr
    PORTAbits.RA1=0;
    NRFin=0x02;
    spi_txrx_byte(NRFin);
    spi_txrx_byte(NRF_EN_RXADDR);
    PORTAbits.RA1=1;
    __delay_us(1);
//shift in w_register instruction, shift in nrf_rf_ch
    PORTAbits.RA1=0;
    NRFin=0x05;
    spi_txrx_byte(NRFin);
    spi_txrx_byte(NRF_RF_CH);
    PORTAbits.RA1=1;
    __delay_us(1);
//shift in w_register instruction, shift in nrf_setup
    PORTAbits.RA1=0;
    NRFin=0x06;
    spi_txrx_byte(NRFin);
    spi_txrx_byte(NRF_RF_Setup);
    PORTAbits.RA1=1;
}

uint8_t spi_txrx_byte(uint8_t txdata)
{
    uint8_t bitn;
    for (bitn = 0; bitn < 7; ++bitn)
    {
        PORTAbits.RA3 = (txdata > 127); // Copy bit 7 of txdata to RA3 (MOSI)
        PORTAbits.RA2 = 0;              // Bring SPI clock low
        PORTAbits.RA2 = 1;              // Bring SPI clock high
        txdata <<= 1;                   // Shift bits up in txdata
        txdata |= PORTAbits.RA5;        // Shift MISO pin state into bit 0
    }//for bitn
    PORTAbits.RA2 = 0;                  // Return SPI clock low (for tidiness)
    PORTAbits.RA3 = 0;                  // Ditto for MOSI
    return txdata;                      // txdata doubles as rxdata
}
 

KrisBlueNZ

Sadly passed away in 2015
I was just looking at the function you wrote and in this line: PORTAbits.RA3 = (txdata > 127); // Copy bit 7 of txdata to RA3 (MOSI)
I've never seen an argument like this before, wish this was something my professors taught me, very useful. Can you apply this to select out certain bits, like: PORTAbits.RA3 = (txdata>1 && txdata<4)
would that give me access to only bit 1?
No. Comparing the byte value to a constant (in this case, 127) only works for isolating the top bit. Because if the top bit is 1, the byte value will be 128 or more; if the top bit is 0, the byte value will be 127 or less.

A more general way to isolate any bit, which you can use in that function for better clarity, is:

PORTAbits.RA3 = ((txdata & 0b10000000) != 0);

This performs a bitwise AND between txdata and that binary constant, which has only one bit set, then compares the result to 0. If the bit we're interested in was set, the result of the AND would be non-zero, so the "!= 0" comparison would succeed and would produce a result of 1, to be assigned to PORTAbits.RA3. If the bit we're interested in was clear, the result of the AND would be zero, the comparison would fail and the result assigned to PORTAbits.RA3 would be 0. In both cases, the value assigned to PORTAbits.RA3 is the value of the bit identified by the bitmask in the bitwise AND operation with txdata.

I found in the NRF datasheet(p.53) it says that the microcontroller needs to write a '1' to the IRQ source bit in the status register in order for the IRQ pin the release control. So it looks like I will need to write to the NRF twice whenever it has data that needs to be processed. Good thing I found this because for some reason I was under the impression that once the RX-FIFO was emptied the IRQ went back high.
Cool.

I had a quick look at your code. You seem to have several const uint8_t variables that you don't need. Just say #define NRF_CONFIG 0x4F and so on, and pass those named constants to spi_txrx_byte() instead of the variables.

You can, and should, use more #defines to equate meaningful names to I/O bits. You're using PORTAbits.RA0 as an active high chip enable for the nRF, so you could say:
#define NRF_CHIP_ENABLE PORTAbits.RA0
then later you can say:
NRF_CHIP_ENABLE = 0; // Disable nRF receiver
which looks a lot clearer. You can also #define statements as pseudofunctions:
#define ENABLE_NRF() PORTAbitsRA0 = 1
#define DISABLE_NRF() PORTAbits.RA0 = 0
then just say ENABLE_NRF() when you want to enable the nRF, and DISABLE_NRF() when you want to disable it.

By convention, constant values, and pseudofunctions created using #define, are named in full upper case.

Finally, I'm not sure you have the right sequence of commands for reading the data and resetting the interrupt. I would expect you should request the data, receive it (into a buffer with enough room for the maximum response; receive the number of bytes that the nRF tells you it has received), and only then clear the interrupt request flag.

Other than that, the code looks good to me. But I haven't studied the nRF communication protocol so I can't say it's exactly right.
 
Thanks a lot for the help, tips, and expertise; I will apply these changes tomorrow when I have some free time. Then it's on to the transmitter! I have a feeling the transmitter will go a lot smoother since I spent all this time with the receiver learning how the NRF works
 
Hey everyone,

just a little update. I had taken a break from this mostly because I needed to experiment with the sensor I was using (ultrasonic) and I don't really have the equipment to test it at home. I lack a P/S so I just ended up using an old 120VAC/12VDC converter and ran it through a 7805. The basketball goal I'm trying to use this on has a net on it as I previously mentioned and I was kind of hoping that the small strings wouldn't affect it too much but I was wrong. I waved some wires in front of the sensor and it tripped so a net may give false positives. I can either remove the net (would rather not since it's not mine) or try to find a way around this problem. I'm thinking maybe I'll have the uController enter some sort of debounce routine to stop errors, sound good?

The sensor is a LV-MaxSonar-EZ1

This sensor spits out various methods of outputs, these include RS232, analoge(~9.8mv/inch), and PWM. I've settled on analog since it seems easier to just run the analog through the uControllers comparators. I'll post more as I work this out

Any input is appreciated ;)
 

KrisBlueNZ

Sadly passed away in 2015
I don't think ultrasonic is a reliable way to detect a basketball falling through the goal net. I would use modulated infra-red light, with the emitter and detector-demodulator on opposite sides of the net (or perhaps the emitter hanging in front of the net, pointing back towards the detector on the wall behind it). You would need to set the distances so the ball completely blocks the light as it goes through the net, but the receiver gets a fairly wide beam so small interruptions caused by the net don't affect it. Perhaps a lens at the receiver would help. I'd guess the detector should be 5~10 cm behind the edge of the ball, and the emitter could be close to the ball (that's not so important).

The emitter can be driven from an oscillator (cheap) or a divided-down crystal (stable). There are lots of options for the receiver. Have a look at this thread for more information:

https://www.electronicspoint.com/threads/remote-control-circuit-with-cd4017-counter-decoder.268176/
 
would it be possible to have the emitter and detector side-by-side and use the basketball as the reflecting surface to bounce the signal back?
 

KrisBlueNZ

Sadly passed away in 2015
would it be possible to have the emitter and detector side-by-side and use the basketball as the reflecting surface to bounce the signal back?
Not with light, no, I don't think so. But you could put the emitter and detector facing each other, one on each side of the net, but not in line with the widest part of the hoop - i.e. not half way between the hoop edge closest to the wall and the hoop edge furthest away from the wall, but closer to the wall, so they don't stick out so far from the wall. Of course you also need to make sure that the net can't get tangled in them, so you might want to keep both the emitter and detector more than a certain distance away from the net.

If you mean using ultrasonic, bouncing it off the ball, you might be onto something there. I guess you would want to angle the emitter an detector so they both point at the closest surface of the ball as it falls through the net, and you would need an amplitude threshold in the receiver. Check it with under-inflated and over-inflated balls too, I guess, and make sure that it's far enough below the hoop that it won't be fooled by a ball that tap-dances on the hoop but doesn't go through.

These are all just gut feelings; you'll have to use some trial and error.
 
I was referring to IR. I might just end up doing what you mentioned of having the diodes on either side of the hoop in between where the net hooks into the goal to help avoid interference.
 
I also figured it would probably be a good idea to go ahead and test the RF link before I started testing sensors so I'm just going to send an LED signal back and forth, then I'll move on from there
 
okay so i have finished what I hope is a working RF link between the two NRF's. I have been pouring myself over datasheets but am happy to announce that I am going to go home, wire something up, and see if they start talking. Here is the transmitter code
Code:
// THIS CODE IS INTENDED FOR USE WITH A NRF24L01 USED AS A PRIMARY TRANSMITTER
#include <pic16f627a.h> //needed for MACRO descriptions of config and pins
#include <stdint.h>//needed for uint8_t
#include <xc.h>//this header is needed for delay macro
#define _XTAL_FREQ 4000000//this value is needed for the delay macro
#define CSN_LOW() PORTAbits.RA1=0;// needed for SPI
#define CSN_HIGH() PORTAbits.RA1=1;// needed for SPI
#define SCK_LOW() PORTAbits.RA2=0;
#define SCK_HIGH() PORTAbits.RA2=1;
//--------------------------------------------------------------------------------------------------------
//Configure device
#pragma config FOSC = INTOSCIO  // Oscillator Selection bits (INTOSC oscillator: I/O function on RA6/OSC2/CLKOUT pin, I/O function on RA7/OSC1/CLKIN)
#pragma config WDTE = OFF // Watchdog Timer Enable bit (WDT disabled)
#pragma config PWRTE = OFF // Power-up Timer Enable bit (PWRT disabled)
#pragma config MCLRE = OFF // RA5/MCLR/VPP Pin Function Select bit (RA5/MCLR/VPP pin function is digital input, MCLR internally tied to VDD)
#pragma config BOREN = OFF // Brown-out Detect Enable bit (BOD disabled)
#pragma config LVP = OFF // Low-Voltage Programming Enable bit (RB4/PGM pin has PGM function, low-voltage programming enabled)
#pragma config CPD = OFF // Data EE Memory Code Protection bit (Data memory code protection off)
#pragma config CP = OFF // Flash Program Memory Code Protection bit (Code protection off)
//--------------------------------------------------------------------------------------------------------
//internal NRF registers
const uint8_t NRF_Config=0x7E;//no int reflected on pins, crc enabled, power up, set as primary transmitter
const uint8_t NRF_EN_AA=0x00;//no AA "Auto Acknowledge" enabled, don't need since rx&tx won't communicate back and forth
const uint8_t NRF_EN_RXADDR=0x01;//enable datapipe zero only (for now)
const uint8_t NRF_RF_CH=0x02;//set up RF channel as 2.402GHz (2.4GHz+2MHz)
const uint8_t NRF_RF_Setup=0x0F;//this can be same for tx&rx for power reasons (might turn down in future to save battery life)
const uint8_t Clear_Status=0x40;
const uint8_t LED_on=0x01;
const uint8_t LED_off=0x00;
//------------------------------------------------------------------------------
//buffer variables
uint8_t PICin=0x00;//used as buffer for data leaving NRF
uint8_t NRFin=0x00;//used as buffer for data entering NRF
//--------------------------------------------------------------------------------------------------------
//function prototypes
void init_PIC(void);//configures PIC for operation
void init_NRF(void);//configures NRF for operation
uint8_t spi_txrx_byte(uint8_t);
void send_packet(void);//toggles CE for 15us to send TX FIFO payload on its way
//--------------------------------------------------------------------------------------------------------

main(void)//main program
{
    init_PIC();//initialize pic
    init_NRF();//initialize NRF
    while(1)
    {
        NRFin=0xA0;//send command byte w_tx_payload
        CSN_LOW();//set CSN low, alerts NRF of incoming SPI
        __delay_us(2);//time buffer to allow CSN to settle before clocking in data
        spi_txrx_byte(NRFin);
        spi_txrx_byte(LED_on);//send data that turns on LED
        send_packet();
        __delay_ms(1000);//wait one second
        NRFin=0xA0;//send command byte w_tx_payload
        CSN_LOW();//set CSN low, alerts NRF of incoming SPI
        __delay_us(2);//time buffer to allow CSN to settle before clocking in data
        spi_txrx_byte(NRFin);
        spi_txrx_byte(LED_off);//send data that turns off led
        send_packet();
        __delay_ms(1000);//wait one second
    }
}
//--------------------------------------------------------
void init_PIC(void)
{
        OPTION_REGbits.T0CS=0;//internal instruction clock
        OPTION_REGbits.PSA=0;   //prescaler assigned to WDT so timer0 increments at a 1:1 ratio
        INTCON=0x00;//disables all interrupts
        CMCON=0x07;//COMPARATORs off
        PORTA=0x00;//clear PORTA prior to operation
        PORTB=0x00;//clear PORTB prior to operation
        TRISA=0x00;//set all PORTA I/O's as outputs
        TRISB=0x80;//set RB7 as input and rest as outputs
        CSN_HIGH();//set CSN high
        PORTAbits.RA0=0;//keep CE low, only need to set high when transmitting
}
//--------------------------------------------------------
void init_NRF(void)
{
//shift in w_register instruction,shift in config data
    NRFin=0x20;//write instruction to NRF config
    CSN_LOW();//set CSN low, alerts NRF of incoming SPI
    __delay_us(2);//time buffer to allow CSN to settle before clocking in data
    spi_txrx_byte(NRFin);
    spi_txrx_byte(NRF_Config);
    CSN_HIGH();//set CSN high, tells NRF SPI data is complete
    __delay_us(1);
//--------------------------------------------------------
//shift in w_register instruction,shift in nrf_en_aa
    NRFin=0x21;
    CSN_LOW();
    __delay_us(2);//time buffer to allow CSN to settle before clocking in data
    spi_txrx_byte(NRFin);
    spi_txrx_byte(NRF_EN_AA);
    CSN_HIGH();
    __delay_us(1);
//--------------------------------------------------------
//shift in w_register instruction, shift in nrf_en_rxaddr
    NRFin=0x22;
    CSN_LOW();
    __delay_us(2);//time buffer to allow CSN to settle before clocking in data
    spi_txrx_byte(NRFin);
    spi_txrx_byte(NRF_EN_RXADDR);
    CSN_HIGH();
    __delay_us(1);
//shift in w_register instruction, shift in nrf_rf_ch
    NRFin=0x25;
    CSN_LOW();
    __delay_us(2);//time buffer to allow CSN to settle before clocking in data
    spi_txrx_byte(NRFin);
    spi_txrx_byte(NRF_RF_CH);
    CSN_HIGH();
    __delay_us(1);
//shift in w_register instruction, shift in nrf_setup
    NRFin=0x26;
    CSN_LOW();
    __delay_us(2);//time buffer to allow CSN to settle before clocking in data
    spi_txrx_byte(NRFin);
    spi_txrx_byte(NRF_RF_Setup);
    CSN_HIGH();
}

uint8_t spi_txrx_byte(uint8_t txdata)
{
    uint8_t bitn;
    for (bitn = 0; bitn < 7; ++bitn)
    {
        PORTAbits.RA3 = (txdata > 127); //Copy bit 7 of txdata to RA3 (MOSI)
        PORTAbits.RA2 = 0;              //Bring SPI clock low
        PORTAbits.RA2 = 1;              //Bring SPI clock high
        txdata <<= 1;                   //Shift bits up in txdata
        txdata |= PORTAbits.RA5;        //Shift MISO pin state into bit 0
    }
    PORTAbits.RA2 = 0;                  //Return SPI clock low (for tidiness)
    PORTAbits.RA3 = 0;                  //Ditto for MOSI
    return txdata;                      //txdata doubles as rxdata
}

void send_packet (void)
{
    PORTAbits.RA0=1;//set CE high
    __delay_us(15);
    PORTAbits.RA0=0;//sets CE back low
}



and here is the receiver code:

Code:
// THIS CODE IS INTENDED FOR USE WITH A NRF24L01 USED AS A PRIMARY RECEIVER
#include <pic16f627a.h> //needed for MACRO descriptions of config and pins
#include <stdint.h>//needed for uint8_t
#include <xc.h>//this header is needed for delay macro
#define _XTAL_FREQ 4000000//this value is needed for the delay macro
#define ENABLE_RECEIVER() PORTAbits.RA0=1;
#define DISABLE_RECEIVER() PORTAbits.RA0=0;
#define CSN_LOW() PORTAbits.RA1=0;
#define CSN_HIGH() PORTAbits.RA1=1;
#define SCK_LOW() PORTAbits.RA2=0;
#define SCK_HIGH() PORTAbits.RA2=1;
//--------------------------------------------------------------------------------------------------------
//Configure device
#pragma config FOSC = INTOSCIO  // Oscillator Selection bits (INTOSC oscillator: I/O function on RA6/OSC2/CLKOUT pin, I/O function on RA7/OSC1/CLKIN)
#pragma config WDTE = OFF // Watchdog Timer Enable bit (WDT disabled)
#pragma config PWRTE = OFF // Power-up Timer Enable bit (PWRT disabled)
#pragma config MCLRE = OFF // RA5/MCLR/VPP Pin Function Select bit (RA5/MCLR/VPP pin function is digital input, MCLR internally tied to VDD)
#pragma config BOREN = OFF // Brown-out Detect Enable bit (BOD disabled)
#pragma config LVP = OFF // Low-Voltage Programming Enable bit (RB4/PGM pin has PGM function, low-voltage programming enabled)
#pragma config CPD = OFF // Data EE Memory Code Protection bit (Data memory code protection off)
#pragma config CP = OFF // Flash Program Memory Code Protection bit (Code protection off)
//--------------------------------------------------------------------------------------------------------
//internal NRF registers
const uint8_t NRF_Config=0x4F;//forces data that is received to trigger the IRQ pin
const uint8_t NRF_EN_AA=0x00;//no AA "Auto Acknowledge" enabled, don't need since rx&tx won't communicate back and forth
const uint8_t NRF_EN_RXADDR=0x01;//enable datapipe zero only (for now)
const uint8_t NRF_RF_CH=0x02;//set up RF channel as 2.402GHz (2.4GHz+2MHz)
const uint8_t NRF_RF_Setup=0x0F;
const uint8_t NRF_RX_PW_PO=0x01;//sets data pipe 0 for 1 byte
const uint8_t Clear_Status=0x40;
//------------------------------------------------------------------------------
//buffer variables
uint8_t PICin=0x00;//used as buffer for data leaving NRF
uint8_t NRFin=0x00;//used as buffer for data entering NRF
//--------------------------------------------------------------------------------------------------------
//function prototypes
void init_PIC(void);//configures PIC for operation
void init_NRF(void);//configures NRF for operation
uint8_t spi_txrx_byte(uint8_t);
//--------------------------------------------------------------------------------------------------------

main(void)//main program
{   
    init_PIC();//initialize pic
    init_NRF();//initialize NRF
    while(1)
    {
        //may need to use r_rx_payload command byte to read information
        if (PORTBbits.RB7==0)//poll IRQ pin
        {
            CSN_HIGH();
            DISABLE_RECEIVER();//bring CE low (disable receiver)
            NRFin=0x27;//load write instruction byte into buffer
            CSN_LOW();//set CSN low, alerts NRF of incoming SPI
            __delay_us(2);//time buffer to allow CSN to settle before clocking in data
            spi_txrx_byte(NRFin);//send buffer data
            spi_txrx_byte(Clear_Status);//clear IRQ interrupt source bit
            CSN_HIGH();
            NRFin=0x61;//load read rx payload instruction byte into buffer
            CSN_LOW();
            __delay_us(2);//time buffer to allow CSN to settle before clocking in data
            spi_txrx_byte(NRFin);//clk in data and place into PICin
            NRFin=0x00;//dummy bytes
            PICin=spi_txrx_byte(NRFin);
            ENABLE_RECEIVER();//bring CE high (enable receiver)
        }
        else
            PORTB = PICin;//this puts the value of PICin onto PORTB which is connected to a 7 seg LED
    }
}
//--------------------------------------------------------------------------------------------------------
void init_PIC(void)
{
        OPTION_REGbits.T0CS=0;//internal instruction clock
        OPTION_REGbits.PSA=0;   //prescaler assigned to WDT so timer0 increments at a 1:1 ratio
        INTCON=0x00;//disables all interrupts
        CMCON=0x07;//turns comparators off
        PORTA=0x00;//clear PORTA prior to operation
        PORTB=0x00;//clear PORTB prior to operation
        TRISA=0x20;//0010 0000
        TRISB=0x80;//1000 0000 set RB7 as input(interrupt on change) and rest as outputs
        CSN_HIGH();//set CSN high
        ENABLE_RECEIVER();//set CE high (enable receiver on NRF)
}
void init_NRF(void)
{
//--------------------------------------------------------
//shift in w_register instruction,shift in config data
    NRFin=0x20;
    CSN_LOW();//set CSN low, alerts NRF of incoming SPI
    __delay_us(2);//time buffer to allow CSN to settle before clocking in data
    spi_txrx_byte(NRFin);
    spi_txrx_byte(NRF_Config);
    CSN_HIGH();//set CSN high, tells NRF SPI data is complete
    __delay_us(1);
//--------------------------------------------------------
//shift in w_register instruction,shift in nrf_en_aa
    NRFin=0x21;
    CSN_LOW();
    __delay_us(2);//time buffer to allow CSN to settle before clocking in data
    spi_txrx_byte(NRFin);
    spi_txrx_byte(NRF_EN_AA);
    CSN_HIGH();
    __delay_us(1);
//--------------------------------------------------------
//shift in w_register instruction, shift in nrf_en_rxaddr
    NRFin=0x22;
    CSN_LOW();
    __delay_us(2);//time buffer to allow CSN to settle before clocking in data
    spi_txrx_byte(NRFin);
    spi_txrx_byte(NRF_EN_RXADDR);
    CSN_HIGH();
    __delay_us(1);
//shift in w_register instruction, shift in nrf_rf_ch
    NRFin=0x25;
    CSN_LOW();
    __delay_us(2);//time buffer to allow CSN to settle before clocking in data
    spi_txrx_byte(NRFin);
    spi_txrx_byte(NRF_RF_CH);
    CSN_HIGH();
    __delay_us(1);
//shift in w_register instruction, shift in nrf_setup
    NRFin=0x26;
    CSN_LOW();
    __delay_us(2);//time buffer to allow CSN to settle before clocking in data
    spi_txrx_byte(NRFin);
    spi_txrx_byte(NRF_RF_Setup);
    CSN_HIGH();
    __delay_us(1);
//shift in w_register instruction, shift in nrf_rx_pw_p0
    NRFin=0x31;
    CSN_LOW();
    __delay_us(2);//time buffer to allow CSN to settle before clocking in data
    spi_txrx_byte(NRFin);
    spi_txrx_byte(NRF_RX_PW_PO);
    CSN_HIGH();
}

uint8_t spi_txrx_byte(uint8_t txdata)
{
    uint8_t bitn;
    for (bitn = 0; bitn < 7; ++bitn)
    {
        PORTAbits.RA3 = (txdata > 127);// Copy bit 7 of txdata to RA3 (MOSI)
        SCK_LOW();// Bring SPI clock low
        SCK_HIGH();// Bring SPI clock high
        txdata <<= 1;// Shift bits up in txdata
        txdata |= PORTAbits.RA5;// Shift MISO pin state into bit 0
    }
    SCK_LOW();// Return SPI clock low (for tidiness)
    PORTAbits.RA3=0;// Ditto for MOSI
    return txdata;// txdata doubles as rxdata
}

hopefully everything works and again, thank you Kris for all the help. basically all this code does is send some data that turns on an LED, wait for one second, then sends data to turn off the LED.

After I had written it I placed "//CHECK" beside each line of code and would only delete that comment once I had double checked the line of code with what is written in the datasheet. This let me catch quite a few errors such as writing to the wrong register and some timing issues. If it doesn't work I will need to hook up the scope and start debugging, wish me luck!
 
So I started up the hardware side of things. the NRF's work off of 3.3V and since I don't have a P/S this became an issue. I (luckily) managed to find a LM317 so I was able to put together something that works. The breakout board on the NRF's are absolutely retarded, they are not in the least bit breadboard friendly. Some genius decided that laying out the header pins in such a way that no matter which way you turn it some of the pins are shorted together. I ended up soldering half of the pins onto a header and the other half I just soldered wire to which I jumped to the other side of the breadboard. I've attached a picture in case I didn't make that confusing enough
 

Attachments

  • IMG_20140801_225121.jpg
    IMG_20140801_225121.jpg
    166.3 KB · Views: 104
Top