Vaša IP adresa: 3.145.108.9
Počet návštev: 30480

AVR a bezdrôtový modul nRF24L01+

Modul nRF24L01+ je lacný bezdrôtový modul pracujúci na frekvencii 2,4 GHz. Jeho dosah je približne 50 až 200 stôp (15 - 61 m). Dosah závisí hlavne od nastaveného výkonu, rýchlosti prenosu údajov a rušenia okolitými sieťami WiFi. Dá sa použiť na ovládanie zariadení a monitorovanie stavu senzorov v dosahu. Modul je dostupný v dvoch základných prevedeniach: so zabudovanou anténou na plošnom spoji a s externou anténou.

Verzia s anténou na DPS. Verzia s anténou na DPS. Verzia s externou anténou.
Verzia s externou anténou.

Konfigurácia vývodov modulu je uvedená na nasledujúcom obrázku a ich význam je uvedený v tabuľke.

Zapojenie vývodov nRF24L01+. Zapojenie vývodov nRF24L01+.
PinNázovFunkciaPopis
1GNDNapájanieZem (0V)
2VCCNapájanie+1,9V – +3,6V
3CEDigitálny vstupChip Enable (aktivuje RX alebo TX mód)
4CSNDigitálny vstupSPI Chip Select
5SCKDigitálny vstupSPI Clock
6MOSIDigitálny vstupSPI Slave Data Input
7MISODigitálny výstupSPI Slave Data Output
8IRQDigitálny výstupMaskable interrupt pin. Activ low.

Prepojenie s AVR (ATmega328P)

nRF24L01+ATmega328P (názov)ATmega 328P (pin)
GNDGND
VCCVCC (3,3V)
CEĽubovoľný I/O pin nakonfigurovaný ako výstup PB6
CSNSSPB2
SCKSCKPB5
MOSIMOSIPB3
MISOMISOPB4
IRQĽubovoľný I/O pin nakonfigurovaný ako výstupPB7

Programovanie AVR

Názvy registrov nRF24L01+ a jednotlivých bitov sú v hlavičkovom súbore nRF24L01.h. Namapovanie registrov umožňuje prehľadný prístup a nastavovanie jednotlivých registrov. Napríklad na prístup ku konfiguračnému registru použijeme názov STATUS namiesto 0x07.

Komunikácia cez SPI

Vzájomná komunikácia medzi bezdrôtovým modulom a AVR prebieha prostredníctvom rozhrania SPI. Definícia jednotlivých pinov a funkcií pre rozhranie SPI vyzerá nasledovne:

#define MOSI PORTB3
#define MISO PORTB4
#define SCK PORTB5
#define SS PORTB2
#define SPI_PORT PORTB

#define SS_enable()  PORTB &= ~(1 << SS)
#define SS_disable() PORTB |= (1 << SS)

Funkcia SS_enable() slúži na výber čipu pre komunikáciu cez rozhranie SPI. SS_enable() nastavuje výstup SS (PB2) na log.0, pretože výstup je invertovaný. Inicializácia SPI rozhrania pre ATmega328P vyzerá nasledovne:

void SPI_Init(){
// Set MOSI, SCK, SS as Output
DDRB|=(1<<MOSI)|(1<<SCK)|(1<<SS);
// set MISO as Input
DDRB&=~(1<<MISO);
SPI_PORT|= (1<<SS) | (1<<MISO);
SPCR=(1 << SPE) | (1 << MSTR); //SPE - enable SPI, MSTR - MASTER mode
SPCR &= ~(1<< DORD); //prenos zacina od MSB first

//nastavenie rychlosti prenosu SCLK pri Fosc=8 MHz -> 1 MHz (SPI2X=1)/500 kHz (SPI2X=0)
SPCR |= (1 << SPR0); //predelicka Fosc/8 - treba zapnut bit SPI2X v SPSR na double speed
SPSR |= (1<< SPI2X); //dvojansobna rychlost

SS_disable(); //aby nebol vybraty cip hned po inicializacii
}

