Skocz do zawartości

Program choinki - zawieszanie się programu [Klon Arduino Mega]


BananWszyscy

Pomocna odpowiedź

Wpierw kod:

//47 zwykłych diod
//3 czubek
//2 przyciski


//rozklad warstwowo:
/*1w 0-1
  2w 2-5
  3w 6-9
  4w 10-14
  5w 15-19
  6w 20-25
  7w 26-31
  8w 32-38
  9w 39-46*/

#include "TimerOne.h"

#define przycisk1 A15
#define przycisk2 A14

#define gwiazda_zielony A0
#define gwiazda_niebieski A1
#define gwiazda_czerwony A2

int numer_programu = 0;
int tryb_gwiazdy = 0;
uint8_t krok_programu = 1;
boolean tablica_led[47];
int licznik_timera = 0; //licznik, ktory zmienia wartosc o 1 co przerwanie

//deklaracje funkcji
void program0();
void program1();
void program2();
void program3();
void program4();
void program5();
void kontrola_krokow(uint8_t liczba_krokow, int czas_opoznienia_swiecenia);
void wystaw_wyjscia_diod();
void obsluga_przyciskow();
void migajaca_gwiazda();
void przerwanie_od_timera();

void setup() {
  //wyjscia
  for (int i = 0; i < 47; i++)
    pinMode( i, OUTPUT);
  //wejscia
  pinMode(gwiazda_zielony, OUTPUT);
  pinMode(gwiazda_niebieski, OUTPUT);
  pinMode(gwiazda_czerwony, OUTPUT);
  pinMode(przycisk1, INPUT);
  pinMode(przycisk2, INPUT);
  //przerwanie od timera na 1ms
  Timer1.initialize(1000);
  Timer1.attachInterrupt(przerwanie_od_timera);
  delay(500);
  digitalWrite(gwiazda_czerwony, LOW);
  digitalWrite(gwiazda_niebieski, LOW);
  digitalWrite(gwiazda_zielony, LOW);
  //  Serial.begin(9600);

}

void loop()
{
  int czas_opoznienia_swiecenia;
  uint8_t liczba_krokow;
  switch (numer_programu)
  {
    case 0:
      program0();
      break;
    case 1:
      liczba_krokow = 2;
      czas_opoznienia_swiecenia = 500;
      program1();
      break;
    case 2:
      liczba_krokow = 9;
      czas_opoznienia_swiecenia = 80;
      program2();
      break;
    case 3:
      liczba_krokow = 8;
      czas_opoznienia_swiecenia = 60;
      program3();
      break;
    case 4:
      program4();
      break;
    case 5:
      program5();
      break;
  }
  switch (tryb_gwiazdy)
  {
    case 1:
      {
        digitalWrite(gwiazda_czerwony, LOW);
        digitalWrite(gwiazda_niebieski, LOW);
        digitalWrite(gwiazda_zielony, LOW);
        break;
      }
    case 2:
      {
        migajaca_gwiazda();
        break;
      }
  }
  wystaw_wyjscia_diod();

  if (numer_programu != 0)
    kontrola_krokow(liczba_krokow, czas_opoznienia_swiecenia);
    
  obsluga_przyciskow(); 

  //debugowanie
  //  Serial.print(numer_programu);
  //  Serial.print("   ");
  //  Serial.print(krok_programu);
  //  Serial.print("   ");
  //  Serial.print(licznik_timera);
  //  Serial.print("   ");
  //  Serial.print(tablica_led[44]);
  //  Serial.print("   ");
  //  Serial.println(tablica_led[45]);
}


void program0()  //wszystko świeci na pełnej
{
  for (int i = 0; i < 47; i++)
    tablica_led[i] = 1;
}

void program1() //mryga na przemian
{
  for (int i = 0; i < 47; i++)
  {
    switch (krok_programu)
    {
      case 1:
        if (!(i % 2)) tablica_led[i] = 1;
        else tablica_led[i] = 0;
        break;
      case 2:
        if (i % 2) tablica_led[i] = 1;
        else tablica_led[i] = 0;
        break;
    }
  }
}

void program2() //zjazd od góry do dołu 
{
    for (int i = 0; i < 47; i++)
    {
      switch (krok_programu)
      {
        case 1:
          if ((i >= 0) && i <= 1)
            tablica_led[i] = 1;
          else tablica_led[i] = 0;
          break;
        case 2:
          if ((i >= 2) && i <= 5)
            tablica_led[i] = 1;
          else tablica_led [i] = 0;
          break;
        case 3:
          if ((i >= 6) && i <= 9)
            tablica_led[i] = 1;
          else tablica_led [i] = 0;
          break;
        case 4:
          if ((i >= 10) && i <= 14)
            tablica_led[i] = 1;
          else tablica_led [i] = 0;
          break;
        case 5:
          if ((i >= 15) && i <= 19)
            tablica_led[i] = 1;
          else tablica_led [i] = 0;
          break;
        case 6:
          if ((i >= 20) && i <= 25)
            tablica_led[i] = 1;
          else tablica_led [i] = 0;
          break;
//        case 7:
//          if ((i >= 26) && i <= 31)
//            tablica_led[i] = 1;
//          else tablica_led [i] = 0;
//          break;
  //      case 8:
  //        if ((i >= 32) && i <= 38)
  //          tablica_led[i] = 1;
  //        else tablica_led [i] = 0;
  //        break;
  //      case 9:
  //        if ((i >= 39) && i <= 46)
  //          tablica_led[i] = 1;
  //        else tablica_led [i] = 0;
  //        break;
    }
  }

}

void program3() //harmonijka
{
  for (int i = 0; i < 47; i++)
  {
    switch (krok_programu)
    {
      case 1:
        if ((i >= 15) && i <= 19)
          tablica_led[i] = 1;
        else tablica_led [i] = 0;
        break;
      case 2:
        if ((i >= 10) && i <= 25)
          tablica_led[i] = 1;
        else tablica_led [i] = 0;
        break;
      case 3:
        if ((i >= 6) && i <= 31)
          tablica_led[i] = 1;
        else tablica_led [i] = 0;
        break;
      case 4:
        if ((i >= 2) && i <= 38)
          tablica_led[i] = 1;
        else tablica_led [i] = 0;
        break;
      case 5:
        if ((i >= 0) && i <= 46)
          tablica_led[i] = 1;
        else tablica_led [i] = 0;
        break;
      case 6:
        if ((i >= 2) && i <= 38)
          tablica_led[i] = 1;
        else tablica_led [i] = 0;
        break;
      case 7:
        if ((i > 5) && i < 32)
          tablica_led[i] = 1;
        else tablica_led [i] = 0;
        break;
      case 8:
        if ((i >= 10) && i <= 25)
          tablica_led[i] = 1;
        else tablica_led [i] = 0;
        break;
    }
  }
}

void program4()
{

}

void program5()
{

}

void wystaw_wyjscia_diod()
{
  for (int i = 0; i <= 46; i++)
  {
    if (tablica_led[i])
      digitalWrite(i, HIGH);
    else
      digitalWrite(i, LOW);
  }
}

void obsluga_przyciskow()
{
  static uint8_t opoznienie_przycisku_1;
  static uint8_t opoznienie_przycisku_2;

  if (!digitalRead(przycisk1) && !opoznienie_przycisku_1)
  {
    opoznienie_przycisku_1 = 1;
    numer_programu++;
    krok_programu = 1;
    if (numer_programu > 5)
      numer_programu = 0;
  }
  else if (opoznienie_przycisku_1 && digitalRead(przycisk1))
    opoznienie_przycisku_1++;

  if (!digitalRead(przycisk2) && !opoznienie_przycisku_2)
  {
    opoznienie_przycisku_2 = 1;
    tryb_gwiazdy++;
    if (tryb_gwiazdy > 3)
      tryb_gwiazdy = 1;
  }
  else if (opoznienie_przycisku_2 && digitalRead(przycisk2))
    opoznienie_przycisku_2++;

}

