Skocz do zawartości

Pomocna odpowiedź

1 godzinę temu, H1M4W4R1 napisał:

Windows bardzo nie lubi połączenia Pico i VSCode.

O ile pamiętam kolega używa jakiegoś Minta czy czegoś Ubuntopodobnego... ale mogę się mylić.

1 godzinę temu, ethanak napisał:

O ile pamiętam kolega używa jakiegoś Minta czy czegoś Ubuntopodobnego... ale mogę się mylić.

Minta LMDE (debianopodobnego). Nie mylisz się. )

  • Lubię! 1

Wprawdzie programy dla ESP32-CAM mam napisane, program dla Pico kończę testować, ale możliwe, że jednak się poddam.

void miganie(short int ile=1, float dlugo=1) {
  int x = 0;
if (debug) { Serial.print("1"); }
  while (x++ < ile) {
if (debug) { Serial.print("2"); }
    digitalWrite(LED_BUILTIN, HIGH);
if (debug) { Serial.print("3"); }
    delay(dlugo*1000);
if (debug) { Serial.print("4"); }
    digitalWrite(LED_BUILTIN, LOW);
if (debug) { Serial.print("5"); }
    delay(dlugo*1000);
if (debug) { Serial.println("6"); }
  }
}

Program zawiesza się na instrukcji delay (po wyświetleniu 3). Po jakiejś godzince pracy i wykonaniu tego co najmniej kilku tysięcy razy poprawnie.

Błąd jest powtarzalny.

całość tu: https://github.com/Szern/Aktywny-System-Monitorujacy/blob/main/pico.ino

1 godzinę temu, Szern napisał:

Po jakiejś godzince pracy

A nie przypadkiem po 4295 sekundach?

W Pico masz 64-bitowy licznik mikrosekund. Jeśli framework Arduino operuje na 32-bitowych uintach to by się zgadzało... chociaż według źródeł delay wywołuje po prostu sleep_ms.

A przy okazji, podawanie parametru float do funkcji przyjmującej uint32_t to takie jakieś fujaste jest...

  • Lubię! 1

Ważniejsze by było wiedzieć z którego miejsca ta funkcja została wywołana. Ogólnie to: pisząc funkcję która ma zwrócić wskaźnik na przykład w tym miejscu

char * ustaw_czas() 
  ...

if ( i > 25 ) {
        client.stop();
        return 0;
      }
...

lepiej jasno określić że się nie udało i napisać

char * ustaw_czas() {
  ...
          if ( i > 25 ) {
        client.stop();
        return null; // <--- zmiana
      }
  ...

konstrukcja if(debug) również nie ułatwia rozczytania programu, od tego są makra:

#include "pico/stdlib.h"
#include <WiFi.h>

int debug = 1; 
#include "pico/stdlib.h"
#include <WiFi.h>

#define DEBUG 1 \\ <--zmiana

później w funkcji:

void miganie(short int ile=1, float dlugo=1) { // ########################################################################################
  int x = 0;
#if DEBUG == 1
 Serial.print("1");
#endif  
 while (x++ < ile) {
#if DEBUG == 1
 Serial.print("2");
#endif  
    digitalWrite(LED_BUILTIN, HIGH);
#if DEBUG == 1
 Serial.print("3");
#endif  
    delay(dlugo*1000);
#if DEBUG == 1
 Serial.print("4");
#endif  
    digitalWrite(LED_BUILTIN, LOW);
#if DEBUG == 1
 Serial.print("5");
#endif  
    delay(dlugo*1000);
#if DEBUG == 1
 Serial.print("6");
#endif  
  }
}

to oczywiście nic nie zmieni jeśli chodzi o działanie w czasie debugowania ale za pomocą jednej zmiany w definicji wycinasz niepotrzebne kawałki kodu. Dobrze by było znać ostatnie miejsce skąd funkcja została wywołana:

void miganie(short int ile=1, float dlugo=1, int from) { // ########################################################################################
  int x = 0;
#if DEBUG == 1
 Serial.print("1");
#endif  
 while (x++ < ile) {
#if DEBUG == 1
 Serial.print("2");
#endif  
    digitalWrite(LED_BUILTIN, HIGH);
#if DEBUG == 1
 Serial.print("3");
#endif  
    delay(dlugo*1000);
#if DEBUG == 1
 Serial.print("4");
#endif  
    digitalWrite(LED_BUILTIN, LOW);
#if DEBUG == 1
 Serial.print("5");
#endif  
    delay(dlugo*1000);
#if DEBUG == 1
 Serial.print("6");
#endif  
  }
}

później wywołujesz:

 miganie(1,0.1,1);

niestety nie pomogę tego wypisać za pomocą c++ bo się nie znam, ale w C zrobiłbym tak:

printf("test 1 from %d\n",from);

 

  • Lubię! 1
9 godzin temu, _LM_ napisał:

Ważniejsze by było wiedzieć z którego miejsca ta funkcja została wywołana. Ogólnie to: pisząc funkcję która ma zwrócić wskaźnik na przykład w tym miejscu

char * ustaw_czas() 
  ...

if ( i > 25 ) {
        client.stop();
        return 0;
      }
...

lepiej jasno określić że się nie udało i napisać

char * ustaw_czas() {
  ...
          if ( i > 25 ) {
        client.stop();
        return null; // <--- zmiana
      }
  ...

Nie bardzo to działa. Nie do końca rozumiem sens tej zmiany.

/home/szern/Arduino/Pic_C_asm_jeden/Pic_C_asm_jeden.ino:351:16: warning: converting to non-pointer type 'int' from NULL [-Wconversion-null]
  351 |         return NULL; // tu ucieka

Dziękuję za lekcję użycia makr do debugowania, poprawiłem.

  • Lubię! 1
6 minut temu, Szern napisał:

Nie bardzo to działa.

Użyj nullptr w C++, czyli:

return nullptr;

Ogólnie w C NULL to (void *)0, ale w C++ kompilatory za tym nie przepadają.

  • Lubię! 1
(edytowany)
10 godzin temu, ethanak napisał:

A nie przypadkiem po 4295 sekundach?

W Pico masz 64-bitowy licznik mikrosekund. Jeśli framework Arduino operuje na 32-bitowych uintach to by się zgadzało... chociaż według źródeł delay wywołuje po prostu sleep_ms.

A przy okazji, podawanie parametru float do funkcji przyjmującej uint32_t to takie jakieś fujaste jest...

Właśnie sprawdzam, ale wydaje mi się, że masz rację, to będzie ok. 70 minut.

Ale... Przepraszam, ale w mikrokontrolery i C to ja początkujący jestem. Nie bardzo rozumiem, dlaczego delay operując na mikrosekundach może stwarzać taki problem. Nie wiem jak to naprawić. Czy mam to rozumieć tak, że problemem może być użycie do kompilowania ArduinoIDE?

float dlatego, że chciałem móc dla własnej wygody podawać sobie parametr funkcji w sekundach. Ale skoro uważasz, że to nieeleganckie, to poprawię...

Edytowano przez Szern
(edytowany)
25 minut temu, ethanak napisał:

Użyj nullptr w C++, czyli:

return nullptr;

Ogólnie w C NULL to (void *)0, ale w C++ kompilatory za tym nie przepadają.

/home/szern/Arduino/Pic_C_asm_jeden/Pic_C_asm_jeden.ino:351:16: error: cannot convert 'std::nullptr_t' to 'int' in return
  351 |         return nullptr; // tu ucieka

Prawdopodobnie chodzi o to, że funkcja zdefiniowana jest przeze mnie tak, aby zwracać int. Dlatego zwracałem tam zero.

Edytowano przez Szern
11 godzin temu, ethanak napisał:

A nie przypadkiem po 4295 sekundach?

W Pico masz 64-bitowy licznik mikrosekund. Jeśli framework Arduino operuje na 32-bitowych uintach to by się zgadzało... chociaż według źródeł delay wywołuje po prostu sleep_ms.

Trafiłeś dokładnie. Podsuniesz mi kieunek, w jakim mam pójść aby rozwiązać problem? Czy sądzisz, że https://github.com/raspberrypi/pico-sdk rozwiąże problem?

48 minut temu, Szern napisał:

Nie bardzo rozumiem, dlaczego delay operując na mikrosekundach może stwarzać taki problem

To przelicz sobie 2^32 mikrosekund na sekundy. Pamiętaj o tym, że RP2040 zakłada istnienie 64-bitowego licznika mikrosekund startującego od zera w chwili uruchomienia procesora, i funkcje typu sleep(cośtam) w sumie kończą się oczekiwaniem na konkretną wartość owego licznika.

 

49 minut temu, Szern napisał:

użycie do kompilowania ArduinoIDE

Arduino IDE nic nie kompiluje, to po prostu wrapper do gcc (dość skomplikowany co prawda, ale wrapper). Winne mogą być biblioteki (platform, czyli implementacja funkcji Arduino dla konkretnej płytki). A warto pamiętać, że owe funkcje były pisane dla ośmiobitowej ATmegi, a nie 32-bitowców.

Jedynym znanym mi wyjątkiem jest implementacja Arduino dla ESP32 - ale była ona tworzona bezpośrednio przez twórców owego ESP i tak naprawdę to tylko wrapper do FreeRTOS-a.

47 minut temu, Szern napisał:

funkcja zdefiniowana jest przeze mnie tak, aby zwracać int

A to przepraszam, ostatnio widziałem że ma zwracać wskaźnik...

(edytowany)
5 godzin temu, ethanak napisał:

To przelicz sobie 2^32 mikrosekund na sekundy. Pamiętaj o tym, że RP2040 zakłada istnienie 64-bitowego licznika mikrosekund startującego od zera w chwili uruchomienia procesora, i funkcje typu sleep(cośtam) w sumie kończą się oczekiwaniem na konkretną wartość owego licznika.

 

Arduino IDE nic nie kompiluje, to po prostu wrapper do gcc (dość skomplikowany co prawda, ale wrapper). Winne mogą być biblioteki (platform, czyli implementacja funkcji Arduino dla konkretnej płytki). A warto pamiętać, że owe funkcje były pisane dla ośmiobitowej ATmegi, a nie 32-bitowców.

Wydaje mi się, że delay() działa w tym przypadku nieprawidłowo (używam https://github.com/earlephilhower/arduino-pico). Zastąpiłem go sleep_ms() i sprawdzam.

Sprawdziłem. Wiesza się tak samo. To niekoniecznie jest 70 minut, czasem wiesza się po niespełna czterdziestu.

Edytowano przez Szern
(edytowany)

Próbowałeś zmienić funkcję miganie aby ewentualnie znaleźć miejsce z którego nastąpiło wywołanie? Żeby już nie przerabiać dużej ilości kodu zrobiłem poprawkę pasującą do twojego kodu:

void miganie(short int ile = 1, float dlugo = 1) { // ########################################################################################
  int x = 0;

  if (debug) {
    Serial.println("ma byc %d", ile); // Wejscie
  }

  if (debug) {
    Serial.print("1");
  }
  while (x++ < ile) {
    if (debug) {
      Serial.print("2");
    }
    digitalWrite(LED_BUILTIN, HIGH);
    if (debug) {
      Serial.print("3");
    }
    delay(dlugo * 1000);
    if (debug) {
      Serial.print("4");
    }
    digitalWrite(LED_BUILTIN, LOW);
    if (debug) {
      Serial.print("5");
    }
    delay(dlugo * 1000);
    if (debug) {
      Serial.println("6");
    }
  }
  if(debug)Serial.print("Q"); //Wyjscie
}

Bo zakładam że "ile" jest wyznacznikiem miejsca z którego następuje wywołanie

Edytowano przez _LM_
37 minut temu, _LM_ napisał:

Próbowałeś zmienić funkcję miganie aby ewentualnie znaleźć miejsce z którego nastąpiło wywołanie? Żeby już nie przerabiać dużej ilości kodu zrobiłem poprawkę pasującą do twojego kodu:

Wiedziałem skąd następuje wywołanie (z logiki programu). To ostatnie polecenie kodu (koniec sekcji loop). Napisałem i uruchomiłem to tak, jak mi podpowiedziałeś, aby się upewnić. Potwierdziło  się - wywołanie funkcji miganie w której następuje zawieszenie następuje na samym końcu kodu. Właściwie to wywołanie nawet nie jest mi niezbędne, ale jeśli mechanizm błędu jest taki jak napisał @ethanak to i tak prędzej czy później (raczej później) program się zawiesi, o ile dobrze to rozumiem. No chyba, że zmienię środowisko i biblioteki, a czasie, który mi pozostał nie dam rady.

Mój problem polega na tym, że de facto mam czas do niedzieli, później wyjeżdżam zostawiając alarm w takim stanie jak będzie i wrócę do niego dopiero wiosną. Zrozumienie i naprawienie obecnego błędu w tym czasie przekracza moje aktualne umiejętności. Spróbuję jeszcze dziś użyć watchdoga jako protezy pilnującej restartu po zawieszeniu, ale mam nikłą wiedzę na ten temat i nawet nie wiem na pewno czy to będzie możliwe.

Zdaje sobie w pełni sprawę, że to jest ordynarna łata, a nie rozwiązanie problemu, ale watchdog działa.

Jedna pętla programu wykonuje się w niecałą sekundę, a kiedy coś się dzieje (naruszone czujki, wysyłane SMS-y, synchronizacja czasu itp.) to wyjątkowo do dziesięciu sekund. Ustawiłem więc sprzętowego watchdoga na 60 sekund i... działa. To znaczy, restartuje system, kiedy wszystko pójdzie w maliny.

Rozwiązanie dalekie jest od elegancji, ale mogę już wyjechać zostawiając ASM na pastwę losu. To pierwszy prototyp i nie musi być doskonały. Zebrane doświadczenia wykorzystam wiosną do budowy kolejnej wersji (drugiego prototypu - @H1M4W4R1 miałeś rację). Wtedy również zbuduję lepszy kod.

Na razie system sprawdza czujki, wysyła ich stan na serwer, gdzie sytuacja jest wizualizowana i logowana. Kiedy zaczyna się dziać coś niepokojącego powiadamia mnie SMS-em. W zależności od rozwoju sytuacji włącza syreny. Według zadanego harmonogramu (z elementem losowym) włącza światło w domu. Mogę na swojej stronie (panelu) podejrzeć w każdej chwili widok (statyczny, z opóźnieniem) z dwóch kamer i zdalnie (SMSem) włączyć syreny, albo np. zresetować kamery, albo włączyć poszczególne światła w domu.

Właściwie jestem tam, gdzie chciałem być jesienią. Wymieniam uszkodzone czujki, robię drobne poprawki w kodzie i na zakończenie podzielę się filmem, na którym pokażę całość w działaniu i podzielę się dokumentacją. Później zamrażam projekt do wiosny i odlatuję do ciepłych krajów. :P

Bardzo dziękuję wszystkim, którzy wspierali mnie zarówno merytorycznie jak i psychicznie. Bez Was nie dałbym rady. :)

  • Lubię! 1

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...