Давно не было у меня такого затыка с драйвером для микросхемы.
Целую неделю я убил на отладку.
Теперь и говорить больно.
Но всеже.
В микросхеме nRF24L01+ есть интерфейс spi, по которому собственно и осуществляется весь обмен.
Я построил работу так, чтобы микросхема больше находилось в режиме приемника и только малое время в режиме передачи. Такой подход позволяет обеспечить более менее стабильную связь в обе стороны.
Что нужно сделать чтобы оживить приемопередатчик ?
На просторах интернета куча статей в которых передача запускается с полупинка ногой AVR, но такой подход почему то себя не оправдал.
Перед передачей nRF24L01+ нужно настроить.
- Указать канал передачи.
- Указать длину данных в каналах
- Указать выходную мощность
- Указать скорость передачи
- Включить auto-acknowledgment
- Указать сколько попыток передачи и с каким интервалом делать
- Выключить динамическую длину (Полезная функция, но пока не разобрался).
- Очистить FIFO
- Сбросить прерывания
Чтобы это сделать нужно уметь читать и писать регистры.
Запись производится посылкой команды W_REGISTER и номера регистра. После чего шлем данные.
u8 nRF24L01_write_reg(u8 reg, u8 data) { u8 resp; reg &= 0x1F; // 5bit reg num nRF24L01_CS_LOW; resp = nRF24L01_spi_send(nRF24L01_W_REGISTER | reg); resp = nRF24L01_spi_send(data); nRF24L01_CS_HIGH; return resp; }
Чтение происходит аналогично, но командой чтения. Пишем R_REGISTER и номер регистра после чего засылаем мусор для того, чтобы выдвинуть нужные данные.
Для установки адреса микросхемы нужно уметь писать пятибайтные регистры:
void nRF24L01_write_regm(u8 reg, u8 *data, u8 len) { reg &= 0x1F; // 5bit reg num nRF24L01_CS_LOW; nRF24L01_spi_send(nRF24L01_W_REGISTER | reg); while(len—) { nRF24L01_spi_send(*data++); } nRF24L01_CS_HIGH; }
Очистка FIFO осуществляется посылкой команд FLUSH_TX и FLUSH_RX.
Для перевода устройства в режим приема устанавливаем в регистре CONFIG биты PWR_UP и PRIM_RX в единицу. После чего установить ногу CE в высокое состояние.
Для перевода в режим приему процедура таже за исключением бита PRIM_RX, которые устанавливается в 0.
Для передачи данных нужно перевести устройство в режим передатчика. После чего записать данные для передачи.
void nRF24L01_write_payload(u8 *data, u8 len) { nRF24L01_CS_LOW; nRF24L01_spi_send(nRF24L01_W_TX_PAYLOAD); while(len—) { nRF24L01_spi_send(*data++); } nRF24L01_CS_HIGH; }
После записи устанавливаем CE в 1 и ждем пока данные улетят.
На приемной стороне ждем когда данные появятся, читая регистр статуса на предмет установки флага RX_DR. Или же цепляем ногу прерывания и по переходу в ноль читаем данные.
u8 nRF24L01_readRx(u8 *resp,u8 len) { nRF24L01_CS_LOW; nRF24L01_spi_send(nRF24L01_R_RX_PAYLOAD); while(len—) { *resp++ = nRF24L01_spi_send(nRF24L01_NOP); } nRF24L01_CS_HIGH; return nRF24L01_read_reg(nRF24L01_STATUS_REG); }
Я сделал так. Одна микросхема передает данные и ждет ответ. После чего сравнивает полученное и переданное.
nRF24L01_writeTx(str); do { status_reg = nRF24L01_readStatus(); } while (status_reg.bit.MAX_RT == 0 && status_reg.bit.TX_DS == 0); nRF24L01_ClearStatus(); nRF24L01_configure_rx(); do { status_reg = nRF24L01_readStatus(); req++; if (req > 1000) { req = 0; break; } } while (status_reg.bit.RX_DR == 0); if (status_reg.bit.RX_DR) { // чистим буфер memset(dataIn,0,32); // читаем nRF24L01_readRx(dataIn,32); // сравниваем int ret = memcmp(dataIn,str,32); if (ret == 0) successfulTransactions++; else badTransactions++; }
Другая микросхема — получает данные и отправляет их назад.
В процессе отладки делал, чтобы она еще выдавала полученное в UART.
Проект можете глянуть тут: https://github.com/lamazavr/nRF24L01_lib
Там же два pdf. Один — документация, другой — описание работы с микросхемой nRF24L01.
PS старался делать библиотеку. Для использования меняйте nRF24L01_gpio_init, nRF24L01_spi_init и nRF24L01_spi_send. По идее все должно заработать.
Источник: