hallo, ich habe vor mehrere sensoren(3x OneWireBUS(Ja 3x der BUS) mit DS18B20 sensoren,3x DHT11,2x PIR und 4x Reed-kontakte) an einen Arduino Mega 2560 R3 zu betreiben welcher über I2C als Slave angesprochen wird, jetzt habe ich mir überlegt bzw mich gefragt ob es nicht möglich ist jeden dieser sensoren bzw quasi jeden "Input" pin eine eigene I2C adresse zu zuweisen und über diese abzufragen.
ich hab bisher keine ahnung wie ich das bewerkstäligen könnte, für die OneWireBus hab ich zwar eine mögliche libary gefunden (OneWireHub Wenn ich mich nicht irre) aber viel weiter hat mich das bisher nicht gebracht.
ich hoffe ihr könnt mir tipps geben.
mfg OW
So ganz verstehe ich dein Problem nicht.
Deine Sensoren sind keine I2C-Sensoren, also wofü brauchst die Adressen.
Die Slave-Adresse für deinen Mega kannst du selbst vergeben.
Bitte deine Beschreibung nochmal etwas genauer schreiben.
du könntest
a) in deinem Slave Sketch auf verschiedene Slave Adressen reagieren.
b) imho sauberer wäre wenn du für jeden deiner Sensoren ein separates "Register" machst und damit gezielt den Sensor abfragst - aber unter der gleichen Slave Adresse. Das ist auch eher das was du bei anderen I2C Komponenten hast: 1 Adresse - verschiedene Register.
Die Vergabe ganzer Adressbereiche wird von der Mega Hardware unterstützt.
Allerdings nicht von Wire.
Der Weg ist also verdorben. (es sei denn ....)
Ja!
nun ja ich würde gerne adressen "emulieren" das somit jeder sensor bzw eigentlich würde es reichen wenn nur die werte von den sensoren über eine eigene adresse abfragbar sind.
ok möglichkeit "b)" hört sich nach dem an was ich suche. jetzt ist die frage wie bewerkstellige ich das ? ich bin anfänger in dem gebiet,möchte zwar so schnell wie nur möglich die codes schreiben aber ich möchte es am besten auch verstehen.
Das musst du nur manuell umsetzen. Also über I2C 0x01, 0x02, oder andere Adressen senden, darauf abfragen und ein Einlesen des jeweiligen OneWire Sensors daraus machen.
Ok, das muss dann ja keine I2C-Adresse sein.
Das kann ja jeder beliebige Wert sein, der dann gezielt angesprochen wird.
schnell geht gar nix. Aber ich kann dir zeigen was ich (vor 4 Jahren!) gemacht habe:
Abfrage von 5 Ultraschallsensoren.
So nebenbei gibts auch Register für Analog-Eingänge und Digitaleingänge.
Die Register stehen oben im Kommentar.
Im Prinzip brauchst nur am Ende die paar neuen Register für deine Temperatursensoren ergänzen...
/*
ARDUINO UNO/NANO as I2C port expander for ultrasonic sensors
by noiasca
inspired by http://forum.arduino.cc/index.php?topic=77310.0
5 ultrasonic proximity sensors
send Digital IN (GPIO) over I2C (register 0 - 31) 00 - 13 used
send Analog IN over I2C (register 31 - 63) 31 - 39 Used
send proximity sensor values over I2C (register 63 - 94) 63 - 72 5 ultrasonic proximity sensors on D2-D11
in detail, the registers are as following:
Register GPIO/usage comment
-----------------------------------
0 Digital 0 RX --> PIN's 0 + 1 could be ocopied by Serial - if debug messages are used
1 Digital 1 TX
2 Digital 2 Trigger Sensor A --> PIN's 2 - 11 are used for the 5 proximity sensors
3 Digital 3 Echo
4 Digital 4 Trigger Sensor B
5 Digital 5 Echo
6 Digital 6 Trigger Sensor C
7 Digital 7 Echo
8 Digital 8 Trigger Sensor D
9 Digital 9 Echo
10 Digital 10 Trigger Sensor E
11 Digital 11 Echo
12 Digital 12 free (could be used for a switch or any other digital sensor)
13 Digital 13 occupied by built in LED
14..30 reserved for future use
31 Analog 0 LSB Analog values are 0..1023 - you need two bytes for each value!
32 Analog 0 MSB
33 Analog 1 LSB
34 Analog 1 MSB
35 Analog 2 LSB
36 Analog 2 MSB
37 Analog 3 LSB
38 Analog 3 MSB
39 reserved Analog 4 is occupied by I2C on UNO/NANO
40 reserved Analog 5 is occupied by I2C on UNO/NANO
41 - could be used for Analog 6 on a NANO - not implemented
42 - could be used for Analog 7 on a NANO - not implemented
43..62 reserved
63 Distance 0 LSB Proximity sensors: all calculated values are in cm are and splitted in LSB and MSB
64 Distance 0 MSB
65 Distance 1 LSB
66 Distance 1 MSB
67 Distance 2 LSB
68 Distance 2 MSB
69 Distance 3 LSB
70 Distance 3 MSB
71 Distance 4 LSB
72 Distance 4 MSB
73..94 reserved for future use
FE Manufacturer ID Register Description
FF Device ID Register Description
Set #define NO_ECHO 65535 in NewPing.h !!!
28500/57 = 500
31635/57 = 555
32767/57 = 574
56943/57 = 999
65535/57 = 1149 <-- each time you receive 1149 cm, you know the sensor has exceeded the limit
*/
#include <Wire.h>
#include <NewPing.h> // Ultrasonic Sensors
/* *******************************************************************
the different boards / die Einstellungen der verschiedenen Boards
* ******************************************************************/
const uint8_t slaveAdress = 8; // I2C adress of this slave
/* *******************************************************************
Globals
* ******************************************************************/
byte registerPointer = 0; // requested register from master
unsigned long previousMillis = 0; // will store last time ADC was read
const long adcInterval = 10; // interval at which to read ADC (milliseconds)
int adc[4]; // will store analog value form analog inputs
byte analog[8]; // i2c output byte: 4 analog values 0..1023 need 8 bytes
byte digital[14]; // i2c output byte: 14 digital PINs but some are occupied
byte proximity[10]; // i2c output byte: proxmity sensors could return more than 255cm, 5 sensors each 2 byte = 10 bytes used
// byte buffer[32]; // MISSING: not shure if I should use a generic buffer or separate buffers for digital/analog/proximity
const byte SONAR_NUM = 5; // count of ultrasonic proximity sensors
const byte SONAR_FRONT = 2; // Number of ultrasonic sensor facing north/front/12 o'clock
const uint16_t MAX_DISTANCE = 350; // Maximum distance (in cm) to ping
unsigned long previousSonarMillis = 0; // will store last time Sonar was called
const long SONAR_INTERVAL = 30; // interval at which to read ADC (milliseconds)
byte sonarActual = 0; // the actual Sonar sensor to read
uint16_t distance[SONAR_NUM]; // measured distance for each sensor
NewPing sonar[SONAR_NUM] = { // Sensor object array. 5 Sensors
NewPing(2, 3, MAX_DISTANCE), // Each sensor needs one trigger pin, one echo pin, and a max distance to ping.
NewPing(4, 5, MAX_DISTANCE),
NewPing(6, 7, MAX_DISTANCE),
NewPing(8, 9, MAX_DISTANCE),
NewPing(10, 11, MAX_DISTANCE)
};
#include "blink.cpp" // on separte tab
BlinkLed led(13); // a status LED (PIN 13) will blink according to the measured distance of proximity sensor 2 (in my case the sensor pointing forwards)
/* *******************************************************************
D E B U G activate to get more serial data
********************************************************************/
#define DEBUG 0 // set to 1 to activate debug messages on serial
/* *******************************************************************
S E T U P
********************************************************************/
void setup()
{
Serial.begin(115200);
Serial.println(F("\nUNO as I2C port expander ultrasonic"));
led.setup();
Wire.begin(slaveAdress); // set slave adress
Wire.onRequest(requestEvent); // add event
Wire.onReceive(receiveEvent); // the master must anounce a starting register before he can read
}
/* *******************************************************************
M A I N L O O P
********************************************************************/
void loop()
{
// read out analog inputs
if (millis() - previousMillis >= adcInterval) { // to avoid to fast reading of adc, we only measure once each adcIntervall and only one ADC
byte adcActual = millis() % 3;
analogRead(adcActual);
adc[adcActual] = analogRead(adcActual);
}
// read out proximity sensors
if (millis() - previousSonarMillis >= SONAR_INTERVAL) // wait some time between reading of the ultrasonic sensors
{
sonarActual++; // only read one sensor. define which one to read
if (sonarActual >= SONAR_NUM)
{
sonarActual = 0;
#if DEBUG
Serial.println();
#endif
}
distance[sonarActual] = sonar[sonarActual].ping_cm();
#if DEBUG
//Serial.print(sonarActual);
//Serial.print("=");
Serial.print(sonar[sonarActual].ping_cm());
Serial.print(F(" "));
//Serial.print("cm ");
#endif
if (sonarActual == SONAR_FRONT) // set blinkfrequency according to forward facing proximity sensor
{
uint16_t blinktime = map(distance[SONAR_FRONT], 0, 1149, 20, 1000); // calculate a blinktime based to the front distance. The sensor out is 0-1149. The Blinkfrequency should be between 20-1000ms
//uint16_t blinktime = distance[SONAR_FRONT] + 100; // calculate a blinktime based to the front distance
led.set(blinktime, 1149 + 100 - blinktime); // ontime = blinktime, offtime = somehow reversed value
}
}
// do other stuff
led.loop(); // update blink led
}
/* *******************************************************************
F U N C T I O N S
********************************************************************/
// function that executes whenever data is requested by master
// this function is added as an event in setup()
// maximum of 32 bytes can be sent
// according to
// https://forum.arduino.cc/index.php?topic=517096.0
// no chance to get the requested bytes from the master (as of 2018-06-19)
// therefore: this slave answeres n bytes according to the requested register block
// in other words: this slave sends the n remaining bytes till end of this regigster block
//
void requestEvent()
{
if (registerPointer <= 13) // handle registers for DIGITAL Inputs
{
for (byte i = 0; i <= 13; i++)
{
digital[i] = digitalRead(i);
}
// Wire.write(data, quantity)
Wire.write(digital + registerPointer, sizeof(digital) - registerPointer);
}
else if (registerPointer >= 31 && registerPointer <= 31 + 8) // handle registers for ANALOG Inputs
{
byte registerStart = 31; // this register group starts at adress 31
analog[0] = adc[0];
analog[1] = adc[0] >> 8;
analog[2] = adc[1];
analog[3] = adc[1] >> 8;
analog[4] = adc[2];
analog[5] = adc[2] >> 8;
analog[6] = adc[3];
analog[7] = adc[3] >> 8;
Wire.write(analog + registerPointer - registerStart, sizeof(analog) - (registerStart - registerPointer));
}
else if (registerPointer >= 63 && registerPointer <= 63 + 10) // handle registers for PROXIMITY Sensors
{
byte registerStart = 63;
proximity[0] = distance[0];
proximity[1] = distance[0] >> 8;
proximity[2] = distance[1];
proximity[3] = distance[1] >> 8;
proximity[4] = distance[2];
proximity[5] = distance[2] >> 8;
proximity[6] = distance[3];
proximity[7] = distance[3] >> 8;
proximity[8] = distance[4];
proximity[9] = distance[4] >> 8;
Wire.write(proximity + registerPointer - registerStart, sizeof(proximity) - (registerStart - registerPointer));
}
else if (registerPointer == 0xFE) // Manufacturer ID Register Description (0xFE)
{
Wire.write(8); // "my" Manufacturer ID is 0x0815
Wire.write(15);
}
else if (registerPointer == 0xFF) // Device ID Register Description
{
Wire.write(5); // my device is able to send 5 proximity sensors,
Wire.write(8); // this values can be set to any value
}
}
void receiveEvent(int howMany)
{
// Read the requested register
registerPointer = Wire.read();
}
und die blink.cpp habe ich offenbar in einem anderen Tab:
#include <Arduino.h> // include Arduino specifica - needed for .cpp in separate tabs if not included with an separate .h
class BlinkLed {
uint8_t state = 1; // 0 off, 1 blink
unsigned long previousMillis; // last blink timestamp
uint16_t on = 180;
uint16_t off = 320; // 180/320 is according ECE
const int ledPin; // a GPIO for the LED
public:
BlinkLed(byte attachTo, uint16_t _on = 180, uint16_t _off = 320):
ledPin(attachTo),
on (_on),
off (_off)
{}
void setup() {
pinMode(ledPin, OUTPUT);
}
void set(uint16_t _on, uint16_t _off) { // modify on/off times during runtime
on = _on;
off = _off;
}
void setState(byte _state) { // 1 Switch on blinking; 0 switch off blinking
state = _state;
}
void loop() {
if (state) {
uint32_t currentMillis = millis();
if (digitalRead(ledPin) && currentMillis - previousMillis >= on) {
previousMillis = currentMillis; // save the last time you blinked the LED
digitalWrite(ledPin, LOW);
}
else if (!digitalRead(ledPin) && currentMillis - previousMillis >= off) {
previousMillis = currentMillis; // save the last time you blinked the LED
digitalWrite(ledPin, HIGH);
}
}
}
};
Für DS18B20 nimm
die Werte danach per I2C senden.
ich wollte mit der gesamten aussage auch aussagen das mir bewusst ist das sowas nicht schnell geht
Wie weit ist die Strecke ? Bei mehr als 0,5m fangen Probleme an, außer dem Schaft der Mega alles selbst, je nach dem was an dem Master alles noch hängt, interessant ist auch wer ist der Master
Also Du hast einen Arduino MEGA mit mehreren Sensoren und willst einzeln jeden Sensor per Slave Abfrage über I2C abfragen.
Du hast die I2C Adresse des MEGA und sendest zusätzlich ein Byte für den Sensor der ausgelesen werden soll.
Der Mega gibt als Antwort den angesprochenen Sensor.
Grüeß Uwe
gut zu wissen aber ich habe mir mehrere lochrasterplatinen gekauft auf einen von denen hatte ich vor stiftleisten zu löten um den mega2560 dort aufstecken zu können wie ein prototypshield quasi nur das ich noch die buchsenleisten vom mega2560 nach unten hin versetze.eine andere platine dient als Master"shield" wo ich das selbe mit einem ESP32 oder eine pfostenbuchse für ein Raspberry pi mache oder beides (ein raspberry pi finde ich zumindest für fehler suche und testzwecke "einfacher" oder angenehmer zuhand haben was für den dauerbetrieb als master aber für mich eher ein kompromiss wäre) und das selbe noch mit einer anderen ich nenne es mal "slave" platine diese platinen werde ich wie weiß ich noch nicht genau über einander stappel eventuell einfach mit M2,5/M3 gewindestangen und je nach abstand mit wahrscheinlich cat oder Modularkabeln mit einander verbinden. also wird es ich denke nicht mal 25cm betragen.
Und warum machst das nicht alles auf einem ESP32 ?
vielen dank ich glaube fürs erste hat mir das schon weiter geholfen. ich werde wahrscheinlich heute nicht mehr groß was tun aber vielleicht schaffe ich es das wochenende noch und melde mich dann mit dem ergebnis.
achso mal nebenbei ein anderer Slave in dem projekt soll ein 4-kanal-ac dimmer werden,was aber erst später ein thema wird, wenn ich es richtig verstanden habe kann ich diese methode auch darauf hin über tragen das ich mit den registern auch die jeweiligen kanäle ansprechen kann oder ?
gruß OW
ESP 32 wie auch RasPI arbeiten mit 3,3V Mega mit 5V also noch an Pegelwandler denken
Du weißt schon daß I2C ein Bus für kurze Kabellängen ist. Max im besten Fall 2m.
Grüße Uwe
3,3V pins.. die kabel längen der sensoren werden in den meisten fällen weit über 1m lang sein,teilweise 3-5m.
davon mal ab möchte ich bei dem esp32 sowenig "last" ziehen wie nur möglich da ich die erfahrung gemacht habe das dieser auch bei guter strom versorgung nur sehr "schwaches" oder "instabiles" wlan liefert wenn zu viele pins belegt sind.
dieses projekt ist derzeit nur ein "prototyp" projekt später möchte ich es vernünftig mit bedruckten leiterplatten selbst bestücken.
ich hab einen bidirektionalen 4-kanal-level-converter hier für dieses projekt.