Conflitto ISP I2C su NodeMCU v3

Salve a tutti! Come da titolo ho un problema con la configurazione dei 3 signori elencati.
Mi spiego meglio sto programmando un datalogger come micro uso un NodeMCU collegato ad un dht22 un RTC e un modulo per SD, tutto con una supervisione scarna da WebServer.

Il modulo SD è ISP
Il modulo RTC è I2C

Facendola corta, se li uso separatamente funziona tutto alla perfezione: nella scheda SD si crea il file di log il dht legge le temperature e l’RTC dice esattamente l’ora giusta!

Al momento di fare il programma definitivo finché non inizializzo la sd funziona tutto alla perfezione. Al momento che la sd viene inclusa (Sd.being()) tutto il protocollo I2c smette di funzionare, ho provato anche con altri sensori I2c ed ho sempre lo stesso problema.

Vi è mai capitato? Grazie mille per la pazienza
Spero di non aver sbagliato sezione!

Potresti mettere uno schema di collegamento con tutti i pin utilizzati?

Guglielmo

Grazie per la risposta Guglielmo!

Come da specifica sulla comunicazione I2C ci sono le resistenze di PULL-UP da 3.33K.

Non ho possibilità di disegnare uno schema però posso indicarti i pin a cosa sono collegati:
G-> GND Modulo SD, - DHT-22, GND RTC
VV-> VCC Modulo SD, + DHT-22, VCC RTC
D0->
D1-> SCL per RTC
D2-> SDA per RTC
D3->
D4->
3V->Led+
G->Led-
D5->SCK modulo SD
D6->MISO modulo SD
D7->MOSI modulo SD
D8->CS modulo SD
TX->
RX-> OUT DHT-22
A0-> AnalogIn (previsione per voltmetro)

Aggiornamento!!
Ho aggirato il problema, è una toppa enorme :fearful: , ma funziona per il mio scopo.
Ho ustato un RTC Software ( nel tempo non è preciso per niente)
L'ho affiancato alla possibilità di aggiustare l'ora da Web visto che non devo fare enormi periodi di campionamento funziona.

Altrimenti avevo pensato di far gestire RTC e sensoristica ad una scheda Arduino Uno e tramite seriale, opportunaemnte cablata, comunicare con il NoneMCU per costruirmi il Web Server.

Grazie a tutti!

A parte che se hai accesso alla rete, semplicemnete con la libreria <time.h> hai lo RTC interno sempre sincronizzato con un server NTP pubblico (e quindi precisione del secondo), ma comunque … c’è qualche altra cosa perché, se i collegamneti fossero fatti bene (occhio alla lunghezza dei cavi e a dove passano perché sia I2C che SPI creano problemi) ed il codice giusto, NON ci sarebbe alcun motivo per cui SPI e I2C non possano convivere … ::slight_smile:

Guglielmo

Purtroppo per motivi di mobilità visto che è un progetto portatile, lavoro in locale altrimeti avevo considerato pure la strada del server NTP.

Ti confermo che SPI e I2C possano convivere perche un progetto analogo, ma con una scheda Arduino Mega già l'ho fatto quando tempo fa (circa un anno) appunto mi stupivo della incompatibilità. che credo sia legato alla scheda.

I cablaggi sono su una millefori 50x70mm circa quindi in pratica sono piste oportunamente divise tra alimentazione e dati.

In ogni caso lunedi mi dovrebbe arrivare un altro modulo SD così replichero il tutto su breadboard.

Vi terrò aggioranti.

mirkogitmor:
Ti confermo che SPI e I2C possano convivere perche un progetto analogo...

... veramente di quello NON ho alcun dubbio ... anche su ESP :slight_smile:

Guglielmo

Puoi pubblicare il codice (…mi raccomando, in conformità al regolamento, punto 7, il codice va racchiuso tra i tag CODE che, in fase di edit, ti inserisce il bottone </> … primo a sinistra) … così diamo un’occhiata anche a quello … visto mai … ::slight_smile:

Guglielmo

Devo dividerlo in 2 parti,
questa è la aprte di impostazioni e di intefaccia web ( spero non ci sia ORRORI HTML)

//librerie importate
#include <SPI.h>
#include <Wire.h>
#include <SD.h>
#include <Arduino.h>
#include <ESP8266WiFi.h>
#include <Hash.h>
#include <ESPAsyncTCP.h>
#include <ESPAsyncWebServer.h>
#include <Adafruit_Sensor.h>
#include <DHT.h>
#include "RTClib.h"

//dichiaro componeti
RTC_Millis rtc;
#define DHTPIN 3     // pin di RX
#define DHTTYPE    DHT22     // DHT 22 (AM2302)
DHT dht(DHTPIN, DHTTYPE);
//dichiaro pin usati
const int chipSelect = 4;
const int analogInPin = A0;
const int LedRosso = 16;

//dichiaro variabili globali
int Allarme = 0;

const char* PARAM_INPUT_1 = "output";
const char* PARAM_INPUT_2 = "state";

const char* ssid     = "****"; //tuo ssid
const char* password = "*****"; //tua paswsord
//variabili di appoggio per aggiornamento rtc
int _day = 0;
int _month = 0;
int _year = 0;
int _hour = 0;
int _min = 0;
int _sec = 0;

float t = 0.0;
float h = 0.0;
String d = "";
String FileData = "";
float VoltValue = 0.00;
float vout = 0.0;
float vin = 0.0;
float R1 = 214900.0; // inserire valore esatto resistenza R1 (215K)
float R2 = 10000.25; // inserire valore esatto resistenza R2 (10.25K)
int value = 0;
float Vref = 3.3;

// Creo AsyncWebServer sulla porta 80
AsyncWebServer server(80);

// Generally, you should use "unsigned long" for variables that hold time
// The value will quickly become too large for an int to store
unsigned long previousMillis = 0;    // will store last time DHT was updated
unsigned long previousMillisSD = 0;    // will store last time sd was updated

// aggiorno i dati ogni 10s
const long interval = 1000;
//intervallo log su sd 20s
const long intervalloSD = 20000;
//**** parte di costruzione interfaccio web ****
const char index_html[] PROGMEM = R"rawliteral(
<!DOCTYPE HTML><html>
<head>
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <style>
    html {
     font-family: Courier New;
     display: inline-block;
     margin: 0px auto;
     text-align: center;
    }
    h2 { font-size: 2.0rem; }
    p { font-size: 1.5rem; }
    .units { font-size: 1.0rem; }
    .dht-labels{
      font-size: 1.0rem;
      vertical-align:middle;
      padding-bottom: 15px;
    }
        .rev{
      font-size: 0.5rem;
      vertical-align:middle;
      padding-bottom: 15px;
    }
   body {max-width: 1000px; margin:0px auto; padding-bottom: 15px;}
    .switch {position: relative; display: inline-block; width:50px; height: 30px} 
    .switch input {display: none}
    .slider {position: absolute; top: 0; left: 0; right: 0; bottom: 0; background-color: #ccc; border-radius: 6px}
    .slider:before {position: absolute; content: ""; height: 22px; width: 22px; left: 4px; bottom: 4px; background-color: #fff; -webkit-transition: .4s; transition: .4s; border-radius: 3px}
    input:checked+.slider {background-color: #82E0FF}
    input:checked+.slider:before {-webkit-transform: translateX(19px); -ms-transform: translateX(19px); transform: translateX(19px)}
    
  </style>
</head>
<body>
    <h2>DataLog RDF-CSM
    <sup class="rev">M_Rev 1.0</sup>
    </h2>
      <p>
    <span class="dht-labels">Data</span> 
    <span id="Data">%DATA%</span>
  </p>
   %BUTTONPLACEHOLDER%
    <p>
    <span class="dht-labels">Voltmetro</span>
    <span id="battery">%BATTERY%</span>
    <sup class="units">V</sup>
  </p>
  <p>
    <span class="dht-labels">Temperatura</span> 
    <span id="temperature">%TEMPERATURE%</span>
    <sup class="units">&deg;C</sup>
  </p>
  <p>
    <span class="dht-labels">Umidita</span>
    <span id="humidity">%HUMIDITY%</span>
    <sup class="units">%</sup>
  </p>
    
</body>
<script>

  function toggleCheckbox(element) {
      var xhr = new XMLHttpRequest();
      if(element.checked){ xhr.open("GET", "/update?output="+element.id+"&state=1", true); }
      else { xhr.open("GET", "/update?output="+element.id+"&state=0", true); }
      xhr.send();
    }
    
setInterval(function ( ) {
  var xhttp = new XMLHttpRequest();
  xhttp.onreadystatechange = function() {
    if (this.readyState == 4 && this.status == 200) {
      document.getElementById("Data").innerHTML = this.responseText;
    }
  };
  xhttp.open("GET", "/Data", true);
  xhttp.send();
}, 500 ) ;

setInterval(function ( ) {
  var xhttp = new XMLHttpRequest();
  xhttp.onreadystatechange = function() {
    if (this.readyState == 4 && this.status == 200) {
      document.getElementById("temperature").innerHTML = this.responseText;
    }
  };
  xhttp.open("GET", "/temperature", true);
  xhttp.send();
}, 500 ) ;

setInterval(function ( ) {
  var xhttp = new XMLHttpRequest();
  xhttp.onreadystatechange = function() {
    if (this.readyState == 4 && this.status == 200) {
      document.getElementById("humidity").innerHTML = this.responseText;
    }
  };
  xhttp.open("GET", "/humidity", true);
  xhttp.send();
}, 500 ) ;

setInterval(function ( ) {
  var xhttp = new XMLHttpRequest();
  xhttp.onreadystatechange = function() {
    if (this.readyState == 4 && this.status == 200) {
      document.getElementById("battery").innerHTML = this.responseText;
    }
  };
  xhttp.open("GET", "/battery", true);
  xhttp.send();
}, 500 ) ;

</script>
</html>)rawliteral";
// inserimento delle variabili
String processor(const String& var) {
  //Serial.println(var);
  if (var == "TEMPERATURE") {
    return String(t);
  }
  else if (var == "HUMIDITY") {
    return String(h);
  }
  else if (var == "DATA") {
    return String(d);
  }

  else if (var == "BATTERY") {
    return String(VoltValue);
  }

  if (var == "BUTTONPLACEHOLDER") {
    String buttons = "";
    buttons += "<p><div<h4>Ora +</h4><label class=\"switch\"><input type=\"checkbox\" onchange=\"toggleCheckbox(this)\" id=\"1\" " + outputState(1) + "><span class=\"slider\"></span></label></div>";
    buttons += "<div<h4>Ora -</h4><label class=\"switch\"><input type=\"checkbox\" onchange=\"toggleCheckbox(this)\" id=\"2\" " + outputState(2) + "><span class=\"slider\"></span></label></div></p>";
    buttons += "<p><div<<h4>Min +</h4><label class=\"switch\"><input type=\"checkbox\" onchange=\"toggleCheckbox(this)\" id=\"3\" " + outputState(3) + "><span class=\"slider\"></span></label></div>";
    buttons += "<div<h4>Min -</h4><label class=\"switch\"><input type=\"checkbox\" onchange=\"toggleCheckbox(this)\" id=\"4\" " + outputState(4) + "><span class=\"slider\"></span></label></div></p>";
    buttons += "<p><div<h4>Gio +</h4><label class=\"switch\"><input type=\"checkbox\" onchange=\"toggleCheckbox(this)\" id=\"5\" " + outputState(5) + "><span class=\"slider\"></span></label></div>";
    buttons += "<div<h4>Gio -</h4><label class=\"switch\"><input type=\"checkbox\" onchange=\"toggleCheckbox(this)\" id=\"6\" " + outputState(6) + "><span class=\"slider\"></span></label></div></p>";
    buttons += "<h4>Mese +</h4><label class=\"switch\"><input type=\"checkbox\" onchange=\"toggleCheckbox(this)\" id=\"7\" " + outputState(7) + "><span class=\"slider\"></span></label>";
    return buttons;
  }
  return String();
}

String outputState(int output) {
  if (output) {
    return "checked";
  }
  else {
    return "";
  }
}

Ecco la seconda parte

void setup() {
  pinMode(LedRosso, OUTPUT);
  pinMode(LED_BUILTIN, OUTPUT);

  Serial.begin(115200);

  delay(300);
  if (!SD.begin(chipSelect)) {
    Serial.println("Initialization failed!");
    Allarme = 1;
  }

  dht.begin();
  rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
  DateTime now = rtc.now();

  _day = now.day();
  _month = now.month();
  _year = now.year();
  _hour = now.hour();
  _min = now.minute();
  _sec = now.second();
  delay(300);
  Serial.print("Imposto AP (Access Point)…");
  // se voglio togliere la PW basta rimuvere PASSWORD
  WiFi.softAP(ssid, password);

  IPAddress IP = WiFi.softAPIP();
  Serial.print("AP IP address: ");
  Serial.println(IP);

  // Scrivo l'indirizzo locale (192.168.4.1)
  Serial.println(WiFi.localIP());

  //richieste per il web
  server.on("/", HTTP_GET, [](AsyncWebServerRequest * request) {
    request->send_P(200, "text/html", index_html, processor);
  });
  server.on("/Data", HTTP_GET, [](AsyncWebServerRequest * request) {
    request->send_P(200, "text/plain", String(d).c_str());
  });
  server.on("/temperature", HTTP_GET, [](AsyncWebServerRequest * request) {
    request->send_P(200, "text/plain", String(t).c_str());
  });
  server.on("/humidity", HTTP_GET, [](AsyncWebServerRequest * request) {
    request->send_P(200, "text/plain", String(h).c_str());
  });

  server.on("/battery", HTTP_GET, [](AsyncWebServerRequest * request) {
    request->send_P(200, "text/plain", String(VoltValue).c_str());
  });

  server.on("/update", HTTP_GET, [] (AsyncWebServerRequest * request) {
    String inputMessage1;
    String inputMessage2;
    if (request->hasParam(PARAM_INPUT_1) && request->hasParam(PARAM_INPUT_2)) {
      inputMessage1 = request->getParam(PARAM_INPUT_1)->value();
      inputMessage2 = request->getParam(PARAM_INPUT_2)->value();

    }
    else {
      inputMessage1 = "No message sent";
      inputMessage2 = "No message sent";
    }
    //case per impostare RTC da Web
    int Var = inputMessage1.toInt();
    switch (Var) {
      case 1:
        // incremento ora
        rtc.adjust(DateTime(_year, _month, _day, _hour + 1, _min, _sec));
        break;
      case 2:
        // decremento ora
        rtc.adjust(DateTime(_year, _month, _day, _hour - 1, _min, _sec));
        break;
      case 3:
        // incremento minuti
        rtc.adjust(DateTime(_year, _month, _day, _hour, _min + 1, _sec));
        break;
      case 4:
        // decremento minuti
        rtc.adjust(DateTime(_year, _month, _day, _hour, _min - 1, _sec));
        break;
      case 5:
        //incremento giorni
        rtc.adjust(DateTime(_year, _month, _day + 1, _hour, _min , _sec));
        break;
      case 6:
        //decremento giorni
        rtc.adjust(DateTime(_year, _month, _day - 1, _hour, _min , _sec));
        break;
      case 7:
        // incremento mese
        rtc.adjust(DateTime(_year, _month + 1, _day, _hour, _min, _sec));
        break;
      default:
        // non faccio nulla
        break;
    }
    request->send(200, "text/plain", "OK");
  });

  //avvio il server
  server.begin();
}

void loop() {
  DateTime now = rtc.now();
  //loop per memorizzazione variabili

  _day = now.day();
  _month = now.month();
  _year = now.year();
  _hour = now.hour();
  _min = now.minute();
  _sec = now.second();


  // misurazione volt:
  value = analogRead(analogInPin);
  vout = (value * Vref) / 1024.0;

  VoltValue = vout / (R2 / (R1 + R2));
  if (VoltValue < 0.09) {
    VoltValue = 0.0;
  }

  d = String(now.hour()) + ':' + String(now.minute()) + ':' + String(now.second()) + " " + String(now.day()) + '/' + String(now.month()) + '/' + String(now.year());
  unsigned long currentMillis = millis();
  if (currentMillis - previousMillis >= interval) {
    previousMillis = currentMillis;
    // Leggo temperatura
    float newT = dht.readTemperature();
    if (isnan(newT)) {
      Serial.println("Non posso leggere i valori di temperatura");
      Allarme = 1;
    }
    else {
      t = newT;

    }
    //leggo Umidità
    float newH = dht.readHumidity();
    if (isnan(newH)) {
      Serial.println("Non posso leggere i valori di umidità");
      Allarme = 1;
    }
    else {
      h = newH;

    }
  }
  unsigned long currentMillisSD = millis();

  if (currentMillisSD - previousMillisSD >= intervalloSD) {
    // log su sd
    previousMillisSD = currentMillisSD;
    //accendo il led per verifica scrittura
    digitalWrite(LED_BUILTIN, !HIGH);
    String dataString = "";

    //Creo la stringa per insrimento in file

    dataString += (d +  "," + "  Umidità: " + h + "%" +  "," + "  Temperatura: " +  t + "°C" +  "," + "  Volt:"  + VoltValue + "V") ;

    // Apro il FIle
    String NomeFile(String(now.day()) + '_' + String(now.month()) + '_' + String(now.year()) + "-" + "DataLog.csv");
    File dataFile = SD.open(NomeFile, FILE_WRITE);

    if (dataFile) {
      dataFile.println(dataString);
      dataFile.close();
    }
    else {
      Serial.println("Non posso aprire il file");
      Allarme = 1;
    }
    delay(200);
  }
  //spengo il led per verifica scrittura
  digitalWrite(LED_BUILTIN, !LOW);

  //gestione allarme
  if (Allarme == 1) {
    digitalWrite(LedRosso, HIGH);
  }
  else {
    digitalWrite(LedRosso, LOW);
  }
}

Beh certo che ...

const int chipSelect = 4;

... su ESP8266, GPIO4 è SDA ... se me lo usi come CS della SD NON ho dubbi che non vada più nulla ... ::slight_smile:

Credo di sapere da quale schifo di sito tu hai copiato il progetto ... ti dico solo che li è sbagliato sia il codice che lo schema hardware ... ::slight_smile:

Guglielmo

Ho usato gli esempi forniti della ide e il mio vecchio codice.

Grazie per l'aiuto.

mirkogitmor:
Ho usato gli esempi forniti della ide e il mio vecchio codice.

... si, ma gli esempi sono, appunto "esempi" che servono a capire come funziona per poi scrivere il proprio programma.
Se li copi brutalmente, senza pensarci tanto ... è ovvio che poi hai problemi ... ::slight_smile:

Guglielmo

Una cosa che spesso trae in inganno chi arriva da Arduino è la nomenclatura dei piedini ...

Se su Arduino scrivi 5 o D5 indichi lo stesso pin ( digitalRaed(5) == digitalread(D5) ) questo grazie al file pins_arduino.h che mappa così i vari pin.

Quando invece ci si sposta su ESP le cose cambiano e D5 diventa GPIO13 quindi o si scrive D5 o si scrive 13, ma D5 e 5 (ovvero GPIO5 == D1) sono cose ben diverse e ... a volte può capitare di sbagliare :wink:

Guglielmo

This topic was automatically closed 120 days after the last reply. New replies are no longer allowed.