arduino / i2c-sensor-sketch auf attiny übertragen ?

hallo zusammen,

ich würde gerne ein beleuchtungssensor (BH1750) mit einem attiny ausslesen.......

mit einem arduino hats geklappt, aber ich hab nicht viel ahnung von i2c und erst recht nicht, von ic2 auf attiny......
wo die pins sind, hab ich rausgefunden. (ist es noch möglich, die pind für sda und scl zu wechseln - softwaremäßig?)
auch das ich vielleicht die tinywireS für einen attiny 84 nehmen kann ?

aber ich hab im moment leider keien idee, wie ich den sketch umschreibe.

#include <Wire.h>

#include <SoftwareSerial.h>
SoftwareSerial softSerial(88, 3 ); //rx= physikalisch Pin 3(attiny85) Pin 11?(attiny84), tx= physikalisch Pin 2(attiny85) Pin 10(attiny84)


byte buff[2];


void setup()
{
  softSerial.begin(9600);
  Wire.begin();
  
  Wire.beginTransmission(0x23);
  Wire.write(0x11); // 0,5 lux aufloesung
  Wire.endTransmission();


}

void loop()
{
  
  byte i=0;
  Wire.beginTransmission(0x23);
  Wire.requestFrom(0x23, 2);
  
  while(Wire.available())
  {
    buff[i] = Wire.read(); 
    i++;
  }
  Wire.endTransmission();
  
  
  float valf=0;

  if(i == 2)
  {
    valf=((buff[0]<<8)|buff[1])/1.2;
    
    if(valf<0)
    softSerial.print("> 65535");
    else 
    softSerial.print((int)valf,DEC); softSerial.println(" lx"); 
  }
  
  
  delay(1000);
}

noch mal eine frage nebenher:
ist für die kommunikation zwischen mehreren attinys softserial oder i2c besser geeignet ?
es sollen strings verschickt werden.

Da sowohl I2C als auch UART auf deinen Attinys nur in Software eingebunden ist, bleibt weiterhin beides nicht sonderlich ratsam. Ansonsten hat I2C einen Vorteil gegenüber UART, dass es ohne extra Hardware (ausser Hühnerfutter) an einem 2 Draht Bus betrieben werden kann.

gibts denn eine alternative ? .....sorry, kenn mich da noch nicht so aus......

was den code angeht, haut das so hin:

#include <TinyWireS.h>

#include <SoftwareSerial.h>
SoftwareSerial softSerial(88, 3 ); //rx= physikalisch Pin 3(attiny85) Pin 11?(attiny84), tx= physikalisch Pin 2(attiny85) Pin 10(attiny84)


byte buff[2];


void setup()
{
  softSerial.begin(9600);
  
  TinyWireS.begin(0x23);
  TinyWireS.onRequest(0x23);
  TinyWireS.send(0x11); // 0,5 lux aufloesung
  TinyWireS_stop_check();


}

void loop()
{
  
  byte i=0;
  TinyWireS.begin(0x23);
  TinyWireS.onRequest(0x23);
  
  while(TinyWireS.available())
  {
    buff[i] = TinyWireS.receive(); 
    i++;
  }
  TinyWireS_stop_check();
  
  
  float valf=0;

  if(i == 2)
  {
    valf=((buff[0]<<8)|buff[1])/1.2;
    
    if(valf<0)
    softSerial.print("> 65535");
    else 
    softSerial.print((int)valf,DEC); softSerial.println(" lx"); 
  }
  
  
  delay(1000);
}

werds gleich mal testen (;......

ne leider nicht:

sketch_jun15b.ino: In function 'void setup()':
sketch_jun15b:16: error: invalid conversion from 'int' to 'void ()()' [-fpermissive]
In file included from sketch_jun15b.ino:2:0:
D:\Desktop\arduino sketche\arduino-1.6.4 -Nano\libraries\TinyWireS/TinyWireS.h:54:10: error: initializing argument 1 of 'void USI_TWI_S::onRequest(void (
)())' [-fpermissive]
void onRequest( void ()(void) );
^
sketch_jun15b.ino: In function 'void loop()':
sketch_jun15b:28: error: invalid conversion from 'int' to 'void (
)()' [-fpermissive]
In file included from sketch_jun15b.ino:2:0:
D:\Desktop\arduino sketche\arduino-1.6.4 -Nano\libraries\TinyWireS/TinyWireS.h:54:10: error: initializing argument 1 of 'void USI_TWI_S::onRequest(void ()())' [-fpermissive]
void onRequest( void (
)(void) );
^
invalid conversion from 'int' to 'void (*)()' [-fpermissive]

onRequest() ist eine Art Event Handler. Da musst du eine Funktion übergeben, die aufgerufen wird wenn ein Request für Daten ankommt. Nicht die Adresse.

Das brauchst du aber beim Empfang sowieso nicht. Das ist für das Senden. Für den Empfang gibt es den onReceive() Handler.

Schau dir die Beispiele zur normalen I2C Klasse an:

EDIT:
Ich verwende "den Slave so implementiert wie man es von einem IC kennt" gerne und erfolgreich.

Ohne Kontext verwirrst du ihn aber auch. Normal sollte man im Receive Event direkt die Daten auslesen können.

Den Code den du gepostet hast ist von einem meiner Beispiele. Das hatte ich so gemacht, weil es irgendwie nicht anders ging und man immer aus irgendeinem Grund immer nur ein Byte auslesen konnte. Also hatte ich es so gemacht, das der Index vom anderen Arduino gesetzt werden konnte und bei einem Request nur ein Byte aus diesem Index gesendet wird.

Funktioniert, aber normal ist das nicht :slight_smile:

vielen dank !

also mit onReceive bekomm ich die gleiche fehlermeldung...

denke mal, es liegt an der adresse, des sensors: 0x23 .......der will ein int haben...

nochmal nebeinbei gefragt, der sensor kann ja bis 10000lux.... mit dem sketch ganz oben bekomme ich ja leider nur bis 65535lux..... was kann man da machen ?
65535 is ja schon recht wenig..... damit bekomme ich nichtmal eine schreibtischlampe, mit einer led gemessen.....
könnt ihr mir vielleicht ein besseren, zuverlässigen sensor empfehlen, der bis ca. 100000lux oder mehr geht ?

magictrips:
nochmal nebeinbei gefragt, der sensor kann ja bis 10000lux.... mit dem sketch ganz oben bekomme ich ja leider nur bis 65535lux..... was kann man da machen ?
65535 is ja schon recht wenig..... damit bekomme ich nichtmal eine schreibtischlampe, mit einer led gemessen.....
könnt ihr mir vielleicht ein besseren, zuverlässigen sensor empfehlen, der bis ca. 100000lux oder mehr geht ?

Da ist dir eine Null unter den Tisch gefallen...

Der Parameter ist eine Funktion!!! Keine die Device-Adresse. Er will eben gerade nicht einen int haben (was das ist was du übergibst).

Das ist ja auch genau was an gemeckert wird:

invalid conversion from 'int' to 'void (*)()'

void(*)() ist ein Zeiger auf eine Funktion. Du musst da den Namen einer Funktion übergeben die keinen Rückgabewert (d.h. void) und keine Parameter hat. Du übergibst statt dessen einen int

onReveive(): die Funktion die man hier übergibt wird aufgerufen wenn Daten ankommen die der Master mit endTransmission() sendet
onRequest(): die Funktion die man hier übergibt wird aufgerufen wenn der Master requestFrom() macht

Wenn der Master ständig sendet und der Slave auslesen soll nimm das hier:

Wenn der Master Daten vom Slave abfragen soll, das hier:

Da du einen Sensor hast, willst du den Master Teil MasterReader. onRequest() und onReceive() brauchst du also überhaupt nicht. Entsprechend braucht du aber auch TinyWireM!

TinyWireS ist für einen Slave.

Das ist für die Hardware I2C Klasse geschrieben, aber geht so analog auch mit TinyWire

Und nochwas:
beginTransmission() fängt das Senden an. endTransmission() schließt das Senden ab. Und nur das Senden! Um Daten anzufordern macht man requestFrom(). Aber ohne beginTransmission()/endTransmission() !

