Вопрос по #ifndef

ulis
ulis аватар
Offline
Зарегистрирован: 09.03.2011

Мучаю библиотеку NRF24L01+ и вот в этом коде возник вопрос:

// BYTE type definition
#ifndef API_H
#define API_H
//****************************************************
// SPI(nRF24L01) commands
#define READ_REG        0x00  // Define read command to register
#define WRITE_REG       0x20  // Define write command to register
#define RD_RX_PLOAD     0x61  // Define RX payload register address
#define WR_TX_PLOAD     0xA0  // Define TX payload register address
#define FLUSH_TX        0xE1  // Define flush TX register command
#define FLUSH_RX        0xE2  // Define flush RX register command
#define REUSE_TX_PL     0xE3  // Define reuse TX payload register command
#define NOP             0xFF  // Define No Operation, might be used to read status register
//***************************************************
#define RX_DR    0x40
#define TX_DS    0x20
#define MAX_RT   0x10
//***************************************************
// SPI(nRF24L01) registers(addresses)
#define CONFIG          0x00  // 'Config' register address
#define EN_AA           0x01  // 'Enable Auto Acknowledgment' register address
#define EN_RXADDR       0x02  // 'Enabled RX addresses' register address
#define SETUP_AW        0x03  // 'Setup address width' register address
#define SETUP_RETR      0x04  // 'Setup Auto. Retrans' register address
#define RF_CH           0x05  // 'RF channel' register address
#define RF_SETUP        0x06  // 'RF setup' register address
#define STATUS          0x07  // 'Status' register address
#define OBSERVE_TX      0x08  // 'Observe TX' register address
#define CD              0x09  // 'Carrier Detect' register address
#define RX_ADDR_P0      0x0A  // 'RX address pipe0' register address
#define RX_ADDR_P1      0x0B  // 'RX address pipe1' register address
#define RX_ADDR_P2      0x0C  // 'RX address pipe2' register address
#define RX_ADDR_P3      0x0D  // 'RX address pipe3' register address
#define RX_ADDR_P4      0x0E  // 'RX address pipe4' register address
#define RX_ADDR_P5      0x0F  // 'RX address pipe5' register address
#define TX_ADDR         0x10  // 'TX address' register address
#define RX_PW_P0        0x11  // 'RX payload width, pipe0' register address
#define RX_PW_P1        0x12  // 'RX payload width, pipe1' register address
#define RX_PW_P2        0x13  // 'RX payload width, pipe2' register address
#define RX_PW_P3        0x14  // 'RX payload width, pipe3' register address
#define RX_PW_P4        0x15  // 'RX payload width, pipe4' register address
#define RX_PW_P5        0x16  // 'RX payload width, pipe5' register address
#define FIFO_STATUS     0x17  // 'FIFO Status Register' register address

//************************************************
#endif

Откуда директива #ifndef "знает", включено ли последующее определение или нет?

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

Если бы директива "знала", то она тем самым бы была не нужна.

Знать или не знать должден препроцессор при обработке директив - что ему попадалось при обработке, а что - нет.

 

В данном слвчае смысл трех имеющихся директив: вкючаем, если впервые, иначе - выбрасываем. Т.е. они служат для того, чтобы фрагмент кода, сколько бы раз он ни встречался, вы выходной результат попал строго в единственном экземпляре.

ulis
ulis аватар
Offline
Зарегистрирован: 09.03.2011

Понятно, этим занимается препроцессор ...

Еще вопрос - файл определений:

#ifndef NRF24L01_h
#define NRF24L01_h

#include "API.h"

//*********************************************
#define SPI_PORT PORTB
#define SPI_DIR  DDRB
#define SPI_IN   PINB
//---------------------------------------------
#define TX_ADR_WIDTH    5   
// 5 unsigned chars TX(RX) address width
#define TX_PLOAD_WIDTH  1  
// 20 unsigned chars TX payload
//---------------------------------------------
#define CE       0x01
// CE_BIT:   Digital Input     Chip Enable Activates RX or TX mode
#define SCK      0x04
// SCK BIT:  Digital Input     SPI Clock

