I2C e Attiny

Come da link, questo codice dovrebbe mettere in comunicazione bidirezionale 2 arduino.
Io sto tentando (oltre che di capirlo) di farne una copia da caricare sull’ attiny85 (o 84) per mettere in comunicazione l’arduino con il tiny.
Ovviamente io che non ci sto capendo 1 mazza di tutto ciò :blush: mi blocco quando vedo che la libreria tinyWire non supporta questo comando: Wire.onReceive(receiveEvent); e cambiarlo con
receiveEvent=TinyWireS.Receive; non funzia.

cosa devo fare? :fearful:
e soprattutto sto facendo giusto a sostituire i vari comandi wire.xx con tiny.wire.S.xx?

Inoltre, cosa significa la graffa dopo le due tonde? dove si chiude?
To Receive:
someByte = TinyWireS.available(){ // returns the number of bytes in the received buffer
someByte = TinyWireS.receive(){ // returns the next byte in the received buffer

http://digitalcave.ca/resources/avr/arduino-i2c.jsp

/**
 *
 * Sample Multi Master I2C implementation.  Sends a button state over I2C to another
 * Arduino, which flashes an LED correspinding to button state.
 * 
 * Connections: Arduino analog pins 4 and 5 are connected between the two Arduinos, 
 * with a 1k pullup resistor connected to each line.  Connect a push button between 
 * digital pin 10 and ground, and an LED (with a resistor) to digital pin 9.
 * 
 */

#include <Wire.h>

#define LED 9
#define BUTTON 10

#define THIS_ADDRESS 0x8
#define OTHER_ADDRESS 0x9

boolean last_state = HIGH;

void setup() {
  pinMode(LED, OUTPUT);
  digitalWrite(LED, LOW);
  
  pinMode(BUTTON, INPUT);
  digitalWrite(BUTTON, HIGH);
  
  Wire.begin(THIS_ADDRESS);
  Wire.onReceive(receiveEvent);
}

void loop() {
  if (digitalRead(BUTTON) != last_state){
    last_state = digitalRead(BUTTON);
    Wire.beginTransmission(OTHER_ADDRESS);
    Wire.send(last_state);
    Wire.endTransmission();
  }
}

void receiveEvent(int howMany){
  while (Wire.available() > 0){
    boolean b = Wire.receive();
    Serial.print(b, DEC);
    digitalWrite(LED, !b);
  }
  Serial.println(); 
}

onEvent è diverso da receive: onEvent richiama una subroutine all'arrivo di dati, mentre receive() si mette in ricezione immediatamente.

someByte = TinyWireS.available(){ immagino sia un esempio. Vorrà dire solo che dopo va messo il blocco di codice, immagino. In quel modo è errato.

Fino a lì ci ero arrivato, è oltre che non vado, cioè come usare l'equivalente di onevent su attiny... Mi sa che non ne vado fuori con sto i2c, con la scusa dell'influenza è da ieri che cerco di fare qualcosa ma... :blush:

Non mi ricordo i metodi che quelle classi implementano. Ma non è detto che ci siano tutti quelli della Wire.

EDIT: Difatti il metodo onReceive NON c'è:

TODO:   (by others!)
    - onReceive and onRequest handlers are not implimented.

leo72: Non mi ricordo i metodi che quelle classi implementano. Ma non è detto che ci siano tutti quelli della Wire. Difatti il metodo onReceive NON c'è:

TODO: (by others!)
    - onReceive and onRequest handlers are not implimented.

si Leo avevo visto, le 2 linee con la graffa di prima vengono da là. Ma allora che comando devo dare (parliamo dell'attiny) per metterlo in ascolto e attivare qualche routine o comando all'arrivo di segnali dal bus?

Basta che controlli se esistono dei caratteri sulla linea.

void loop() {
  if (TinyWireS.available()) { // ho trovato qualcosa!
    .......codice I2C
  }
  .....altro codice....
}

ah! giusto, graziee XD

Ok funziona! XD altro passettino compiuto... 2 pulsantini su arduino come master trasmettono all'attiny il rispettivo valore 1 e 3 che mi fa lampeggiare un led rosso 3 volte o uno rosso 1 volta via i2c. Ora la domandina su questo loop:

void loop(){  
  byte ricevuto = 0;

  if (TinyWireS.available()){           // got I2C input!
    ricevuto = TinyWireS.receive();     // get the byte from master
    if (ricevuto==1){
      Blink(LED1_PIN,ricevuto);           
    }
    if (ricevuto==3){
      Blink(LED2_PIN,ricevuto);
    }
  }

}

perchè c'è byte che definisce ricevuto? se metto int non va bene lo stesso? Ancora, posso inviare stringhe o solo 1 numero alla volta?

MatteoG: perchè c'è byte che definisce ricevuto? se metto int non va bene lo stesso?

Perché tu hai un PC con 4 megabyte di memoria ma qui stai lavorando con un microcontrollore che ha 8 kB di Flash e 512 byte di SRAM! E perché stai usando il modello 85, se usavi il 25 avevi 2 kB di Flash e 128 byte di SRAM! Quindi, regola numero 1: SEMPRE ottimizzare le risorse. Perché usare un "int", che occupa 2 byte in memoria, quando il mio valore non passerà mai il valore massimo di 3, che può quindi benissimo stare dentro ad un tipo "byte" apputnto, occupando quindi solo 1 byte di memoria? :P

Ancora, posso inviare stringhe o solo 1 numero alla volta?

Puoi inviare quello che ti pare, ricordati però che la trasmissione diventa byte per byte quindi una stringa creala come char* così da poterla spedire e ricevere come l'hai inviata. L'oggetto String nelle trasmissioni a me crea sempre un po' di complicazioni.

leo72: Perché tu hai un PC con 4 megabyte di memoria

pochini sarebbero... XD XD

quando il mio valore non passerà mai il valore massimo di 3,

...non ho capito perchè non passerà mai il 3 :blush:

per il discorso ottimizzare ok ho capito.

MatteoG:

leo72: quando il mio valore non passerà mai il valore massimo di 3,

...non ho capito perchè non passerà mai il 3 :blush:

per il discorso ottimizzare ok ho capito.

perché il programma é scritto cosí, la variabile "ricevuto" assume solo i valori 1 e 3 e visto che la I2C manda sempre 1 Byte i valori possibili sono tra 0 e 255.

Ciao Uwe

uwefed:

MatteoG:

leo72: quando il mio valore non passerà mai il valore massimo di 3,

...non ho capito perchè non passerà mai il 3 :blush:

per il discorso ottimizzare ok ho capito.

perché il programma é scritto cosí, la variabile "ricevuto" assume solo i valori 1 e 3 e visto che la I2C manda sempre 1 Byte i valori possibili sono tra 0 e 255.

Ciao Uwe

Ah ok! non capivo perchè quel 3 l'ho messo io a caso... :grin: scusate la confusione. quindi per ipotesi potrei definire la variabile come int e dargli qualsiasi valore ? oppure sarebbe limitata a 255 comunque? Ottimizzazione a parte, è per capire come funziona.

per la cronaca:
I valori possibili per un int sono da -32mila e qualcosa a +32mila e qualcosa.
http://arduino.cc/en/Reference/Int
http://arduino.cc/en/Reference/UnsignedInt
http://arduino.cc/en/Reference/Long
http://arduino.cc/en/Reference/UnsignedLong

Ciao Uwe

uwefed: per la cronaca: I valori possibili per un int sono da -32mila e qualcosa a +32mila e qualcosa. http://arduino.cc/en/Reference/Int http://arduino.cc/en/Reference/UnsignedInt http://arduino.cc/en/Reference/Long http://arduino.cc/en/Reference/UnsignedLong

Ciao Uwe

ok, quello che non mi è chiaro è se si può , e come, mandare un valore grande int tramite i2c. Cioè un valore tipo non so 4,294,967,295 (per citare l'esempio linkato) passa o è limitato a 255? Abbiate pazienza, sto imparando... XD

Come ti ho detto, la spedizione avviene per byte per cui un long (signed o unsigned non cambia) verrà spedito scomposto nei 4 byte che lo compongono. In ricezione basta “ricostruire” il long.

unsigned long numero;
numero=(TinyWireS.receive()<<24) | (TinyWireS.receive()<<16) | (TinyWireS.receive()<<8) | TinyWireS.receive());

Ricostruisci un long recuperando 4 byte via I2C. Come trasmetterli dipende dal protocollo di trasmissione, che ho tralasciato di analizzare ma che devi fare tu.

Per protocollo di trasmissione intendi dire che devo scomporre il numero in 4 parti e spedirle, cioè il contrario dell’esempio che mi hai messo,giusto?

Cosa significa <<8 <<16 e <<24? Intuisco abbia a che fare con gli 8 bit di un byte ma a cosa serve indicarli con il maggiore(<<)?

poi, è Bitwise OR (|) il simbolo verticale?

infine, quando scompongo il numero prima di trasmetterlo devo usare la stessa sintassi?

Quanto riportato in reference nel sito è per livello superiore al mio, dove si può trovare materiale da leggere che spieghi queste cose di cui stiamo parlando partendo da più in basso? Si, google, ma cosa cerco?

Le parentesi tonde dopo la funzione serve per traferire parametri dalla alla funzione, esempio di codice; int temperaturePin = 0; // Inizializzazione, il pin analogico A0 di Arduino uscita del segnale dal sensore float voltage = getVoltage(temperaturePin); // Ottiene il valore in tensione dal sensore di temperatura chiamando la funzione // getVoltage(temperaturePin); la quale restituisce il valore e l'assegna a // voltage float temperatura = (voltage - .5) * 100; // Converte dai 10mV / grado centigrado con la tensione dei 500mV di offset Serial.print("Temperatura = "); // Stampa su Serial Monitor Temperatura = Serial.println(temperatura); // Stampa il valore di temperatura ricavata dalla formula

float getVoltage(int pin) { // funzione getVoltage riceve come parametro il pin analogico di Arduino // (temperaturePin) dato dalla chiamata della funzione il quale viene rinominato // con la variabile ad intero pin return (analogRead(pin) * .004882814); // Converte i valori da 0 ai 5V in valori digitali da 0 a 1023 // il valore letto di 1 digitale è circa uguale a ~ 5mV // return restituisce il parametro calcolato } Le parentesi graffe racchiudono la funzione o le operazioni eseguite e le rende private ossia non globali ne pubbliche a tutto il programma.

grazie XD

Ma di nulla figurati......dimenticavo la funzione non deve essere dichiarata come "void" ad esempio void getVoltage(int pin) {............................................} altrimenti riceve parametri ma non restituisce nulla, float getVoltage(int pin) {............................................} in questo caso quello che restituisce o un valore decimale o in virgola mobile chiamato volgarmente. Per quanto riguarda questo "Le parentesi graffe racchiudono la funzione o le operazioni eseguite e le rende private ossia non globali ne pubbliche a tutto il programma." significa che puoi dare lo stesso nome ad altre variabili ma utilizzate in ambito privato o a un'altra funzione senza alcun pericolo che siano mescolate essendo private, ovviamente per comodità e per evitare confusioni in caso di debugging si danno nomi diversi sia per distinguerle da quelle pubbliche o globali che a quelle date ad altre funzioni. ciao.....

MatteoG:
Per protocollo di trasmissione intendi dire che devo scomporre il numero in 4 parti e spedirle, cioè il contrario dell’esempio che mi hai messo,giusto?

Un protocollo di trasmissione è uno standard che definisce come trasmettere i dati. Siccome ti stai facendo un sistema per comunicare tra 2 chip, dovrai studiare il modo per aprire la connessione, inviare i comandi, i dati, e chiuderla.

Cosa significa <<8 <<16 e <<24? Intuisco abbia a che fare con gli 8 bit di un byte ma a cosa serve indicarli con il maggiore(<<)?

Sposti gli 8 bit del byte ricevuto di 8, 16, 24 bit a sinistra (<<) all’interno di un long (4 byte).
Quindi spostarlo di 24 bit significa che il tuo ottetto occuperà le 8 posizioni più significative (gli 8 bit più a sinistra, dal 31° al 24 bit) del numero, poi il secondo verrà spostato di 16 bit sempre a sinistra (dal 23° bit al 16) ecc…
Alla fine avrai un long composto dai 4 byte in cui era stato scomposto il dato in fase di trasmissione.

poi, è Bitwise OR (|) il simbolo verticale?

Sì, si usa per sommare (inteso come “fondere insieme”) il valore di 2 numeri bit-per-bit.

infine, quando scompongo il numero prima di trasmetterlo devo usare la stessa sintassi?

Sarebbe meglio spedirlo byte per byte.

Quanto riportato in reference nel sito è per livello superiore al mio, dove si può trovare materiale da leggere che spieghi queste cose di cui stiamo parlando partendo da più in basso? Si, google, ma cosa cerco?

Le operazioni sui bit sono la base della manipolazione delle singole celle del calcolatore. Ci sono tanti documenti, prova cercando “bit manipulation”.