Skip to content

Instantly share code, notes, and snippets.

@klalle
Last active October 12, 2022 11:30
Show Gist options
  • Star 13 You must be signed in to star a gist
  • Fork 6 You must be signed in to fork a gist
  • Save klalle/5652658 to your computer and use it in GitHub Desktop.
Save klalle/5652658 to your computer and use it in GitHub Desktop.
This is a simple code that waits for the USART interrupt, that receives the payload from the USART and then calls the send-function to broadcast the data to listening nRFs.
/*
* RF_Tranceiver.c
*
* Created: 2012-08-10 15:24:35
* Author: Kalle
* Atmega88
*/
#include <avr/io.h>
#include <stdio.h>
#define F_CPU 8000000UL // 8 MHz
#include <util/delay.h>
#include <avr/interrupt.h>
#include "nRF24L01.h"
#define dataLen 3 //längd på datapacket som skickas/tas emot
uint8_t *data;
uint8_t *arr;
/*****************ändrar klockan till 8MHz ist för 1MHz*****************************/
void clockprescale(void)
{
CLKPR = 0b10000000; //Prepare the chip for a change of clock prescale (CLKPCE=1 and the rest zeros)
CLKPR = 0b00000000; //Wanted clock prescale (CLKPCE=0 and the four first bits CLKPS0-3 sets division factor = 1)
//See page 38 in datasheet
}
////////////////////////////////////////////////////
/*****************USART*****************************/ //Skickar data från chip till com-port simulator på datorn
//Initiering
void usart_init(void)
{
DDRD |= (1<<1); //Set TXD (PD1) as output for USART
unsigned int USART_BAUDRATE = 9600; //Same as in "terminal.exe"
unsigned int ubrr = (((F_CPU / (USART_BAUDRATE * 16UL))) - 1); //baud prescale calculated according to F_CPU-define at top
/*Set baud rate */
UBRR0H = (unsigned char)(ubrr>>8);
UBRR0L = (unsigned char)ubrr;
/* Enable receiver and transmitter */
UCSR0B = (1<<RXEN0)|(1<<TXEN0);
/* Set frame format: 8data, 2stop bit, The two stop-bits does not seem to make any difference in my case!?*/
UCSR0C = (1<<USBS0)|(3<<UCSZ00);
}
//Funktionen som skickar iväg byten till datorn
void USART_Transmit(uint8_t data)
{
/* Wait for empty transmit buffer */
while ( !( UCSR0A & (1<<UDRE0)) );
/* Put data into buffer, sends the data */
UDR0 = data;
}
//Funktionen som Tar emot kommandon av datorn som senare ska skickas till transmittern
uint8_t USART_Receive( void )
{
/* Wait for data to be received */
while ( !(UCSR0A & (1<<RXC0)) ); //This loop is only needed if you not use the interrupt...
/* Get and return received data from buffer */
return UDR0; //Return the received byte
}
/*****************SPI*****************************/ //Skickar data mellan chip och nrf'ens chip
//initiering
void InitSPI(void)
{
//Set SCK (PB5), MOSI (PB3) , CSN (SS & PB2) & C as outport
//OBS!!! Måste sättas innan SPI-Enable neadn
DDRB |= (1<<DDB5) | (1<<DDB3) | (1<<DDB2) |(1<<DDB1);
/* Enable SPI, Master, set clock rate fck/16 .. kan ändra hastighet utan att det gör så mycket*/
SPCR |= (1<<SPE)|(1<<MSTR);// |(1<<SPR0) |(1<<SPR1);
SETBIT(PORTB, 2); //CSN IR_High to start with, vi ska inte skicka nåt till nrf'en ännu!
CLEARBIT(PORTB, 1); //CE low to start with, nrf'en ska inte sända/ta emot nåt ännu!
}
//Skickar kommando till nrf'en å får då tillbaka en byte
char WriteByteSPI(unsigned char cData)
{
//Load byte to Data register
SPDR = cData;
/* Wait for transmission complete */
while(!(SPSR & (1<<SPIF)));
//Returnera det som sänts tillbaka av nrf'en (första gången efter csn-låg kommer Statusregistert)
return SPDR;
}
////////////////////////////////////////////////////
/*****************in/out***************************/ //ställ in t.ex. LED
//sätter alla I/0 portar för t.ex. LED
void ioinit(void)
{
DDRB |= (1<<DDB0); //led
}
////////////////////////////////////////////////////
/*****************interrupt***************************/ //orsaken till att köra med interrupt är att de avbryter koden var den än är och kör detta som är viktigast!
//när data tas emot/skickas så går interr uptet INT0 näst längst ner igång
void INT0_interrupt_init(void)
{
DDRD &= ~(1<<DDD2); //Extern interrupt på INT0, dvs sätt den till input!
EICRA |= (1<<ISC01);// INT0 falling edge PD2
EICRA &= ~(1<<ISC00);// INT0 falling edge PD2
EIMSK |= (1<<INT0); //enablar int0
//sei(); // Enable global interrupts görs sen
}
//när chipets RX (usart) får ett meddelande fårn datorn går interruptet USART_RX igång längst ner.
void USART_interrupt_init(void)
{
UCSR0B |= (1<<RXCIE0); //Enable interrupt that triggers on USART-data is received,
}
//////////////////////////////////////////////////////
//funktion för att hämta nåt av nrf's register
uint8_t GetReg(uint8_t reg)
{
//andvändning: USART_Transmit(GetReg(STATUS)); //där status är registret du vill kolla
_delay_us(10);
CLEARBIT(PORTB, 2); //CSN low
_delay_us(10);
WriteByteSPI(R_REGISTER + reg); //Vilket register vill du läsa (nu med R_Register för att inget ska skrivas till registret)
_delay_us(10);
reg = WriteByteSPI(NOP); //Skicka NOP antalet byte som du vill hämta (oftast 1gång, men t.ex addr är 5 byte!) och spara isf inte i "reg" utan en array med en loop
_delay_us(10);
SETBIT(PORTB, 2); //CSN IR_High
return reg; // Returnerar registret förhoppningsvis med bit5=1 (tx_ds=lyckad sändning)
}
/*****************nrf-setup***************************/ //Ställer in nrf'en genoma att först skicka vilket register, sen värdet på registret.
uint8_t *WriteToNrf(uint8_t ReadWrite, uint8_t reg, uint8_t *val, uint8_t antVal) //tar in "ReadWrite" (W el R), "reg" (ett register), "*val" (en array) & "antVal" (antal integer i variabeln)
{
cli(); //disable global interrupt
if (ReadWrite == W) //W=vill skriva till nrf-en (R=läsa av den, R_REGISTER (0x00) ,så skiter i en else funktion)
{
reg = W_REGISTER + reg; //ex: reg = EN_AA: 0b0010 0000 + 0b0000 0001 = 0b0010 0001
}
//Static uint8_t för att det ska gå att returnera en array (lägg märke till "*" uppe på funktionen!!!)
static uint8_t ret[dataLen]; //antar att det längsta man vill läsa ut när man kallar på "R" är dataleng-långt, dvs använder man bara 1byte datalengd å vill läsa ut 5byte RF_Adress så skriv 5 här ist!!!
_delay_us(10); //alla delay är så att nrfen ska hinna med! (microsekunder)
CLEARBIT(PORTB, 2); //CSN low = nrf-chippet börjar lyssna
_delay_us(10);
WriteByteSPI(reg); //första SPI-kommandot efter CSN-låg berättar för nrf'en vilket av dess register som ska redigeras ex: 0b0010 0001 write to registry EN_AA
_delay_us(10);
int i;
for(i=0; i<antVal; i++)
{
if (ReadWrite == R && reg != W_TX_PAYLOAD)
{
ret[i]=WriteByteSPI(NOP); //Andra och resten av SPI kommandot säger åt nrfen vilka värden som i det här fallet ska läsas
_delay_us(10);
}
else
{
WriteByteSPI(val[i]); //Andra och resten av SPI kommandot säger åt nrfen vilka värden som i det här fallet ska skrivas till
_delay_us(10);
}
}
SETBIT(PORTB, 2); //CSN IR_High = nrf-chippet slutar lyssna
sei(); //enable global interrupt
return ret; //returnerar en array
}
//initierar nrf'en (obs nrfen måste vala i vila när detta sker CE-låg)
void nrf24L01_init(void)
{
_delay_ms(100); //allow radio to reach power down if shut down
uint8_t val[5]; //en array av integers som skickar värden till WriteToNrf-funktionen
//EN_AA - (auto-acknowledgements) - Transmittern får svar av recivern att packetet kommit fram, grymt!!! (behöver endast vara enablad på Transmittern!)
//Kräver att Transmittern även har satt SAMMA RF_Adress på sin mottagarkanal nedan ex: RX_ADDR_P0 = TX_ADDR
val[0]=0x01; //ger första integern i arrayen "val" ett värde: 0x01=EN_AA på pipe P0.
WriteToNrf(W, EN_AA, val, 1); //W=ska skriva/ändra nåt i nrfen, EN_AA=vilket register ska ändras, val=en array med 1 till 32 värden som ska skrivas till registret, 1=antal värden som ska läsas ur "val" arrayen.
//SETUP_RETR (the setup for "EN_AA")
val[0]=0x2F; //0b0010 00011 "2" sets it up to 750uS delay between every retry (at least 500us at 250kbps and if payload >5bytes in 1Mbps, and if payload >15byte in 2Mbps) "F" is number of retries (1-15, now 15)
WriteToNrf(W, SETUP_RETR, val, 1);
//Väljer vilken/vilka datapipes (0-5) som ska vara igång.
val[0]=0x01;
WriteToNrf(W, EN_RXADDR, val, 1); //enable data pipe 0
//RF_Adress width setup (hur många byte ska RF_Adressen bestå av? 1-5 bytes) (5bytes säkrare då det finns störningar men långsammare dataöverföring) 5addr-32data-5addr-32data....
val[0]=0x03;
WriteToNrf(W, SETUP_AW, val, 1); //0b0000 00011 motsvarar 5byte RF_Adress
//RF channel setup - väljer frekvens 2,400-2,527GHz 1MHz/steg
val[0]=0x01;
WriteToNrf(W, RF_CH, val, 1); //RF channel registry 0b0000 0001 = 2,401GHz (samma på TX å RX)
//RF setup - väljer effekt och överföringshastighet
val[0]=0x07;
WriteToNrf(W, RF_SETUP, val, 1); //00000111 bit 3="0" ger lägre överföringshastighet 1Mbps=Längre räckvidd, bit 2-1 ger effektläge hög (-0dB) ("11"=(-18dB) ger lägre effekt =strömsnålare men lägre range)
//RX RF_Adress setup 5 byte - väljer RF_Adressen på Recivern (Måste ges samma RF_Adress om Transmittern har EN_AA påslaget!!!)
int i;
for(i=0; i<5; i++)
{
val[i]=0x12; //RF channel registry 0b10101011 x 5 - skriver samma RF_Adress 5ggr för att få en lätt och säker RF_Adress (samma på transmitterns chip!!!)
}
WriteToNrf(W, RX_ADDR_P0, val, 5); //0b0010 1010 write registry - eftersom vi valde pipe 0 i "EN_RXADDR" ovan, ger vi RF_Adressen till denna pipe. (kan ge olika RF_Adresser till olika pipes och därmed lyssna på olika transmittrar)
//TX RF_Adress setup 5 byte - väljer RF_Adressen på Transmittern (kan kommenteras bort på en "ren" Reciver)
//int i; //återanvänder föregående i...
for(i=0; i<5; i++)
{
val[i]=0x12; //RF channel registry 0b10111100 x 5 - skriver samma RF_Adress 5ggr för att få en lätt och säker RF_Adress (samma på Reciverns chip och på RX-RF_Adressen ovan om EN_AA enablats!!!)
}
WriteToNrf(W, TX_ADDR, val, 5);
// payload width setup - Hur många byte ska skickas per sändning? 1-32byte
val[0]=dataLen; //"0b0000 0001"=1 byte per 5byte RF_Adress (kan välja upp till "0b00100000"=32byte/5byte RF_Adress) (definierat högst uppe i global variabel!)
WriteToNrf(W, RX_PW_P0, val, 1);
//CONFIG reg setup - Nu är allt inställt, boota upp nrf'en och gör den antingen Transmitter lr Reciver
val[0]=0x1E; //0b0000 1110 config registry bit "1":1=power up, bit "0":0=transmitter (bit "0":1=Reciver) (bit "4":1=>mask_Max_RT,dvs IRQ-vektorn reagerar inte om sändningen misslyckades.
WriteToNrf(W, CONFIG, val, 1);
//device need 1.5ms to reach standby mode
_delay_ms(100);
//sei();
}
void ChangeAddress(uint8_t adress)
{
_delay_ms(100);
uint8_t val[5];
//RX RF_Adress setup 5 byte - väljer RF_Adressen på Recivern (Måste ges samma RF_Adress om Transmittern har EN_AA påslaget!!!)
int i;
for(i=0; i<5; i++)
{
val[i]=adress; //RF channel registry 0b10101011 x 5 - skriver samma RF_Adress 5ggr för att få en lätt och säker RF_Adress (samma på transmitterns chip!!!)
}
WriteToNrf(W, RX_ADDR_P0, val, 5); //0b0010 1010 write registry - eftersom vi valde pipe 0 i "EN_RXADDR" ovan, ger vi RF_Adressen till denna pipe. (kan ge olika RF_Adresser till olika pipes och därmed lyssna på olika transmittrar)
//TX RF_Adress setup 5 byte - väljer RF_Adressen på Transmittern (kan kommenteras bort på en "ren" Reciver)
//int i; //återanvänder föregående i...
for(i=0; i<5; i++)
{
val[i]=adress; //RF channel registry 0b10111100 x 5 - skriver samma RF_Adress 5ggr för att få en lätt och säker RF_Adress (samma på Reciverns chip och på RX-RF_Adressen ovan om EN_AA enablats!!!)
}
WriteToNrf(W, TX_ADDR, val, 5);
_delay_ms(100);
}
/////////////////////////////////////////////////////
/*****************Funktioner***************************/ //Funktioner som används i main
//Resettar nrf'en för ny kommunikation
void reset(void)
{
_delay_us(10);
CLEARBIT(PORTB, 2); //CSN low
_delay_us(10);
WriteByteSPI(W_REGISTER + STATUS); //
_delay_us(10);
WriteByteSPI(0b01110000); //radedrar alla irq i statusregistret (för att kunna lyssna igen)
_delay_us(10);
SETBIT(PORTB, 2); //CSN IR_High
}
//Reciverfunktioner
/*********************Reciverfunktioner********************************/
//öppnar Recivern och "Lyssnar" i 1s
void receive_payload(void)
{
sei(); //Enable global interrupt
SETBIT(PORTB, 1); //CE IR_High = "Lyssnar"
_delay_ms(1000); //lyssnar i 1s och om mottaget går int0-interruptvektor igång
CLEARBIT(PORTB, 1); //ce låg igen -sluta lyssna
cli(); //Disable global interrupt
}
//Sänd data
void transmit_payload(uint8_t * W_buff)
{
WriteToNrf(R, FLUSH_TX, W_buff, 0); //skickar 0xE1 som flushar registret för att gammal data inte ska ligga å vänta på att bli skickad när man vill skicka ny data! R står för att W_REGISTER inte ska läggas till. skickar inget kommando efterråt eftersom det inte behövs! W_buff[]står bara där för att en array måste finnas där...
WriteToNrf(R, W_TX_PAYLOAD, W_buff, dataLen); //skickar datan i W_buff till nrf-en (obs går ej att läsa w_tx_payload-registret!!!)
sei(); //enable global interrupt- redan på!
//USART_Transmit(GetReg(STATUS));
_delay_ms(10); //behöver det verkligen vara ms å inte us??? JAAAAAA! annars funkar det inte!!!
SETBIT(PORTB, 1); //CE hög=sänd data INT0 interruptet körs när sändningen lyckats och om EN_AA är på, också svaret från recivern är mottagen
_delay_us(20); //minst 10us!
CLEARBIT(PORTB, 1); //CE låg
_delay_ms(10); //behöver det verkligen vara ms å inte us??? JAAAAAA! annars funkar det inte!!!
//cli(); //Disable global interrupt... ajabaja, då stängs USART_RX-lyssningen av!
}
/////////////////////////////////////////////////////
int main(void)
{
clockprescale();
usart_init();
InitSPI();
ioinit();
INT0_interrupt_init();
USART_interrupt_init();
nrf24L01_init();
SETBIT(PORTB,0); //För att se att dioden fungerar!
_delay_ms(1000);
CLEARBIT(PORTB,0);
while(1)
{
//Wait for USART-interrupt to send data...
}
return 0;
}
ISR(INT0_vect) //vektorn som går igång när transmit_payload lyckats sända eller när receive_payload fått data OBS: då Mask_Max_rt är satt i config registret så går den inte igång när MAX_RT är uppnåd å sändninge nmisslyckats!
{
cli(); //Disable global interrupt
CLEARBIT(PORTB, 1); //ce låg igen -sluta lyssna/sända
SETBIT(PORTB, 0); //led on
_delay_ms(500);
CLEARBIT(PORTB, 0); //led off
//Receiver function to print out on usart:
//data=WriteToNrf(R, R_RX_PAYLOAD, data, dataLen); //läs ut mottagen data
//reset();
//
//for (int i=0;i<dataLen;i++)
//{
//USART_Transmit(data[i]);
//}
//
sei();
}
ISR(USART_RX_vect) ///Vector that triggers when computer sends something to the Atmega88
{
uint8_t W_buffer[dataLen]; //Creates a buffer to receive data with specified length (ex. dataLen = 5 bytes)
int i;
for (i=0;i<dataLen;i++)
{
W_buffer[i]=USART_Receive(); //receive the USART
USART_Transmit(W_buffer[i]); //Transmit the Data back to the computer to make sure it was correctly received
//This probably should wait until all the bytes is received, but works fine in to send and receive at the same time... =)
}
reset(); //reset irq - kan skicka data på nytt
if (W_buffer[0]=='9') //om projektorduk
{
ChangeAddress(0x13); //change address to send to different receiver
transmit_payload(W_buffer); //Sänder datan
ChangeAddress(0x12); //tillbaka till ultimata fjärrisen
}
else
{
transmit_payload(W_buffer); //Sänder datan
}
USART_Transmit('#'); //visar att chipet mottagit datan...
}
@yerih
Copy link