Wobei du dir da auch mal das Datenblatt des Sensors durchlesen musst. Da muss man wohl erst mal ein Kommando-Byte hinschicken um die Messung zu starten, dann einige Zeit warten und dann auslesen. Da gibt es auch mehrere Modi.

Auch muss man den Sensor erst mal einschalten, da er am Anfang im Powerdown ist. Siehe Seite 4:
http://rohmfs.rohm.com/en/products/databook/datasheet/ic/sensor/light/bh1750fvi-e.pdf

vielen dank für die infos !

funktioniert die tinyWireM denn mit dem attiny84 ???
so wie ich das verstehe, funktioniert bei dem nur die TinyWireS ?
http://letsmakerobots.com/node/39130

und wie ich mit dem sensor bis 100000lux messen kann verstehe ich auch nicht.
im datenblatt steht nur:
11) Adjustable measurement result for influence of optical window
( It is possible to detect min. 0.11 lx, max. 100000 lx by using this function. )

Da kenne ich mich nicht so aus

Um das noch mal klar zu machen wie die I2C Kommandos funktionieren.

Senden:

beginTransmission(DEVICE_ADDRESS);
write(...);
....
endTransmission();

Daten lesen:

requestFrom(DEVICE_ADDRESS, NUMBER_OF_BYTES);
read();
read();

Und nicht durcheinander. Zum Lesen brauchst du nur requestFrom() und read()

Dann gibt es zwei Modi mit je drei Auflösungen. One Time geht nach der Messung wieder in Power Down. Bei dem Continious Mode ist mir ganz klar ob da wirklich ständig gemessen wird oder ob er nur nicht nach Powerdown geht. Es liest sich fast so, also ob wirklich ständig gemessen wird und man nur die erste Messung anfordern muss. Da bin ich mir nicht sicher.

Und zwischen Anforderung und Auslesen musst du je nach Auflösung 16 oder 120ms warten

und wie ich mit dem sensor bis 100000lux messen kann verstehe ich auch nicht.

Seite 11 glaube ich

Das Datenblatt ist aber nicht sauber übersetzt.

ich hab eine sehr interessante lib für den sensor gefunden:

zeigt mir bis maximal 117758.2lux an.........
das sind ja 177758,2 mehr, als der sensor können soll.......
ist das möglich oder ist das ein berechnungsfehler in der lib ?

ich würde gerne aus der lib den teil zur sensor-überprüfung und den teil zum messen von 0,11lux bis 100000lux übernehmen, aber so ganz blick ich da noch nicht durch.......

das mit dem tinyWireM versuch ich noch mal aber das klingt so als, wurde nur die "S" auf dem laufen:

ATtiny84 Support 2012.10.30

If you need support for the ATtiny84 (or 44), there is a forked version of the above library on Github that supports the ATtiny44/84 series. GitHub - svoisen/TinyWire: My modifications to TinyWire Arduino libs

ich hab da noch was sehr interessantes gefunden:

file:///D:/Desktop/i2cmaster/group__pfleury__ic2master.html

magictrips:
ich würde gerne aus der lib den teil zur sensor-überprüfung und den teil zum messen von 0,11lux bis 100000lux übernehmen, aber so ganz blick ich da noch nicht durch.......

Das Ding hat mit readLevel() einen automatischen Modus um sich selbst zu justieren. Da ist das glaube ich mit drin.

Was da gemacht wird ist die Empfindlichkeit des Sensors zu verringern. Siehe auch defineMTReg(). Der Wert dieses Registers ändert aber auch die Umrechnung von Rohwert nach Lux!

Da steht auch wieso das bei dir wohl ging ohne explizit PowerOn zu machen. Nur den Modus zu setzten reicht wohl um den Sensor einzuschalten

Serenifly:
Ohne Kontext verwirrst du ihn aber auch.
...
Den Code den du gepostet hast ist von einem meiner Beispiele.
...
Funktioniert, aber normal ist das nicht :slight_smile:

Verwirren wollte ich natürlich nicht. Da ich aber Deinen Code prima finde, da er funktioniert, wollte ich darauf hinweisen. Ich habe jetzt den Link zu Deinem Beitrag anstelle meines Codes eingefügt, auch wenn jetzt ein Master gesucht wird.

@magictrips: Ich habe keinen ATtiny84 aber dies in meiner Linksammlung: I2C Master Interface "It can be used to communicate with I2C devices (serial EEPROM, serial RTC etc) from any AVR device."

Konfiguration: SDA an PA6, SCL an PA4, dies müßte dann angepaßt werden in i2cmaster.S:

;***** Adapt these SCA and SCL port and pin definition to your target !!
;
#define SDA     4 // SDA Port D, Pin 4   
#define SCL 5 // SCL Port D, Pin 5
#define SDA_PORT        PORTD           // SDA Port D
#define SCL_PORT        PORTD           // SCL Port D

Ich hoffe, nicht zu verwirren :slight_smile:

@ sernifly
ich glaube, ich hab mich falsch ausgedrückt ?
ich wollte auf die lib verzichten, und nur den teil, der zur überprüfung des sensors nötig ist
und diesen 0,11-100000lux sketch übernehmen........
in diesem high_auto_irgendwas modus ließt der erst den bereich ein und entscheidet dann, welche auflösung verwendet wird....
ich verstehe nur noch nicht so ganz, wie ich auf die 100000lux komme....
für die anderen wird doch im sensor-register etwas geändert zb 0x24 oder 0x11 oder so

diese i2cmaster wollte ich grad ausprobieren, aber da steht nur sketch wird komplimiert und dann gehts nicht weiter.......

ich wollte jetzt erstmal klein anfangen.....
hab erstmal ein attiny85 mit der tinywireM versucht:

#include <TinyWireM.h>

#include <SoftwareSerial.h>
SoftwareSerial softSerial(88, 3 ); //rx= physikalisch Pin 3(attiny85) Pin 11?(attiny84), tx= physikalisch Pin 2(attiny85) Pin 10(attiny84)


byte buff[2];


void setup()
{
  softSerial.begin(9600);
  softSerial.print("starte setup");
  
  TinyWireM.beginTransmission(0x23); 

  TinyWireM.send(0x11); 
     
  TinyWireM.endTransmission();
}

void loop()
{
  
  byte i=0;
  
  TinyWireM.beginTransmission(4);
  
  while(TinyWireM.available())
  {
    buff[i] = TinyWireM.receive(); 
    i++;
  }
  TinyWireM.endTransmission();
  
 
  float valf=0;

  if(i == 2)
  {
    valf=((buff[0]<<8)|buff[1])/1.2;
    
    if(valf<0)
    softSerial.print("> 65535");
    else 
    softSerial.print((int)valf,DEC); softSerial.println(" lx"); 
  }
  

  
  delay(1000);
  

}

sda-sensor an sda(phys. pin 5 am tiny)
und slc-sensor an slc (phys. pin 7)

5ko pullups von vcc an sda
5ko pullup von vcc an scl

empfange leider nichts......

hab dann auch noch mal versucht mit dem arduino mega zu kommunizieren, aber ging leider auch nicht

Was soll die "4" in TinyWireM.beginTransmission(4); sein? Da müßte eine Adresse stehen.

// ein Byte anfordern und lesen
int readByte(int adr)
{
  TinyWireM.requestFrom(adr, 1);
  return TinyWireM.receive();
}

void send_i2c(unsigned char address, unsigned char c0)
{
  TinyWireM.beginTransmission(address);  // transmit to device address
  TinyWireM.send(c0);                    // sends one byte
  TinyWireM.endTransmission();           // stop transmitting
}

Wie oft muss ich den noch sagen, dass beginTransmission()/endTransmission() beim Empfang gar nichts verloren hat? :slight_smile:

Das ist nur für das Senden!!! Empfangen geht mit requestFrom() und danach read()

Um das mal ganz klar zu machen: endTransmission() sendet die Byte die mit write() in den Ausgangspuffer geschrieben werden. requestFrom() empfängt Bytes und read() entfernt sie aus dem Eingangspuffer.