void migajaca_gwiazda()
{
  //miganie gwiazda na zmiane na 3
}

void przerwanie_od_timera()
{
  if (licznik_timera)
    licznik_timera--;
}

void kontrola_krokow(uint8_t liczba_krokow, int czas_opoznienia_swiecenia)
{
  {
    if (!licznik_timera) //kontrola czasu kroku
    {
      krok_programu++;
      if (krok_programu > liczba_krokow) krok_programu = 1;
      licznik_timera = czas_opoznienia_swiecenia;
    }
  }
}

 

Dostałem do rozwiązania taki oto problemik - jest sobie choinka, ledy podłączone są do klona arduino mega (2x led w szeregu), błędów w podłączeniu nie ma (przynajmniej ja nie widzę)

Problem jest taki, że całość zwiesza się podczas przejścia do programu2(), gdy cały kod jest odkomentowany w tej funkcji. Gdy zostaje zakomentowany case od  7 do 9 - wszystko jest ok i działa bez zarzutu. Jakoś nie widzę, żeby tu coś było nie tak. Pomocy, bo po nockach to już zgłupiałem, albo o czymś zapomniałem

PS. to jest płytka,na której przerwanie zewnętrzne wykonuje się zawsze 2x, co by się nie działo i tego też nie rozkminiłem.

Edit. poprawa błędów w poście i uprzedzenie pytania, jak przyciski są podłączone, to wg załącznika:

 

 

Przechwytywanie.JPG

Edytowano przez BananWszyscy
Link do komentarza
Share on other sites

A jak masz te diodki podłączone? Wprost do procesora? Jakie to LEDy i z jakimi opornikami? Z czego to zasilasz? Bo może przekraczasz dopuszczalny prąd pinów zasilania/GND procesora albo dopuszczalne obciążenie stabilizatora/zasilacza? Może program2() jest pierwszym w kolejności, który zapala za dużo LEDów na raz i to dlatego na nim sie wykłada a nie z powodu jakiejś magii? Czy robiłeś test np. mrugania on-off wszystkimi diodkami jednocześnie? Czy prosty programik zapalający wszystkie punkty na raz na powiedzmy 10s działa poprawnie?

Przy okazji: zmienna, która jest modyfikowana w przerwaniu i odczytywana poza nim powinna być "atomowa", tzn. w tym procesorze co najwyżej 8-bitowa, chyba że zrobisz trochę machania uszami. W obecnej sytuacji może zdarzyć się tak, że w funkcji kontrola_krokow() warunek w if() będzie spełniony, mimo że licznik_timera wcale zerowy nie jest. Przemyśl to w jaki spsób procesor 8-bitowy obsługuje zmienne 16-bitowe. O wiele bardziej bezpiecznie (i elegacko) byłoby, gdybyś w przerwaniu, po dojściu licznika do zera ustawiał np. jakąś prostą flagę typu volatile uint8_t.

Edytowano przez marek1707
  • Lubię! 1
Link do komentarza
Share on other sites

(edytowany)

Świecenie wszystkimi diodami działa bez zarzutów. poza tym wejście w program2 zaswieca 2 ledy i kaplica. przy ciągłym świeceniu na wyjściu z pinu procka jest 13mA. nie zmierzę ile jest w stanie przełączania, bo nie mam jak. A tam w przerwaniu jak poprawiałem to nie zauważyłem, że stoi int. poza tym program0 zaświeca all i kontroler dalej jest responsywny nawet po minucie świecenia.

 

edit. jeszcze przed wyjściem do pracy zauważyłem, że jak zakomentuje cały program3, a odkomentuje program2 w całości to też działa... xD

Edytowano przez BananWszyscy
Link do komentarza
Share on other sites

Heh, to rzeczywiście dziwna sprawa. Prąd pnów VCC/GND biednego procesora i tak jest przekroczony (47*13mA to ponad 600mA a maksimum to 200mA), ale skoro działa...

