nRF24L01 + DualShock2 = радиоуправление
Я, наконец-то решился купить модули nRF24L01. Для знакомства с ними нужно придумать что из них сделать. И сделал, естественно, радиоуправляемую машинку. Из всего, что есть. Наверное, все в детстве хотели радиоуправляемую машинку :)
![]() |
Выглядят модули вот так:
Рисунок 1 – Радиомодуль nRF24L01
Описание:
Дальность до 100 м.
Скорость до 2 Мб
Интерфейс SPI для управления
Напряжение: 3-3.6В (рекомендуется 3,3) В
Максимальная выходная мощность: +20 дБм
Коэффициент усиления антенны (пиковая): 2dBi
Работает радиомодуль на частоте 2.4ГГц (как эти ваши вайфаи и блютузы).
В качестве пульта я решил использовать тот самый белый геймпад (он не обиделся). Нормальных библиотек особо не нашёл, почитал мануал, посмотрел структуру пакета (рисунок 2), решил написать сам. Геймпад общается по протоколу SPI.
Рисунок 2 – Структура пакета геймпада
Вроде бы ничего сложного, написал. Подключил экран и проверил. Работает:
И всё работало замечательно пока не отключили свет. И так повезло, что после этого все исходники превратились в кровавое месиво. И тут я случайно нашёл другую библиотеку и взял ее.
После обработки напильником библиотека стала иметь более-менее приличный вид:
#ifndef PSX_lib_h #define PSX_lib_h #include <avr/io.h> #include <stdbool.h> #define PSX_DATA_PORT PORTD #define PSX_SCK_PORT PORTD #define PSX_DC_PORT PORTD #define PSX_CS_PORT PORTD #define PSX_DATA_PINREG PIND #define PSX_DATA_DDR DDRD #define PSX_SCK_DDR DDRD #define PSX_DC_DDR DDRD #define PSX_CS_DDR DDRD #define PSX_SCK_PIN 4 #define PSX_DC_PIN 7 #define PSX_CS_PIN 5 #define PSX_DATA_PIN 6 // задержка тактов SPI, us #define CTRL_CLK 10 // кнопкм #define PSB_SELECT 0x0001 #define PSB_L3 0x0002 #define PSB_R3 0x0004 #define PSB_START 0x0008 #define PSB_PAD_UP 0x0010 #define PSB_PAD_RIGHT 0x0020 #define PSB_PAD_DOWN 0x0040 #define PSB_PAD_LEFT 0x0080 #define PSB_L2 0x0100 #define PSB_R2 0x0200 #define PSB_L1 0x0400 #define PSB_R1 0x0800 #define PSB_TRIANGLE 0x1000 #define PSB_CIRCLE 0x2000 #define PSB_CROSS 0x4000 #define PSB_SQUARE 0x8000 // джойстики #define PSS_RX 5 #define PSS_RY 6 #define PSS_LX 7 #define PSS_LY 8 // инициализация геймпада void psx_init(bool analog); // получить состояние всех кнопок uint16_t psx_buttons(); // получить состояниие кнопки (PSB_x) uint8_t psx_button(uint16_t); // получить состояниие оси джойстика (PSS_x) uint8_t psx_stick(unsigned int); // обновить состояние кнопок void psx_read_gamepad(); #endif
#include "psx.h" #include <util/delay.h> // буфер static uint8_t _psx_data[21]; // отправить байт программным SPI и получить ответ uint8_t _psx_gamepad_shift(uint8_t transmit_byte) { uint8_t received_byte = 0; for(uint8_t i = 0; i < 8; i++) { PSX_SCK_PORT &= ~_BV(PSX_SCK_PIN); if (transmit_byte & (_BV(i))) { PSX_DC_PORT |= _BV(PSX_DC_PIN); } else { PSX_DC_PORT &= ~_BV(PSX_DC_PIN); } _delay_us(CTRL_CLK); PSX_SCK_PORT |= _BV(PSX_SCK_PIN); if(PSX_DATA_PINREG & _BV(PSX_DATA_PIN)) { received_byte |= _BV(i); } _delay_us(CTRL_CLK); } PSX_SCK_PORT |= _BV(PSX_SCK_PIN); return received_byte; } // отправить команду void _psx_send_command(uint8_t send_data[], uint8_t size){ PSX_CS_PORT &= ~(_BV(PSX_CS_PIN)); PSX_DC_PORT |= _BV(PSX_DC_PIN); PSX_SCK_PORT |= _BV(PSX_SCK_PIN); for (uint8_t i = 0; i < size; i++){ send_data[i] = _psx_gamepad_shift(send_data[i]); } PSX_CS_PORT |= _BV(PSX_CS_PIN); } // обновить состояние кнопок void psx_read_gamepad() { _psx_data[0] = 0x01; _psx_data[1] = 0x42; for (uint8_t i = 2; i < 21; i++){ _psx_data[i] = 0x00; } _psx_send_command(_psx_data, 21); } // инициализация геймпада void psx_init(bool analog){ PSX_SCK_DDR |= _BV(PSX_SCK_PIN); PSX_CS_DDR |= _BV(PSX_CS_PIN); PSX_DC_DDR |= _BV(PSX_DC_PIN); PSX_DATA_DDR &= ~(_BV(PSX_DATA_PIN)); PSX_DATA_PORT |= _BV(PSX_DATA_PIN); PSX_SCK_PORT |= _BV(PSX_SCK_PIN); PSX_DC_PORT |= _BV(PSX_DC_PIN); psx_read_gamepad(); if(!analog) return; // войти в режим конфигурации uint8_t enter_config_command[] = {0x01, 0x43, 0x00, 0x01, 0x00}; _psx_send_command(enter_config_command, 5); // заблокирвать геймпад в аналоговом режиме uint8_t lock_analog_mode_command[] = {0x01, 0x44, 0x00, 0x01, 0x03, 0x00, 0x00, 0x00, 0x00}; _psx_send_command(lock_analog_mode_command, 9); // выйти из режима конфигурации uint8_t exit_config_command[] = {0x01, 0x43, 0x00, 0x00, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A}; _psx_send_command(exit_config_command, 9); } // получить состояние всех кнопок uint16_t psx_buttons() { uint16_t buttons = *(uint16_t*)(_psx_data + 3); // получить 2 байта, содержащих позиции данных 3 и 4 return ~buttons; } // получить состояниие кнопки (PSB_x uint8_t psx_button(uint16_t button) { uint16_t buttons = psx_buttons(); return ((buttons & button) > 0); } // получить состояниие оси джойстика (PSS_x) uint8_t psx_stick(unsigned int stick) { return _psx_data[stick]; }
Код передатчика:
#define NRF24_IO_PORT PORTC #define NRF24_IO_PINREG PINC #define NRF24_IO_DDR DDRC #include <avr/io.h> #include <util/delay.h> #include "lib/nrf24.h" #include "lib/psx.h" // ATMega8 nrf24 // ________ _________ // | PC0 |----| CE | // | PC1 |----| CSN | // | PC2 |----| SCK | // | PC3 |----| MOSI | // | PC4 |----| MISO | // | | |_________| // | | // | | Геймпад // | | _________ // | PD4 |----| SCK | // | PD5 |----| CS | // | PD6 |----| DATA | // | PD7 |----| DC | // |________| |_________| uint8_t data_array[2]; uint8_t tx_address[5] = {0xE7, 0xE7, 0xE7, 0xE7, 0xE7}; uint8_t rx_address[5] = {0xD7, 0xD7, 0xD7, 0xD7, 0xD7}; int main() { nrf24_init(); nrf24_config(2, 2); // канал 2, размер пакета 2 nrf24_tx_address(tx_address); nrf24_rx_address(rx_address); psx_init(false); while (1) { psx_read_gamepad(); // чтение геймпада data_array[0] = 0xFE; // проверочное значение // вверх - левое шасси вперёд // вниз - левое шасси назад // треугольник - правое шасси вперёд // крест - правое шасси назад data_array[1] = (psx_button(PSB_PAD_UP) << 1) | (psx_button(PSB_PAD_DOWN) << 2) | (psx_button(PSB_TRIANGLE) << 3) | (psx_button(PSB_CROSS) << 4); // запихиваем кнопки nrf24_send(data_array); // отправляем данные while (!nrf24_isSending()); _delay_ms(20); } }
Код черепахи:
#include <avr/io.h> #include "lib/nrf24.h" #include <util/delay.h> #include <stdbool.h> // ATMega8 nrf24 // ________ _________ // | PC0 |----| CE | // | PC1 |----| CSN | // | PC2 |----| SCK | // | PC3 |----| MOSI | // | PC4 |----| MISO | // | | |_________| // | | // | | Шасси // | PD0 |-(2) (1)--[/\ /\]--(3) // | PD1 |-(1) |L| |R| // | PD2 |-(3) |L| |R| // | PD3 |-(4) (2)--[\/ \/]--(4) // |________| uint8_t data_array[2]; uint8_t tx_address[5] = {0xD7, 0xD7, 0xD7, 0xD7, 0xD7}; uint8_t rx_address[5] = {0xE7, 0xE7, 0xE7, 0xE7, 0xE7}; #define ENGINES_PORT PORTD #define ENGINES_DDR DDRD #define LEFT_CHASSIS_FWD_PIN 1 #define LEFT_CHASSIS_REV_PIN 0 #define RIGHT_CHASSIS_FWD_PIN 3 #define RIGHT_CHASSIS_REV_PIN 2 int main() { ENGINES_DDR |= 0b00001111; nrf24_init(); nrf24_config(2, 2); // канал 2, размер пакета 2 nrf24_tx_address(tx_address); nrf24_rx_address(rx_address); while (1) { if (nrf24_dataReady()) nrf24_getData(data_array); if (data_array[0] == 0xFE) { // проверка типа пакета bool left_fw = (data_array[1] & (1 << 1)) != 0; bool left_bck = (data_array[1] & (1 << 2)) != 0; bool right_fw = (data_array[1] & (1 << 3)) != 0; bool right_bck = (data_array[1] & (1 << 4)) != 0; ENGINES_PORT = (left_fw << LEFT_CHASSIS_FWD_PIN) | (right_fw << RIGHT_CHASSIS_FWD_PIN) | (left_bck << LEFT_CHASSIS_REV_PIN) | (right_bck << RIGHT_CHASSIS_REV_PIN); } _delay_ms(20); } } /* ------------------------------------------------------------------------- */
Библиоткека для nRF24:
/* * ---------------------------------------------------------------------------- * “THE COFFEEWARE LICENSE” (Revision 1): * <[email protected]> wrote this file. As long as you retain this notice you * can do whatever you want with this stuff. If we meet some day, and you think * this stuff is worth it, you can buy me a coffee in return. * ----------------------------------------------------------------------------- * This library is based on this library: * https://github.com/aaronds/arduino-nrf24l01 * Which is based on this library: * http://www.tinkerer.eu/AVRLib/nRF24L01 * ----------------------------------------------------------------------------- */ #ifndef NRF24 #define NRF24 #include <stdint.h> #include <avr/io.h> #ifdef TURTLE #define NRF24_IO_PORT PORTB #define NRF24_IO_PINREG PINB #define NRF24_IO_DDR DDRB #else #define NRF24_IO_PORT PORTC #define NRF24_IO_PINREG PINC #define NRF24_IO_DDR DDRC #endif #define NRF24_CE_PIN 0 #define NRF24_CSN_PIN 1 #define NRF24_SCK_PIN 2 #define NRF24_MOSI_PIN 3 #define NRF24_MISO_PIN 4 /* IO Helpers */ #define nrf24_set_bit(reg,bit) reg |= (1<<bit) #define nrf24_clr_bit(reg,bit) reg &= ~(1<<bit) #define nrf24_check_bit(reg,bit) (reg&(1<<bit)) /* Memory Map */ #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 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 #define DYNPD 0x1C /* Bit Mnemonics */ /* configuratio nregister */ #define MASK_RX_DR 6 #define MASK_TX_DS 5 #define MASK_MAX_RT 4 #define EN_CRC 3 #define CRCO 2 #define PWR_UP 1 #define PRIM_RX 0 /* enable auto acknowledgment */ #define ENAA_P5 5 #define ENAA_P4 4 #define ENAA_P3 3 #define ENAA_P2 2 #define ENAA_P1 1 #define ENAA_P0 0 /* enable rx addresses */ #define ERX_P5 5 #define ERX_P4 4 #define ERX_P3 3 #define ERX_P2 2 #define ERX_P1 1 #define ERX_P0 0 /* setup of address width */ #define AW 0 /* 2 bits */ /* setup of auto re-transmission */ #define ARD 4 /* 4 bits */ #define ARC 0 /* 4 bits */ /* RF setup register */ #define PLL_LOCK 4 #define RF_DR 3 #define RF_PWR 1 /* 2 bits */ /* general status register */ #define RX_DR 6 #define TX_DS 5 #define MAX_RT 4 #define RX_P_NO 1 /* 3 bits */ #define TX_FULL 0 /* transmit observe register */ #define PLOS_CNT 4 /* 4 bits */ #define ARC_CNT 0 /* 4 bits */ /* fifo status */ #define TX_REUSE 6 #define FIFO_FULL 5 #define TX_EMPTY 4 #define RX_FULL 1 #define RX_EMPTY 0 /* dynamic length */ #define DPL_P0 0 #define DPL_P1 1 #define DPL_P2 2 #define DPL_P3 3 #define DPL_P4 4 #define DPL_P5 5 /* Instruction Mnemonics */ #define R_REGISTER 0x00 /* last 4 bits will indicate reg. address */ #define W_REGISTER 0x20 /* last 4 bits will indicate reg. address */ #define REGISTER_MASK 0x1F #define R_RX_PAYLOAD 0x61 #define W_TX_PAYLOAD 0xA0 #define FLUSH_TX 0xE1 #define FLUSH_RX 0xE2 #define REUSE_TX_PL 0xE3 #define ACTIVATE 0x50 #define R_RX_PL_WID 0x60 #define NOP 0xFF #define LOW 0 #define HIGH 1 #define nrf24_ADDR_LEN 5 #define nrf24_CONFIG ((1<<EN_CRC)|(0<<CRCO)) #define NRF24_TRANSMISSON_OK 0 #define NRF24_MESSAGE_LOST 1 /* IO functions */ void nrf24_setupPins(); void nrf24_ce_digitalWrite(uint8_t state); void nrf24_csn_digitalWrite(uint8_t state); void nrf24_sck_digitalWrite(uint8_t state); void nrf24_mosi_digitalWrite(uint8_t state); uint8_t nrf24_miso_digitalRead(); /* adjustment functions */ void nrf24_init(); void nrf24_rx_address(uint8_t* adr); void nrf24_tx_address(uint8_t* adr); void nrf24_config(uint8_t channel, uint8_t pay_length); /* state check functions */ uint8_t nrf24_dataReady(); uint8_t nrf24_isSending(); uint8_t nrf24_getStatus(); uint8_t nrf24_rxFifoEmpty(); /* core TX / RX functions */ void nrf24_send(uint8_t* value); void nrf24_getData(uint8_t* data); /* use in dynamic length mode */ uint8_t nrf24_payloadLength(); /* post transmission analysis */ uint8_t nrf24_lastMessageStatus(); uint8_t nrf24_retransmissionCount(); /* Returns the payload length */ uint8_t nrf24_payload_length(); /* power management */ void nrf24_powerUpRx(); void nrf24_powerUpTx(); void nrf24_powerDown(); /* low level interface ... */ uint8_t spi_transfer(uint8_t tx); void nrf24_transmitSync(uint8_t* dataout,uint8_t len); void nrf24_transferSync(uint8_t* dataout,uint8_t* datain,uint8_t len); void nrf24_configRegister(uint8_t reg, uint8_t value); void nrf24_readRegister(uint8_t reg, uint8_t* value, uint8_t len); void nrf24_writeRegister(uint8_t reg, uint8_t* value, uint8_t len); /* -------------------------------------------------------------------------- */ /* You should implement the platform spesific functions in your code */ /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ /* In this function you should do the following things: * - Set MISO pin input * - Set MOSI pin output * - Set SCK pin output * - Set CSN pin output * - Set CE pin output */ /* -------------------------------------------------------------------------- */ extern void nrf24_setupPins(); /* -------------------------------------------------------------------------- */ /* nrf24 CE pin control function * - state:1 => Pin HIGH * - state:0 => Pin LOW */ /* -------------------------------------------------------------------------- */ extern void nrf24_ce_digitalWrite(uint8_t state); /* -------------------------------------------------------------------------- */ /* nrf24 CE pin control function * - state:1 => Pin HIGH * - state:0 => Pin LOW */ /* -------------------------------------------------------------------------- */ extern void nrf24_csn_digitalWrite(uint8_t state); /* -------------------------------------------------------------------------- */ /* nrf24 SCK pin control function * - state:1 => Pin HIGH * - state:0 => Pin LOW */ /* -------------------------------------------------------------------------- */ extern void nrf24_sck_digitalWrite(uint8_t state); /* -------------------------------------------------------------------------- */ /* nrf24 MOSI pin control function * - state:1 => Pin HIGH * - state:0 => Pin LOW */ /* -------------------------------------------------------------------------- */ extern void nrf24_mosi_digitalWrite(uint8_t state); /* -------------------------------------------------------------------------- */ /* nrf24 MISO pin read function /* - returns: Non-zero if the pin is high */ /* -------------------------------------------------------------------------- */ extern uint8_t nrf24_miso_digitalRead(); #endif
/* * ---------------------------------------------------------------------------- * “THE COFFEEWARE LICENSE” (Revision 1): * <[email protected]> wrote this file. As long as you retain this notice you * can do whatever you want with this stuff. If we meet some day, and you think * this stuff is worth it, you can buy me a coffee in return. * ----------------------------------------------------------------------------- * This library is based on this library: * https://github.com/aaronds/arduino-nrf24l01 * Which is based on this library: * http://www.tinkerer.eu/AVRLib/nRF24L01 * ----------------------------------------------------------------------------- */ #include "nrf24.h" uint8_t payload_len; void nrf24_setupPins() { nrf24_set_bit(NRF24_IO_DDR, NRF24_CE_PIN); // CE output nrf24_set_bit(NRF24_IO_DDR, NRF24_CSN_PIN); // CSN output nrf24_set_bit(NRF24_IO_DDR, NRF24_SCK_PIN); // SCK output nrf24_set_bit(NRF24_IO_DDR, NRF24_MOSI_PIN); // MOSI output nrf24_clr_bit(NRF24_IO_DDR, NRF24_MISO_PIN); // MISO input } void nrf24_ce_digitalWrite(uint8_t state) { if (state) { nrf24_set_bit(NRF24_IO_PORT, NRF24_CE_PIN); } else { nrf24_clr_bit(NRF24_IO_PORT, NRF24_CE_PIN); } } void nrf24_csn_digitalWrite(uint8_t state) { if (state) { nrf24_set_bit(NRF24_IO_PORT, NRF24_CSN_PIN); } else { nrf24_clr_bit(NRF24_IO_PORT, NRF24_CSN_PIN); } } void nrf24_sck_digitalWrite(uint8_t state) { if (state) { nrf24_set_bit(NRF24_IO_PORT, NRF24_SCK_PIN); } else { nrf24_clr_bit(NRF24_IO_PORT, NRF24_SCK_PIN); } } void nrf24_mosi_digitalWrite(uint8_t state) { if (state) { nrf24_set_bit(NRF24_IO_PORT, NRF24_MOSI_PIN); } else { nrf24_clr_bit(NRF24_IO_PORT, NRF24_MOSI_PIN); } } uint8_t nrf24_miso_digitalRead() { return nrf24_check_bit(NRF24_IO_PINREG, NRF24_MISO_PIN); } /* init the hardware pins */ void nrf24_init() { nrf24_setupPins(); nrf24_ce_digitalWrite(LOW); nrf24_csn_digitalWrite(HIGH); } /* configure the module */ void nrf24_config(uint8_t channel, uint8_t pay_length) { /* Use static payload length ... */ payload_len = pay_length; // Set RF channel nrf24_configRegister(RF_CH, channel); // Set length of incoming payload nrf24_configRegister(RX_PW_P0, 0x00); // Auto-ACK pipe ... nrf24_configRegister(RX_PW_P1, payload_len); // Data payload pipe 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 // 1 Mbps, TX gain: 0dbm nrf24_configRegister(RF_SETUP, (0 << RF_DR) | ((0x03) << RF_PWR)); // CRC enable, 1 byte CRC length nrf24_configRegister(CONFIG, nrf24_CONFIG); // Auto Acknowledgment nrf24_configRegister(EN_AA, (1 << ENAA_P0) | (1 << ENAA_P1) | (0 << ENAA_P2) | (0 << ENAA_P3) | (0 << ENAA_P4) | (0 << ENAA_P5)); // Enable RX addresses nrf24_configRegister(EN_RXADDR, (1 << ERX_P0) | (1 << ERX_P1) | (0 << ERX_P2) | (0 << ERX_P3) | (0 << ERX_P4) | (0 << ERX_P5)); // Auto retransmit delay: 1000 us and Up to 15 retransmit trials nrf24_configRegister(SETUP_RETR, (0x04 << ARD) | (0x0F << ARC)); // Dynamic length configurations: No dynamic length nrf24_configRegister(DYNPD, (0 << DPL_P0) | (0 << DPL_P1) | (0 << DPL_P2) | (0 << DPL_P3) | (0 << DPL_P4) | (0 << DPL_P5)); // Start listening nrf24_powerUpRx(); } /* Set the RX address */ void nrf24_rx_address(uint8_t *adr) { nrf24_ce_digitalWrite(LOW); nrf24_writeRegister(RX_ADDR_P1, adr, nrf24_ADDR_LEN); nrf24_ce_digitalWrite(HIGH); } /* Returns the payload length */ uint8_t nrf24_payload_length() { return payload_len; } /* Set the TX 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); } /* Checks if data is available for reading */ /* Returns 1 if data is ready ... */ uint8_t nrf24_dataReady() { // See note in getData() function - just checking RX_DR isn't good enough uint8_t status = nrf24_getStatus(); // We can short circuit on RX_DR, but if it's not set, we still need // to check the FIFO for any pending packets if (status & (1 << RX_DR)) { return 1; } return !nrf24_rxFifoEmpty();; } /* Checks if receive FIFO is empty or not */ uint8_t nrf24_rxFifoEmpty() { uint8_t fifoStatus; nrf24_readRegister(FIFO_STATUS, &fifoStatus, 1); return (fifoStatus & (1 << RX_EMPTY)); } /* Returns the length of data waiting in the RX fifo */ uint8_t nrf24_payloadLength() { uint8_t status; nrf24_csn_digitalWrite(LOW); spi_transfer(R_RX_PL_WID); status = spi_transfer(0x00); return status; } /* Reads payload bytes into data array */ void nrf24_getData(uint8_t *data) { /* Pull down chip select */ nrf24_csn_digitalWrite(LOW); /* Send cmd to read rx payload */ spi_transfer(R_RX_PAYLOAD); /* Read payload */ nrf24_transferSync(data, data, payload_len); /* Pull up chip select */ nrf24_csn_digitalWrite(HIGH); /* Reset status register */ nrf24_configRegister(STATUS, (1 << RX_DR)); } /* Returns the number of retransmissions occured for the last message */ uint8_t nrf24_retransmissionCount() { uint8_t rv; nrf24_readRegister(OBSERVE_TX, &rv, 1); rv = rv & 0x0F; return rv; } // Sends a data package to the default address. Be sure to send the correct // amount of bytes as configured as payload on the receiver. void nrf24_send(uint8_t *value) { /* Go to Standby-I first */ nrf24_ce_digitalWrite(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 */ nrf24_csn_digitalWrite(LOW); /* Write cmd to flush transmit FIFO */ spi_transfer(FLUSH_TX); /* Pull up chip select */ nrf24_csn_digitalWrite(HIGH); #endif /* Pull down chip select */ nrf24_csn_digitalWrite(LOW); /* Write cmd to write payload */ spi_transfer(W_TX_PAYLOAD); /* Write payload */ nrf24_transmitSync(value, payload_len); /* Pull up chip select */ nrf24_csn_digitalWrite(HIGH); /* Start the transmission */ nrf24_ce_digitalWrite(HIGH); } uint8_t nrf24_isSending() { uint8_t status; /* read the current status */ status = nrf24_getStatus(); /* if sending successful (TX_DS) or max retries exceded (MAX_RT). */ if ((status & ((1 << TX_DS) | (1 << MAX_RT)))) { return 0; /* false */ } return 1; /* true */ } uint8_t nrf24_getStatus() { uint8_t rv; nrf24_csn_digitalWrite(LOW); rv = spi_transfer(NOP); nrf24_csn_digitalWrite(HIGH); return rv; } uint8_t nrf24_lastMessageStatus() { uint8_t rv; rv = nrf24_getStatus(); /* Transmission went OK */ if ((rv & ((1 << TX_DS)))) { return NRF24_TRANSMISSON_OK; } /* Maximum retransmission count is reached */ /* Last message probably went missing ... */ else if ((rv & ((1 << MAX_RT)))) { return NRF24_MESSAGE_LOST; } /* Probably still sending ... */ else { return 0xFF; } } void nrf24_powerUpRx() { nrf24_csn_digitalWrite(LOW); spi_transfer(FLUSH_RX); nrf24_csn_digitalWrite(HIGH); nrf24_configRegister(STATUS, (1 << RX_DR) | (1 << TX_DS) | (1 << MAX_RT)); nrf24_ce_digitalWrite(LOW); nrf24_configRegister(CONFIG, nrf24_CONFIG | ((1 << PWR_UP) | (1 << PRIM_RX))); nrf24_ce_digitalWrite(HIGH); } void nrf24_powerUpTx() { nrf24_configRegister(STATUS, (1 << RX_DR) | (1 << TX_DS) | (1 << MAX_RT)); nrf24_configRegister(CONFIG, nrf24_CONFIG | ((1 << PWR_UP) | (0 << PRIM_RX))); } void nrf24_powerDown() { nrf24_ce_digitalWrite(LOW); nrf24_configRegister(CONFIG, nrf24_CONFIG); } /* software spi routine */ uint8_t spi_transfer(uint8_t tx) { uint8_t i = 0; uint8_t rx = 0; nrf24_sck_digitalWrite(LOW); for (i = 0; i < 8; i++) { if (tx & (1 << (7 - i))) { nrf24_mosi_digitalWrite(HIGH); } else { nrf24_mosi_digitalWrite(LOW); } nrf24_sck_digitalWrite(HIGH); rx = rx << 1; if (nrf24_miso_digitalRead()) { rx |= 0x01; } nrf24_sck_digitalWrite(LOW); } return rx; } /* send and receive multiple bytes over SPI */ void nrf24_transferSync(uint8_t *dataout, uint8_t *datain, uint8_t len) { uint8_t i; for (i = 0; i < len; i++) { datain[i] = spi_transfer(dataout[i]); } } /* send multiple bytes over SPI */ void nrf24_transmitSync(uint8_t *dataout, uint8_t len) { uint8_t i; for (i = 0; i < len; i++) { spi_transfer(dataout[i]); } } /* Clocks only one byte into the given nrf24 register */ void nrf24_configRegister(uint8_t reg, uint8_t value) { nrf24_csn_digitalWrite(LOW); spi_transfer(W_REGISTER | (REGISTER_MASK & reg)); spi_transfer(value); nrf24_csn_digitalWrite(HIGH); } /* Read single register from nrf24 */ void nrf24_readRegister(uint8_t reg, uint8_t *value, uint8_t len) { nrf24_csn_digitalWrite(LOW); spi_transfer(R_REGISTER | (REGISTER_MASK & reg)); nrf24_transferSync(value, value, len); nrf24_csn_digitalWrite(HIGH); } /* Write to a single register of nrf24 */ void nrf24_writeRegister(uint8_t reg, uint8_t *value, uint8_t len) { nrf24_csn_digitalWrite(LOW); spi_transfer(W_REGISTER | (REGISTER_MASK & reg)); nrf24_transmitSync(value, len); nrf24_csn_digitalWrite(HIGH); }
Первая проверка без заднего хода:
Проверка с задним ходом:
Геймпад:
Мануал по структурам пакетов геймпада
Оригинальная библиотека для геймпада
nrf24:
