collapse

* Posts Recentes

Amplificador - Rockboard HA 1 In-Ear por almamater
[Ontem às 19:13]


O que é isto ? por KammutierSpule
[26 de Março de 2024, 19:35]


Bateria - Portátil por almamater
[25 de Março de 2024, 22:14]


Emulador NES em ESP32 por dropes
[13 de Março de 2024, 21:19]


Escolher Osciloscópio por jm_araujo
[06 de Fevereiro de 2024, 23:07]


TP4056 - Dúvida por dropes
[31 de Janeiro de 2024, 14:13]


Leitura de dados por Porta Serie por jm_araujo
[22 de Janeiro de 2024, 14:00]


Distancia Cabo por jm_araujo
[08 de Janeiro de 2024, 16:30]


Meu novo robô por josecarlos
[06 de Janeiro de 2024, 16:46]


Laser Engraver - Alguém tem? por almamater
[16 de Dezembro de 2023, 14:23]

Autor Tópico: Módulo Wifi nRF24L01 - Programação em C  (Lida 5893 vezes)

0 Membros e 1 Visitante estão a ver este tópico.

Offline Pinout

  • Mini Robot
  • *
  • Mensagens: 22
Módulo Wifi nRF24L01 - Programação em C
« em: 12 de Dezembro de 2014, 09:09 »
Olá pessoal,

estou tentando fazer funcionar o módulo nRF24L01, porém, ainda não obtive sucesso, pensei que talvez um de vocês possa me ajudar. Montei num arquivo só tudo o que precisaria para fazer o módulo funcionar. Pesquisando, encontrei inúmeras bibliotecas grandes e um tanto confusas para uso, então procurei entender e montar algo simples.

Segue o código.

Código: [Seleccione]
#include <avr/io.h>
#include <avr/interrupt.h>

#define F_CPU 16000000UL
#define BAUDRATE 9600
#define BAUD_PRESCALER (F_CPU / (BAUDRATE * 16UL) -1)

#include <util/delay.h>

// pinos do mcu usados no nRF24L01
#define MISO (1 << PB4) // Pino de saída digital - Pino de saída de dados
#define MOSI (1 << PB3) // Pino de entrada digital - Pino de entrada de dados
#define SCK (1 << PB5) // Pino de entrada digital - Clock
#define CE (1 << PB0) // Pino de entrada digital - Habilita/ativa modo RX ou TX
#define CSN (1 << PD7) // Pino de entrada digital - Pino de seleção SPI
#define IRQ (1 << PD2) // Pino de saída digital -

// configurações gerais do nRF24L01
#define RXADDR_CHANNEL 75 // define endereço do canal RX
#define TXADDR_CHANNEL 75 // define endereço do canal TX (precisa ser igual ao endereço do canal RX)
#define BUFFER_SIZE 10 // define tamanho do buffer
#define CHANNEL 107

// registradores do nRF24L01
#define R_REGISTER 0x00
#define RX_ADDR_P0 0x2A
#define TX_ADDR 0x30
#define EN_AA 0x21
#define EN_RXADDR 0x22
#define SETUP_AW 0x23
#define SETUP_RETR 0x24
#define RF_CH 0x05
#define RF_SETUP 0x26
#define STATUS 0x27
#define RX_PW_P0 0x31
#define CONFIG 0x20
#define NOP 0xFF

#define LED (1 << PD3)

static char bufferTX[10]; // variável que vai armazenar pacote de envio e recepção
static char bufferRX[10]; // variável que vai armazenar pacote de envio e recepção
uint16_t waitAck;

void USART_init() {
UBRR0H = (uint8_t) (BAUD_PRESCALER >> 8);
UBRR0L = (uint8_t) (BAUD_PRESCALER);
UCSR0B = (1 << RXEN0) | (1 << TXEN0);
UCSR0C = (3 << UCSZ00);
}

void USART_send(unsigned char data) {
while(!(UCSR0A & (1 << UDRE0)));
UDR0 = data;
}

void USART_putvalue(char* DataPtr) {
while(*DataPtr != 0x00) {
USART_send(*DataPtr);
DataPtr++;
}
}

void SPI_init() {
DDRB |= (SCK) | (MOSI) | (CE); // seta os pinos como saída
PORTB &= ~((SCK) | (MOSI) | (CE));
DDRB &= ~MISO; // configura pino como entrada
DDRD |= (CSN) | (LED); // configura pino como saída
DDRD &= ~IRQ;
SPCR |= (1 << SPE) | (1 << MSTR); // SPCR (SPI Control Register); SPE (SPI Enable) - Habilita o SPI; MSTR (Master Slave Select) - Selecionado como mestre

PORTB |= CSN; // coloca o CSN em nível lógico 1
PORTB &= ~CE; // coloca CE em nível lógico 0
}