Na zaslanie jedného bajtu cez SPI slúži funkcia:

void SPI_MasterTransmit(unsigned char cData){
/* Start transmission */
SPDR = cData;
/* Wait for transmission complete */
while (!( SPSR & (1<< SPIF)));
}

Na zaslanie jedného bajtu cez SPI so synchrónnym načítaním odpovede (bajtu) použijeme modifikovanú funkciu:

unsigned char SPI_MasterTransmitSync(unsigned char cData)
{
/* Start transmission */
SPDR = cData;
/* Wait for transmission complete */
while(!(SPSR & (1<<SPIF)))
;
return SPDR; //SPI return value
}

Na načítanie bajtu cez SPI môžeme použiť predchádzajúcu funkciu (odoslaním ľubovoľného bajtu) alebo nasledujúcu funkciu:

unsigned char SPI_MasterReceive(void)
{
SPDR = 0xff; //Start transmission of byte
while(!(SPSR & (1<<SPIF))); //wait for transmission complete
return SPDR; //SPI return value
}

Konfigurácia registra nRF24L01+

Ako už bolo uvedené, komunikácia prebieha prostredníctvom rozhrania SPI. Registre v nRF24L01+ sú väčšinou jednobajtové, niektoré sú však viacbajtové. Rozhodol som sa opísať niektoré zaujímavé funkcie z knižnice funkcií, ktoré sú v nrf24.c. Knižnica s funkciami, ktoré slúžia na prácu s nRF24L01+ je modifikáciou knižnice od kehribar, ktorú najdete tu a návodu od klalle, ktorý nájdete tu. Na zápis jedného bajtu do registra použijeme funkciu:

/* Clocks only one byte into the given nrf24 register */
void nrf24_configRegister(uint8_t reg, uint8_t value)
{
_delay_us(10);
SS_enable();  //start SPI communication
_delay_us(10);
SPI_MasterTransmit(W_REGISTER | (REGISTER_MASK & reg));
_delay_us(10);
SPI_MasterTransmit(value);
_delay_us(10);
SS_disable();  //end SPI communication
}

Vstupná hodnota reg je názov registra, ktorý chceme nastaviť a value je hodnota, ktorá sa má nastaviť. Napríklad na nastavenie kanála (register RF_CH) na hodnotu 0x60 použijeme zápis: nrf24_configRegister(RF_CH, 0x60). Na zápis viacerých bajtov do jedného registra sa používa funkcia: void nrf24_writeRegister(uint8_t reg, uint8_t * value, uint8_t len). Význam jednotlivých vstupných premenných je podobný ako pri funkcii nrf24_readRegister, ktorá je uvedená nižšie.

Pre načítanie obsahu registra z nRF24L01+ (jedného alebo viacerých bajtov) použijeme nasledovnú funkciu:

/* Read single register from nrf24 */
void nrf24_readRegister(uint8_t reg, uint8_t* value, uint8_t len)
{
_delay_us(10);
SS_enable();
_delay_us(10);
SPI_MasterTransmit(R_REGISTER | (REGISTER_MASK & reg));
_delay_us(10);
nrf24_transferSync(value, value, len);
_delay_us(10);
SS_disable();
}

Kde reg je názov registra, value je hodnota alebo pole hodnôt (bajtov) načítaných z registra a len je počet bajtov na čítanie. Funkcia nrf24_transferSync slúži na načítanie viacerých bajtov s počtom len. Napríklad na načítanie obsahu konfiguračného registra použijeme zápis:

uint8_t hodnota_conf;
nrf24_readRegister(CONFIG, &hodnota_conf, 1); //load content of CONFIG register to hodnota_conf

Inicializácia nRF24L01+