BTW: To oczywiście nie odnosi się wprost do Twojego problemu, ale jakoś nieładnie wyglądają wyrażenia warunkowe z brakującą drugą parą nawiasów. Masz teraz:

if ((i >= 0) && i <= 1)

a o wiele lepiej wygląda:

if ((i >= 0) && (i <= 1))

No i generalnie zamiast kopiowanych na okrągło warunków z prostym podstawieniem 0 lub 1 można zrobić tak:

tablica_led[i] = ((i >= 10) && (i <= 14));

co znacznie uprości ten piętrowy zapis. Przecież wyrażenie warunkowe jest !=0 gdy jest prawdziwe a potem i tak tylko sprawdzasz czy w tablica_led[] jest zero albo nie.

I podobnie w ustawianiu stanu wyjść:

for (int i = 0; i <= 46; i++)
  digitalWrite(i, tablica_led[i]);

Drugi argument digitalWrite() ma być zerem albo nie - to wystarczy.

Edytowano przez marek1707
  • Lubię! 1
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

(edytowany)

 

O, nawet nie wiedziałem, że digitalWrite może obsługiwać tablice 😄 dobra już nic, jednak zmęczenie powoduje braki w czytaniu
Prawdopodobnie takie sterowanie było brane przy użyciu info z załącznika.

Wiem też, że programik pisany "chamsko" z delay'ami śmiga aż miło. Jak wrócę to spróbuję wyhaczyć moment dokładnie w którym staje dęba... bo on się nie resetuje tylko staje dęba. Już był z tą płytką problem, że przerwania zewnętrzne przy dobrym (tak jak w poprzednim załączniku) podłączeniu microswitcha zawsze wykonywały się dwukrotnie... może ona jest jakaś nie ten teges... ja niestety mam same atmegi i musiałbym multiplexować wsio, an ie chce mi się sklejać takiego pająka.

 

edit2. po prostu też odepnę wszystkie masy oprócz przycisków i zobaczę, czy program odpowiada 🙂

 

Przechwytywanie.JPG

Edytowano przez BananWszyscy
Link do komentarza
Share on other sites

(edytowany)

Dodam już jako następny post. Sprawdziłem na masowym przewodzie ile płynie: 294 miliampery przy ciągłym świeceniu całego dobrobytu (nie będę teraz sprawdzał każdej nóżki xD).. trochę sporo ale tragedii nie ma. No ale odpiąłem przewód masy tych diodek, wgrałem od nowa, paczam na port szeregowy co się dzieje i.. nic się nie zmieniło. Zgłupiałem absolutnie.

EDIT. No to problem rozwiązałem doraźnie - na początku program2(); do debugowania wrzuciłem println("rozp_prog2") i wszystko zadziałało z marszu... więc dopisałem na starcie delay(1); i działa...

Edytowano przez BananWszyscy
Link do komentarza
Share on other sites

Rzeczywiście noc była już głęboka, bo i ja przepuściłem babola. Przecież zapis:

digitalWrite(i, tablica_led);

jest bez sensu. Miało być rzecz jasna:

digitalWrite(i, tablica_led[i]);

i daję sobie uciąć, że tak to widziałem. Drugim argumentem musi być przecież wartość wyrażenia (zerowa gdy ustawiamy stan niski i <>0 gdy wysoki) a nie wskaźnik na tablicę. A dziś cóż, post wygląda inaczej. Zgodnie z obecną modą przyczyna może być tylko jedna: ktoś włamał się na moje konto i strollował wynurzenia garażowego geniusza.. Taa...jasne.

No a teraz o tym prądzie. To co zmierzyłeś wcale nie musi być sprzeczne z pomiarem pojedynczej diody. Kiedy zapalasz jedną, wstawiasz w obwód multimetr i widzisz 16mA, to masz konkretne rezystancje i konkretny prąd wywołujący konkretne spadki napięcia. Myślę tu przede wszystkim o tych cieńszych od włosa drucikach łączących stalowy ażur obudowy procesora z jego strukturą krzemową. No a teraz, gdy przez ten sam drucik ma popłynąć ponad 0.5A to tak jak z gniazdkiem w ścianie: przy obciążeniu ładowarką USB masz tam 235V a po dołączeniu piecyka 2kW zostaje już tylko 210V. Większy prąd to większy spadek napięcia po drodze i próba zapalenia wszystkich LEDów na raz może powodować, że suma prądów nie jest prostą arytmetyczną wielokrotnością pojedynczego, pierwotnego składnika. Zwyczajnie im więcej diodek tym prąd każdej powinien lekko przysiadać włąsnie z powodu rezystancji widzianych na wspólnej części obwodu. Ale to oznacza także, że powinno być widać wyraźne przygasanie diod w miarę zapalnia coraz większej ich liczby. Drugą przyczyną tak małego prądu sumacyjnego może być to, że prądy są różne w zależności od koloru. Niestety nie widzieliśmy tego twojego świątecznego cuda (zdjęcie w pełnej krasie?), ale jeśli kolorki masz różne to i prądy (przy tych samych opornikach) będą rózne. Być może zmierzyłeś czerwoną i wyszło 16mA a np. zielone mogą ciagnąć tylko 8mA (bo mają większe tzw. napięcie przewodzenia UF) i wtedy w sumie wychodzi mniej niż proste 47*16mA. To tylko takie dywagacje, choć warto rozumieć co się dzieje we własnym projekcie - szcególnie w tak prostych sprawach jak prądy statyczne. A być może przyczyna dziwnie małego prądu jest bardziej trywialna: spada zasilanie 5V z powodu przeciążenia zasilacza? stabilizatora? spadku napięcia na kablu (USB)? itp. Diodkom jak to diodkom (elementom nieliniowym) wystarczy lekki spadek napięcia a prąd maleje gwałtownie. Napisz gdy ten problem rozkminisz, bo to nauka dla każdego.. Rzadko zdarza się, by ktoś robił taki overkill i pakował ArduinoMega do napędzania kilkudziesięciu LEDów wprost z kilkudzisięciu pinów procesora.. Jednak narzucającym się rozwiązaniem jest jakiś maluch za 12zł (MINI? NANO?) i multipleksowanie lub ekspandery/rejestry na SPI czy coś..

A przerwania zewnętrzne to osobna sprawa - zgłaszanie ich poprzez układ RC z przycisku i naiwne oczekiwanie, że będzie to deterministyczne (np. tylko jedno zbocze) to zupełna bzdura, ale było o tym tyle, że nie warto bić piany.

Kontrukcja Twojego kodu jest taka, że wykonujesz wszystko (łącznie z generowaniem nowych wzorków) zawsze w kółko i powtarzasz to tak szybko jak tylko procesor zdoła wykonywać główną pętlę. To powoduje, że program jest responsywny w każdym stanie i to z jednej strony dobrze, ale są też ciemne strony tego rozwiązania (pomijam pobór mocy). Gdyby problemem była właśnie "nieatomowość" sprawdzania stanu licznika, to wtedy opoźnienie zwyczajnie zmniejsza częstość występowania błędu być może rzędy wielkości razy i nie naprawia a jedynie "rozrzedza" niepoprawne przeskoki programu przez kolejne kroki.

A jeśli jesteś przywiązany do konstrukcji if, to gdybyś na początku zawsze wykonywał proste czyszczenie (zerowanie) całej tablicy LEDów, wtedy musiałbyś w dalszych switch-ach/if-ach wpisywać jedynie wartości niezerowe i odpadłyby wszystkie else "gaszące" poprzednie śmiecie. Program byłby bardziej przejrzysty i na pewno krótszy.

Edytowano przez marek1707
Link do komentarza
Share on other sites

Ej, zaraz. Dziś na pewno w edytorze było dobrze. Jeszcze przed chwilą spróbowałem poprawić i znów jest źle. Wygląda na to, że napisanie:

"nawias kwadratowy-litera i-nawias kwadratowy" czyli (uwaga,tego nie będzie widać):

powoduje, że skrypt Forum robi z tego zmianę liternictwa na italiki (pochylone). Czyli nikt się nie włamał na konto, widocznie nie jest tego warte.. chlip, chlip... Poprawiam jeszcze raz powyżej, tym razem "w cytacie". Poprawiłem w kilku miejscach żeby jednak nie siać głupot, choć w w tym kontekście uwaga @ethanak staje się bezprzedmiotowa. Dzięki.

Edytowano przez marek1707
Link do komentarza
Share on other sites

12 minut temu, marek1707 napisał:

powoduje, że skrypt Forum robi z tego zmianę liternictwa na italiki (pochylone)

Normalka - bbcode. Co prawda @Treker obiecywał że tego nie będzie ale jak to wyłączy to go powieszę 🙂

A tak przy okazji - @Treker już wiesz po co jest ta ostatnia ikonka z karteczka i lupką co jej podobno nikt nie używa oprócz mnie 😉

Edytowano przez ethanak
  • Lubię! 1
Link do komentarza
Share on other sites

27 minut temu, Treker napisał:

Podtrzymuję, kiedyś to zniknie i nie będzie to nawet zależne ode mnie

Rozumiem przez to, że będzie istniał jakiś sensowny sposób wrzucenia np. url-a bez kombiinacji w stylu

  1. zdejmij rękę z klawiatury
  2. połóż rękę na mysz
  3. przeskroluj kawałek ekranu bo "wstaw url" jest gdzieś nad ekranem
  4. aha, nie to się przeskrolowało, wróć i przeskroluj coś innego
  5. kliknij na "wstaw url"
  6. Zabierz rękę z myszy z powrotem na klawiaturę
  7. Wpisz url
  8. Zabierz rękę z klawiatury i wróć do myszki
  9. Kliknij "wstaw do wiadomości"
  10. Zabierz rękę z myszki i wróć do klawiatury żeby pisać dalej

Ufff... dziesięć czynności zamiast wpisania [ url=http://forbot.pl]forbot[ /url]

Rozumiem także, że np. w przypadku publikacji artykułu będzie można go przygotować w jakimś edytorze łącznie z pogrubieniami, italikami, urlami i wszystkimi bajerami...

 

Link do komentarza
Share on other sites

Na forum pozostanie edytor, który jest dostępny w obecnej wersji. Po prostu nie będzie obsługiwany bbcode, nie wynika to z niczyjej złośliwości - po prostu na roadmapie twórców skryptu, z którego korzystamy jest wykreślenie bbcode. Niestety koniec i kropka, nie mam na to żadnego wpływu. Rozumiem przyzwyczajenia, sam czasami korzystamy z tej opcji, ale będzie trzeba zmienić przyzwyczajenia i tyle. Używanie bbcode generowało wiele błędów z formatowaniem na starym forum, często trzeba było poprawiać coś w imieniu nowych użytkowników. Od kiedy jest nowy edytor takie błędy nie występują. Z mojego widzenia jest to dobra zmiana.

Link do komentarza
Share on other sites

Dołącz do dyskusji, napisz odpowiedź!

Jeśli masz już konto to zaloguj się teraz, aby opublikować wiadomość jako Ty. Możesz też napisać teraz i zarejestrować się później.
Uwaga: wgrywanie zdjęć i załączników dostępne jest po zalogowaniu!

Anonim
Dołącz do dyskusji! Kliknij i zacznij pisać...

×   Wklejony jako tekst z formatowaniem.   Przywróć formatowanie

  Dozwolonych jest tylko 75 emoji.

×   Twój link będzie automatycznie osadzony.   Wyświetlać jako link

×   Twoja poprzednia zawartość została przywrócona.   Wyczyść edytor

×   Nie możesz wkleić zdjęć bezpośrednio. Prześlij lub wstaw obrazy z adresu URL.

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