Spiegazione di un codice

Salve, qualcuno potrebbe spiegarmi come funziona questo codice e come si fa a decidere quali sono gli indirizzi di memoria del sensore?

/*
 SCP1000 Barometric Pressure Sensor Display

 Shows the output of a Barometric Pressure Sensor on a
 Uses the SPI library. For details on the sensor, see:
 http://www.sparkfun.com/commerce/product_info.php?products_id=8161
 http://www.vti.fi/en/support/obsolete_products/pressure_sensors/

 This sketch adapted from Nathan Seidle's SCP1000 example for PIC:
 http://www.sparkfun.com/datasheets/Sensors/SCP1000-Testing.zip

 Circuit:
 SCP1000 sensor attached to pins 6, 7, 10 - 13:
 DRDY: pin 6
 CSB: pin 7
 MOSI: pin 11
 MISO: pin 12
 SCK: pin 13

 created 31 July 2010
 modified 14 August 2010
 by Tom Igoe
 */

// the sensor communicates using SPI, so include the library:
#include <SPI.h>

//Sensor's memory register addresses:
const int PRESSURE = 0x1F;      //3 most significant bits of pressure
const int PRESSURE_LSB = 0x20;  //16 least significant bits of pressure
const int TEMPERATURE = 0x21;   //16 bit temperature reading
const byte READ = 0b11111100;     // SCP1000's read command
const byte WRITE = 0b00000010;   // SCP1000's write command

// pins used for the connection with the sensor
// the other you need are controlled by the SPI library):
const int dataReadyPin = 6;
const int chipSelectPin = 7;

void setup() {
  Serial.begin(9600);

  // start the SPI library:
  SPI.begin();

  // initalize the  data ready and chip select pins:
  pinMode(dataReadyPin, INPUT);
  pinMode(chipSelectPin, OUTPUT);

  //Configure SCP1000 for low noise configuration:
  writeRegister(0x02, 0x2D);
  writeRegister(0x01, 0x03);
  writeRegister(0x03, 0x02);
  // give the sensor time to set up:
  delay(100);
}

void loop() {
  //Select High Resolution Mode
  writeRegister(0x03, 0x0A);

  // don't do anything until the data ready pin is high:
  if (digitalRead(dataReadyPin) == HIGH) {
    //Read the temperature data
    int tempData = readRegister(0x21, 2);

    // convert the temperature to celsius and display it:
    float realTemp = (float)tempData / 20.0;
    Serial.print("Temp[C]=");
    Serial.print(realTemp);


    //Read the pressure data highest 3 bits:
    byte  pressure_data_high = readRegister(0x1F, 1);
    pressure_data_high &= 0b00000111; //you only needs bits 2 to 0

    //Read the pressure data lower 16 bits:
    unsigned int pressure_data_low = readRegister(0x20, 2);
    //combine the two parts into one 19-bit number:
    long pressure = ((pressure_data_high << 16) | pressure_data_low) / 4;

    // display the temperature:
    Serial.println("\tPressure [Pa]=" + String(pressure));
  }
}

//Read from or write to register from the SCP1000:
unsigned int readRegister(byte thisRegister, int bytesToRead) {
  byte inByte = 0;           // incoming byte from the SPI
  unsigned int result = 0;   // result to return
  Serial.print(thisRegister, BIN);
  Serial.print("\t");
  // SCP1000 expects the register name in the upper 6 bits
  // of the byte. So shift the bits left by two bits:
  thisRegister = thisRegister << 2;
  // now combine the address and the command into one byte
  byte dataToSend = thisRegister & READ;
  Serial.println(thisRegister, BIN);
  // take the chip select low to select the device:
  digitalWrite(chipSelectPin, LOW);
  // send the device the register you want to read:
  SPI.transfer(dataToSend);
  // send a value of 0 to read the first byte returned:
  result = SPI.transfer(0x00);
  // decrement the number of bytes left to read:
  bytesToRead--;
  // if you still have another byte to read:
  if (bytesToRead > 0) {
    // shift the first byte left, then get the second byte:
    result = result << 8;
    inByte = SPI.transfer(0x00);
    // combine the byte you just got with the previous one:
    result = result | inByte;
    // decrement the number of bytes left to read:
    bytesToRead--;
  }
  // take the chip select high to de-select:
  digitalWrite(chipSelectPin, HIGH);
  // return the result:
  return (result);
}


//Sends a write command to SCP1000

void writeRegister(byte thisRegister, byte thisValue) {

  // SCP1000 expects the register address in the upper 6 bits
  // of the byte. So shift the bits left by two bits:
  thisRegister = thisRegister << 2;
  // now combine the register address and the command into one byte:
  byte dataToSend = thisRegister | WRITE;

  // take the chip select low to select the device:
  digitalWrite(chipSelectPin, LOW);

  SPI.transfer(dataToSend); //Send register location
  SPI.transfer(thisValue);  //Send value to record into register

  // take the chip select high to de-select:
  digitalWrite(chipSelectPin, HIGH);
}

