Continue to Site

Welcome to

Welcome to our site! is an international Electronics Discussion Forum focused on EDA software, circuits, schematics, books, theory, papers, asic, pld, 8051, DSP, Network, RF, Analog Design, PCB, Service Manuals... and a whole lot more! To participate you need to register. Registration is free. Click here to register now.

[PIC] PIC16F1829 and nRF24L01


Mar 27, 2024
Reaction score
Trophy points
Activity points
I've been struggling to get a PIC16F1829 and my nRF24L01+ to transmit data to an Arduino Uno with an nRF24L01+. I am new to MCU's and the SPI so anything would help.
Here's the code for the main.c:
#include <xc.h>

#pragma config FOSC = INTOSC    // Oscillator Selection (INTOSC oscillator: I/O function on CLKIN pin)
#pragma config WDTE = OFF       // Watchdog Timer Enable (WDT disabled)
#pragma config PWRTE = OFF      // Power-up Timer Enable (PWRT disabled)
#pragma config MCLRE = ON       // MCLR Pin Function Select (MCLR/VPP pin function is MCLR)
#pragma config CP = OFF         // Flash Program Memory Code Protection (Program memory code protection is disabled)
#pragma config CPD = OFF        // Data Memory Code Protection (Data memory code protection is disabled)
#pragma config BOREN = ON       // Brown-out Reset Enable (Brown-out Reset enabled)
#pragma config CLKOUTEN = OFF   // Clock Out Enable (CLKOUT function is disabled. I/O or oscillator function on the CLKOUT pin)
#pragma config IESO = ON        // Internal/External Switchover (Internal/External Switchover mode is enabled)
#pragma config FCMEN = ON       // Fail-Safe Clock Monitor Enable (Fail-Safe Clock Monitor is enabled)

#pragma config WRT = OFF        // Flash Memory Self-Write Protection (Write protection off)
#pragma config PLLEN = OFF       // PLL Enable (4x PLL disable)
#pragma config STVREN = ON      // Stack Overflow/Underflow Reset Enable (Stack Overflow or Underflow will cause a Reset)
#pragma config BORV = LO        // Brown-out Reset Voltage Selection (Brown-out Reset Voltage (Vbor), low trip point selected.)
#pragma config LVP = ON         // Low-Voltage Programming Enable (Low-voltage programming enabled)

#include <stdio.h>
#include <xc.h>
#include <pic16f1829.h>
#define _XTAL_FREQ 8000000

#include "nRF24L01.h"