yerih commented Jul 6, 2016

I have a problem with receiver radio. i have do everything that you explain in Blogspot2013 but no result! this is my codes:

Transmitter code
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void init_nRF24L01()
{
delay(100); // allow the radio to reach power-down if the shutdown
uint8_t val[5]; // an array of integers that sends values ??to WriteToNrf function

    //EN_AA - (enable auto-acknowledgments) - Transmitter gets automatic response from receiver when successful transmission! (lovely function!)
    //Only works if Transmitter has identical RF_Adress on its channel ex: RX_ADDR_Po = TX_ADDR
    val[0]=0x01; //set value
    WriteToNrf(W, EN_AA, val, 1); //N=write mode, EN_AA=register to write to, val=data to write, 1=number of data bytes.

    //Choose number of enabled data pipes (1-5)
    val[0]=0x01;
    WriteToNrf(W, EN_RXADDR, val, 1); //enable data pipe 0

    //RF_Adress width setup (how many bytes is the receiver address, the more the merrier 1-5)
    val[0]=0x03; //0b0000 00011 = 5 bytes RF_Adress
    WriteToNrf(W, SETUP_AW, val, 1);

    // RF channel setup - select the frequency from 2.400 to 2.527 GHz 1MHz/steg
    val[0] = 0x01 ;
    WriteToNrf(W,RF_CH,val,1);  // RF channel registry 0b0000 0001 = 2.401 GHz (same on the TX RX)

    //RF setup - choose power mode and data speed. Here is the diference with the (+) version!!!
    val[0]=0x07; //00000111 bit 3="0" 1Mbps=longer range, bit 2-1 power mode ("11" = -odB ; "00"=-18dB)
    WriteToNrf(W, RF_SETUP, val, 1);

    //RF_Adress setup 5 byte - Set Receiver address (set RX_ADDR_Po = TX_ADDR if EN_AA is enabled!!!)
    int i=0;
    for(i=0; i<5; i++){
            val[i]=0x12; //ox12 x 5 to get a long and secure address.
    }
    WriteToNrf(W, RX_ADDR_P0, val, 5); //since we chose pipe 0 on EN_RXADDR we give this address to that channel.
    //Here you can give different addresses to different channels (if they are enabled in EN_RXADDR) to listen on several different transmitters)

    //TX RF_Adress setup 5 byte - Set Transmitter address (not used in a receiver but can be set anyway)
    for(i=0; i<5; i++){
            val[i]=0x12; //ox12 x 5 - same on the Receiver chip and the RX-RF_Address above if EN_AA is enabled!!!
    }
    WriteToNrf(W, TX_ADDR, val, 5);

    //Payload width Setup - 1-32byte (how many bytes to send per transmission)
    val[0]=0x05; //Send 5 bytes per package this time (same on receiver and transmitter)
    WriteToNrf(W,RX_PW_P0,val,1);

    val[0]=0x2F; //0b00l0 00011 "2" sets it up to 7SouS delay between every retry (at least Seeus at 25okbps and if payload >5bytes in 1Hbps,
    //and if payload >1Sbyte in 2Hbps) "F" is number of retries (1-15, now 15)
    WriteToNrf(W, SETUP_RETR, val, 1);

    //CONFIG reg setup - Now it's time to boot up the Qgf and choose if it's suppose to be a transmitter or receiver
    val[0]=0x3E; //0b0001 1110 - bit 0="0":transmitter bit 0="1":Receiver, bit 1="1"=power up,
    //bit 4="1"= mask_Max_RT i.e. IRQ-interrupt is not triggered if transmission failed.
    WriteToNrf(W, CONFIG, val, 1);

    //device need 1.5ms to reach standby mode (CE=low)
    delay(100);

}

uint8_t WriteToNrf(uint8_t ReadWrite, uint8_t reg, uint8_t *val, uint8_t antVal)
{
/
Esta funcion transfiere es capaz de leer y escribir en el nRF y deberia ser
capaz de ejecutar un arreglo de enteros y retornar un arreglo de enteros*/
if(ReadWrite == W) //Si es "W", significa que escribiras un registro
{
reg = W_REGISTER + reg;
}

//Crea un arreglo para ser retornado al final de la funcion
static uint8_t ret[32];

delayMicroseconds(10);
CLEARBIT(PORTB, 2); //CSN low - nRF empieza a escuchar por comandoo
delayMicroseconds(10);
WriteByteSPI(reg); //setea el nRF para modo escritura o de lectura del registro "reg""
delayMicroseconds(10);

int i;
for(i = 0; i< antVal; i++)
{
if(ReadWrite == R && reg != W_TX_PAYLOAD) //Lectura de registro?
{
ret[i] = WriteByteSPI(NOP); //envia comando "NOP" para leer los datos
delayMicroseconds(10);
}

else
{
  WriteByteSPI(val[i]);     //envia el comando al nRF 
  delayMicroseconds(10);
}

}
SETBIT(PORTB, 2); //CSN High - nRF vuelve a su estado de reposo
return ret; //Retorna el arreglo
}