Inicializácia spočíva v nastavení parametrov, ktoré sú potrebné pre komunikáciu medzi modulmi. Oba moduly musia mať nastavené rovnaké parametre: použitý kanál, adresu, dĺžka packetu (payload), počet dátových "rúr" (datapipes), ... Nasledujúca funkcia slúži na konfiguráciu modulu:

/* conpicture the module */
void nrf24_config(uint8_t channel, uint8_t pay_length)
{
/* Use static payload length ... */
payload_len = pay_length;
// Set RF channel - choose frequency 2,400-2,527GHz step=1MHz
nrf24_configRegister(RF_CH, channel);

// Set length of incoming payload
nrf24_configRegister(RX_PW_P0, payload_len); // payload_len per package
nrf24_configRegister(RX_PW_P1, 0x00); // Pipe not used
nrf24_configRegister(RX_PW_P2, 0x00); // Pipe not used
nrf24_configRegister(RX_PW_P3, 0x00); // Pipe not used
nrf24_configRegister(RX_PW_P4, 0x00); // Pipe not used
nrf24_configRegister(RX_PW_P5, 0x00); // Pipe not used

// Set speed 250kbs, TX gain: 0dbm
uint8_t rf_setup = 0x00;
rf_setup |= (1<<RF_DR_LOW) | ((0x03)<<RF_PWR);
rf_setup &= ~(1<<RF_DR_HIGH);
nrf24_configRegister(RF_SETUP, rf_setup);

// CRC enable, 2 byte CRC length
nrf24_configRegister(CONFIG, nrf24_CONFIG);

// Enable Auto Acknowledgment
uint8_t en_aa = 0x00;
en_aa |= ((1<<ENAA_P0)); //enable pipe 0
nrf24_configRegister(EN_AA, en_aa);

//RX/TX Address field width

nrf24_configRegister(SETUP_AW, 0x03); // width of 5 bytes

// Enable RX addresses
uint8_t en_rxaddr=0x00;
en_rxaddr |= ((1<<ERX_P0));
nrf24_configRegister(EN_RXADDR, en_rxaddr);

// Auto retransmit delay: 1250 us (ARD=0100) and Up to 15 retransmit trials (ARC=1111)
nrf24_configRegister(SETUP_RETR,(0x04<<ARD)|(0x0F<<ARC));

// Dynamic length configurations: No dynamic length
//nrf24_configRegister(DYNPD,0x00);


// Dynamic length configurations: Dynamic length for all datapipes
nrf24_configRegister(DYNPD, (1<<DPL_P0) | (1<<DPL_P1) | (1<<DPL_P2) | (1<<DPL_P3) | (1<<DPL_P4) | (1<<DPL_P5));

// Enable Dynamic Payload Length and Enables Payload with ACK
nrf24_configRegister(FEATURE, (1<<EN_DPL) | (1<<EN_ACK_PAY)); _delay_ms(100);

// Start listening
nrf24_powerUpRx();
}

Predchádzajúca funkcia nastaví modulu tieto parametere:

  • rýchlosť prenosu 250 kbs
  • TX gain 0 dbm
  • zapnutie CRC (2 bajty) - Cyclic Redundancy Test
  • zapnutie potvrdenia - Acknowledgment (ACK) packet
  • automatické preposlanie po zlyhaní po 1250 us;počet opakovaní max. 15
  • použitie datapipe P0 (ostatné sa nepoužívajú)

Frekvencia kanála a dĺžka packetu sa nastavuje pomocou vstupných premenných funkcie. Napríklad nastavenie frekvencie 2,401 GHz (RF_CH = 0x01) a dĺžky packetu 5 bajtov vykonáme nasledovne: nrf24_config(0x01, 5). Je vhodné nastaviť frekvenciu aspoň na hodnotu 2,508 GHz (RF_CH = 108), aby sme predošli rušeniu okolitými sieťami WiFi.