int main ( void ) {
    OSCCONbits.IRCF = 0b1110; // 8MHz
    TRISAbits.TRISA2 = 1;
    TRISAbits.TRISA3 = 1;
    TRISAbits.TRISA4 = 1;
    nRF_Init(TX_MODE, 0x40);
    char bufferTX[32];
    bufferTX[0] = '-';
    while(1) {
        if(PORTAbits.RA2 == 1) {
            bufferTX[0] = 'A';
        if(PORTAbits.RA3 == 1) {
            bufferTX[0] = 'B';
        if(PORTAbits.RA4 == 1) {
            bufferTX[0] = 'C';
    return (0);
#include "nRF24L01.h"

// This data type sets the address data pipe 0.
unsigned char ADDRESS_DATA_PIPE0[5] = {0x05,0x04,0x03,0x02,0x01};

void nRF_Init(char mode, char rf_channel) {
    // SPI
    // disable MSSP
    SSP1CON1bits.SSPEN = 0;
    // SDI1 set
    TRISBbits.TRISB4 = 1; // configure RC4 as input
    ANSELBbits.ANSB4 = 0; // enable digital input buffer on RC4

    // SS1 set
    TRISCbits.TRISC6 = 0;

    // SDO1 cleared
    ANSELCbits.ANSC7 = 0;
    TRISCbits.TRISC7 = 0;

    // SCK1 cleared
    TRISBbits.TRISB6 = 0;
    TRISBbits.TRISB6 = 0;

    // SPI mode 0
    SSP1CON1bits.CKP = 0; // Idle state for clock is a low level
    SSP1STATbits.CKE = 1; // Transmit occurs on transition from active to Idle clock state
    SSP1STATbits.SMP = 1; // Input data sampled at end of data output time (took me 5 friggin' hours)
    SSP1CON1bits.SSPM = 0b0001; //0001 = SPI Master mode, clock = FOSC/16
    SSP1CON1bits.SSPEN = 1; // enable MSSP1
    nRF_WriteRegister(CONFIG, 0x0E); // Power Up, CRC Enable, CRC 2 byte
    nRF_WriteRegister(EN_AA, 0x01); // Enable RX Address (data pipe 0)
    nRF_WriteRegister(SETUP_AW, 0x03); // RX/TX Address field width is 5 bytes
    nRF_WriteRegister(SETUP_RETR, 0x00); // Auto Retransmit Delay = 250us
    // Sets the frequency channel nRF24L01+ operates on
    nRF_WriteRegister(RF_CH, rf_channel);
    nRF_WriteRegister(RF_SETUP, 0x06); // RF Data Rate = 1Mbs, RF output power in TX mode = 0dBm

    nRF_WriteRegister(RX_PW_P0, PAYLOAD_BYTES);

void nRF_WriteRegister(char mnemonic, char value) {
    CSN_Low();        // Enable chip
    SPI_Write(W_REGISTER | mnemonic);
    CSN_High();        // Disable chip

void SPI_Write(char data) {
    SSP1BUF = data;           // Copy data in SSBUF to transmit
    while(!SSPSTATbits.BF);     // Wait for complete 1 byte transmission
    data = SSP1BUF;         // Clear SSP2IF flag

void nRF_WriteBuffer(char data, char* buffer, char bytes) {
    for(char i = 0; i < bytes; i++) {

void nRF_SetMode(char mode) {
    nRF_Flush();        // Clear RX and TX FIFO
    nRF_WriteRegister(STATUS_N, 0x70); // Clear STATUS
    if(mode) {
        nRF_WriteRegister(CONFIG, 0x0F);  // RX Control
        CE_High();  // RX Mode
    } else {
        nRF_WriteRegister(CONFIG, 0x0E);  // TX Control
        CE_Low();  // TX Mode

void nRF_Flush() {
    CSN_Low();         // Enable chip
    CSN_High();         // Disable chip
    CSN_Low();         // Enable chip
    CSN_High();         // Disable chip

void nRF_SendData(char* buffer) {
    nRF_WriteBuffer(W_TX_PAYLOAD, buffer, PAYLOAD_BYTES);
    CE_High();      // RX Mode
    CE_Low();      // TX Mode

void CE_High(){
    PORTBbits.RB5 = 1;

void CE_Low() {
    PORTBbits.RB5 = 0;

void CSN_High() {
    PORTCbits.RC6 = 1;

void CSN_Low() {
    PORTCbits.RC6 = 0;

void CSN_DDR_Low(){
    TRISCbits.TRISC6 = 0;

void CE_DDR_Low() {
    TRISBbits.TRISB5 = 0;
and nRF24L01.h
#ifndef NRF24L01
#define    NRF24L01

#include <xc.h> // include processor files - each processor file is guarded. 

#ifndef _XTAL_FREQ
#define _XTAL_FREQ 8000000

// CE Pin RB5
// SS Pin RC6
// SDI Pin RB4
// SDO Pin RC7
// SCK Pin RB6

void nRF_Init(char, char);
void nRF_WriteRegister(char, char);
void SPI_Write(char);;
void nRF_WriteBuffer(char, char *, char);
void nRF_SetMode(char);
void nRF_Flush(void);
void nRF_SendData(char *);
void CE_High(void);
void CE_Low(void);
void CSN_High(void);
void CSN_Low(void);
void CSN_DDR_High(void);
void CSN_DDR_Low(void);
void CE_DDR_High(void);
void CE_DDR_Low(void);

#define PAYLOAD_BYTES       5 // Sets the bytes to send or read.
#define RX_MODE             1
#define TX_MODE             0

// Register Map.
#define R_REGISTER          0x00 
#define W_REGISTER          0x20 
#define R_RX_PAYLOAD        0x61 
#define W_TX_PAYLOAD        0xA0 
#define FLUSH_TX            0xE1 
#define FLUSH_RX            0xE2 
#define REUSE_TX_PL         0xE3 

#define CONFIG             0x00 
#define EN_AA               0x01 
#define EN_RXADDR           0x02 
#define SETUP_AW            0x03 
#define SETUP_RETR          0x04 
#define RF_CH               0x05 
#define RF_SETUP            0x06 
#define STATUS_N            0x07 
#define OBSERVE_TX          0x08 
#define CD                  0x09 
#define RX_ADDR_P0          0x0A 
#define RX_ADDR_P1          0x0B 
#define RX_ADDR_P2          0x0C 
#define RX_ADDR_P3          0x0D 
#define RX_ADDR_P4          0x0E 
#define RX_ADDR_P5          0x0F 
#define TX_ADDR             0x10 
#define RX_PW_P0            0x11 
#define RX_PW_P1            0x12 
#define RX_PW_P2            0x13 
#define RX_PW_P3            0x14 
#define RX_PW_P4            0x15 
#define RX_PW_P5            0x16 
#define FIFO_STATUS         0x17 


Anything would help as I've been working on this for weeks. Thank you.

"I've been struggling" is no error description.
It´s good to have the code, it seems to be well documented ... but you can´t expect - that without any error description - a "human debugger" steps through all of your code.

please give short informations about:
* connections / schematics
* picture of circuit, antennas, ...
* test setup of the transmitter side
* test setup of the receiver side
* what did you expect
* what in detail was not like expected

I even don´t know whether you think the problem is on the transmitter side or the receiver side.
It could be a power supply problem, it could be a continpusly activated RESET, it could be wrong clock setup...
You - as an electronics designer - need to use simple techniques to verify whether the hardwore is working at all and whether the software is working at all.

Like: Let a LED blink with 1Hz and verify the speed with your watch. This very basic test verifies that the hardware is working, that the software is working and also if the clock setup is correct.

What I often do to debug:
* using a software debugger (if available)
* Using unused port pins to output states that can be visualized with a LED .. or a scope
* using unused port pins to stop/resum at code lines (using similar like "while (PIN_State == 0) {};"
* using UART to communicate with a PC
* using a voltmeter to verify power supply voltages and signal levels
* using a current measurement to detect activity (here I expect a higher power supply current when device is transmitting)

Also which package are you using?
In 'nRF_Init()' under the 'SDI1 Set' comment, you manipulate RB4 but the comment refers to RC4. PortB is only available on the 20-pin package so I assume you are using that. If not then you need to both correct the comment (which you should do anyway) and use the correct pins.

LaTeX Commands Quick-Menu:

Similar threads

Part and Inventory Search

Welcome to