logo elektroda
logo elektroda
X
logo elektroda
Adblock/uBlockOrigin/AdGuard mogą powodować znikanie niektórych postów z powodu nowej reguły.

[Rozwiązano] Arduino - Nieprawidłowy odczyt stanu niskiego na pinach wejściowych PCF8574 z optoizolatorami PC817

mr_grabarz 04 Lut 2022 20:45 678 15
  • #1 19864711
    mr_grabarz
    Poziom 20  
    Posty: 416
    Pomógł: 29
    Ocena: 42
    Witam serdecznie

    Ostatnio postanowiłem uruchomić jeden z ekspanderów portów IO, konkretnie
    PCF8574

    I napotkałem ciekawy problem

    4 pierwsze piny mam zdefiniowane jako wejścia pozostałe cztery jako wyjścia

    ,//  expander I/O
      Serial.println(" PCF8574...");
      flap.pinMode(P0, OUTPUT, LOW);
      flap.pinMode(P1, OUTPUT, LOW);
      flap.pinMode(P2, OUTPUT, LOW);
      flap.pinMode(P3, OUTPUT, LOW);
      flap.pinMode(P4, INPUT_PULLUP);
      flap.pinMode(P5, INPUT_PULLUP);
      flap.pinMode(P6, INPUT_PULLUP);
      flap.pinMode(P7, INPUT_PULLUP);
      flap.begin();
      Serial.println("Done ;-)");  


    o ile co do wyjść nie mam zastrzeżeń, działają prawidłowo o tyle wejścia pomimo że panuje na nich stan niski są odczytywane jako logiczne "1"
    Przez stan niski mam na myśli ok 0,6V względem masy

    Sygnał na wejścia podawany jest przez optoizolatory PC817

    obsługa wejść i wyjść obrabiana jest teraz w dwóch funkcjach, w sumie z racji problemów z odczytem wejść, raczej testowych...

    void wyrzucenie_skrzyni()
    {
      if ((flap.digitalRead(P0) == 1 || flap.digitalRead(P1) == 1) && flap_ruch == 1)
      {
       // czekamy na dotarcie flapa na pozycję
       if ((digitalRead(6) == 0 && flap.digitalRead(P1) == 0) ||(digitalRead(7) == 0 && flap.digitalRead(P0) == 0))
       {
          flap.digitalWrite(P0, LOW);
          flap.digitalWrite(P1, LOW);
          flap_ruch = 0;
          flap_time = 0;
       }
      }
      else
      {
        //flap nie ma zgody na ruch, ale na sterowaniu cos jest..
        flap.digitalWrite(P0, LOW);
        flap.digitalWrite(P1, LOW);
        flap_ruch = 0;
      }
    
      if (digitalRead(6) == 1 && digitalRead(7) == 1 && flap.digitalRead(P0) == 0 && flap.digitalRead(P1) == 0)
      {
        Serial.println("Brak pozycji Flapsa...");
        Serial.println("a wiec prewencyjnie flaps w dol...");
        flap.digitalWrite(P1, HIGH);
        flap_ruch = 1;
      }  
    }
    


      if (millis() - time_stamp > 1000)
      {  
        time_stamp = millis();
        uptime();
      
      if (flap_time >= 3)
      {
        if (digitalRead(6) == 0 && flap.digitalRead(P0) == 0) //flap w górze, więc opusc
        {
          Serial.println("Opuszczam flapsa...");
          flap.digitalWrite(P1, HIGH);
          flap_ruch = 1;
        }
        if (digitalRead(7) == 0 && flap.digitalRead(P1) == 0)  //flap na dole, wiec podnies
        {
          Serial.println("Podnoszę flapsa...");
          flap.digitalWrite(P0, HIGH);
          flap_ruch = 1;
        }
      } else flap_time++;
          
      }


    co ciekawe podpięcie sygnałów pod piny na płytce arduino i zmiana w programie tylko miejsca odczytu wejść (z expandera na płytę) i wszystko działa ok...
    Jakieś pomysły?
  • #2 19864757
    krru
    Poziom 33  
    Posty: 1819
    Pomógł: 230
    Ocena: 214
    Ten układ ma piny OpenDrain i nie występuje w nim ustawianie kierunku pracy.
  • #3 19864975
    Konto nie istnieje
    Poziom 1  
  • #4 19865015
    krru
    Poziom 33  
    Posty: 1819
    Pomógł: 230
    Ocena: 214
    Używałem tego scalaka z kilkadziesiąt razy i mniej więcej tyleż razy czytałem jego datasheet. I dalej podtrzymuje co napisałem. To jest tak prosty układ, że używanie jakiejś biblioteki do
    jego obsługi to zdecydowany przerost formy nad treścią. Szczególnie takiej biblioteki, która wymaga by do sprawdzenia/ustawienia 2 bitów wykonywać 2 transfery.
  • #5 19865067
    mr_grabarz
    Poziom 20  
    Posty: 416
    Pomógł: 29
    Ocena: 42
    krru napisał:
    Ten układ ma piny OpenDrain i nie występuje w nim ustawianie kierunku pracy.

    no chyba nie rozumiem...
    piny są ustawiane jako wejścia lub jako wyjścia, możesz rozwinąć swoją wypowiedz?
    bo dla mnie kierunek programowy jest ustawiony

    emarcus napisał:
    krru napisał:
    Ten układ ma piny OpenDrain i nie występuje w nim ustawianie kierunku pracy.

    Skoro istnieje wybór wykorzystywania pinu jako 'wejście' lub alternatywnie 'wyjście' to istnieje tez na to odpowiedni sposób. Nie dzieje się to automatycznie, ani tez intuicyjnie zgodnie z zamiarem programisty, czego autor akurat doświadczył.

    ale czy ja oczekuje żeby działo się coś automatycznie?
    piny są definiowane, czy mają być jako wejście czy jako wyjście, nie oczekuje aby PCF miał szklaną kulę, no chyba że nie rozumiem o czym piszesz...

    mr_grabarz napisał:
    Kod: ,//  expander I/O
      Serial.println(" PCF8574...");
      flap.pinMode(P0, OUTPUT, LOW);
      flap.pinMode(P1, OUTPUT, LOW);
      flap.pinMode(P2, OUTPUT, LOW);
      flap.pinMode(P3, OUTPUT, LOW);
      flap.pinMode(P4, INPUT_PULLUP);
      flap.pinMode(P5, INPUT_PULLUP);
      flap.pinMode(P6, INPUT_PULLUP);
      flap.pinMode(P7, INPUT_PULLUP);
      flap.begin();
      Serial.println("Done ;-)");


    emarcus napisał:
    Należałoby przecztać odpowiedni fragment w datasheet.
    Jeżeli jest problem z czytaniem i Googlowy Translator nie jest w zasięgu(?). to przynajmniej oglądnąc ten 'vid-clip',
    https://www.youtube.com/watch?v=mXMkgQf3fqU

    gdzie prezenter/narrator pokazuje gdzie w datasheet ten aspekt jest opisany i objaśnia zagadnienie w szerszym zakresie niż 'suche' i lakoniczne stwierdzenie: "ma pinyOpenDrain".

    data sheeta przejrzałem, ale nie trafiłęm na rozwiązanie problemu, ale wydaje mi się, że nie tylko ja się "naciołem" bo przykłady z biblioteki mają podobny problem.
    Więc albo biblioteka po prostu jest niedopracowana, albo ja coś źle robię....
    krru napisał:
    To jest tak prosty układ, że używanie jakiejś biblioteki do
    jego obsługi to zdecydowany przerost formy nad treścią. Szczególnie takiej biblioteki, która wymaga by do sprawdzenia/ustawienia 2 bitów wykonywać 2 transfery.

    być może tak jest, dla mnie jednak biblioteka jest po prostu wygodna i jeżeli będzie działać tak jak bym chciał to nie widzę problemu w jej używaniu
    Wydaje mi się, że jeżeli uda się osiągnąć sukces to w tym konkretnym przypadku jest to istotne, a nie sposób w jaki się go osiągnęło...



    Panowie (i Panie) ja nie czuję się wybitnym programistą, więc naprawdę to co dla Was jest oczywiste, dla mnie takie nie jest....
    Podpowiecie jak to ogarnąć?
  • #7 19865361
    mr_grabarz
    Poziom 20  
    Posty: 416
    Pomógł: 29
    Ocena: 42
    Witam ponownie

    chyba się nie rozumiemy

    problem nie jest w uruchomieniu samego układu, żeby działał
    problemem nie jest skonfigurowanie pinu jako wejścia

    problemem jest to, że pętla która odczytuje stan wejścia działa dziwnie tzn.
    mamy pin w stanie wysokim, cały czas
    pin nie zmienia stanu!!!
    ale w pętli odczytującej z jakiegoś powodu nagle przy odczycie pinu przy co którymś odczycie pętli pojawia się "0" logiczne
    skąd to zero? żadna z powyższych odpowiedzi mi tego nie tłumaczy
    w pierwszym filmiku jest używany allread i jak "któryś" jest aktywny to reaguje resetując układ migania LED do stanu "startowego"
    nie ma słowa o tym, że '1" logiczna pojawia się na pinie bez wciskania czegokolwiek.
    w pozostałych przykładach analogicznie

    u mnie jest tak, że piny są normalnie w stanie wysokim i w konkretnym przypadku są ściągane do masy
    i tu jest problem, bo po ściągnięciu pinu do masy w programie "0" logiczne na tym pinie nie pojawia się od razu, ale po nastym odczycie, ale jednocześnie wyjścia są aktualizowane prawidłowo, zapisujemy "LOW" pojawia się od razu
    i potem pin wraca do stanu "HIGH" ale program odczytuje sobie dalej "0" logiczne na pinie, mija 3~5 sek i nagle odczyt jest prawidłowy
    w programie nie ma żadnych delay, więc skąd opóźnienia ?
    dlaczego ten problem występuje TYKO przy konfiguracji 4 pinów jako wejścia?
    jeżeli wszystkie 8 jest ustawionych jako wejścia problem nie występuje

    Panowie wydaj mi się, że nie doczytaliście, problemem nie jest to, że układ nie działa, czy, że nie da się odczytać wejść - da się, ale od zmiany stanu do prawidłowego odczytu mija kilka sekund, TYLKO wtedy kiedy wejścia są 4....
    Rozumiecie?
  • #8 19865369
    ex-or
    Poziom 28  
    Posty: 785
    Pomógł: 147
    Ocena: 151
    Bez wglądu w kod biblioteki można sobie tak szczebiotać jeszcze baaardzo długo. Pokaż to cudo (link do kodu)
  • #9 19865385
    mr_grabarz
    Poziom 20  
    Posty: 416
    Pomógł: 29
    Ocena: 42
    cały kod:
    Spoiler:
    //======================= Biblioteki =======================
    #include <LiquidCrystal_I2C.h>
    LiquidCrystal_I2C lcd(0x27, 20, 4);
    
    #include <PCF8574.h>
    PCF8574 flap(0x20);
    
    //======================= VAR ==============================
    const String
      wersja = "v1.2",
      data_kompilacji = "2021-12-15";
      
    const byte
      zwloka_wejscia = 20;
    
    byte
      in_13 = 0, in_13_lock = 0,
      flap_time = 0,
      flap_ruch = 0,
      in_1 = 0, in_1_lock = 0,
      in_2 = 0, in_2_lock = 0,
      in_3 = 0, in_3_lock = 0,
      in_4 = 0, in_4_lock = 0,
      wyrzut_skrzyni = 0,
      wysokosc_ok = 1,
      kontrola_wys_aktywna = 0,
      uptime_d = 0, uptime_h = 0, uptime_min = 0, uptime_sek = 0;  
    
    unsigned long 
      time_stamp = 0,
      skrzyn_ok = 0, skrzyn_ng = 0;
    
    //======================= SETUP ============================
    void setup()
    { //Serial port
      Serial.begin(9600);
      Serial.print("Wersja oprogramowania: ");
      Serial.print(wersja);
      Serial.print(" z dnia: ");
      Serial.println(data_kompilacji);
    
    //  INPUT
      Serial.println("INPUT...");
      pinMode(2,INPUT_PULLUP);
      pinMode(3,INPUT_PULLUP);
      pinMode(4,INPUT_PULLUP);
      pinMode(5,INPUT_PULLUP);
      pinMode(6,INPUT_PULLUP);
      pinMode(7,INPUT_PULLUP);
      pinMode(13,INPUT_PULLUP);
    
      
      Serial.println("Done ;-)");
    
    //  OUTPUT
      Serial.println("OUTPUT...");
      pinMode(8, OUTPUT);
      digitalWrite(8, HIGH);  //OUT 4
      pinMode(9, OUTPUT);
      digitalWrite(9, HIGH);  // OUT 3
      pinMode(10, OUTPUT);
      digitalWrite(10, HIGH); // OUT 2
      pinMode(11, OUTPUT);
      digitalWrite(11, HIGH); // OUT 1
    
      Serial.println("Done ;-)");
    
    //  expander I/O
      Serial.println(" PCF8574...");
      flap.pinMode(P0, OUTPUT, LOW);
      flap.pinMode(P1, OUTPUT, LOW);
      flap.pinMode(P2, OUTPUT, LOW);
      flap.pinMode(P3, OUTPUT, LOW);
      flap.pinMode(P4, INPUT_PULLUP);
      flap.pinMode(P5, INPUT_PULLUP);
      flap.pinMode(P6, INPUT_PULLUP);
      flap.pinMode(P7, INPUT_PULLUP);
      flap.begin();
      Serial.println("Done ;-)");  
    //  wyswietlacz LCD
    /*  Serial.println("LCD...");
      lcd.init();
      lcd.backlight();
      lcd.clear();
      lcd.setCursor(0,0);
      lcd.print("Wersja: ");
      lcd.print(wersja);
      lcd.setCursor(0,1);
      lcd.print("z dnia: ");
      lcd.print(data_kompilacji);
      Serial.println("Done ;-)");
      
      delay(3000);
      lcd.clear();
      lcd.setCursor(0,0);
      lcd.print("Kontrola nieaktywna");*/
    
      Serial.println("Start...");
    }
    //======================= Funkcje ==========================
    void uptime()
    {
      if (uptime_sek >= 60)
      {
        uptime_sek = 0;
        uptime_min++;
      }
      if (uptime_min >= 60)
      {
        uptime_h++;
        uptime_min = 0;
      }
    
      if (uptime_h >= 24)
      {
        uptime_d++;
        uptime_h = 0;
      }
     
    //  LCD
      lcd.setCursor(0,3);
      lcd.print("UpTime: ");
      if (uptime_d > 0)
      {
        lcd.print(uptime_d);
        lcd.print("d "); 
      }
      if (uptime_h < 10)
      lcd.print("0");
      lcd.print(uptime_h);
      lcd.print(":");
      if (uptime_min < 10)
      lcd.print("0");
      lcd.print(uptime_min);
      lcd.print(":");
      if (uptime_sek < 10)
      lcd.print("0");
      lcd.print(uptime_sek);
      uptime_sek++;  
    }
    //----------------------------------------------
    void kontrola_aktywna()
    {  
      if (digitalRead(13) == 0 && in_13 <= zwloka_wejscia &&  in_13_lock == 0)
        in_13++;  
    
      if (in_13 >= zwloka_wejscia && kontrola_wys_aktywna == 1)
      {
    //    lcd.setCursor(0,0);
        kontrola_wys_aktywna = 0;
    //    lcd.print("Kontrola nieaktywna ");
        Serial.println("Kontrola wysoklości nieaktywna");
        in_13_lock = 1;
        in_13 = 0;
      }
      
      if (in_13 >= zwloka_wejscia && kontrola_wys_aktywna == 0)
      {
        kontrola_wys_aktywna = 1;
        skrzyn_ok = 0;
        skrzyn_ng = 0;
        lcd.clear();
        
        lcd.setCursor(0,1);
        lcd.print("OK: ");
        lcd.print(skrzyn_ok);
        
        lcd.setCursor(0,2);
        lcd.print("NG: ");
        lcd.print(skrzyn_ng);
    
        lcd.setCursor(0,0);
        lcd.print("Kontrola aktywna    ");
        Serial.println("Kontrola wysokości aktywna");
        in_13_lock = 1;
        in_13 = 0;
      }
    
      if (digitalRead(13) == 1)
      {
        in_13 = 0;
        in_13_lock = 0;
      }
    }
    //----------------------------------------------
    void kontrola_wysokosci_skrzyni()
    {
      if (digitalRead(2) == 1 && in_1_lock == 0)
        in_1++;
        else in_1 = 0;
        
      if (in_1 >= zwloka_wejscia) //skrzynia na czujniku obecnosci
      {
        in_1_lock = 1;
      }  
      if (in_1_lock == 1 && digitalRead(3) == 1)  //kontrola wysokosci po ustawieniu bitu obecnosci skrzyni
          wysokosc_ok = 0;
    
    
      if (in_1_lock == 1 && digitalRead(2) == 0) //skrzynia zjechala z czujnika
      {
    
        if (wysokosc_ok == 1) // skrzynia OK
          skrzyn_ok++;
          else
          {
            skrzyn_ng++;
            wyrzut_skrzyni = 1;
          }
         
        lcd.setCursor(0,1);
        lcd.print("OK: ");
        lcd.print(skrzyn_ok);
        lcd.setCursor(0,2);
        lcd.print("NG: ");
        lcd.print(skrzyn_ng);
    
        wysokosc_ok = 1;
        in_1_lock = 0;
        in_1 = 0;
      }
    
      if (digitalRead(2) == 0)
      {
        in_1_lock = 0;
        in_1 = 0;
      }
    }
    //----------------------------------------------
    void wyrzucenie_skrzyni()
    {
      if ((flap.digitalRead(P0) == 1 || flap.digitalRead(P1) == 1) && flap_ruch == 1)
      {
       // czekamy na dotarcie flapa na pozycję
       if ((digitalRead(6) == 0 && flap.digitalRead(P1) == 0) ||(digitalRead(7) == 0 && flap.digitalRead(P0) == 0))
       {
          flap.digitalWrite(P0, LOW);
          flap.digitalWrite(P1, LOW);
          flap_ruch = 0;
          flap_time = 0;
       }
      }
      else
      {
        //flap nie ma zgody na ruch, ale na sterowaniu cos jest..
        flap.digitalWrite(P0, LOW);
        flap.digitalWrite(P1, LOW);
        flap_ruch = 0;
      }
    
      if (digitalRead(6) == 1 && digitalRead(7) == 1 && flap.digitalRead(P0) == 0 && flap.digitalRead(P1) == 0)
      {
        Serial.println("Brak pozycji Flapsa...");
        Serial.println("a wiec prewencyjnie flaps w dol...");
        flap.digitalWrite(P1, HIGH);
        flap_ruch = 1;
      }  
    }
    //----------------------------------------------
    //----------------------------------------------
    //----------------------------------------------
    //----------------------------------------------
    //======================= LOOP =============================
    void loop()
    {
      kontrola_aktywna();
      if (kontrola_wys_aktywna == 1)
      {
        kontrola_wysokosci_skrzyni();
    
      }  
      wyrzucenie_skrzyni();
    
    //------------------- 1 sek --------------------
      if (millis() - time_stamp > 1000)
      {  
        time_stamp = millis();
        uptime();
      
      if (flap_time >= 3)
      {
        if (digitalRead(6) == 0 && flap.digitalRead(P0) == 0) //flap w górze, więc opusc
        {
          Serial.println("Opuszczam flapsa...");
          flap.digitalWrite(P1, HIGH);
          flap_ruch = 1;
        }
        if (digitalRead(7) == 0 && flap.digitalRead(P1) == 0)  //flap na dole, wiec podnies
        {
          Serial.println("Podnoszę flapsa...");
          flap.digitalWrite(P0, HIGH);
          flap_ruch = 1;
        }
      } else flap_time++;
          
      }
    //----------------------------------------------
    }
    

    jeżeli 8 portów expander jest jako wyjścia - OK
    jeżel 4 porty jako wyjścia, 4 jako wejścia, to wejścia expandera nagle dostają opóźnienie po kilka sekund, ALE TYLKO WEJŚCIA, wyjścia działają bez problemu
    nie używam przerwania, bo sam kod wykonuje się na tyle szybko, że nie są potrzebne
    w kodzie nie ma żadnych delay, więc nie ma problemu, że wisimy na "delay" i dlatego odczyt wejścia nie trybi, chyba, że ja czegoś nie widzę.
    nie doczytałem się nigdzie potrzeby podciągania zewnętrznie pinów wejść do Vcc
    nie ogarniam...
    Załączniki:
    • PCF8574_library.zip (31.66 MB) Musisz być zalogowany, aby pobrać ten załącznik.
  • Pomocny post
    #10 19865439
    ex-or
    Poziom 28  
    Posty: 785
    Pomógł: 147
    Ocena: 151
    Funkcja digitalRead ma drugi parametr bool forceReadNow z domyślną wartością false, co jak sądzę, "buforuje" operację odczytu. Spróbuj odczytywać wejścia z ustawionym parametrem
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod

    Sposób inicjacji wejść (z pullupem czy bez) też jakoś wpływa na odczyt ale aż tak mi się nie chce grzebać w kodzie.
  • #11 19865481
    mr_grabarz
    Poziom 20  
    Posty: 416
    Pomógł: 29
    Ocena: 42
    ex-or napisał:
    Funkcja digitalRead ma drugi parametr bool forceReadNow z domyślną wartością false, co jak sądzę, "buforuje" operację odczytu.

    przegapiłem...
    ale to może być przyczyna, sprawdzę w poniedziałek, na "żywym organizmie" i dam znać.
  • #12 19865574
    mpier
    Poziom 29  
    Posty: 818
    Pomógł: 153
    Ocena: 141
    Witam,
    co masz podłączone do P0 i P1, że na zmianę ustawisz oba na wyjście w stanie niskim albo wysokim i jednocześnie próbujesz te wyjścia odczytać? Napisz program migający ledami z przyciskami i wtedy sprawdź.

    Pozdrawiam.
  • #13 19867047
    Konto nie istnieje
    Poziom 1  
  • #14 19867545
    mr_grabarz
    Poziom 20  
    Posty: 416
    Pomógł: 29
    Ocena: 42
    mpier napisał:
    Witam,
    co masz podłączone do P0 i P1, że na zmianę ustawisz oba na wyjście w stanie niskim albo wysokim i jednocześnie próbujesz te wyjścia odczytać? Napisz program migający ledami z przyciskami i wtedy sprawdź.

    wejścia sterownika silnika.
    odczytuje je dla pewności, żeby nie pojawiły się tam dwie "1", bo to jest stan zabroniony

    co do migania LED-ami,
    naprawdę?
    wyjścia działają...
    wejścia nie, przy przyciskach dochodzi jeszcze drgania styków, ale to nie ma znaczenia z czego jest wejście, nie działa

    to może być strzał w dziesiątkę
    ex-or napisał:
    Funkcja digitalRead ma drugi parametr bool forceReadNow z domyślną wartością false, co jak sądzę, "buforuje" operację odczytu


    sprawdzę w poniedziałek, dam znać
  • #15 19868873
    mpier
    Poziom 29  
    Posty: 818
    Pomógł: 153
    Ocena: 141
    Przecież jedyne "wejścia" jakie testujesz w załączonych programach to wyjścia P0 i P1 sterujące silnikiem. Może ja czegoś nie widzę.
  • #16 19869951
    mr_grabarz
    Poziom 20  
    Posty: 416
    Pomógł: 29
    Ocena: 42
    ex-or napisał:
    Funkcja digitalRead ma drugi parametr bool forceReadNow z domyślną wartością false, co jak sądzę, "buforuje" operację odczytu. Spróbuj odczytywać wejścia z ustawionym parametrem


    Sprawdzone,
    Jak się okazało, dodanie parametru forceREadNow na true rozwiązało problem


    w przykładach przytoczonych przez kolegów nie ma użytej bibliotek więc zakładam, że stąd brak problemu z odczytem

Podsumowanie tematu

LABEL_AI_GENERATED
Użytkownik napotkał problem z odczytem stanu niskiego na pinach wejściowych ekspandera portów I/O PCF8574, które są podłączone przez optoizolatory PC817. Mimo że piny są skonfigurowane jako wejścia, odczytywane są jako logiczne "1", nawet gdy napięcie wynosi około 0,6V. W dyskusji poruszono kwestie związane z konfiguracją pinów, opóźnieniami w odczycie oraz użyciem funkcji digitalRead z parametrem forceReadNow, co ostatecznie rozwiązało problem. Użytkownik podkreślił, że wyjścia działają poprawnie, a problem dotyczy jedynie wejść.
Podsumowanie AI na podstawie dyskusji. Może zawierać błędy.
REKLAMA