• Witaj na Forum Arduino Polska! Zapraszamy do rejestracji!
  • Znajdziesz tutaj wiele informacji na temat hardware / software.
Witaj! Logowanie Rejestracja


Ocena wątku:
  • 0 głosów - średnia: 0
  • 1
  • 2
  • 3
  • 4
  • 5
Komunikacja i2c pomiędzy NodeMCU a ProMini
#1
Witajcie!
Do mojego projektu muszę skomunikować NodeMCU v3 oraz ProMini za pomocą szyny i2c. Teoria jest całkiem jasna i zrozumiała, ale... nie działa tak jak należy, w zasadzie, nie działa wcale.
Kiedy robię zwykłą komunikację i2c typu master -> slave, wszystko jest super. Jednak kiedy master requestuje slave  już tak fajnie nie jest. Zastanawiam się, czy to ja popełniam błąd w kodzie, czy to jednak jakaś inna przyczyna. Robiłem testy z rezystorami podciągającymi oraz bez i nie przynosi to rezultatów. Dystans między urządzeniami to ok. 15 cm, docelowo będzie ok. 6-8m.
Czy możecie spojrzeć w mój kod i stwierdzić, czy są tam jakieś rażące błędy?

Master
Kod:
#include <Wire.h>
#include <RBD_Timer.h>

RBD::Timer timer_1(2500);
int x;

void setup() {
  Wire.begin();
  Serial.begin(115200);
  Serial.println("Connected to serial port.");
  pinMode(LED_BUILTIN, OUTPUT);
}

void blysk() {
  digitalWrite(LED_BUILTIN, LOW); 
  delay(20);                     
  digitalWrite(LED_BUILTIN, HIGH);   
  delay(10);
}

void loop() {
  if (timer_1.isExpired()) { 
  Wire.requestFrom(8, 1);
  Serial.println("Wysłano request i2c.");
  x = Wire.read();
  if (x > -1) {
  Serial.print("Odebrano wartość: ");
  Serial.println(x);   
  }
  blysk();
  timer_1.restart();
  }


Slave
Kod:
#include <Wire.h>

int pom, percent;
const int AirValue = 670;   //663 -> w powietrzu
const int WaterValue = 140;  //310 -> w wodzie 

void setup() {
  Wire.begin(8);               
  Serial.begin(115200);          
  Serial.println("Connected to serial port.");
  Wire.onRequest(requestEvent);
  pinMode(LED_BUILTIN, OUTPUT);
}

void blysk() {
  digitalWrite(LED_BUILTIN, LOW);  
  delay(200);                      
  digitalWrite(LED_BUILTIN, HIGH);   
  delay(10);
}

void requestEvent() {
       pom = analogRead(A0);
       percent = map(pom,AirValue,WaterValue,0,100);;
       Wire.write(percent);
           Serial.print("Wysłano odpowiedź i2c: ");
           Serial.println(percent);
        blysk();  
}


void loop() {
 
   }


Z góry dzięki za pomoc!
K.
 
Odpowiedź
#2
Czy nie lepiej rozważyć komunikację po UART. W wątku I2C "zacina" się poruszyłem problem biblioteki wire, która powoduje, że, najprawdopodobniej podczas zakłócenia, zawiesza się program i tylko reset pomaga.
No ale niech wypowiedzą się specjaliści.
 
Odpowiedź
#3
ESP8266 z I2C jest wyjątkowo cienki, bo ma to robione tylko programowo, jako master powinno działać. Dodatkowo działa różnie z różnymi wersjami core (czytałem na Elektrodzie). Pobaw się między AVR na początek i sprawdź czy działa jak chcesz.
Przykład odczytu slava:

Kod:
Master:

#include <Wire.h>
#define slave 8
const char str[]="1abcdefghijk";
  char buf[32];
int dane;
void setup() {
  // put your setup code here, to run once:
Serial.begin(115200);
Wire.begin();

}

void loop() {
  // put your main code here, to run repeatedly:
  int ilosc = I2CRead(slave,buf,sizeof(buf)+1);
  Serial.print("Odebrane dane: ");
  Serial.println(buf);
  Serial.println();
  Serial.print("Odebrano bajtow: ");
  Serial.println(ilosc);
  delay(2000);
}


uint16_t I2CRead(uint8_t adres, void *data, int len) {
        uint8_t receive;
        byte *b;
        Wire.beginTransmission(adres); //wyslanie danych konfiguracyjnych
        Wire.write(15);
        Wire.endTransmission();
        Wire.requestFrom(adres, len);
        for (receive = 0, b = (byte *) data; Wire.available() && receive< len; receive++, b++) {
        *b = Wire.read();
        }
        return (receive);
    }



Slave:
#include <Wire.h>
#define slave 8
const byte str[]="1fdgabcdfgdfgkkkl";
uint32_t c;
volatile uint8_t newreq=0;

void setup() {
  // put your setup code here, to run once:
  Serial.begin(115200);
Wire.begin(slave);   
Wire.onRequest(requestEvent);
//Wire.onReceive(receiveEvent);
}

void loop() {
  // put your main code here, to run repeatedly:
  if(newreq)
  {
    newreq=0;
    Serial.print(c);
  }
}

 
 
void requestEvent() {
I2CWrite(str,sizeof(str)+1);
}

void I2CWrite( void *data, int len) {
        Wire.write((byte *) data, len);
}
 
Odpowiedź
#4
Dzięki za odpowiedź!
Zgadza się, ten przykład działa bez pudła. Problem w tym, że mam już zrobioną stacje pogody na ESP8266, a teraz chcę wykorzystać ją do pomiaru wilgotności gleby. Czujnik światła, temperatury powietrza, wilgotności i ciśnienia śmigają tak od ponad roku.
Znalazłem bardzo fajny czujnik pojemnościowy na i2c, ale wychodzi drogo dla jednej sztuki.
https://www.tindie.com/products/miceuz/i...re-sensor/

Czas mnie nagli, bo niedługo sezon na podlewanie ogrodu się zacznie Wink

Może jednak iść w kierunku UART?

KST
 
Odpowiedź
#5
Kupiłem kiedyś garść takich, ale na razie nie miałem czasu się pobawić: link. Za pozostałe 10$ można kupić 6 ESP8266 lub 3 ESP32 i zrobić odczyt analogiem, przesłać przez WIFI do drugiego ESP, garść scalaków RS485 i przesłać kablem.
 
Odpowiedź
#6
Dokładnie na takim oparty jest mój czujnik plus ProMini. I ten "zestaw" chcę połączyć z ESP8266 po i2c. Ponieważ całość będzie zakopana pod ziemią jakieś 10 cm WiFi raczej odpada, ale sprawdze to Wink
Obecnie do ESP8266 mam podłączony ten czujnik na długim kablu, ale pojemność kabla i zmieniająca się wartość wilgotności gleby, powodują kompletna niestabilność odczytów.
Wykonam testy połączenia "spod ziemi" i być może to będzie rozwiązaniem problemu. Póki co walczę z i2c.

Dzięki
KST
 
Odpowiedź
#7
Poszukaj na Elektrodzie o problemie blokowania magistrali przez niektóre slave lub źle napisana obsługę I2C slave. Jest na to metoda. Kolejny temat zawieszanie TWI w AVR. Są na to procedury ale wire.h ich nie ma. Musisz więc sam napisać obsługę I2C dla AVR.
 
Odpowiedź
#8
Dzięki za wszelkie podpowiedzi!
Cobym nie robił, nie zadziałało. Ostatecznie użyłem komunikacji szeregowej i poszło od kopa.
Przy okazji chciałbym podzielić się moja obserwacją dotyczącą przytoczonego czujnika wilgotności. Kiedy napięcie na nim jest w granicach 3,1 - 3,3V wszystko gra, ale kiedy spada do ok. 3V czujnik przestaje całkowicie działać. Wypróbowałem 6 sztuk, tylko jedna działa, przy 3,08V, reszta nie startowała.

Jeszcze raz dzięki!
 
Odpowiedź
  


Skocz do:


Przeglądający: 1 gości