char SPI_write(unsigned char data) {
SPDR = data; // SPDR (SPI Data Register) - Aqui o SPDR está bufferRXndo dado e jogando para o SPI
while(!(SPSR & (1 << SPIF))); // SPSR (SPI Status Register); SPIF (SPI Interrupt Flag) - Espera SPIF sinalizar que a transmissão foi completada
return SPDR;
}

uint8_t getReg(uint8_t reg) {
_delay_us(10);
PORTB &= ~CSN;
_delay_us(10);
SPI_write(R_REGISTER + reg);
_delay_us(10);
reg = SPI_write(NOP);
_delay_us(10);
PORTB |= CSN;
return reg;
}

void nRF24L01_init() {
SPI_init();

// RX_ADDR_P0 - Configura endereço de recepção
PORTB &= ~CSN;
SPI_write(RX_ADDR_P0);
SPI_write(RXADDR_CHANNEL);
SPI_write(0xC2);
SPI_write(0xC2);
SPI_write(0xC2);
SPI_write(0xC2);
PORTB |= CSN;

// RX_ADDR_P0 - Configura endereço de recepção
PORTB &= ~CSN;
SPI_write(TX_ADDR);
SPI_write(TXADDR_CHANNEL);
SPI_write(0xC2);
SPI_write(0xC2);
SPI_write(0xC2);
SPI_write(0xC2);
PORTB |= CSN;

// EN_AA - habilita autoACK no PIPE0
PORTB &= ~CSN;
SPI_write(EN_AA);
SPI_write(0x01);
PORTB |= CSN;

// EN_RXADDR - ativa o PIPE0
PORTB &= ~CSN;
SPI_write(EN_RXADDR);
SPI_write(0x01);
PORTB |= CSN;

// SETUP_AW - define o endereço com tamanho de 5 Bytes
PORTB &= ~CSN;
SPI_write(SETUP_AW);
SPI_write(0x03);
PORTB |= CSN;

// SETUP_RETR - configura para nao retransmitir pacotes
PORTB &= ~CSN;
SPI_write(SETUP_RETR);
SPI_write(0x00);
PORTB |= CSN;

// RF_CH - define o canal do modulo (TX e RX devem ser iguais)
PORTB &= ~CSN;
SPI_write(RF_CH);
SPI_write(CHANNEL);
PORTB |= CSN;

// RF_SETUP - ativa LNA, taxa em 250K, e maxima potencia 0dbm
PORTB &= ~CSN;
SPI_write(RF_SETUP);
SPI_write(0x26);
PORTB |= CSN;

// STATUS - reseta o resgistrador STATUS
PORTB &= ~CSN;
SPI_write(STATUS);
SPI_write(0x70);
PORTB |= CSN;

// RX_PW_P0 - tamanho do buffer PIPE0
PORTB &= ~CSN;
SPI_write(RX_PW_P0);
SPI_write(BUFFER_SIZE);
PORTB |= CSN;

// CONFIG - coloca em modo de recepção, e define CRC de 2 Bytes
PORTB &= ~CSN;
SPI_write(CONFIG);
SPI_write(0x0F);
PORTB |= CSN;

// tempo para sair do modo standby entrar em modo de recepçao
_delay_ms(2);
PORTB |= CE;
_delay_us(150);
}

void INT0_interrupt_init(void) {
EICRA |= (1 << ISC01);
EICRA &= ~(1 << ISC00); // EICRA (External Interrupt Control Register); ISC01:00 (Interrupt Sense Control) - Interrupção para a borda da descida em INT0 (PD2)

EIMSK |= (1 << INT0); // EIMSK (External Interrupt Mask Register); INT0 - Interrupção habilitada em INT0 (PD2)
}

void STATUS_clear () {
//STATUS - reseta registrador STATUS
PORTB &= ~CSN;
SPI_write(0x27);
SPI_write(0x70);
PORTB |= CSN;
}

uint8_t STATUS_read() {
PORTB &= ~CSN;
SPI_write(R_REGISTER + STATUS);
SPI_write(NOP);
PORTB |= CSN;
return SPDR;
}

void DATA_send() {

uint8_t i;
uint8_t status;

PORTB |= (CE);

//STATUS - reseta registrador STATUS
STATUS_clear ();

// W_TX_PAYLOAD - Envia os dados para o buffer FIFO TX
PORTB &= ~CSN;
SPI_write(0xA0);
for (i=0; i<BUFFER_SIZE; i++)SPI_write(bufferTX[i]);
PORTB |= CSN;

//CONFIG - ativa modo de transmissão
PORTB &= ~CSN;
SPI_write(0x20);
SPI_write(0x0E);
PORTB |= CSN;

//pulso para transmitir os dados
PORTB &= ~(CE);
_delay_us(15);
PORTB |= (CE);

//STATUS - leitura do registrador
PORTB &= ~CSN;
SPI_write(0x07);
status = STATUS_read();
PORTB |= CSN;

//STATUS - limpa registrador
STATUS_clear ();

//TX_FLUSH - limpa o buffer FIFO TX
PORTB &= ~CSN;
SPI_write(0xE1);
PORTB |= CSN;
}

//função que envia os dados e joga num vetor
void DATA_receive() {

uint8_t i;
uint8_t status;

//desabilita interrupção
cli();

//STATUS - leitura do registrador
PORTB &= ~CSN;
SPI_write(0x07);
status=STATUS_read();
PORTB |= CSN;

//STATUS - limpa registrador
PORTB &= ~CSN;
SPI_write(0x27);
SPI_write(0x70);
PORTB |= CSN;

//R_RX_PAYLOAD - Recebe os dados do buffer FIFO RX
PORTB &= ~CSN;
SPI_write(0x61);
for(i=0; i<BUFFER_SIZE; i++)bufferRX[i]=STATUS_read();
PORTB |= CSN;

cli();
sei();
}

int main(void) {
nRF24L01_init();
INT0_interrupt_init();
SPI_init();
USART_init();
while(1) {
/*
// transmitir dados
bufferTX[0] = 'w';
bufferTX[1] = 'i';
bufferTX[2] = 'n';
DATA_send();
*/

/*
// receber dados
USART_putvalue(bufferRX);
*/
}
return 1;
}

uint8_t data;
ISR(INT0_vect) {
cli();
PORTB &= ~CE;
PORTD |= LED; // Acende led para sinalizar sucesso no recebimento
_delay_ms(500);
PORTD &= ~LED;
sei();
}

Desculpem qualquer equívoco no código, não havia feito comunicação SPI antes e talvez tenha algo errado com a forma que estou tentando fazer.

Obrigado.
A wise person listens and takes in more instruction;
A man of understanding acquires skillful direction

Offline lucaslimaduarte

  • Mini Robot
  • *
  • Mensagens: 7
Re: Módulo Wifi nRF24L01 - Programação em C
« Responder #1 em: 12 de Dezembro de 2014, 15:49 »
Estava com dificuldade com o nRF24L01 depois de ler vários tutoriais, o mais simples e que funcionou foi este: http://futebol-uff.blogspot.com.br/2012/12/nrf24l01-testes-iniciais.html

http://futebol-uff.blogspot.com.br/2013/05/exp-06-quatro-nrf14l01-com-rf24network.html

Da uma olhada e incrementar va que ele  me parece simples para o que vc quer fazer.
« Última modificação: 12 de Dezembro de 2014, 15:51 por lucaslimaduarte »

Offline Pinout

  • Mini Robot
  • *
  • Mensagens: 22
Re: Módulo Wifi nRF24L01 - Programação em C
« Responder #2 em: 12 de Dezembro de 2014, 16:35 »
Estava com dificuldade com o nRF24L01 depois de ler vários tutoriais, o mais simples e que funcionou foi este: http://futebol-uff.blogspot.com.br/2012/12/nrf24l01-testes-iniciais.html

http://futebol-uff.blogspot.com.br/2013/05/exp-06-quatro-nrf14l01-com-rf24network.html

Da uma olhada e incrementar va que ele  me parece simples para o que vc quer fazer.

Obrigado pela resposta, lucaslimaduarte


mas estou procurando fazer em C, para ter um acesso mais baixo nível ao microcontrolador. Conheci um pouco do Arduino, mas não gostei se certas limitações que ele impõe. Esse é só o código para o módulo, no projeto que estou tentando fazer, já possui muita coisa escrita e tudo em C.

De qualquer forma obrigado pela resposta.
A wise person listens and takes in more instruction;
A man of understanding acquires skillful direction

Offline jm_araujo

  • Mini Robot
  • *
  • Mensagens: 2.947
  • NERD!
Re: Módulo Wifi nRF24L01 - Programação em C
« Responder #3 em: 12 de Dezembro de 2014, 17:05 »
O arduino é C++ "disfarçado", podes aproveitar tudo  :P

Offline Pinout

  • Mini Robot
  • *
  • Mensagens: 22
Re: Módulo Wifi nRF24L01 - Programação em C
« Responder #4 em: 12 de Dezembro de 2014, 17:34 »
O arduino é C++ "disfarçado", podes aproveitar tudo  :P

Pois é, jm_araujo, o arduino não passa de um framework em C/C++, mas são bibliotecas muito grandes e uma biblioteca chama outra biblioteca o que acaba gerando um estudo dentro das bibliotecas do arduio, e eu quero fazer coisas simples, caso não consiga solução o jeito vai ser fazer desse jeito mesmo. Testei a mirf pelo arduino e deu certo. Estou analizando mais uns códigos que achei antes de me aventurar a desvendar uma biblioteca inteira.
A wise person listens and takes in more instruction;
A man of understanding acquires skillful direction

Offline Pinout

  • Mini Robot
  • *
  • Mensagens: 22
Re: Módulo Wifi nRF24L01 - Programação em C
« Responder #5 em: 14 de Dezembro de 2014, 02:43 »
Pessoal, estou tentando escrever em um registrador e então ler o valor escrito no mesmo, para exiber no Terminal Serial, via USART, mas estou tendo como retorno 0xFF (11111111), mesmo estando a escrever no registrador, o valor 0xC0 (11000000). Não sei se o erro é na escrita ou na leitura.
Estou utilizando um push button, com pullup no pino, para disparar as operações.

Se alguém com experiência com o CI puder me ajudar, eu agradeço. Estou utilizando o Atmega328P

Segue meu código:

Código: [Seleccione]
#include <avr/io.h>

#define F_CPU 16000000UL
#define BAUDRATE 9600
#define BAUD_PRESCALER ((F_CPU / (BAUDRATE * 16UL)) -1)

#include <util/delay.h>

#define SCK (1 << PB5)
#define CSN (1 << PB2)
#define CE (1 << PB1)
#define MISO (1 << PB4)
#define MOSI (1 << PB3)
#define IRQ (1 << PD2)

#define PUSH_BUTTON (1 << PD7)

void SPI_init() {
    DDRB |= SCK | MOSI | CSN | CE;
    DDRB &= ~MISO;
    DDRD &= ~IRQ;

    SPCR = (1 << SPE) | (1 << MSTR) | (1 << SPR0); // Habilita SPI, como mestre, e com clock de 16Mhz

    PORTB |= CSN;
    PORTB &= ~CE;
}

uint8_t SPI_masterTransmit(uint8_t cData) {
    SPDR = cData;
    while(!(SPSR & (1<<SPIF)));
    return SPDR;
}

void USART_init() {
    UBRR0H = (uint8_t) (BAUD_PRESCALER >> 8);
    UBRR0L = (uint8_t) (BAUD_PRESCALER);
    UCSR0B = (1 << RXEN0) | (1 << TXEN0);
    UCSR0C = (3 << UCSZ00);
}

void USART_send(uint8_t data) {
    while(!(UCSR0A & (1 << UDRE0)));
    UDR0 = data;
}

void USART_printBinaryByte(uint8_t c) {
    for (int i = 7; i >= 0; --i) {
        USART_send( (c & (1 << i)) ? '1' : '0' );
    }
    USART_send('\n');
}

void STATUS_write(uint8_t statusValue){
PORTB &= ~CSN;
SPI_masterTransmit(0x27); // send STATUS register address
SPI_masterTransmit(statusValue); // set a value to STATUS register
PORTB |= CSN;

_delay_ms(2);
PORTB |= CE;
_delay_us(150);
}

uint8_t STATUS_read(){
PORTB &= ~CE;
_delay_ms(10);
uint8_t reg;
PORTB &= ~CSN;
SPI_masterTransmit(0x07); // sending STATUS register addres
reg = SPI_masterTransmit(0xFF); // dummy mode
PORTB |= CSN;
return reg;
}

void PULLUP_config(){ // pull up configuration
DDRD &= ~PUSH_BUTTON;
PORTD |= PUSH_BUTTON;
}

int main(void) {
    SPI_init();
PULLUP_config();
    USART_init();
    for(;;) {
if(!(PIND & (PUSH_BUTTON))) { // pull up to
_delay_ms(25);
STATUS_write(0xC0);
USART_printBinaryByte(STATUS_read());
}
_delay_ms(150);
    }
    return 1;
}

« Última modificação: 14 de Dezembro de 2014, 02:48 por Pinout »
A wise person listens and takes in more instruction;
A man of understanding acquires skillful direction

Offline jm_araujo

  • Mini Robot
  • *
  • Mensagens: 2.947
  • NERD!
Re: Módulo Wifi nRF24L01 - Programação em C
« Responder #6 em: 14 de Dezembro de 2014, 03:27 »
Pareceu-me ver na datasheet que 16Mhz é demais para o SPI do nRF... confirma lá ;)

Offline Pinout

  • Mini Robot
  • *
  • Mensagens: 22
Re: Módulo Wifi nRF24L01 - Programação em C
« Responder #7 em: 14 de Dezembro de 2014, 13:01 »
Era exatamente isso, jm_araujo! Tava ficando maluco já, sem conseguir resolver isso. O nRF aceita um clock de, no máximo, 8Mhz.
Não consegui alterar o valor do registrador STATUS, por algum motivo que vou pesquisar no datasheet ainda, mas o TX_ADDR mostra
que está tudo nos conformes. Mais uma vez obrigado! =)

Resolvido da seguinte maneira:

Código: [Seleccione]
#include <avr/io.h>

#define F_CPU 8000000UL
#define BAUDRATE 9600
#define BAUD_PRESCALER ((F_CPU / (BAUDRATE * 8UL)) -1)

#include <util/delay.h>

#define SCK (1 << PB5)
#define CSN (1 << PB2)
#define CE (1 << PB1)
#define MISO (1 << PB4)
#define MOSI (1 << PB3)
#define IRQ (1 << PD2)

#define PUSH_BUTTON (1 << PD7)

void SPI_init() {
    DDRB |= SCK | MOSI | CSN | CE;
    DDRB &= ~MISO;
    DDRD &= ~IRQ;

    SPCR = (1 << SPE) | (1 << MSTR);

    PORTB |= CSN;
    PORTB &= ~CE;
}

uint8_t SPI_masterTransmit(uint8_t cData) {
    SPDR = cData;
    while(!(SPSR & (1<<SPIF)));
    return SPDR;
}

void USART_init() {
    UBRR0H = (uint8_t) (BAUD_PRESCALER >> 8);
    UBRR0L = (uint8_t) (BAUD_PRESCALER);
    UCSR0B = (1 << RXEN0) | (1 << TXEN0);
    UCSR0C = (3 << UCSZ00);
}

void USART_send(uint8_t data) {
    while(!(UCSR0A & (1 << UDRE0)));
    UDR0 = data;
}

void USART_printBinaryByte(uint8_t c) {
    for (int i = 7; i >= 0; --i) {
        USART_send( (c & (1 << i)) ? '1' : '0' );
    }
    USART_send('\n');
}

void TX_ADDR_write(uint8_t statusValue) {
    PORTB &= ~CSN;
    SPI_masterTransmit(0x30); // send STATUS register address
    SPI_masterTransmit(statusValue); // set a value to STATUS register
    PORTB |= CSN;

    _delay_ms(2);
    PORTB |= CE;
    _delay_us(150);
}

uint8_t TX_ADDR_read() {
    PORTB &= ~CE;   
    uint8_t reg;
    PORTB &= ~CSN;
    SPI_masterTransmit(0x10); // sending STATUS register addres
    reg = SPI_masterTransmit(0xFF); // dummy mode
    PORTB |= CSN;
    return reg;
}

void PULLUP_config() { // pull up configuration
    DDRD &= ~PUSH_BUTTON;
    PORTD |= PUSH_BUTTON;
}

int main(void) {
    SPI_init();
    PULLUP_config();
    USART_init();
    for(;;) {
        if(!(PIND & (PUSH_BUTTON))) { // pull up to
            _delay_ms(25);
            TX_ADDR_write(0x07);
            USART_printBinaryByte(TX_ADDR_read());
        }
        _delay_ms(150);
    }
    return 1;
}
« Última modificação: 14 de Dezembro de 2014, 14:50 por Pinout »
A wise person listens and takes in more instruction;
A man of understanding acquires skillful direction

Offline Pinout

  • Mini Robot
  • *
  • Mensagens: 22
Re: Módulo Wifi nRF24L01 - Programação em C
« Responder #8 em: 18 de Dezembro de 2014, 22:40 »
Bom, consegui finalizar o código, apesar de pouco tempo disponível para me dedicar ao projeto e ele está enviando o sinal ADC gerado pelo potenciômetro no transmissor e movimentando o servo motor no receptor, porém, ocorre um comportamento muito estranho. O receptor só recebe o código quando eu chamo a USART na função main, caso contrário ele não atualiza mais o valor ADC na variável. Será que alguém saberia o porquê?
« Última modificação: 18 de Dezembro de 2014, 22:47 por Pinout »
A wise person listens and takes in more instruction;
A man of understanding acquires skillful direction