void transmit_payload(uint8_t *W_buff)
{

WriteToNrf(R, FLUSH_TX, W_buff, 0);
WriteToNrf(R, W_TX_PAYLOAD, W_buff, 5);
//Serial.println(GetReg(FIFO_STATUS));
CE_HIGH; //CE high
delayMicroseconds(20);
CE_LOW; //CE low
//Serial.println(GetReg(FIFO_STATUS));
}

void reset(void)
{
delayMicroseconds(5);
CLEARBIT(PORTB, 2); //CSN LOW
delayMicroseconds(5);
WriteByteSPI(W_REGISTER + STATUS); //Escribe en el registro STATUS
delayMicroseconds(5);
WriteByteSPI(0x70); //Resetea todos los IRQ del STTATUS register
delayMicroseconds(5);
SETBIT(PORTB, 2); //CSN HIGH.
}

uint8_t RF_MOD_TX()
{
uint8_t *var;
var = WriteToNrf(R, CONFIG, var, 1); //Lee el registro CONFIG y almacena el resultado
*var &= PRIM_TX; //Colocar en modo PRIM_TX (bit0 LOW)
WriteToNrf(W, CONFIG, var, 1); //Escribe en el registro config
}

uint8_t RF_MOD_RX()
{
uint8_t *var;
var = WriteToNrf(R, CONFIG, var, 1); //Lee el registro CONFIG y almacena el resultado
*var |= PRIM_RX; //Colocar en modo PRIM_RX (bit0 HIGH)
WriteToNrf(W, CONFIG, var, 1); //Escribe en el registro config

}