ciao…questo sketch l’hai preso dagli esempi della libreria SPI presente anche nel sito di Arduino giusto!?
bhe…nella pagina dell’esempio c’è un link al data sheet del sensore; nel data sheet trovi illustarti tutti i registri ed i loro possibili valori.
questo lo devi fare (verifica dei registri/valori) per ogni device con cui vuoi comunicare.

per quanto riguarda il codice…in testa si sono fatte alcune impostazioni base (sempre riferite al sensore specifico):

//Sensor's memory register addresses:
const int PRESSURE = 0x1F;      //3 most significant bits of pressure
const int PRESSURE_LSB = 0x20;  //16 least significant bits of pressure
const int TEMPERATURE = 0x21;   //16 bit temperature reading
const byte READ = 0b11111100;     // SCP1000's read command
const byte WRITE = 0b00000010;   // SCP1000's write command

poi si sono definiti i pin per SS (7) e quello per verificare se il sensore ha aggiornato la sua lettura DRDY (6):

// pins used for the connection with the sensor
// the other you need are controlled by the SPI library):
const int dataReadyPin = 6;
const int chipSelectPin = 7;

inizializzazione dei pin, SPI e Serial:

void setup() {
  Serial.begin(9600);

  // start the SPI library:
  SPI.begin();

  // initalize the  data ready and chip select pins:
  pinMode(dataReadyPin, INPUT);
  pinMode(chipSelectPin, OUTPUT);

prime impostazioni di cosa e come deve inviare il sensore (vedi data sheet):

  //Configure SCP1000 for low noise configuration:
  writeRegister(0x02, 0x2D);
  writeRegister(0x01, 0x03);
  writeRegister(0x03, 0x02);
  // give the sensor time to set up:
  delay(100);

si richiede l’alta risoluzione:

  //Select High Resolution Mode
  writeRegister(0x03, 0x0A);

nel loop() si verifica che il sensore abbia qualche cosa di nuovo da inviare:

if (digitalRead(dataReadyPin) == HIGH) {

e lo si legge e stampa a video:

    int tempData = readRegister(0x21, 2);

    // convert the temperature to celsius and display it:
    float realTemp = (float)tempData / 20.0;
    Serial.print("Temp[C]=");
    Serial.print(realTemp);


    //Read the pressure data highest 3 bits:
    byte  pressure_data_high = readRegister(0x1F, 1);
    pressure_data_high &= 0b00000111; //you only needs bits 2 to 0

    //Read the pressure data lower 16 bits:
    unsigned int pressure_data_low = readRegister(0x20, 2);
    //combine the two parts into one 19-bit number:
    long pressure = ((pressure_data_high << 16) | pressure_data_low) / 4;

    // display the temperature:
    Serial.println("\tPressure [Pa]=" + String(pressure));

la vera comunicazione è gestita dalle due funzioni: readRegister() e writeRegister() dopo la loop().

ORSO2001:
ciao…questo sketch l’hai preso dagli esempi della libreria SPI presente anche nel sito di Arduino giusto!?
bhe…nella pagina dell’esempio c’è un link al data sheet del sensore; nel data sheet trovi illustarti tutti i registri ed i loro possibili valori.
questo lo devi fare (verifica dei registri/valori) per ogni device con cui vuoi comunicare.

per quanto riguarda il codice…in testa si sono fatte alcune impostazioni base (sempre riferite al sensore specifico):

//Sensor's memory register addresses:

const int PRESSURE = 0x1F;      //3 most significant bits of pressure
const int PRESSURE_LSB = 0x20;  //16 least significant bits of pressure
const int TEMPERATURE = 0x21;  //16 bit temperature reading
const byte READ = 0b11111100;    // SCP1000’s read command
const byte WRITE = 0b00000010;  // SCP1000’s write command




poi si sono definiti i pin per SS (7) e quello per verificare se il sensore ha aggiornato la sua lettura DRDY (6):


// pins used for the connection with the sensor
// the other you need are controlled by the SPI library):
const int dataReadyPin = 6;
const int chipSelectPin = 7;




inizializzazione dei pin, SPI e Serial:


void setup() {
  Serial.begin(9600);

// start the SPI library:
  SPI.begin();

// initalize the  data ready and chip select pins:
  pinMode(dataReadyPin, INPUT);
  pinMode(chipSelectPin, OUTPUT);



prime impostazioni di cosa e come deve inviare il sensore (vedi data sheet):


//Configure SCP1000 for low noise configuration:
  writeRegister(0x02, 0x2D);
  writeRegister(0x01, 0x03);
  writeRegister(0x03, 0x02);
  // give the sensor time to set up:
  delay(100);



si richiede l'alta risoluzione:


//Select High Resolution Mode
  writeRegister(0x03, 0x0A);



nel loop() si verifica che il sensore abbia qualche cosa di nuovo da inviare:


if (digitalRead(dataReadyPin) == HIGH) {



e lo si legge e stampa a video:


int tempData = readRegister(0x21, 2);

// convert the temperature to celsius and display it:
    float realTemp = (float)tempData / 20.0;
    Serial.print(“Temp[C]=”);
    Serial.print(realTemp);

//Read the pressure data highest 3 bits:
    byte  pressure_data_high = readRegister(0x1F, 1);
    pressure_data_high &= 0b00000111; //you only needs bits 2 to 0

//Read the pressure data lower 16 bits:
    unsigned int pressure_data_low = readRegister(0x20, 2);
    //combine the two parts into one 19-bit number:
    long pressure = ((pressure_data_high << 16) | pressure_data_low) / 4;

// display the temperature:
    Serial.println("\tPressure [Pa]=" + String(pressure));



la vera comunicazione è gestita dalle due funzioni: readRegister() e writeRegister() dopo la loop().

Grazie mille per l’aiuto. Non ho fatto caso che sul quella pagine c’era anche il data sheet. Questo esempio lo devo applicare un altro sensore che misura la differenza di pressione. Il problema è che sul suo data sheet non ho nessun registro e/o valore.

Non posso quindi utilizzare questi stessi registri vero?

ciao...consiglio...NON quotare un intero post ma le sole parti che t'interessa evidenziare...detto questo...ogni device ha i suoi registri che si riferiscono a cose specifiche...posta un link al sensore che ci diamo un occhio...e sei sicuro che il tuo sensore usi la SPI?

Chiedo scusa, ancora non mi so muovere bene nei forum. Si secondo il codice seriale del mio sensore, esso utilizza la comunicazione SPI.

Questo è il data sheet ( a pagina 13 c'è la pin map)

Qui invece spiega come funziona la comunicazione SPI di questo specifico sensore
https://sensing.honeywell.com/index.php?ci_id=45843

Il mio sensore praticamente misura una differenza di pressione tra le due porte. Il modello è ABP D JJ T 001PD S A 3

Grazie mille per l'aiuto. Non so come andare avanti, perchè per questo sensore sto bloccando tutto il progetto!

ciao...ho dato un occhio al data sheet del sensore...non ci sono registri...è un sensore che NON accetta alcun comando, non c'è nemmeno il collegamento MOSI (master out slave in)...nel momento in cui interessa a te abiliti la lettura (pin SS a LOW) e lui inzia a trasmettere in riferimento a clock (SCLK).

non ho grossa esperienza con la SPI ma la configurazione che fa per te dovrebbe essere:
speed max 800 KHz (800000), MSBFIRST (questo è per i bits), SPI_MODE0

quello che trasmette sono, a seconda se ha o non ha la compsanzione della temperatura (non ho controllato il modello) o 2 o 4 bytes. i primi due bytes includono la "diagnostic condition" e la pressione; il 3o e 4o byte alla correzzione della temperatura.
lui invia i dati in MSB (most significand byte) e, come scritto, con i bit ordinati dal 15 allo 0.
de primo byte i bits 15 e 14 servono per la "diagnostic condition"; gli altri bit, più quelli del secondo byte, si riferiscono al valore della pressione.
se il tuo sensore ha la compensazione della temperatura, dei due byte che invia (3-4) solo 11 bit sono significativi...vedi schema del data sheet.

come detto non ho grossa esperienza con la SPI, ti conviene studiare bene la libreria,...però per leggeri i dati dovresti usare i metodi:
receivedVal = SPI.transfer(val)....(legge un byte)
receivedVal16 = SPI.transfer16(val16)...(legge 2 byte = int)
SPI.transfer(buffer, size)...(legge n byte e li salva in una array)
dato che il sensore non gestisce "comandi" penso che come val o val16 o buffer tu possa inzializzarli a 0

Ciao ORSO2001, grazie per l’aiuto. Io ho provato a scrivere il codice seguendo le tue indicazioni che già avevo letto sul datasheet, ma continuo ad avere problemi: quando stampo reveivedVal16 mi stampa sempre uno 0, quindi non credo sta funzionando. Ho sbagliato io a dichiarare qualcosa? O il sensore non funziona come dovrebbe?

#include <SPI.h>

int address;
byte val16;
byte receivedVal16;

void setup() {
  Serial.begin(9600);
  // imposta pin 10 come output:
  pinMode(10, OUTPUT);
  // inizializza SPI:
  SPI.beginTransaction(SPISettings(800000, MSBFIRST, SPI_MODE0));
}
void loop() {
 digitalWrite(10, LOW);
  receivedVal16 = SPI.transfer(val16);
  Serial.println(receivedVal16);
  digitalWrite(10, HIGH);
  delay (1000);
}

ciao...adesso sono via e non riesco a verificare...prova semplice...il parametro SPI_MODE può essere 0,1,2,3...prova se con uno degli altri rimanenti 3 metodi ti da qualche cosa.

Quindi le dichiarazione di variabili e utilizzo delle funzioni SPI sono giuste?

ciao…prova questo:

#include <SPI.h>

int address;
byte val16 = 0x00;
byte receivedVal16[4];

void setup() {
  Serial.begin(9600);
  // imposta pin 10 come output:
  pinMode(10, OUTPUT);
  pinMode(10, LOW);
  // inizializza SPI:
  SPI.beginTransaction(SPISettings(800000, MSBFIRST, SPI_MODE0));
}
void loop() {
  digitalWrite(10, LOW);
  for (byte i = 0; i < 4; i++) {
    receivedVal16[i] = SPI.transfer(val16);
    Serial.print(receivedVal16[i], BIN);
    Serial.print(" ");
  }
  digitalWrite(10, HIGH);
  Serial.println();
  delay (1000);
}

Ciao! Niente, la scheda carica il firmware, mi stampa una sola volta sul monitor seriale uno O e poi si blocca nel senso che ne TX ne RX lampeggiano.
Sembra che si blocchi nel ciclo for. Può essere?

ciao...hai provato come SPI_MODE1 o 2 o 3 ?
abbassa anche la velocità del clock da 800000 a 500000.

Ciao, si ho provato me senza successo. Ho contattato l’azienda per saperne di più e mi hanno risposto che loro utilizzano questo codice per verificare se il sensore funziona.

case {ABP_type):
                debug_print {"ABP type read sensor\n"): 
                //if che inter-.:ace type is SPI
                if (Sensorlnterface = 2 ) 
                    { 
                      debug_print {"ABP type read sensor-SPI\n\n"); 
                      if (SleepEnabled == 1 ) 
                        {
                        //Pull down Chip Select
                        digitalWrite (PRESS_CS, LOW); 
                        //delay
                        for (iCnt = O; iCnt <= 100; iCnt++ ); 
                        //Pull up chip selecc
                        digitalWrite(PRESS_CS, HIGH); //
                        //Wait for conversion cime 
                        delay(2); 
                       }
                     //Pull down Chip Select
                     digitalWrite ( PRESS_CS, LOW); 
                     //Read four bytes of data
                     PushData(SPI.transfer(2SS));
                     PushData(SPI.transfer(2SS));
                     PushData(SPI.transfer(2SS));
                     PushData(SPI.transfer(2SS)); 
                     // Pull up chip select
                     digitalWrite( PRESS_CS, HIGH);
                     }

Inoltre mi hanno specificato che quando programmano il sensore con arduino utilizzano una loro shield cioè questa

pensi che mi serva davvero?

ciao...non penso che la shield sia necessaria per leggere i valori.
Hai postato quel pezzo di programma facendo un copia/incolla o scrivendolo a mano?...
comunque nel tuo codice sostituisci il:

receivedVal16[i] = SPI.transfer(val16);
// dove val16 parte da 0x00 cioè 0

con:

receivedVal16[i] = SPI.transfer(255);

Dato che, se non ho capito male, SPI funziona in invio/ricezione alternato BIT su BIT, in questo modo invece di inviare sempre "0" invierai sempre "1"...

Ciao, ho provato ad utilizzare dei print per vedere dove si blocca il tutto e ho notato che il programma si blocca una volta che va a leggere il secondo byte. Infatti come puoi vedere dallo screen che ho allegato, entra nel ciclo, legge il primo byte, cicla una seconda volta e poi si blocca. Cosa può essere?

Se invece rimuovo la riga di codice:

receivedVal16[i] = SPI.transfer(255);

il ciclo continuascia

ciao...penso si blocchi li per via del while contenuto in quel metodo:

while (!(SPSR & _BV(SPIF))) ;

che dovrebbe controllare se il tuo registro è stato inviato e riscritto.

Allora ritorno su l'ultimo suggerimento...non inviafre 255 ma 0.
sei sicuro dei collegamenti ?
hai alimentato il sensore con i 3,3 Volt?
non sono un espertissimo di eletronnica...quindi forse ti conviene chiedere se c'è qualche resistenza da mettere nelle varie linee....