Programmazione avanzata arudino

Buona sera a tutti! Inizio questo topic per capire qualcosa in più su come interfacciare i sensori con Arduino senza usare librerie già pronte. Per esempio, per usare il sensore DHT11 (o il DHT22) cosa bisogna "fare"? oppure per il DS18B20, come fare per "sentire cosa dice"? Finchè si tratta di valori analogici con una semplice conversione si trova il dato cercato, ma come districarsi tra datasheet e protocolli? Probabilente continuerò ad usare librerie già esistenti, ma vorrei provare a capire qualcosa in più del semplice scomapatta libreria. Scusate per la confusione spero capiate cosa intendo, ma, in caso contrario, provvederò a rendermi più esplicito. XD Grazie mille!

La risposta è semplice: devi scriverti tu il codice :wink:

A parte gli scherzi, una libreria è un modo semplificato per fare qualcosa usando del codice scritto da altri.
Ad esempio, l’interfacciarsi con i tuoi sensori DHTxx.

Come si deve fare? Devi partire dal datasheet del componente e studiarti innanzi tutto come lavora, poi come si collega ed infine come dialogarci. A questo punto devi metterti lì e replicare via software il modo di comunicarci che hai studiato sul datasheet. Potrebbe essere facile come no. Ad esempio, se hai un componente che comunica via One-Wire, ti prendi la libreria One-Wire e poi spedisci i comandi che il sensore accetta e poi leggi sempre con quella libreria cosa esso “dice”.
La One-Wire ti semplifica la vita perché è una libreria che implementa un protocollo di comunicazione. Se poi ti trovi anche la libreria che gestisce quel componente (es. DS18B20) sei a cavallo: includi 2 lib e sei a posto.
Ma se vuoi scriverti tutto da solo, devi:

  1. scriverti il software per implementare la comunicazione One-Wire
  2. scriverti il codice per comunicare con il DS18B20.

Capisci bene che con il tempo che sprechi a fare queste cose avevi già scritto il tuo programma usando le librerie fatte da altri :wink:

Grazie mille Leo! Sì, io facevo un discorso giusto per capire, poi magari nell'applicazione pratica userò librerie pronte. Possiamo far l'esempio del DHT11? http://www.micro4you.com/files/sensor/DHT11.pdf è il data, da cosa capisco come lavora? Se permetete, provo a rispondermi da solo :stuck_out_tongue_closed_eyes:: fine pagina 5, inizio 6. Dice che trasmette 40 bit, ma io come faccio a capire quando e quale è il bit? come faccio a farlo capire ad arduino? :(

E' tramite il protocollo One-Wire. Devi prenderti le specifiche del protocollo, studiartele e replicare il protocollo via software. A questo punto, avendo il protocollo di comunicazione, gestire quei 40 bit diventa compito del protocollo. Ecco come avere quei 40 bit:

When MCU sends a start signal, DHT11 changes from the low-power-consumption mode to the running-mode, waiting for MCU completing the start signal. Once it is completed, DHT11 sends a response signal of 40-bit data that include the relative humidity and temperature information to MCU. Users can choose to collect (read) some data. Without the start signal from MCU, DHT11 will not give the response signal to MCU. Once data is collected, DHT11 will change to the low-power-consumption mode until it receives a start signal from MCU again.

Quindi prima ti scrivi la One-Wire, poi con questa interroghi il chip. E poi il tuo codice troverà i dati in base a quei 40 bit.

Ecco perché ti dico che è sempre meglio, quando si può, evitare di reinventare la ruota ;)

ok, quindi si usa il one-wire, e quindi quasi sicuramente libreria, ma cosa darebbe fuori, già i dati leggibili? P.s. Per le specifiche del protocollo, wikipedia?

--> http://en.wikipedia.org/wiki/1-Wire

SUBSEA: ok, quindi si usa il one-wire, e quindi quasi sicuramente libreria, ma cosa darebbe fuori, già i dati leggibili?

Sì, assemblati in quei 40 bit in un certo ordine, compreso un CRC di controllo, da cui poi tu devi estrarli e ricomporre l'informazione.

Quindi dice già temperatura e umidità? E la conversione da bit a leggibile la fa il one wire? Ultima cosa su wiki ce scritto già come interpretare i dati? E questi dati come arrivano? 001101 ecc? Se si, come Vanno riconosciuti da Arduino? Grazie ancora per la pazienza! :sweat_smile: :grin:

SUBSEA: Quindi dice già temperatura e umidità?

Così dice il datasheet. Pag. 5

E la conversione da bit a leggibile la fa il one wire?