ISR(TIMER0_COMPA_vect)
{
cli();

if(estado<2)
{

int_timer0++;
if(int_timer0 == 31)
{
  int_timer0 = 0;
  estado = 1;

}

}

sei();
}

void init_timer0(byte i)
{
if(i == 1)
{

//Configuracion de Timer para operacion normal
//set timer0 interrupt at 2kHz
TCCR0A = 0;// set entire TCCR0A register to 0
TCCR0B = 0;// same for TCCR0B
TCNT0 = 0;//initialize counter value to 0
// set compare match register for 2khz increments
OCR0A = 99;// = (16_10^6) / (10000_8) - 1 (must be <256)
// turn on CTC mode
TCCR0A |= (1 << WGM01);
// Set CS21 and CS20 bits for 8 prescaler
TCCR0B |= (0 << CS22) | (1 << CS21) | (0 << CS20);
// enable timer compare interrupt
TIMSK0 |= (1 << OCIE0A);
TIMSK0 &= ~(1 << OCIE0B);
TIMSK0 &= ~(1 << TOIE0);

}
else if(i == 2)
{
//Configuracion de Timer para operacion: estabilizacion
//set timer0 interrupt
TCCR0A = 0;// set entire TCCR0A register to 0
TCCR0B = 0;// same for TCCR0B
TCNT0 = 0;//initialize counter value to 0
// set compare match register for 2khz increments
OCR0A = 255;// = (16_10^6) / (10000_8) - 1 (must be <256)
// turn on CTC mode
TCCR0A |= (1 << WGM01);
// Set CS21 and CS20 bits for 8 prescaler
TCCR0B |= (1 << CS22) | (0 << CS21) | (1 << CS20);
// enable timer compare interrupt
TIMSK0 |= (1 << OCIE0A);
TIMSK0 &= ~(1 << OCIE0B);
TIMSK0 &= ~(1 << TOIE0);
}
}

