Технический форум по робототехнике.
elesy » 14 июл 2015, 13:08
Прикупил себе данные модули по 110 рублей.
Начинаю мучать в связке STM8S105.
Если кто с ними имел дело - прошу отписаться.
Потихоньку буду в первом посте выкладывать код
- Код: Выделить всё • Развернуть
/*
********************************************************************************
** File : nrf24l01+.h
** Date : 07.07.2015
** Autors :
** Notes :
********************************************************************************
*/
#ifndef __NRF24L01_PLUS_H__
#define __NRF24L01_PLUS_H__
#include "stm8s.h"
#include "gpio.h"
#include "spi.h"
#include "delay.h"
#include "led.h"
/*
Распиновка модуля
1 - 3.3V
2 - gnd
3 - CE
4 - CSn
5 - SCK
6 - MOSI
7 - MISO
8 - IRQ
CN2->4 PC3 3
CN2->5 PC4 4
CN2->6 PC5->SPI_CLK 5
CN2->7 gnd 2
CN2->8 +3.3V 1
CN2->9 PC6->SPI_MOSI 6
CN2->10 PC7->SPI_MISO 7
CN4->8 PD3 8
*/
/*
********************************************************************************
** Definitions
********************************************************************************
*/
/* PC4 - Chip Select */
#define CSN_GPIO GPIOC
#define CSN_PIN GPIO_PIN_4
#define RF_CSN_PIN CSN_GPIO, CSN_PIN
/* PC3 - CE */
#define CE_GPIO GPIOC
#define CE_PIN GPIO_PIN_3
#define RF_CE_PIN CE_GPIO, CE_PIN
/* SPI */
/* PC5 - SPI_SCK */
/* PC6 - SPI_MOSI */
/* PC7 - SPI_MISO */
/* PD3 - IRQ */
#define IRQ_GPIO GPIOD
#define IRQ_PIN GPIO_PIN_3
#define RF_IRQ_PIN IRQ_GPIO, IRQ_PIN
#define Config_Reg_Reset_Value 0x0E
#define Max_Data_Len 32 //maximum Bytes in Payload, typ. 32
#define Max_Adress_Len 5 //maximum Bytes in Data Adress, typ. 5
#define Init_Delay_us 4000 //useconds wait for init chip delay, typ. 4000us
#define Payload_send_delay 40000 //maximum delay in cycles for data send ready in case of error
/* nRF24L01 адреса регистров */
#define CONFIG_REG 0x00
#define EN_AA_REG 0x01
#define EN_RXADDR_REG 0x02
#define SETUP_AW_REG 0x03
#define SETUP_RETR_REG 0x04
#define RF_CH_REG 0x05
#define RF_SETUP_REG 0x06
#define STATUS_REG 0x07
#define OBSERVE_TX_REG 0x08
#define RPD_REG 0x09
#define RX_ADDR_P0_REG 0x0A
#define RX_ADDR_P1_REG 0x0B
#define RX_ADDR_P2_REG 0x0C
#define RX_ADDR_P3_REG 0x0D
#define RX_ADDR_P4_REG 0x0E
#define RX_ADDR_P5_REG 0x0F
#define TX_ADDR_REG 0x10
#define RX_PW_P0_REG 0x11
#define RX_PW_P1_REG 0x12
#define RX_PW_P2_REG 0x13
#define RX_PW_P3_REG 0x14
#define RX_PW_P4_REG 0x15
#define RX_PW_P5_REG 0x16
#define FIFO_STATUS_REG 0x17
#define DYNPD_REG 0x1C
/* nRF24L01 команды */
#define CMD_R_REGISTER 0x00 // читаем регистр
#define CMD_W_REGISTER 0x20 // пишем в регистр
#define CMD_R_RX_PAYLOAD 0x61 // считывание из буфера принятых данных
#define CMD_W_TX_PAYLOAD 0xA0 // запись данных в буфер для отправки в космос
#define CMD_FLUSH_TX 0xE1 //
#define CMD_FLUSH_RX 0xE2 //
#define CMD_NOP 0xFF // команда заглушка, ничего не делает.
/* Биты регистра CONFIG */
#define CONFIG_MASK_RX_DR 6 //вкл/откл прерывание от бита RX_DR в рег. STATUS. 0-вкл, 1-выкл.
#define CONFIG_MASK_TX_DS 5 //вкл/откл прерывание от бита TX_DS в рег. STATUS. 0-вкл, 1-выкл.
#define CONFIG_MASK_MAX_RT 4 //вкл/откл прерывание от бита MAX_RT в рег. STATUS. 0-вкл, 1-выкл.
#define CONFIG_EN_CRC 3 //включение CRC. По умолчанию вкл. если один из битов регистра EN_AA включен.
#define CONFIG_CRCO 2 //режим CRC. 0-1 байт, 1-2 байта.
#define CONFIG_PWR_UP 1 //1-POWER UP, 0-POWER DOWN, по умолчанию 0.
#define CONFIG_PRIM_RX 0 //0-режим передачи, 1-режим приема.
/* Биты регистра STATUS */
#define STATUS_RX_DR 6 /*прерывание: данные получены. Для сброса записать 1.*/
#define STATUS_TX_DS 5 /*прерывание: данные переданы. Для сброса записать 1.*/
#define STATUS_MAX_RT 4 /*прерывание: данные не переданы. Для сброса записать 1.*/
#define STATUS_RX_P_NO2 3
#define STATUS_RX_P_NO1 2
#define STATUS_RX_P_NO0 1
#define STATUS_TX_FULL0 0 /*флаг переполнения TX FIFO буфера передачи. */
/* 1-переполнен, 0-есть еще место.*/
/*
********************************************************************************
** Constants
********************************************************************************
*/
/*
********************************************************************************
** Typedefs
********************************************************************************
*/
//#pragma bitfields = reversed
//
//typedef struct _nrf_reg_CONFIG_content {
// uint8_t reserved : 1;
// uint8_t MASK_RX_DX : 1;
//} nrf_reg_CONFIG_content;
typedef struct _nrf_reg_ {
uint8_t Config;
uint8_t EN_AA;
uint8_t En_RxAddr;
uint8_t Setup_AW;
uint8_t Setup_RETR;
uint8_t RF_Chahell;
uint8_t RF_Setup;
uint8_t Status;
uint8_t observe_Tx;
uint8_t RPD;
uint8_t Rx_Addr_Pipe0[5];
uint8_t Rx_Addr_Pipe1[5];
uint8_t Rx_Addr_Pipe2[5];
uint8_t Rx_Addr_Pipe3[5];
uint8_t Rx_Addr_Pipe4[5];
uint8_t Rx_Addr_Pipe5[5];
uint8_t Tx_Addr[5];
uint8_t Rx_Pw_Pipe0;
uint8_t Rx_Pw_Pipe1;
uint8_t Rx_Pw_Pipe2;
uint8_t Rx_Pw_Pipe3;
uint8_t Rx_Pw_Pipe4;
uint8_t Rx_Pw_Pipe5;
uint8_t FIFO_Status;
} _nrf_reg;
/*
********************************************************************************
** Variables
********************************************************************************
*/
extern _nrf_reg nrf_reg;
/*
********************************************************************************
** Function prototypes
********************************************************************************
*/
void nrf24l01_SendCommand ( uint8_t cmd );
void nrf24l01_WriteRegister ( uint8_t address, uint8_t *value, uint8_t length );
uint8_t nrf24l01_ReadRegister ( uint8_t address );
void nrf24l01_SendAddress ( uint8_t address, uint8_t cmd[Max_Adress_Len] );
void nrf24l01_Init ( void );
void nrf24l01_Setup ( void );
void nrf24l01_ReadAllRegister ( void );
void nrf24l01_WriteAllRegister ( void );
void nrf24l01_prx ( void );
void nrf24l01_ptx ( void );
void nrf24l01_standby ( void );
void nrf24l01_PowerDown ( void );
void nrf24l01_SetTxLength ( uint8_t l );
void nrf24l01_ClearInterrupts ( void );
void RF_SendByte ( uint8_t data );
uint8_t RF_ReceiveByte ( void );
void nrf24l01_FirstStart ( void );
#endif
- Код: Выделить всё • Развернуть
/*
********************************************************************************
** File : nrf24l01+.c
** Date : 07.07.2015
** Autors :
** Notes :
********************************************************************************
*/
#include "nrf24l01+.h"
/*$PAGE$*/
/*
********************************************************************************
** Descriptions :
** Parameter :
** Return :
** Notes :
********************************************************************************
*/
void nrf24l01_SendCommand ( uint8_t cmd )
{
PIN_OFF ( CSN_GPIO, CSN_PIN ); // PC.4 = 0
while ( SPI_GetFlagStatus ( SPI_FLAG_TXE ) == RESET );
SPI_SendData ( cmd );
while ( SPI_GetFlagStatus ( SPI_FLAG_BSY ) == SET );
while ( SPI_GetFlagStatus ( SPI_FLAG_RXNE ) == RESET );
SPI_ReceiveData ();
PIN_ON ( CSN_GPIO, CSN_PIN ); // PC.4 = 1
}
/*$PAGE$*/
/*
********************************************************************************
** Descriptions :
** Parameter :
** Return :
** Notes :
********************************************************************************
*/
void nrf24l01_WriteRegister ( uint8_t address, uint8_t *value, uint8_t length )
{
uint8_t i = 0;
PIN_OFF ( CSN_GPIO, CSN_PIN ); // PC.4 = 0
//spi_SendByte ( address );
//spi_SendByte ( value );
//Send address and write command
while ( SPI_GetFlagStatus ( SPI_FLAG_TXE ) == RESET );
SPI_SendData ( CMD_W_REGISTER | address );
while ( SPI_GetFlagStatus ( SPI_FLAG_BSY ) == SET );
while ( SPI_GetFlagStatus ( SPI_FLAG_RXNE ) == RESET );
SPI_ReceiveData();
//Send data
for ( i = 0; i < length; i++ ) {
while ( SPI_GetFlagStatus ( SPI_FLAG_TXE ) == RESET);
SPI_SendData ( value[ i ] );
while ( SPI_GetFlagStatus ( SPI_FLAG_BSY ) == SET );
while ( SPI_GetFlagStatus ( SPI_FLAG_RXNE ) == RESET );
SPI_ReceiveData();
}
PIN_ON ( CSN_GPIO, CSN_PIN ); // PC.4 = 1
}
/*$PAGE$*/
/*
********************************************************************************
** Descriptions :
** Parameter :
** Return :
** Notes :
********************************************************************************
*/
uint8_t nrf24l01_ReadRegister ( uint8_t address )
{
uint8_t retVal = 0;
PIN_OFF ( CSN_GPIO, CSN_PIN ); // PC.4 = 0
//retVal = spi_ReadByte ( address );
//retVal = spi_ReadByte ( CMD_NOP );
//Send address and read command
while ( SPI_GetFlagStatus ( SPI_FLAG_TXE ) == RESET );
SPI_SendData ( CMD_R_REGISTER | address );
while ( SPI_GetFlagStatus ( SPI_FLAG_BSY ) == SET );
while ( SPI_GetFlagStatus ( SPI_FLAG_RXNE ) == RESET );
SPI_ReceiveData ();
//Get data
while ( SPI_GetFlagStatus( SPI_FLAG_TXE ) == RESET );
SPI_SendData(0x00);
while ( SPI_GetFlagStatus( SPI_FLAG_BSY )== SET );
while ( SPI_GetFlagStatus ( SPI_FLAG_RXNE ) == RESET );
retVal = SPI_ReceiveData ();
PIN_ON ( CSN_GPIO, CSN_PIN ); // PC.4 = 1
return retVal;
}
- Вложения
-
- Распиновка
-
- Сами модули
Последний раз редактировалось
elesy 14 июл 2015, 13:56, всего редактировалось 3 раз(а).
Angel71 » 14 июл 2015, 13:16
отписался
elesy » 14 июл 2015, 13:20
У меня сейчас проблема с приемом. Не могу принять данные. Играл и с номером канала и с идентификатором. У тебя получилось установить связь?
Angel71 » 14 июл 2015, 13:29
да, разобрался со всем кроме регистра cd. или в этом клоне оно не реализовано или лыжи не едут, как он работает.
elesy » 14 июл 2015, 13:31
Регистр CD есть в nRF24L01, а у меня nRF24L01+
Angel71 » 14 июл 2015, 13:41
тоже +, а в даташите про нерабочесть cd нигде не встречал. ну то такое, не сильно он и нужен. всё-равно уровень сигнала не даёт.
в общем что бы не отвлекаться и где не запутаться или адреса не трогай или ставь как по даташиту. отрубай динамическую длину данных и пробуй. ну даташит бегло глянуть можно, но самое нужное это расписание регистров. можно даже распечатать, постоянно страницы листать утомительно. внимательно обрати внимание на то, как дёргаешь пины ce и csn. они очень мозговыносящие, если не так дёрнуть.
holomrn » 14 июл 2015, 13:43
На казусе просто огромная ветка про эти нрф..
elesy » 14 июл 2015, 13:47
holomrn писал(а):На казусе просто огромная ветка про эти нрф..
То что на кактусе не идет. И ответа я там не смог получить.
Добавлено спустя 51 секунду:Angel71 писал(а):, постоянно страницы листать утомительно. внимательно обрати внимание на то, как дёргаешь пины ce и csn. они очень мозговыносящие, если не так дёрнуть.
Основной код выкладываю в первом посту
Angel71 » 14 июл 2015, 13:50
надёргал пару ф-ий для примера
- Код: Выделить всё • Развернуть
static const uint8_t CMD_R_REGISTER = 0x00;
static const uint8_t MASK_RW_REGISTER = 0x1F;
uint8_t NRF24::read_register(uint8_t reg)
{
csnLow();
SPI.transfer(CMD_R_REGISTER | (MASK_RW_REGISTER & reg));
uint8_t result = SPI.transfer(0xff);
csnHi();
return result;
}
void NRF24::read_register(uint8_t reg, uint8_t *buf, uint8_t len)
{
csnLow();
status.value = SPI.transfer(CMD_R_REGISTER | (MASK_RW_REGISTER & reg));
while (len--)
*buf++ = SPI.transfer(0xff);
csnHi();
}
void NRF24::write_register(uint8_t reg, uint8_t value)
{
csnLow();
SPI.transfer(CMD_W_REGISTER | (MASK_RW_REGISTER & reg));
SPI.transfer(value);
csnHi();
}
void NRF24::powerDown()
{
reg_config.value = read_register(REG_CONFIG_ADDR);
reg_config.bits.PWR_UP = false;
write_register(REG_CONFIG_ADDR, reg_config.value);
ceLow();
}
void NRF24::powerUp()
{
reg_config.value = read_register(REG_CONFIG_ADDR);
reg_config.bits.PWR_UP = true;
write_register(REG_CONFIG_ADDR, reg_config.value);
ceHi();
}
void NRF24::powerUpTx()
{
//The TX mode is an active mode where the nRF24L01 transmits a packet. To enter this mode, the
//nRF24L01 must have the PWR_UP bit set high, PRIM_RX bit set low, a payload in the TX FIFO and, a high
//pulse on the CE for more than 10µs.
//...
//datasheet page 21
reg_config.value = read_register(REG_CONFIG_ADDR);
reg_config.bits.PWR_UP = true;
reg_config.bits.PRIM_RX = 0;
write_register(REG_CONFIG_ADDR, reg_config.value);
//ceHi();
//delay(10);
}
void NRF24::powerUpRx()
{
//The RX mode is an active mode where the nRF24L01 radio is a receiver. To enter this mode, the
//nRF24L01 must have the PWR_UP bit set high, PRIM_RX bit set high and the CE pin set high.
//datasheet page 21
ceLow();
reg_config.value = read_register(REG_CONFIG_ADDR);
reg_config.bits.PWR_UP = true;
reg_config.bits.PRIM_RX = 1;
write_register(REG_CONFIG_ADDR, reg_config.value);
ceHi();
}
void NRF24::send(const uint8_t *buf, uint8_t len)
{
ceLow();
//len = min(len, payload_size);
csnLow();
SPI.transfer(CMD_W_TX_PAYLOAD);
//SPI.transfer(CMD_W_ACK_PAYLOAD);
for (int i = 0; i < len; i++) SPI.transfer(buf[i]);
csnHi();
ceHi();
delay(15);
}
void NRF24::recieve(uint8_t* buf, uint8_t len)
{
len = max(len, payload_size);
csnLow();
SPI.transfer(CMD_R_RX_PAYLOAD);
for (int i = 0; i < 32; i++)
buf[i] = SPI.transfer(0xff);
csnHi();
}
на классах только делать... я либу переписал и о том, что оно выжрет чуть больше ожидаемого уже потом понял. хотя так удобней. в общем не рекомендую классы, а там сами думайте.
даташит читать нужно, толку от тех веток. чуть выше я написал, что адреса не трогай и отключи во всех регистрах динамическую длину пакетов, с ними сразу туго работать.
elesy » 14 июл 2015, 13:54
Angel71 писал(а):н
даташит читать нужно, толку от тех веток. чуть выше я написал, что адреса не трогай и отключи во всех регистрах динамическую длину пакетов, с ними сразу туго работать.
Его читал и читаю. Лежит рядом распечататный. А в форум полез когда не пошло
Angel71 » 14 июл 2015, 14:08
регистры сбрасываются только при отключении питания, сброса у чипа нет. перечитываете в даташите все регистры и смотрите, что инициализировать. чем меньше трогать, тем лучше, меньше запутаетесь.
если поможет, я примерно так в последний раз инициализировал, тут без динамической длины пакета (payload_size = 32)
- Код: Выделить всё • Развернуть
ceLow();
csnHi();
delay( 5 );
reg_config.value = 0;
reg_config.bits.PRIM_RX = 1;
reg_config.bits.PWR_UP = 0;
reg_config.bits.CRCO = 1;
reg_config.bits.EN_CRC = 1;
reg_config.bits.MASK_MAX_RT = 0; //0: Reflect MAX_RT as active low interrupt on the IRQ pin
reg_config.bits.MASK_TX_DS = 0; //0: Reflect TX_DS as active low interrupt on the IRQ pin
reg_config.bits.MASK_RX_DR = 0; //0: Reflect RX_DR as active low interrupt on the IRQ pin
write_register(REG_CONFIG_ADDR, reg_config.value);
//EN_AA - Enhanced ShockBurst
write_register(REG_EN_AA_ADDR, 0x1F); //Enable auto acknowledgement data pipe 0-5
//write_register(REG_EN_AA_ADDR, 0);
write_register(REG_EN_RX_ADDR, 0x01); //Enable data pipe 0
write_register(REG_SETUP_AW_ADDR, 0x01); //RX/TX Address field width, 0x03 - '11' – 5 bytes
UNION_SETUP_RETR reg_setup_retr;
reg_setup_retr.value = 0;
reg_setup_retr.bits.ARC = 3; //Auto Retransmit Count. 0 - off
reg_setup_retr.bits.ARD = 1; //Auto Retransmit Delay, 0001 – Wait 500µS
write_register(REG_SETUP_RETR_ADDR, reg_setup_retr.value);
setChannel(0);
UNION_RF_SETUP reg_rf_setup;
reg_rf_setup.value = 0;
reg_rf_setup.bits.LNA_HCURR = 1;
reg_rf_setup.bits.RF_PWR = (rf24_pa_dbm)0;// rf24_pa_dbm::RF24_PA_MIN;
reg_rf_setup.bits.RF_DR = (rf24_datarate)0; // rf24_datarate::RF24_1MBPS;
write_register(REG_RF_SETUP_ADDR, reg_rf_setup.value);
status.value = 0x70;//1110000 - clear RX_DR, TX_DS, MAX_RT
write_register(REG_STATUS_ADDR, status.value);
uint8_t arr5[5] = { 0xE7, 0xE7, 0xE7, 0xE7, 0xE7 };
//arr5[0] = 0xE7;
//arr5[1] = 0xE7;
//arr5[2] = 0xE7;
//arr5[3] = 0xE7;
//arr5[4] = 0xE7;
write_register(REG_RX_ADDR_BASE, arr5, 3); //RX_ADDR_P0
write_register(REG_TX_ADDR, arr5, 3); //TX_ADDR_P0
arr5[0] = 0xC2;
arr5[1] = 0xC2;
arr5[2] = 0xC2;
arr5[3] = 0xC2;
arr5[4] = 0xC2;
write_register(REG_RX_ADDR_BASE + 1, arr5, 3); //RX_ADDR_P1
write_register(REG_RX_ADDR_BASE + 2, 0xC3); //RX_ADDR_P2
write_register(REG_RX_ADDR_BASE + 3, 0xC4); //RX_ADDR_P3
write_register(REG_RX_ADDR_BASE + 4, 0xC5); //RX_ADDR_P4
write_register(REG_RX_ADDR_BASE + 5, 0xC6); //RX_ADDR_P5
write_register(REG_RX_PW_P_ADDR_BASE, payload_size); //Number of bytes in RX payload in data pipe 0.
write_register(REG_RX_PW_P_ADDR_BASE + 1, payload_size); //Number of bytes in RX payload in data pipe 1.
write_register(REG_RX_PW_P_ADDR_BASE + 2, payload_size); //Number of bytes in RX payload in data pipe 2.
write_register(REG_RX_PW_P_ADDR_BASE + 3, payload_size); //Number of bytes in RX payload in data pipe 3.
write_register(REG_RX_PW_P_ADDR_BASE + 4, payload_size); //Number of bytes in RX payload in data pipe 4.
write_register(REG_RX_PW_P_ADDR_BASE + 5, payload_size); //Number of bytes in RX payload in data pipe 5.
flush_rx();
flush_tx();
write_register(REG_DYNPD_ADDR, 0); //Enable dynamic payload length. pipe 0-5 off
UNION_FEATURE reg_feature;
reg_feature.value = 0;
reg_feature.bits.EN_DYN_ACK = 0; //Enables the W_TX_PAYLOAD_NOACK command
reg_feature.bits.EN_ACK_PAY = 0; //Enables Payload with ACK
reg_feature.bits.EN_DPL = 0; //Enables Dynamic Payload Length
write_register(REG_DYNPD_ADDR, reg_feature.value);
у меня оно по прерыванию ноги irq данные считывает.
есть три весёлых бита: RX_DR, TX_DS, MAX_RT. с ними больше всего веселья в начале изучения модуля. при отладке отправки и получения лучше проверять и с отключенной и с включенной ф-ей автоподтверждения доставки пакета + поотправлять пакетики в никуда (просто второй модуль отключить).
chu » 25 июл 2015, 11:54
В ветке
Форт-система почти полностью описана работа с nRF24L01+.
Приведенный там код даже избыточен и предназначался для изучения этого модуля.
На примерах показан обмен (и обработка ошибочных пакетов), сканнер диапазонов и
измеритель дальности с использованием CD.
из отзыва европейского коллеги:
Andreas Wagner писал(а):...
After going back through the forum thread to collect some missing words and
making a few modifications to nRF24_init I got the scanner+ranger to work!
Your posting is godsend for my remote sensing network project as it saves
me much time.
Angel71 » 25 июл 2015, 12:44
форт? да вы весельчак. работа модуля боле чем нормлаьно описана в спецификации, его нужно взять и внимательно читать. просто с небольшим примером кода это немного проще и быстрей.