No. One-Wire è il canale di trasmissione. La conversione la fa l'algoritmo che spedisce le richieste al sensore e che riceve i dati da questo. Che sia una lib già fatta o un tuo codice, il succo non cambia.

Ultima cosa su wiki ce scritto già come interpretare i dati? E questi dati come arrivano? 001101 ecc? Se si, come Vanno riconosciuti da Arduino? Grazie ancora per la pazienza! :sweat_smile: :grin:

Continui a fare confusione fra canale di trasmissione e dati trasmessi su quel canale ;) I dati ogni sensore li spedisce secondo un proprio protocollo di trasmissione, nel caso del DHT11 è scritto nel PDF che hai linkato (pag 5):

Data format: 8bit integral RH data + 8bit decimal RH data + 8bit integral T data + 8bit decimal Tdata + 8bit check sum. If the data transmission is right, the check-sum should be the last 8 bit of "8 bit integral RH data+ 8 bit decimal RH data + 8 bit integral T data + 8 bit decimal T data"

Grazie ancora, approfitterò ancora un po' della tua esperienza.

La conversione la fa l'algoritmo che spedisce le richieste al sensore e che riceve i dati da questo. Che sia una lib già fatta o un tuo codice, il succo non cambia.

questo algoritmo quindi prende questi

Data format: 8bit integral RH data + 8bit decimal RH data + 8bit integral T data + 8bit decimal Tdata + 8bit check sum. If the data transmission is right, the check-sum should be the last 8 bit of "8 bit integral RH data+ 8 bit decimal RH data + 8 bit integral T data + 8 bit decimal T data

e li rende leggibili. Ma Arduino come fa a sapere quale è un bit? glielo dice il one wire? e poi, questi bit sono 0 e 1, giusto? come faccio a dire: bene, dopo 8 0 o 1 che ti arrivano fermali e converti da binario a decimale (se così bisogna fare)?

Un consiglio, per capire certe cose spesso è meglio vederle che *sentirle * ;) Quindi prendi la lib One-Wire ed una lib che accede ai DHTxx e studiati i sorgenti.

ok, provo a fare così, poi se non capisco chiedo! quindi, preparatevi!!! XD

SUBSEA: preparatevi!!! XD

Dobbiamo studiare la one-wire anche noi? :sweat_smile:

rieccomi! Allora, intanto quale file devo aprire? :sweat_smile:
Proviamo col .h

 private:
  uint8_t data[6];
  uint8_t _pin, _type, _count;
  boolean read(void);
  unsigned long _lastreadtime;
  boolean firstreading;

 public:
  DHT(uint8_t pin, uint8_t type, uint8_t count=6);
  void begin(void);
  float readTemperature(bool S=false);
  float convertCtoF(float);
  float readHumidity(void);

};

E’ qui che legge i bit? mmmm, credo di no. Proviamo con questo:

DHT::DHT(uint8_t pin, uint8_t type, uint8_t count) {
  _pin = pin;
  _type = type;
  _count = count;
  firstreading = true;
}

void DHT::begin(void) {
  // set up the pins!
  pinMode(_pin, INPUT);
  digitalWrite(_pin, HIGH);
  _lastreadtime = 0;
}

//boolean S == Scale.  True == Farenheit; False == Celcius
float DHT::readTemperature(bool S) {
  float f;

  if (read()) {
    switch (_type) {
    case DHT11:
      f = data[2];
      if(S)
      	f = convertCtoF(f);
      	
      return f;
    case DHT22:
    case DHT21:
      f = data[2] & 0x7F;
      f *= 256;
      f += data[3];
      f /= 10;
      if (data[2] & 0x80)
	f *= -1;
      if(S)
	f = convertCtoF(f);

      return f;
    }
  }
  Serial.print("Read fail");
  return NAN;
}

float DHT::convertCtoF(float c) {
	return c * 9 / 5 + 32;
}

float DHT::readHumidity(void) {
  float f;
  if (read()) {
    switch (_type) {
    case DHT11:
      f = data[0];
      return f;
    case DHT22:
    case DHT21:
      f = data[0];
      f *= 256;
      f += data[1];
      f /= 10;
      return f;
    }
  }
  Serial.print("Read fail");
  return NAN;
}


boolean DHT::read(void) {
  uint8_t laststate = HIGH;
  uint8_t counter = 0;
  uint8_t j = 0, i;
  unsigned long currenttime;

  // pull the pin high and wait 250 milliseconds
  digitalWrite(_pin, HIGH);
  delay(250);

  currenttime = millis();
  if (currenttime < _lastreadtime) {
    // ie there was a rollover
    _lastreadtime = 0;
  }
  if (!firstreading && ((currenttime - _lastreadtime) < 2000)) {
    return true; // return last correct measurement
    //delay(2000 - (currenttime - _lastreadtime));
  }
  firstreading = false;
  /*
    Serial.print("Currtime: "); Serial.print(currenttime);
    Serial.print(" Lasttime: "); Serial.print(_lastreadtime);
  */
  _lastreadtime = millis();

  data[0] = data[1] = data[2] = data[3] = data[4] = 0;
  
  // now pull it low for ~20 milliseconds
  pinMode(_pin, OUTPUT);
  digitalWrite(_pin, LOW);
  delay(20);
  cli();
  digitalWrite(_pin, HIGH);
  delayMicroseconds(40);
  pinMode(_pin, INPUT);

  // read in timings
  for ( i=0; i< MAXTIMINGS; i++) {
    counter = 0;
    while (digitalRead(_pin) == laststate) {
      counter++;
      delayMicroseconds(1);
      if (counter == 255) {
        break;
      }
    }
    laststate = digitalRead(_pin);

    if (counter == 255) break;

    // ignore first 3 transitions
    if ((i >= 4) && (i%2 == 0)) {
      // shove each bit into the storage bytes
      data[j/8] <<= 1;
      if (counter > _count)
        data[j/8] |= 1;
      j++;
    }

  }

  sei();
  
  /*
  Serial.println(j, DEC);
  Serial.print(data[0], HEX); Serial.print(", ");
  Serial.print(data[1], HEX); Serial.print(", ");
  Serial.print(data[2], HEX); Serial.print(", ");
  Serial.print(data[3], HEX); Serial.print(", ");
  Serial.print(data[4], HEX); Serial.print(" =? ");
  Serial.println(data[0] + data[1] + data[2] + data[3], HEX);
  */

  // check we read 40 bits and that the checksum matches
  if ((j >= 40) && 
      (data[4] == ((data[0] + data[1] + data[2] + data[3]) & 0xFF)) ) {
    return true;
  }
  

  return false;

}

AIUTOOO!! e’ pieno di unit8!!! :slight_smile:

Per favore non urlare.... :roll_eyes: Inoltre sono uint8, non unit8... Se conosci il C, sai che uint8 è l'unsigned char, che in Arduino corrisponde al tipo "byte".

Scusa. :( comunque, all'inizio dichiara delle variabili, e mi sembra di aver capito che i dati sono conenuti in data[ ]. È un arrai? Avrebbe un senso, perche contiene i vari bit, ma come ha fatto a leggerli?tuttora letti penso si trasformino da binario a decimale, giusto?

Le parentesi quadre indicano un vettore, o array. Ma queste sono le basi del C/C++. :sweat_smile: :sweat_smile:

Sei sicuro di voler scrivere una tua libreria per la gestione del protocollo OneWire?

SubSea, forse dovresti accantonate temporaneamente questa impresa. Reperire o acquistare un libro sul C e imparare le basi del linguaggio.
Se non sai neanche che file aprire tra .h e .cpp, non hai le basi per poterti costruire una tua libreria.
Ci sono degli ottimi tutorial anche su internet tra cui
http://cpiupiu.altervista.org/ (http://www.cpiupiu.tk/)
http://www.html.it/guide/guida-c2/
http://www.sitoserio.it/cpp/
http://www.tuttogratis.it/studenti/manuali_c_gratis.html
Dev.Labs - C++

oh sì, dovrei davvero imparare il C, e penso userò il link di html che mi sembra davvero ben fatto. Posso solo togliermi la curiosità di come fa arudino a capire quando inizia e quando finisce il byte? Non solo per qquesto tipo di sensore, ma metti che un giorno mi servisse usare un adc che mi dà fuori dei bit. Come faccio a far capire all'arduino che quello che scrive l'integrato è un bit? poi dovremo dirgli mettilo insieme fino a 8 (o più), e poi converti da binario a decimale, ma questo magari mi sarà più chiaro dopo aver approfondito il C. Grazie ancora per la pazienza. :sweat_smile:

Subsea, è il protocollo di trasmissione che si occupa di gestire questo. Ad esempio, il protocollo può essere 1 bit di avvio - 8 bit di dati - 1 bit di stop. Quindi il sensore per esempio trasmetterà 10 bit di cui però solo 8 saranno interessanti per te. Oppure nel caso di cui parlavamo sopra, ci sono 40 bit spediti che saranno composti da un mix di dati di sincronizzazione (start/stop), dai dati veri e propri e dal CRC di controllo.