Bezprostredne po inicializácii modulu je potrebné nastaviť adresu vysielača (TX) a adresu prijímača (RX). Adresa môže mať dĺžku 3, 4 alebo 5 bajtov. Dĺžka adresy sa nastavuje pomocou registra SETUP_AW. Prednastavená je dĺžka 5 bajtov. Adresy prijímača a vysielača nastavíme pomocou funkcie:

/* Set the TX and RX address */
void nrf24_tx_address(uint8_t* adr)
{
/* RX_ADDR_P0 must be set to the sending addr for auto ack to work. */
nrf24_writeRegister(RX_ADDR_P0, adr, nrf24_ADDR_LEN);
nrf24_writeRegister(TX_ADDR, adr, nrf24_ADDR_LEN);
}

V prípade, že sa používa Auto ACK, tak musia mať vysielač a prijímač rovnakú adresu. Napríklad, ak chceme nastaviť adresu {0xC2,0xC2,0xC2,0xC2,0xC2} použijeme funkciu nasledovne:

uint8_t address[5] = {0xC2,0xC2,0xC2,0xC2,0xC2};
/* Set the device addresses */
nrf24_tx_address(address);

Po nastavení všetkých potrebných registrov je modul pripravený na odosielanie a prijímanie údajov. Režim prijímača alebo vysielača sa nastavuje pomocou bitu PRIM_RX v registri CONFIG. Ak je nastavený bit PRIM_RX modul je prijímač, v opačnom prípade je vysielač. Pred prijímaním alebo odosielaním údajov je potrebné modul prepnúť z režimu Stand by do normálneho režimu nastavením bitu PWR_UP v registri CONFIG. Odosielanie alebo prímanie údajov prebieha po privedení log.1 na vstup modulu označený ako CE. Nasledujúca funkcia slúži na odosielanie údajov:

// Sends a data package to the default address. Be sure to send the correct
// amount of bytes as conpictured as payload on the receiver.

void nrf24_send(uint8_t* value)
{
/* Go to Standby first */
CE_disable(); // CE low

/* Set to transmitter mode , Power up if needed */
nrf24_powerUpTx();

/* Do we really need to flush TX fifo each time ? */
#if 1
/* Pull down chip select */
SS_enable();
/* Write cmd to flush transmit FIFO */
SPI_MasterTransmit(FLUSH_TX);
/* Pull up chip select */
SS_disable();
#endif

/* Pull down chip select */
SS_enable();

/* Write cmd to write payload */
SPI_MasterTransmit( W_TX_PAYLOAD );

/* Write payload */
nrf24_transmitSync(value, payload_len);

/* Pull up chip select */
SS_disable();

/* Start the transmission */
_delay_ms(10);
CE_enable(); //CE high - transmit the data in payload
_delay_us(20); //delay at least 10 us!
CE_disable(); //CE low - stop transmitting
_delay_ms(10);
}

Vstupný parameter value je pole hodnôt s dĺžkou (payload length) nastavenou v nrf24_config(). Odosielanie hodnôt vyzerá nasledovne:

/* Fill the data buffer */
data_array[0] = 0x01;
data_array[1] = 0x02;
data_array[2] = 0x03;
data_array[3] = 0x04;
data_array[4] = 0x05;

// Send the data
nrf24_send(data_array);

// Wait for transmission to end
while(nrf24_isSending());

// Make analysis on last tranmission attempt
temp = nrf24_lastMessageStatus();

Funkcia nrf24_isSending() zabezpečí zdržanie programu pokiaľ nedošlo k odoslaniu packetu. Funkcia nrf24_lastMessageStatus() informuje o úspešnosti prenosu. Keď je návratová hodnota rovná hodnote 1, tak prijímač nezachytil zaslané údaje a došlo k chybe prenosu. Ak je návratová hodnota rovná 0, tak prijímač úspešne prijal zaslané dáta.

Súbory na stiahnutie

Zaujímavé odkazy

RF24L01 2.4GHz Radio/Wireless Transceivers How-To
Tutorial - nRF24L01 and AVR
Arduino Using NRF24L01 Rf Module