void state_timer0(byte i)
{
if(i == 0)
{
TIMSK0 &= ~(1<<OCIE0A); //Desactiva interrupcion timer
}
else if(i == 1)
{
TIMSK0 |= (1<<OCIE0A); //Activa interrupcion timer
}

}

void loop()
{

    //Inicializacion de perifericos

    initSPI();
    //transmit_init();
    init_nRF24L01();
    //init_interrupt();

    //Inicializacion de variables
    uint8_t w_buf[5], dato;
    //estado = 0;
    RF_MOD_TX();

    //Sincronizacion
    while (1/*estado == 0*/)
    {
        //PORTC ^= (1<<PC3);
        w_buf[0] = 0xAA;
        w_buf[1] = 0xAA;
        w_buf[2] = 0xAA;
        w_buf[3] = 0xAA;
        w_buf[4] = 0xAA;
        //Serial.println(GetReg(STATUS));
        transmit_payload(w_buf);
        //Serial.println(GetReg(STATUS));
        reset();
    }

}

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

Receiver code:
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

void init_nRF24L01()
{
delay(100); // allow the radio to reach power-down if the shutdown
uint8_t val[5]; // an array of integers that sends values ??to WriteToNrf function

    //EN_AA - (enable auto-acknowledgments) - Transmitter gets automatic response from receiver when successful transmission! (lovely function!)
    //Only works if Transmitter has identical RF_Adress on its channel ex: RX_ADDR_Po = TX_ADDR
    val[0]=0x01; //set value
    WriteToNrf(W, EN_AA, val, 1); //N=write mode, EN_AA=register to write to, val=data to write, 1=number of data bytes.

    //Choose number of enabled data pipes (1-5)
    val[0]=0x01;
    WriteToNrf(W, EN_RXADDR, val, 1); //enable data pipe 0

    //RF_Adress width setup (how many bytes is the receiver address, the more the merrier 1-5)
    val[0]=0x03; //0b0000 00011 = 5 bytes RF_Adress
    WriteToNrf(W, SETUP_AW, val, 1);

    // RF channel setup - select the frequency from 2.400 to 2.527 GHz 1MHz/steg
    val[0] = 0x01 ;
    WriteToNrf(W,RF_CH,val,1);  // RF channel registry 0b0000 0001 = 2.401 GHz (same on the TX RX)

    //RF setup - choose power mode and data speed. Here is the diference with the (+) version!!!
    val[0]=0x07; //00000111 bit 3="0" 1Mbps=longer range, bit 2-1 power mode ("11" = -odB ; "00"=-18dB)
    WriteToNrf(W, RF_SETUP, val, 1);

    //RF_Adress setup 5 byte - Set Receiver address (set RX_ADDR_Po = TX_ADDR if EN_AA is enabled!!!)
    int i=0;
    for(i=0; i<5; i++){
            val[i]=0x12; //ox12 x 5 to get a long and secure address.
    }
    WriteToNrf(W, RX_ADDR_P0, val, 5); //since we chose pipe 0 on EN_RXADDR we give this address to that channel.
    //Here you can give different addresses to different channels (if they are enabled in EN_RXADDR) to listen on several different transmitters)

    //TX RF_Adress setup 5 byte - Set Transmitter address (not used in a receiver but can be set anyway)
    for(i=0; i<5; i++){
            val[i]=0x12; //ox12 x 5 - same on the Receiver chip and the RX-RF_Address above if EN_AA is enabled!!!
    }
    WriteToNrf(W, TX_ADDR, val, 5);

    //Payload width Setup - 1-32byte (how many bytes to send per transmission)
    val[0]=0x05; //Send 5 bytes per package this time (same on receiver and transmitter)
    WriteToNrf(W,RX_PW_P0,val,1);

    val[0]=0x2F; //0b00l0 00011 "2" sets it up to 7SouS delay between every retry (at least Seeus at 25okbps and if payload >5bytes in 1Hbps,
    //and if payload >1Sbyte in 2Hbps) "F" is number of retries (1-15, now 15)
    WriteToNrf(W, SETUP_RETR, val, 1);

    //CONFIG reg setup - Now it's time to boot up the Qgf and choose if it's suppose to be a transmitter or receiver
    val[0]=0x3E; //0b0001 1110 - bit 0="0":transmitter bit 0="1":Receiver, bit 1="1"=power up,
    //bit 4="1"= mask_Max_RT i.e. IRQ-interrupt is not triggered if transmission failed.
    WriteToNrf(W, CONFIG, val, 1);

    //device need 1.5ms to reach standby mode (CE=low)
    delay(100);

}

uint8_t RF_MOD_RX()
{
uint8_t *var;
var = WriteToNrf(R, CONFIG, var, 1); //Lee el registro CONFIG y almacena el resultado
*var |= PRIM_RX; //Colocar en modo PRIM_RX (bit0 HIGH)
WriteToNrf(W, CONFIG, var, 1); //Escribe en el registro config

}

uint8_t RF_MOD_TX()
{
uint8_t *var;
var = WriteToNrf(R, CONFIG, var, 1); //Lee el registro CONFIG y almacena el resultado
*var &= PRIM_TX; //Colocar en modo PRIM_TX (bit0 LOW)

WriteToNrf(W, CONFIG, var, 1); //Escribe en el registro config

}

void transmit_payload(uint8_t *W_buff)
{
WriteToNrf(R, FLUSH_TX, W_buff, 0); //Se usa "R" para enviar un comando al nRF.
WriteToNrf(R, W_TX_PAYLOAD, W_buff, 1);

delayMicroseconds(10); //Tiempo de espera para que el nRF cargue el payload.
SETBIT(PORTB, 1); //CE high
delayMicroseconds(5);
CLEARBIT(PORTB, 1); //CE low
}

void receive_payload(void)
{
SETBIT(PORTB, 1); //CE IR_HIGH = leer datos.
//delayMicroseconds(70);
delay(1000);
CLEARBIT(PORTB, 1); //CE LOW - deja la lectura de datos.
}

void init_interrupt(){
cli(); // switch interrupts off while messing with their settings
EICRA = 0x0A; // Falling edge. Interrupcion por Flancos de bajada.
EIMSK = 0x00; // Deshabilita interrupciones externas standard.
PCICR = 0x03; // Habilita las interrupciones 8 - 14 y 1 - 7.
PCMSK0 = 0x01; // Habilita unicamente la interrupcion 0.
PCMSK1 = 0b00000100; // Habilita unicamente la interrupcion 10.
sei(); // turn interrupts back on
}

//Rutina de interrupcion externa (Boton de Llamada)
ISR(PCINT1_vect)
{
/Segun el manual del AVR, La interrupcion
por cambio de puerto se genera por cualquier
cambio generado en el pin de interrupcion externa
/

cli(); //desactiva interrupciones
int_count1++;
if(int_count1 == 2)
{
int_boton = 1; //Cambio de estado: reposo - llamada
int_count1 = 0; //reinicio de contador
PORTD ^= (1<<PB6); //toggle de bit 0 de puerto B.
}
sei(); //Activa interrupciones
}

//Interrupcion para IRQ
///*
ISR(PCINT0_vect)
{
//Segun el manual del AVR, La interrupcion
//por cambio de puerto se genera por cualquier
//cambio generado en el pin de interrupcion externa
int_count0++;
cli(); //desactiva interrupciones
if(int_count0 == 2)
{
PORTD ^= (1<<PD7);
int_count0 = 0;
CLEARBIT(PORTB, 1); //CE LOW - deja de leer o enviar.

   CSN_LOW;
   //WriteByteSPI(R_RX_PAYLOAD);


   WriteByteSPI(R_RX_PAYLOAD);

   //recibido = WriteToNrf(R, R_RX_PAYLOAD, recibido, 1); //Lee el dato recibido
   CSN_HIGH;

   //*arreglo[0] = WriteByteSPI(0xfe);
}

sei(); //Activa interrupciones
}
///
/