#define MISO     0x10
// MISO BIT: Digital Output    SPI Slave Data Output, with tri-state option
#define CSN      0x02
// CSN BIT:  Digital Input     SPI Chip Select
#define MOSI     0x08
// MOSI BIT: Digital Input     SPI Slave Data Input
#define IRQ      0x20
// IRQ BIT:  Digital Output    Maskable interrupt pin
//*********************************************
#endif

И далее в основном файле библиотеки идет:

SPI_DIR = ( CE + SCK + CSN + MOSI);
SPI_DIR &=~ ( IRQ + MISO);

Имя SPI_DIR определяет регистр направления передачи, но нафига значение этого регистра вычислять как сумму и затем применять к нему побитную операцию?

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

SPI_DIR - это некоторая комбинация флагов. И вычисляется она вполне стандартным способом.

А зачем нужен каждый из этих флагов, наверняка указано в дэйташите.

ulis
ulis аватар
Offline
Зарегистрирован: 09.03.2011

andriano пишет:

SPI_DIR - это некоторая комбинация флагов. И вычисляется она вполне стандартным способом.

А зачем нужен каждый из этих флагов, наверняка указано в дэйташите.

Просто непонятно, к чему такие сложности, когда всего-то навсего нужно настроить направление передачи порта ... сразу бы написали SPI_DIR = 0x0F

 

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

ulis пишет:

Просто непонятно, к чему такие сложности, когда всего-то навсего нужно настроить направление передачи порта ... сразу бы написали SPI_DIR = 0x0F

А что такое 0x0F?

ulis
ulis аватар
Offline
Зарегистрирован: 09.03.2011

Ну, это я в уме :) прикинул результат вычисления SPI_DIR

ulis
ulis аватар
Offline
Зарегистрирован: 09.03.2011
//*********************************************
#define SPI_PORT PORTB
#define SPI_DIR  DDRB
#define SPI_IN   PINB
//---------------------------------------------
#define TX_ADR_WIDTH    5   
// 5 unsigned chars TX(RX) address width
#define TX_PLOAD_WIDTH  1  
// 20 unsigned chars TX payload
//---------------------------------------------

#define CE       0x01
// CE_BIT:   Digital Input     Chip Enable Activates RX or TX mode
#define SCK      0x04
// SCK BIT:  Digital Input     SPI Clock

#define MISO     0x10
// MISO BIT: Digital Output    SPI Slave Data Output, with tri-state option
#define CSN      0x02
// CSN BIT:  Digital Input     SPI Chip Select
#define MOSI     0x08
// MOSI BIT: Digital Input     SPI Slave Data Input
#define IRQ      0x20
// IRQ BIT:  Digital Output    Maskable interrupt pin
//*********************************************

void setup()
{
  Serial.begin(9600);
  SPI_DIR = ( CE + SCK + CSN + MOSI);
  SPI_DIR &=~ ( IRQ + MISO);
  Serial.println(SPI_DIR,HEX);
}

void loop()
{  

}

Результат = 0xof;

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

Видите ли, ulis считается, что так: SPI_DIR = ( CE + SCK + CSN + MOSI); писать понятнее. У меня, правда, есть некоторые сомнения на этот счет. Да, конечно, сходу непонятно, что такое 0x0F, но это при желании можно выяснить, заглянув в дэйташит. А вот для понимания CE + SCK + CSN + MOSI одного дэйташита недостаточно - придется загоянуть еще и в заголовочный файл.

Но есть и другой момент. Может оказаться, что у другого процессора (контроллера, библиотеки) интересующие нас биты расположены в другом порядке. Тогде комбинация ( CE + SCK + CSN + MOSI) может уже оказаться не равной 0x0F. Т.е. символическая константа сохранится, а численная - будет другой.

ulis
ulis аватар
Offline
Зарегистрирован: 09.03.2011

andriano пишет:

Но есть и другой момент. Может оказаться, что у другого процессора (контроллера, библиотеки) интересующие нас биты расположены в другом порядке. Тогде комбинация ( CE + SCK + CSN + MOSI) может уже оказаться не равной 0x0F. Т.е. символическая константа сохранится, а численная - будет другой.

Ну, наверно польза есть, значит, для другого процессора, просто поменять значения CE, SCK, CSN, MOSI? Как все запущено!