Go Down

Topic: Zahlenwerte über I2C senden (Read 524 times) previous topic - next topic

mario01

Hallo,

ich möchte einen Temperaturwert von einen NANO auf einen UNO senden.

Im Forum und im WWW habe ich schon "alles" durchsucht, aber leider nicht wirklich etwas gefunden was funktioniert:-(



Code Slave

Code: [Select]
// Wire Slave Sender
// by Nicholas Zambetti <http://www.zambetti.com>

// Demonstrates use of the Wire library
// Sends data as an I2C/TWI slave device
// Refer to the "Wire Master Reader" example for use with this

// Created 29 March 2006

// This example code is in the public domain.


#include <Wire.h>
#include <OneWire.h>
#include <DallasTemperature.h>
#define ONE_WIRE_BUS 2 /* Digitalport Pin 2 definieren */

OneWire ourWire(ONE_WIRE_BUS); /* Ini oneWire instance */
int temp = 0;
DallasTemperature sensors(&ourWire);/* Dallas Temperature Library für Nutzung der oneWire Library vorbereiten */

void setup()
{
  Serial.begin(9600);
  Wire.begin(8);                // join i2c bus with address #8
  Wire.onRequest(requestEvent); // register event

  sensors.begin();/* Inizialisieren der Dallas Temperature library */
}


void loop()
{
  delay(100);

  sensors.requestTemperatures(); // Temp abfragen

  float t = sensors.getTempCByIndex(0);
  char buffer1[10];
  String temp = dtostrf(t, 8, 0, buffer1);
  Serial.println(t);
}
// function that executes whenever data is requested by master
// this function is registered as an event, see setup()
void requestEvent()
{
  Wire.write(temp); // respond with message of 6 bytes
  // as expected by master
}




Code Master

Code: [Select]
// Wire Master Reader
// by Nicholas Zambetti <http://www.zambetti.com>

// Demonstrates use of the Wire library
// Reads data from an I2C/TWI slave device
// Refer to the "Wire Slave Sender" example for use with this

// Created 29 March 2006

// This example code is in the public domain.


#include <Wire.h>

void setup()
{
  Wire.begin();        // join i2c bus (address optional for master)
  Serial.begin(9600);  // start serial for output
}

void loop()
{
  Wire.requestFrom(8,10);    // request 6 bytes from slave device #8

  while (Wire.available())   // slave may send less than requested
  {
    char c = Wire.read(); // receive a byte as character
    Serial.print(c);         // print the character
  }

  delay(500);
}

Kann mir jemand einen kleinen Wink mit einer Laterne geben was ich vergessen habe oder falsch mache ?:-)


MfG Mario

combie

#1
Aug 10, 2017, 11:19 pm Last Edit: Aug 10, 2017, 11:20 pm by combie
Mehrere Fehler....

Fangen wir mal mit dem ersten an:
Quote
Wire.write(temp);
Wo füllst du temp ?
"Freiheit, Gleichheit, Brüderlichkeit!"
Aber wie gelangen wir zu den Tätigkeitswörtern?
Quelle: Stanislaw Jerzy Lec

Serenifly

#2
Aug 10, 2017, 11:46 pm Last Edit: Aug 10, 2017, 11:49 pm by Serenifly
Vorsicht mit Wire.write(). Das ist eine Falle. Damit kann man entweder ein Byte oder ein Array senden. Wenn man da einen int oder long übergibt wird der einfach auf ein Byte gecastet. Das kann so also nicht gehen.
Allerdings geht im Request Event Handler nur ein einziges mal write() wodurch man nicht einfach mehrere Bytes senden kann


Ohne Strings, direkt mit Zahlen:

http://forum.arduino.cc/index.php?topic=407599.msg2804476#msg2804476

Die Data Union entsprechend anpassen! Wenn du nur einen Wert hast brauchst du das anonyme struct darin nicht. Für einen int geht einfach das:
Code: [Select]

union Data
{
  byte asArray[sizeof(int)];
  int temp;
};


Das ist Test/Demo-Code! Es wird gezeigt wie der Master Daten an den Slave schickt. Aber auch wie der Master vom Slave Daten anfordert. In dem Beispiel schickt der Master zwei Zahlen, der Slave inkrementiert sie und der Master liest sie sofort wieder zurück. Praktisch musst du dich für eine Variante entscheiden!

1.) Master schickt Daten an den Slave:
Auf dem Master writeValues() nehmen und auf dem Slave den Receive Event Handler

2.) Master fordert Daten vom Slave an (analog zu I2C Sensoren):
Auf dem Master getValues() verwenden und auf dem Slave den Request Event Handler


Die Idee dahinter ist dass in einer Union alle Variablen den gleichen Speicherplatz belegen. Wenn man also auf das Array Byte für Byte schreibt, schreibt man gleichzeitig in die eigentliche Variable. Und beim Lesen genauso. Man kann also Variablen sowohl als Array als auch als Integer/Float ansprechen

guntherb

#3
Aug 11, 2017, 09:03 am Last Edit: Aug 11, 2017, 09:06 am by guntherb
Ich habe das mit der EasyTransferI2C.h Library gelöst.
Funktioniert gut und recht unkompliziert.

Grüße
Gunther

mario01

Ich danke euch erstmal für eure Hilfe.


Zunächst möchte ich euch mein eigentliches vorhaben erklären.

Ich verwende für meine Haussteuerung FHEM, welches auf einem Netbook läuft, dann gibt es z.B. im Gewächshaus einen  Arduino Mega (mit Configurable Firmata)der über ein Ethernetshield mit dem "Server" kommuniziert.
Nun habe ich einen Wind und Regenmesser gebaut der die Daten über einen Arduino Nano (verbunden mit dem Mega über I2C) an FHEM senden soll.


Bevor ich mich an dieses Projekt wage wollte ich erstmal mit I2c mich vertraut machen:-)


Zunächst muss ich noch herausfinden in welcher Form FHEM die Daten auch verarbeiten kann.

Kennt ihr FHEM? 

Serenifly

Wenn es darum geht Daten von einem Arduino an einen anderen zu senden ist es egal was mit den Daten danach geschieht. Das hat eigentlich nichts miteinander zu tun. Du kannst das auf dem anderen Ende erstmal auf der seriellen Schnittstelle ausgeben.

Du musst halt zwei Eigenheiten der Wire Library beachten:
1.) Man kann nur entweder ein Byte oder ein Array senden. Man kann nicht direkt Multi-Byte Variablen schicken!
2.) Man kann im Request Event Handler nur einmal write() machen

Beides macht es sehr attraktiv das mit Unions zu handhaben. Es gibt noch eine andere Variante (Zeiger und Casts), aber das ist für Anfänger schwer verständlich

Scherheinz

Wie weit sind die beiden Arduinos eigentlich voneinander entfernt?

FHEM hab ich auf einem Raspberry am Laufen an dem meine Heizung hängt, eine Wetterstation soll noch folgen....
Hier könnte ihre Werbung stehen

mario01

Das Problem ist dass ich auf dem anderen Arduino nicht einfach über einen serielle Schnittstelle auslesen kann.
Auf dem Mega (der die Daten Windgeschwindigkeit und Regenmenge empfangen soll) ist die Confugurable Firmata.
Ich glaube nicht dass es egal ist in welcher form die Daten ankommen.

Die beiden Arduino`s sind circa 15 cm auseinander.

Ich möchte den Nano zum verarbeiten der Sensorwerte verwenden da sonst die Kommunikation auf dem Netztwerk bei einer Windgeschwindigkeit von 50 Kmh und 12 Impulsen pro Umdrehung zu stark wäre und es zu Messfehlern führen würde oder wiedermal das Ethernetshield den Dienst verweigert :smiley-confuse:

Serenifly

Ich glaube nicht dass es egal ist in welcher form die Daten ankommen.
Wenn FHEM ein bestimmtes Format möchte kannst du das nach dem Empfang umsetzten. Am einfachsten ist es jedenfalls den Wert einfach als Integer oder evtl. Float zu übertragen

mario01

Dann sollte ich die "Union Data" Variante weiter verfolgen. Oder?

mario01

Das ist die Configurable Firmata

Code: [Select]


#include <Firmata.h>
#include <SPI.h>
#include <Ethernet.h>

/*
 * To configure 'Network Firmata' to use an ENC28J60 based board include
 * 'UIPEthernet.h' (no SPI.h required). The UIPEthernet-library can be downloaded
 * from: https://github.com/ntruchsess/arduino_uip
 */

//#include <UIPEthernet.h>

/*
 * To execute Network Firmata on Yun uncomment Bridge.h and YunClient.h.
 * Do not include Ethernet.h or SPI.h in this case.
 * On Yun there's no need to configure local_ip and mac in the sketch
 * as this is configured on the linux-side of Yun.
 */

//#include <Bridge.h>
//#include <YunClient.h>

#if defined ethernet_h || defined UIPETHERNET_H || defined _YUN_CLIENT_H_
/*==============================================================================
 * Network configuration for Network Firmata
 *============================================================================*/
#define NETWORK_FIRMATA
//replace with ip of server you want to connect to, comment out if using 'remote_host'
#define remote_ip IPAddress(192,168,0,150)
//replace with hostname of server you want to connect to, comment out if using 'remote_ip'
//#define remote_host "server.local"
//replace with the port that your server is listening on
#define remote_port 3232
//replace with arduinos ip-address. Comment out if Ethernet-startup should use dhcp. Is ignored on Yun
#define local_ip IPAddress(192,168,0,152)
//replace with ethernet shield mac. It's mandatory every device is assigned a unique mac. Is ignored on Yun
const byte mac[] = {0x90, 0xA2, 0xDA, 0x0D, 0x07, 0x02};
#endif

// To configure, save this file to your working directory so you can edit it
// then comment out the include and declaration for any features that you do
// not need below.

// Also note that the current compile size for an Arduino Uno with all of the
// following features enabled is about 22.4k. If you are using an older Arduino
// or other microcontroller with less memory you will not be able to include
// all of the following feature classes.

#include <utility/DigitalInputFirmata.h>
DigitalInputFirmata digitalInput;

#include <utility/DigitalOutputFirmata.h>
DigitalOutputFirmata digitalOutput;

#include <utility/AnalogInputFirmata.h>
AnalogInputFirmata analogInput;

#include <utility/AnalogOutputFirmata.h>
AnalogOutputFirmata analogOutput;

#include <Servo.h> //wouldn't load from ServoFirmata.h in Arduino1.0.3
#include <utility/ServoFirmata.h>
ServoFirmata servo;

#include <Wire.h> //wouldn't load from I2CFirmata.h in Arduino1.0.3
#include <utility/I2CFirmata.h>
I2CFirmata i2c;

#include <utility/OneWireFirmata.h>
OneWireFirmata oneWire;

#include <utility/StepperFirmata.h>
StepperFirmata stepper;

#include <utility/FirmataExt.h>
FirmataExt firmataExt;

#include <utility/FirmataScheduler.h>
FirmataScheduler scheduler;

#include <utility/EncoderFirmata.h>
EncoderFirmata encoder;


// dependencies. Do not comment out the following lines
#if defined AnalogOutputFirmata_h || defined ServoFirmata_h
#include <utility/AnalogWrite.h>
#endif

#if defined AnalogInputFirmata_h || defined I2CFirmata_h || defined EncoderFirmata_h
#include <utility/FirmataReporting.h>
FirmataReporting reporting;
#endif

// dependencies for Network Firmata. Do not comment out.
#ifdef NETWORK_FIRMATA
#if defined remote_ip && defined remote_host
#error "cannot define both remote_ip and remote_host at the same time!"
#endif
#include <utility/EthernetClientStream.h>
#ifdef _YUN_CLIENT_H_
YunClient client;
#else
EthernetClient client;
#endif
#if defined remote_ip && !defined remote_host
#ifdef local_ip
EthernetClientStream stream(client, local_ip, remote_ip, NULL, remote_port);
#else
EthernetClientStream stream(client, IPAddress(0, 0, 0, 0), remote_ip, NULL, remote_port);
#endif
#endif
#if !defined remote_ip && defined remote_host
#ifdef local_ip
EthernetClientStream stream(client, local_ip, IPAddress(0, 0, 0, 0), remote_host, remote_port);
#else
EthernetClientStream stream(client, IPAddress(0, 0, 0, 0), IPAddress(0, 0, 0, 0), remote_host, remote_port);
#endif
#endif
#endif

/*==============================================================================
 * FUNCTIONS
 *============================================================================*/

void systemResetCallback()
{
  // initialize a defalt state

  // pins with analog capability default to analog input
  // otherwise, pins default to digital output
  for (byte i = 0; i < TOTAL_PINS; i++) {
    if (IS_PIN_ANALOG(i)) {
#ifdef AnalogInputFirmata_h
      // turns off pullup, configures everything
      Firmata.setPinMode(i, ANALOG);
#endif
    } else if (IS_PIN_DIGITAL(i)) {
#ifdef DigitalOutputFirmata_h
      // sets the output to 0, configures portConfigInputs
      Firmata.setPinMode(i, OUTPUT);
#endif
    }
  }

#ifdef FirmataExt_h
  firmataExt.reset();
#endif
}


void setup()
{
  
#ifdef NETWORK_FIRMATA
#ifdef _YUN_CLIENT_H_
  Bridge.begin();
#else
#ifdef local_ip
  Ethernet.begin((uint8_t *)mac, local_ip); //start ethernet
#else
  Ethernet.begin((uint8_t *)mac); //start ethernet using dhcp
#endif
#endif
  delay(1000);
#endif
  Firmata.setFirmwareVersion(FIRMATA_MAJOR_VERSION, FIRMATA_MINOR_VERSION);

#if defined AnalogOutputFirmata_h || defined ServoFirmata_h
  /* analogWriteCallback is declared in AnalogWrite.h */
  Firmata.attach(ANALOG_MESSAGE, analogWriteCallback);
#endif

#ifdef FirmataExt_h
#ifdef DigitalInputFirmata_h
  firmataExt.addFeature(digitalInput);
#endif
#ifdef DigitalOutputFirmata_h
  firmataExt.addFeature(digitalOutput);
#endif
#ifdef AnalogInputFirmata_h
  firmataExt.addFeature(analogInput);
#endif
#ifdef AnalogOutputFirmata_h
  firmataExt.addFeature(analogOutput);
#endif
#ifdef ServoFirmata_h
  firmataExt.addFeature(servo);
#endif
#ifdef I2CFirmata_h
  firmataExt.addFeature(i2c);
#endif
#ifdef OneWireFirmata_h
  firmataExt.addFeature(oneWire);
#endif
#ifdef StepperFirmata_h
  firmataExt.addFeature(stepper);
#endif
#ifdef FirmataReporting_h
  firmataExt.addFeature(reporting);
#endif
#ifdef FirmataScheduler_h
  firmataExt.addFeature(scheduler);
#endif
#ifdef EncoderFirmata_h
  firmataExt.addFeature(encoder);
#endif
#endif
  /* systemResetCallback is declared here (in ConfigurableFirmata.ino) */
  Firmata.attach(SYSTEM_RESET, systemResetCallback);

  // Network Firmata communicates with Ethernet-shields over SPI. Therefor all
  // SPI-pins must be set to IGNORE. Otherwise Firmata would break SPI-communication.
  // add Pin 10 and configure pin 53 as output if using a MEGA with Ethernetshield.
  // No need to ignore pin 10 on MEGA with ENC28J60, as here pin 53 should be connected to SS:
#ifdef NETWORK_FIRMATA
  // ignore SPI and pin 4 that is SS for SD-Card on Ethernet-shield
  for (byte i = 0; i < TOTAL_PINS; i++) {
    if (IS_PIN_SPI(i)
        || 4 == i
        // || 10==i //explicitly ignore pin 10 on MEGA as 53 is hardware-SS but Ethernet-shield uses pin 10 for SS
       ) {
      Firmata.setPinMode(i, IGNORE);
    }
  }
  //  pinMode(PIN_TO_DIGITAL(53), OUTPUT); configure hardware-SS as output on MEGA
  pinMode(PIN_TO_DIGITAL(4), OUTPUT); // switch off SD-card bypassing Firmata
  digitalWrite(PIN_TO_DIGITAL(4), HIGH); // SS is active low;

  // start up Network Firmata:
  Firmata.begin(stream);
#else
  // start up the default Firmata using Serial interface:
  Firmata.begin(57600);
#endif
  systemResetCallback();  // reset to default config
}

void loop()
{
  
#ifdef DigitalInputFirmata_h
  digitalInput.report();
#endif
  while (Firmata.available()) {
    Firmata.processInput();
#ifdef FirmataScheduler_h
    if (!Firmata.isParsingMessage()) {
      goto runtasks;
    }
  }
  if (!Firmata.isParsingMessage()) {
runtasks: scheduler.runTasks();
#endif
  }

#ifdef FirmataReporting_h
  if (reporting.elapsed()) {
#ifdef AnalogInputFirmata_h
    analogInput.report();
#endif
#ifdef I2CFirmata_h
    // report i2c data for all device with read continuous mode enabled
    i2c.report();
#endif
#ifdef EncoderFirmata_h
    // report encoders positions if reporting enabled.
    encoder.report();
#endif
  }
#endif
#ifdef StepperFirmata_h
  stepper.update();
#endif
#if defined NETWORK_FIRMATA && !defined local_ip &&!defined _YUN_CLIENT_H_
  if (Ethernet.maintain())
  {
    stream.maintain(Ethernet.localIP());
  }
#endif
}

Serenifly

Du hast gefragt wie I2C Kommunikation funktioniert und wolltest das verstehen. Dann beschränke dich erst mal darauf. Ich habe dir Demo-Code gegeben, den du selbst anpassen musst. Entweder so dass der Master Daten sendet oder Daten vom Slave anfordert. Also lass den anderen Kram erst mal komplett weg und schau dass du das verstehst.

Wenn das denn geht kannst du es mit dem anderen Zeug kombinieren

Scherheinz

Brauchst du die Firmata überhaupt? Was eigenes wäre viel kleiner und verständlicher. Das Beispiel "WebClient" bringt schon alles mit um FHEM Daten bereitzustellen. Schau mal hier rein:

Temperaturdaten an FHEM

Gruß

Hier könnte ihre Werbung stehen

mario01

Ich habe  nun ein bisschen herum probiert und habe nun als Rückmeldung  "  Master:
                                                                                                                0           "

Irgendetwas habe ich übersehen :smiley-sad-blue:



MASTER:

Code: [Select]

#include <Wire.h>
int led=13;
union Data
{
  byte asArray[sizeof(int)];
  int temp;
};

Data slaveOne;

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

void loop()
{
 
  if (getValues(1, slaveOne))    //Daten anfordern
  {
    Serial.println("Master:");
    Serial.println(slaveOne.temp);
   
    Serial.println();
 
  }
 
  delay(1000);
}

void writeValues(byte slave, union Data& values)
{
  Wire.beginTransmission(slave);
  Wire.write(values.asArray, sizeof(values));
  Wire.endTransmission();
}

bool getValues(byte slave, union Data& values)
{
  Wire.requestFrom(slave, sizeof(values));
   
  if (Wire.available() > 0)
  {
    for (unsigned int i = 0; i < sizeof(values); i++)
      values.asArray[i] = Wire.read();

    return true;
  }
  else
    return false;
}




Slave:

Code: [Select]
#include <Wire.h>
#include <OneWire.h>
#include <DallasTemperature.h>
#define ONE_WIRE_BUS 2 /* Digitalport Pin 2 definieren */

OneWire ourWire(ONE_WIRE_BUS); /* Ini oneWire instance */

DallasTemperature sensors(&ourWire);/* Dallas Temperature Library für Nutzung der oneWire Library vorbereiten */

union Data
{
 byte asArray[sizeof(int)];
  int temp=sensors.getTempCByIndex(0);
};

Data values;

void setup()
{
  Wire.begin(1);
Serial.begin(9600);
   
  Wire.onRequest(requestHandler);
 


  sensors.begin();/* Inizialisieren der Dallas Temperature library */
}

void loop()
{
  sensors.requestTemperatures(); // Temp abfragen


}



void requestHandler()
{
  //hier geht nur einmal write() !!
 
  Wire.write(values.asArray, sizeof(values));
}

Serenifly

#14
Aug 12, 2017, 09:33 pm Last Edit: Aug 13, 2017, 12:36 pm by Serenifly
Code: [Select]

union Data
{
 byte asArray[sizeof(int)];
  int temp=sensors.getTempCByIndex(0);
};

Das hat da nichts zu suchen. Das Auslesen der Temperatur gehört in loop(). Erst macht man requestTemperatures() um eine Messung zu starten. Danach liest man die Temperatur aus.

Code: [Select]

values.temp = sensors.getTempCByIndex(0);


Und writeValues() kann auf dem Master bei der Variante entfallen

Go Up