ISR(PCINT0_vect)
{
int_count0++;
cli(); //desactiva interrupciones
if(int_count0 == 2)
{
uint8_t _val[3];
cli();
CE_LOW;
*val = WriteToNrf(R,R_RX_PAYLOAD,_val,3);
delay(100);
for(int i=0;i<3;i++)
{
Serial.println(*val[i]);
}
reset();
delay(1);
sei();
}
sei();
}
*/

uint8_t GetReg(uint8_t reg)
{
delayMicroseconds(10);
CLEARBIT(PORTB, 2); //CSN LOW
delayMicroseconds(5);
WriteByteSPI(R_REGISTER + reg);
delayMicroseconds(10);
reg = WriteByteSPI(NOP);
delayMicroseconds(10);
SETBIT(PORTB, 2);
return reg;
}

void reset(void)
{
uint8_t val;
*val=0x70;
WriteToNrf(R, FLUSH_RX, val, 1);
CLEARBIT(PORTB, 2); //CSN LOW
delayMicroseconds(5);
WriteByteSPI(W_REGISTER + STATUS); //Escribe en el registro STATUS
delayMicroseconds(5);
WriteByteSPI(0x70); //Resetea todos los IRQ del STATUS register
delayMicroseconds(5);
SETBIT(PORTB, 2); //CSN HIGH.
/

WriteToNrf(W, STATUS, val, 1);
delay(1000);
*val = 0x40;
WriteToNrf(W, STATUS, val, 1);
*/

}

void state_timer0(byte i)
{
if(i == 0)
{
TIMSK0 &= ~(1<<OCIE0A); //Desactiva interrupcion timer
}
else if(i == 1)
{
TIMSK0 |= (1<<OCIE0A); //Activa interrupcion timer
}

}

void init_timer0(byte i)
{
if(i == 1)
{

//Configuracion de Timer para operacion normal
//set timer0 interrupt at 2kHz
TCCR0A = 0;// set entire TCCR0A register to 0
TCCR0B = 0;// same for TCCR0B
TCNT0 = 0;//initialize counter value to 0
// set compare match register for 2khz increments
OCR0A = 99;// = (16_10^6) / (10000_8) - 1 (must be <256)
// turn on CTC mode
TCCR0A |= (1 << WGM01);
// Set CS21 and CS20 bits for 8 prescaler
TCCR0B |= (0 << CS22) | (1 << CS21) | (0 << CS20);
// enable timer compare interrupt
TIMSK0 |= (1 << OCIE0A);
TIMSK0 &= ~(1 << OCIE0B);
TIMSK0 &= ~(1 << TOIE0);

}
else if(i == 2)
{
//Configuracion de Timer para operacion: estabilizacion
//set timer0 interrupt
TCCR0A = 0;// set entire TCCR0A register to 0
TCCR0B = 0;// same for TCCR0B
TCNT0 = 0;//initialize counter value to 0
// set compare match register for 2khz increments
OCR0A = 255;// = (16_10^6) / (10000_8) - 1 (must be <256)
// turn on CTC mode
TCCR0A |= (1 << WGM01);
// Set CS21 and CS20 bits for 8 prescaler
TCCR0B |= (1 << CS22) | (0 << CS21) | (1 << CS20);
// enable timer compare interrupt
TIMSK0 |= (1 << OCIE0A);
TIMSK0 &= ~(1 << OCIE0B);
TIMSK0 &= ~(1 << TOIE0);
}
}

ISR(TIMER0_COMPA_vect)
{
cli();

//condicion para etapa de sincronizacion
if(estado<2)
{

int_timer0++;
if(int_timer0 == 31)
{
  int_timer0 = 0;
  estado = 2;

}

}

sei();
}

void loop() {

//Inicializacion de perifericos
initSPI();
init_nRF24L01();

//init_interrupt();
//receive_init();
CE_LOW;

//Configura el NRF en Modo Rx
RF_MOD_RX();

//Inicializacion de variables
//int_boton = 0; int_count0 = int_count1 = 0;
*recibido = 0;
uint8_t dato[5], w_buf[5]; estado = 0;

while(1/estado == 0/)
{
//PORTC ^= (1<<PC3);
CE_HIGH;
//delay(1000);
delayMicroseconds(700);
CE_LOW;

while(1){Serial.println(GetReg(STATUS));}

CSN_LOW;
  //recibido = WriteToNrf(R,R_RX_PAYLOAD,recibido,1);
  dato[0] = ReadToNrf(R_RX_PAYLOAD);
  /*dato[1] = WriteByteSPI(NOP);
  dato[2] = WriteByteSPI(NOP);
  dato[3] = WriteByteSPI(NOP);
  dato[4] = WriteByteSPI(NOP);
  */
CSN_HIGH;
    Serial.println(dato[0]);
    /*Serial.println(dato[1]);
    Serial.println(dato[2]);
    Serial.println(dato[3]);
    Serial.println(dato[4]);
    */
    reset();

}

}

Help me please, from Venezuela!

@vaizq
Copy link

vaizq commented Mar 21, 2021

Thanks for the example. You should consider to use #defines to make code easier to read.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment