Skocz do zawartości

Problem z zaprogramowaniem czujnika poziomu cieczy Grove Seeedstudio 101020635


piet

Pomocna odpowiedź

Witam,

zakupiłem czujnik poziomu cieczy wymieniony w tytule, jednak pomimo zrealizowania kursu nie potrafię go zaprogramować. Producent podał przykładowy kod lecz jest on dla mnie nieczytelny. 

#include <Wire.h>

#ifdef ARDUINO_SAMD_VARIANT_COMPLIANCE
#define SERIAL SerialUSB
#else
#define SERIAL Serial
#endif

unsigned char low_data[8] = {0};
unsigned char high_data[12] = {0};


#define NO_TOUCH       0xFE
#define THRESHOLD      100
#define ATTINY1_HIGH_ADDR   0x78
#define ATTINY2_LOW_ADDR   0x77

void getHigh12SectionValue(void)
{
  memset(high_data, 0, sizeof(high_data));
  Wire.requestFrom(ATTINY1_HIGH_ADDR, 12);
  while (12 != Wire.available());

  for (int i = 0; i < 12; i++) {
    high_data[i] = Wire.read();
  }
  delay(10);
}

void getLow8SectionValue(void)
{
  memset(low_data, 0, sizeof(low_data));
  Wire.requestFrom(ATTINY2_LOW_ADDR, 8);
  while (8 != Wire.available());

  for (int i = 0; i < 8 ; i++) {
    low_data[i] = Wire.read(); // receive a byte as character
  }
  delay(10);
}

void check()
{
  int sensorvalue_min = 250;
  int sensorvalue_max = 255;
  int low_count = 0;
  int high_count = 0;
  while (1)
  {
    uint32_t touch_val = 0;
    uint8_t trig_section = 0;
    low_count = 0;
    high_count = 0;
    getLow8SectionValue();
    getHigh12SectionValue();

    Serial.println("low 8 sections value = ");
    for (int i = 0; i < 8; i++)
    {
      Serial.print(low_data[i]);
      Serial.print(".");
      if (low_data[i] >= sensorvalue_min && low_data[i] <= sensorvalue_max)
      {
        low_count++;
      }
      if (low_count == 8)
      {
        Serial.print("      ");
        Serial.print("PASS");
      }
    }
    Serial.println("  ");
    Serial.println("  ");
    Serial.println("high 12 sections value = ");
    for (int i = 0; i < 12; i++)
    {
      Serial.print(high_data[i]);
      Serial.print(".");

      if (high_data[i] >= sensorvalue_min && high_data[i] <= sensorvalue_max)
      {
        high_count++;
      }
      if (high_count == 12)
      {
        Serial.print("      ");
        Serial.print("PASS");
      }
    }

    Serial.println("  ");
    Serial.println("  ");

    for (int i = 0 ; i < 8; i++) {
      if (low_data[i] > THRESHOLD) {
        touch_val |= 1 << i;

      }
    }
    for (int i = 0 ; i < 12; i++) {
      if (high_data[i] > THRESHOLD) {
        touch_val |= (uint32_t)1 << (8 + i);
      }
    }

    while (touch_val & 0x01)
    {
      trig_section++;
      touch_val >>= 1;
    }
    SERIAL.print("water level = ");
    SERIAL.print(trig_section * 5);
    SERIAL.println("% ");
    SERIAL.println(" ");
    SERIAL.println("*********************************************************");
    delay(1000);
  }
}

void setup() {
  SERIAL.begin(115200);
  Wire.begin();
}

void loop()
{
  check();
}


 

Zależy mi na pobraniu informacji o poziomie cieczy oraz przypisaniu jej do zmiennej. Czy jest ktoś w stanie wytłumaczyć poszczególne elementy powyższego kodu lub napisać własny ale mniej skomplikowany. Największą wartość ma dla mnie zrozumienie kodu a nie tylko przekopiowanie.

Z góry dziękuje za odpowiedź.

Edytowano przez piet
źle wstawiony kod
Link do komentarza
Share on other sites

Dnia 21.09.2024 o 20:33, piet napisał:

Producent podał przykładowy kod lecz jest on dla mnie nieczytelny. 

Wrzuć w AI, niech ci opisze kod, może coś rozjaśni. Tak komentuje gpt4o.
 

#include <Wire.h> // Importuje bibliotekę Wire do komunikacji I2C

// Ustawia odpowiedni interfejs szeregowy w zależności od platformy
#ifdef ARDUINO_SAMD_VARIANT_COMPLIANCE
#define SERIAL SerialUSB
#else
#define SERIAL Serial
#endif

// Deklaracja tablic na dane z odczytów I2C
unsigned char low_data[8] = {0};  // Tablica na 8 bajtów danych z niskiego adresu
unsigned char high_data[12] = {0}; // Tablica na 12 bajtów danych z wysokiego adresu

// Stałe definiujące pewne progi i adresy I2C
#define NO_TOUCH       0xFE    // Wartość oznaczająca brak dotyku (niewykorzystana w kodzie)
#define THRESHOLD      100     // Próg dla wykrywania
#define ATTINY1_HIGH_ADDR   0x78  // Adres I2C pierwszego urządzenia
#define ATTINY2_LOW_ADDR    0x77  // Adres I2C drugiego urządzenia

// Funkcja odczytująca 12 bajtów z urządzenia pod adresem ATTINY1_HIGH_ADDR
void getHigh12SectionValue(void)
{
  memset(high_data, 0, sizeof(high_data)); // Czyści tablicę high_data
  Wire.requestFrom(ATTINY1_HIGH_ADDR, 12); // Żąda 12 bajtów z urządzenia
  while (12 != Wire.available()); // Czeka aż wszystkie bajty będą dostępne
  for (int i = 0; i < 12; i++) {
    high_data[i] = Wire.read(); // Odczytuje dane i zapisuje do tablicy
  }
  delay(10); // Krótka przerwa, na stabilizację
}

// Funkcja odczytująca 8 bajtów z urządzenia pod adresem ATTINY2_LOW_ADDR
void getLow8SectionValue(void)
{
  memset(low_data, 0, sizeof(low_data)); // Czyści tablicę low_data
  Wire.requestFrom(ATTINY2_LOW_ADDR, 8); // Żąda 8 bajtów z urządzenia
  while (8 != Wire.available()); // Czeka aż wszystkie bajty będą dostępne
  for (int i = 0; i < 8; i++) {
    low_data[i] = Wire.read(); // Odczytuje dane i zapisuje do tablicy
  }
  delay(10); // Krótka przerwa, na stabilizację
}

// Funkcja analizująca odczytane dane i obliczająca poziom wody
void check()
{
  int sensorvalue_min = 250; // Minimalna wartość dla czujników do zaliczenia
  int sensorvalue_max = 255; // Maksymalna wartość dla czujników do zaliczenia
  int low_count = 0;         // Licznik dla sekcji niskich
  int high_count = 0;        // Licznik dla sekcji wysokich

  while (1)
  {
    uint32_t touch_val = 0;   // Przechowuje wartości sekcji po przekroczeniu progu
    uint8_t trig_section = 0; // Liczy, ile sekcji przekroczyło próg
    low_count = 0;
    high_count = 0;

    getLow8SectionValue();     // Pobiera wartości niskich sekcji
    getHigh12SectionValue();   // Pobiera wartości wysokich sekcji

    SERIAL.println("low 8 sections value = ");
    for (int i = 0; i < 8; i++)
    {
      SERIAL.print(low_data[i]); // Drukuje każdą wartość z niskich sekcji
      SERIAL.print(".");
      if (low_data[i] >= sensorvalue_min && low_data[i] <= sensorvalue_max)
      {
        low_count++; // Zlicza ilość wartości mieszczących się w przedziale
      }
      if (low_count == 8)
      {
        SERIAL.print("      ");
        SERIAL.print("PASS"); // Drukuje "PASS", jeśli wszystkie wartości spełniają warunek
      }
    }

    SERIAL.println("  ");
    SERIAL.println("  ");

    SERIAL.println("high 12 sections value = ");
    for (int i = 0; i < 12; i++)
    {
      SERIAL.print(high_data[i]); // Drukuje każdą wartość z wysokich sekcji
      SERIAL.print(".");
      if (high_data[i] >= sensorvalue_min && high_data[i] <= sensorvalue_max)
      {
        high_count++; // Zlicza ilość wartości mieszczących się w przedziale
      }
      if (high_count == 12)
      {
        SERIAL.print("      ");
        SERIAL.print("PASS"); // Drukuje "PASS", jeśli wszystkie wartości spełniają warunek
      }
    }

    SERIAL.println("  ");
    SERIAL.println("  ");

    // Przetwarza dane i przekształca je na wartość binarną touch_val
    for (int i = 0; i < 8; i++) {
      if (low_data[i] > THRESHOLD) {
        touch_val |= 1 << i; // Ustawia odpowiednie bity dla sekcji niskich
      }
    }
    for (int i = 0; i < 12; i++) {
      if (high_data[i] > THRESHOLD) {
        touch_val |= (uint32_t)1 << (8 + i); // Ustawia odpowiednie bity dla sekcji wysokich
      }
    }

    // Liczy ilu-sekcyjne detekcje zostały uruchomione
    while (touch_val & 0x01)
    {
      trig_section++;
      touch_val >>= 1;
    }

    // Oblicza poziom wody w procentach i drukuje wynik
    SERIAL.print("water level = ");
    SERIAL.print(trig_section * 5);
    SERIAL.println("% ");
    SERIAL.println(" ");
    SERIAL.println("*********************************************************");

    delay(1000); // Opóźnienie przed kolejnym pomiarem
  }
}

void setup() {
  SERIAL.begin(115200); // Inicjalizuje komunikację szeregową z prędkością 115200 bps
  Wire.begin();         // Inicjalizuje interfejs I2C
}

void loop()
{
  check(); // Nieskończona pętla wykonywująca funkcję check()
}

 

Link do komentarza
Share on other sites

Ten program wiele się nie da uprościć.

Z czujnika trzeba pobrać sporo danych - 8 bajtów z jednego adresu i 12 bajtów z drugiego. Problem tylko jak te dane interpretować; przydałby się jakiś podręcznik użytkownika, ale tak na szybko nie udało mi się go znaleźć.

 

Link do komentarza
Share on other sites

Zarejestruj się lub zaloguj, aby ukryć tę reklamę.
Zarejestruj się lub zaloguj, aby ukryć tę reklamę.

jlcpcb.jpg

jlcpcb.jpg

Produkcja i montaż PCB - wybierz sprawdzone PCBWay!
   • Darmowe płytki dla studentów i projektów non-profit
   • Tylko 5$ za 10 prototypów PCB w 24 godziny
   • Usługa projektowania PCB na zlecenie
   • Montaż PCB od 30$ + bezpłatna dostawa i szablony
   • Darmowe narzędzie do podglądu plików Gerber
Zobacz również » Film z fabryki PCBWay

Widziałem tę stronę z kodem.

Jest tam nawet animowany obraz ekranu, przedstawiający wynik działania programu, ale niewiele on pomaga w zrozumieniu struktury danych.

Trzeba by pobawić się czujnikiem, zanurzając go stopniowo i obserwując dane, przy jednoczesnej analizie kodu.

Link do komentarza
Share on other sites

Biorąc pod uwagę brak dokumentacji w desperacji można z tego kodu wywnioskować, że końcowy wynik (liczbę zanurzonych sekcji czujnika) ustala się się jako liczbę kolejnych następujących po sobie odczytanych bajtów (z 8 + 12 = 20 bajtów reprezentujących kolejnych 20 sekcji czujnika), które mają wartość powyżej wartości THRESHOLD (w kodzie zdefiniowana na 100). Jeżeli odczytany bajt ma wartość mniejszą niż THRESHOLD to ten bajt i wszystkie następne są pomijane przy obliczaniu wyniku (nawet gdybyś jeszcze któreś miały wartość powyżej THRESHOLD). Każdy zliczony bajt dodaje 5% (1 z 20) do wyniku głębokości zanurzenia.

Zliczanie liczby odczytów powyżej progu (wynik trafia do trig_section) odbywa się w tym fragmencie:

    for (int i = 0 ; i < 8; i++) {
      if (low_data[i] > THRESHOLD) {
        touch_val |= 1 << i;

      }
    }
    for (int i = 0 ; i < 12; i++) {
      if (high_data[i] > THRESHOLD) {
        touch_val |= (uint32_t)1 << (8 + i);
      }
    }

    while (touch_val & 0x01)
    {
      trig_section++;
      touch_val >>= 1;
    }

Ponadto ten fragment przykładowego programu - dwie pętle - zawiera jakąś dodatkową weryfikację danych z sygnalizacją na konsoli, ale bez wpływu na dalszy przebieg programu - nie ma nic wspólnego z obliczaniem wyniku:

    Serial.println("low 8 sections value = ");
    for (int i = 0; i < 8; i++)
    {
     	// (...) zobacz wyzej
    }
    Serial.println("  ");
    Serial.println("  ");
    Serial.println("high 12 sections value = ");
    for (int i = 0; i < 12; i++)
    {
      // (...) zobacz wyzej
    }

 

 

 

Edytowano przez ReniferRudolf
Link do komentarza
Share on other sites

Bądź aktywny - zaloguj się lub utwórz konto!

Tylko zarejestrowani użytkownicy mogą komentować zawartość tej strony

Utwórz konto w ~20 sekund!

Zarejestruj nowe konto, to proste!

Zarejestruj się »

Zaloguj się

Posiadasz własne konto? Użyj go!

Zaloguj się »
×
×
  • Utwórz nowe...

Ważne informacje

Ta strona używa ciasteczek (cookies), dzięki którym może działać lepiej. Więcej na ten temat znajdziesz w Polityce Prywatności.