• 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
Łączenie kilku programów w jeden.
#1
Cześć, na wstępie jestem nowy zarówno na tym forum jak i w temacie Arduino tak więc witam wszystkich Big Grin .

Potrzebuje pomocy z małym projektem już mniejsza oco w nim chodzi, ale głowie się w jaki sposób upchać 3 osobne działające programy w jeden tak by po uruchomieniu arduino to użytkownik wybierał jaki ma odpalić.

Dla rozjaśnienia do arduino podłączyłem wyświetlacz lcd 2x16 z wlutowanym I2C, wszystko działa do tego przyciski w pinach 6,5,4 pwm. Pin 6 jako przycisk ma służyć do zatwierdzania a pin 5,4 do wybierania prawo lewo(czy analogicznie więcej mniej). Napisałem z pomocą GPTchatu 3 działające w pełni programy ale z tym już nie jest w stanie mi pomóc. Reasumując potrzebuje z 3 osobnych działających programów zrobić tak aby po uruchomieniu użytkownik sam wybierał jaki program uruchomić, a więc na wyświetlaczu po uruchomieniu powinno sie wyświetlić jaki "Wybierz program np2" i przyciskami 5,4 użytkownik wybiera a 6 zatwierdza i arduino odpala wybrany program. Zaznacze że są to dosyć rozbudowane programy końcowy program może mieć nawet około 500 wierszy. Czy w ogóle jest możliwe zrobić coś takiego? Prosze o pomoc 
 Oto wspomniane 3 gotowe i działające programy:
Kod:
#include <Wire.h>
#include <LiquidCrystal_I2C.h>

const int lcdAdres = 0x27;
const int lcdKolumny = 16;
const int lcdWiersze = 2;
LiquidCrystal_I2C lcd(lcdAdres, lcdKolumny, lcdWiersze);

const int pinPwm = 2;
const int pinPrzycisk = 7;
const int pinRozpoczecie = 6; // Przycisk rozpoczynający sekwencję

unsigned long czasRozpoczecia = 0;
bool rozpoczetoOdliczanie = false;
unsigned long czasPoczatkowyLiczenia = 0; // Zmienna przechowująca czas rozpoczęcia liczenia punktów
const int opoznienieAutomatycznegoStartu = 4000;
int punkty = 0;
bool poprzedniStanPrzycisku = HIGH;
bool pierwszeLiczenieZakonczone = false;
bool drugieLiczenieZakonczone = false;

int czestotliwoscBuzzer1 = 4000;
int czasDzwiekuBuzzer1 = 900;
int czestotliwoscBuzzer2 = 4000;
int czasDzwiekuBuzzer2 = 300;

void setup() {
  Wire.begin();
  lcd.begin(lcdKolumny, lcdWiersze);
  lcd.backlight();
  pinMode(pinPwm, OUTPUT);
  pinMode(pinPrzycisk, INPUT_PULLUP);
  pinMode(pinRozpoczecie, INPUT_PULLUP); // Ustawienie pinu rozpoczynającego sekwencję jako wejście z rezystorem pull-up
}

void loop() {
  unsigned long obecnyCzas = millis();
  unsigned long uplywCzasu = obecnyCzas - czasRozpoczecia;

  // Rozpoczęcie sekwencji po wciśnięciu przycisku na pinie rozpoczynającym sekwencję
  if (digitalRead(pinRozpoczecie) == LOW && !rozpoczetoOdliczanie) {
    rozpocznijOdliczanie();
  }

  if (digitalRead(pinPrzycisk) == LOW && !rozpoczetoOdliczanie && poprzedniStanPrzycisku == HIGH && digitalRead(pinRozpoczecie) == LOW) {
    rozpocznijOdliczanie();
    poprzedniStanPrzycisku = LOW;
  } else if (digitalRead(pinPrzycisk) == HIGH) {
    poprzedniStanPrzycisku = HIGH;
  }

  if (rozpoczetoOdliczanie) {
    if (uplywCzasu < opoznienieAutomatycznegoStartu) {
      wyswietlTekst("Rozpoczynam za:", floatNaTekst((opoznienieAutomatycznegoStartu - uplywCzasu) / 1000.0, 1));
    } else if (uplywCzasu < opoznienieAutomatycznegoStartu + 10000) {
      wyswietlTekst("Czas 10 sekund:_", floatNaTekst((10 - (uplywCzasu - opoznienieAutomatycznegoStartu) / 1000.0), 1));

      // Warunek sprawdzający, czy minęło co najmniej 4 sekundy od rozpoczęcia liczenia punktów
      if (!pierwszeLiczenieZakonczone && obecnyCzas - czasPoczatkowyLiczenia >= 4000) {
        pierwszeLiczenieZakonczone = true;
        uruchomBuzzer(czestotliwoscBuzzer1, czasDzwiekuBuzzer1);
      }

      if (digitalRead(pinPrzycisk) == LOW) {
        punkty++;
        if (punkty > 99) {
          punkty = 0;
        }
        delay(245);
      }

      lcd.setCursor(13, 1);
      lcd.print(punkty / 10);
      lcd.setCursor(14, 1);
      lcd.print(punkty % 10);
    } else {
      wyswietlTekst("Koniec liczenia:", "");
      if (!drugieLiczenieZakonczone) {
        drugieLiczenieZakonczone = true;
        uruchomBuzzer(czestotliwoscBuzzer2, czasDzwiekuBuzzer2);
      }
      rozpoczetoOdliczanie = false;
      punkty = 0;
    }
  }
}

void rozpocznijOdliczanie() {
  czasRozpoczecia = millis();
  rozpoczetoOdliczanie = true;
  czasPoczatkowyLiczenia = millis(); // Ustawienie początkowego czasu liczenia punktów
  punkty = 0;
  pierwszeLiczenieZakonczone = false; // Resetujemy flagę po rozpoczęciu nowej rundy
  drugieLiczenieZakonczone = false; // Resetujemy flagę po rozpoczęciu nowej rundy
}

void uruchomBuzzer(int czestotliwosc, int czasDzwieku) {
  tone(pinPwm, czestotliwosc, czasDzwieku); // Uruchomienie buzzera na podanej częstotliwości przez podany czas
  delay(czasDzwieku); // Oczekaj, aby dźwięk buzzer'a trwał przez określony czas
  noTone(pinPwm); // Wyłączenie buzzer'a
}

void wyswietlTekst(String linia1, String linia2) {
  lcd.setCursor(0, 0);
  lcd.print(linia1);

  if (linia2 != "") {
    lcd.setCursor(0, 1);
    lcd.print(linia2);
  }
}

String floatNaTekst(float wartosc, int miejscaPoPrzecinku) {
  char bufor[10];
  dtostrf(wartosc, 1, miejscaPoPrzecinku, bufor);
  return String(bufor);
}

Kod:
#include <Wire.h>
#include <LiquidCrystal_I2C.h>

const int lcdAdres = 0x27;
const int lcdKolumny = 16;
const int lcdWiersze = 2;
LiquidCrystal_I2C lcd(lcdAdres, lcdKolumny, lcdWiersze);

const int pinPwm = 2; // Pin dla buzzer
const int pinPrzycisk = 7;
const int pinRozpoczecie = 6; // Przycisk rozpoczynający sekwencję
unsigned long czasRozpoczecia = 0;
bool rozpoczetoOdliczanie = false;
unsigned long czasPoczatkowyLiczenia = 0; // Zmienna przechowująca czas rozpoczęcia liczenia punktów
unsigned long czasPoczatkowyWstepnegoLiczenia = 0; // Zmienna przechowująca czas rozpoczęcia odliczania wstępnego
const int opoznienieAutomatycznegoStartu = 4000;
int punkty = 0;
bool poprzedniStanPrzycisku = HIGH;

void setup() {
  Wire.begin();
  lcd.begin(lcdKolumny, lcdWiersze);
  lcd.backlight();
  pinMode(pinPwm, OUTPUT);
  pinMode(pinPrzycisk, INPUT_PULLUP);
  pinMode(pinRozpoczecie, INPUT_PULLUP); // Ustawienie pinu rozpoczynającego sekwencję jako wejście z rezystorem pull-up
}

void loop() {
  unsigned long obecnyCzas = millis();
  unsigned long uplywCzasu = obecnyCzas - czasRozpoczecia;

  // Rozpoczęcie sekwencji po wciśnięciu przycisku na pinie rozpoczynającym sekwencję
  if (digitalRead(pinRozpoczecie) == LOW && !rozpoczetoOdliczanie) {
    lcd.clear(); // Wyczyszczenie wyświetlacza przed nową akcją
    rozpocznijLiczeniePunktow();
    liczenieWstepne();
  }

  if (digitalRead(pinPrzycisk) == LOW && !rozpoczetoOdliczanie && poprzedniStanPrzycisku == HIGH && digitalRead(pinRozpoczecie) == LOW) {
    lcd.clear(); // Wyczyszczenie wyświetlacza przed nową akcją
    rozpocznijLiczeniePunktow();
    liczenieWstepne();
    poprzedniStanPrzycisku = LOW;
  } else if (digitalRead(pinPrzycisk) == HIGH) {
    poprzedniStanPrzycisku = HIGH;
  }

  if (rozpoczetoOdliczanie) {
    if (punkty < 10) {
       // Wyczyszczenie wyświetlacza przed nową akcją
      // Liczenie punktów
      wyswietlTekst("Czas: " + floatNaTekst((obecnyCzas - czasPoczatkowyLiczenia) / 1000.0, 2) + "s", "Punkty: " + String(punkty) + "P - 10P");
      if (digitalRead(pinPrzycisk) == LOW) {
        punkty++;
        if (punkty > 10) {
          punkty = 10; // Maksymalnie do 10 punktów
        }
        delay(245);
      }
    } else {
      // Wyłączanie buzzer po zakończeniu odliczania punktów
      noTone(pinPwm);

      // Wyświetlanie komunikatu po osiągnięciu 10 punktów
      if (digitalRead(pinPrzycisk) == LOW) {
        wyswietlWynikCzasuIPunktow();
        while (digitalRead(pinPrzycisk) == LOW) {} // Czekaj, aż przycisk zostanie zwolniony
      }
      rozpoczetoOdliczanie = false;
      punkty = 0; 

      // Włączanie buzzer po zakończeniu odliczania punktów
      tone(pinPwm, 4000); // Częstotliwość 830 Hz
      delay(300); // Buzzer działa przez 0.5 sekundy
      noTone(pinPwm); // Wyłączanie buzzera
    }
  }
}

void rozpocznijLiczeniePunktow() {
  czasRozpoczecia = millis();
  czasPoczatkowyLiczenia = millis(); // Zresetowanie czasu początkowego liczenia
  rozpoczetoOdliczanie = true;
  punkty = 0; 
}

void liczenieWstepne() {
  czasPoczatkowyWstepnegoLiczenia = millis();
  while (millis() - czasPoczatkowyWstepnegoLiczenia < opoznienieAutomatycznegoStartu) {
    wyswietlTekst("START ZA: ", floatNaTekst((opoznienieAutomatycznegoStartu - (millis() - czasPoczatkowyWstepnegoLiczenia)) / 1000.0, 2) + "s");
  }

  // Włączanie buzzer po zakończeniu odliczania wstępnego
  tone(pinPwm, 4000); // Częstotliwość 830 Hz
  delay(900); // Buzzer działa przez 0.5 sekundy
  noTone(pinPwm); // Wyłączanie buzzera
 
  // Reset czasu początkowego liczenia głównego
  czasPoczatkowyLiczenia = millis();
}

void wyswietlTekst(String linia1, String linia2) {
  lcd.setCursor(0, 0);
  lcd.print(linia1);

  if (linia2 != "") {
    lcd.setCursor(0, 1);
    lcd.print(linia2);
  }
}

String floatNaTekst(float wartosc, int miejscaPoPrzecinku) {
  char bufor[10];
  dtostrf(wartosc, 1, miejscaPoPrzecinku, bufor);
  return String(bufor);
}

void wyswietlWynikCzasuIPunktow() {
  lcd.setCursor(0, 0);
  lcd.print("Koniec :");

  lcd.setCursor(0, 1);
  lcd.print("Czas: ");
  lcd.print(floatNaTekst((millis() - czasPoczatkowyLiczenia) / 1000.0, 2));
  lcd.print("s");

  delay(3000); // Poczekaj 3 sekundy przed powrotem do normalnego działania
}

Kod:
#include <Wire.h>
#include <LiquidCrystal_I2C.h>

const int lcdAdres = 0x27;
const int lcdKolumny = 16;
const int lcdWiersze = 2;
LiquidCrystal_I2C lcd(lcdAdres, lcdKolumny, lcdWiersze);

const int pinPrzycisk = 7;
const int pinRozpoczecie = 6; // Przycisk rozpoczynający sekwencję
const int pinBuzzer = 2; // Pin podłączony do buzzera
unsigned long czasRozpoczecia = 0;
bool rozpoczetoOdliczanie = false;
unsigned long czasPoczatkowyLiczenia = 0; // Zmienna przechowująca czas rozpoczęcia liczenia punktów
const int opoznienieAutomatycznegoStartu = 4000;
int punkty = 0;
bool poprzedniStanPrzycisku = HIGH;

void setup() {
  Wire.begin();
  lcd.begin(lcdKolumny, lcdWiersze);
  lcd.backlight();
  pinMode(pinPrzycisk, INPUT_PULLUP);
  pinMode(pinRozpoczecie, INPUT_PULLUP); // Ustawienie pinu rozpoczynającego sekwencję jako wejście z rezystorem pull-up
}

void loop() {
  unsigned long obecnyCzas = millis();
  unsigned long uplywCzasu = obecnyCzas - czasRozpoczecia;

  // Rozpoczęcie sekwencji po wciśnięciu przycisku na pinie rozpoczynającym sekwencję
  if (digitalRead(pinRozpoczecie) == LOW && !rozpoczetoOdliczanie) {
    rozpocznijOdliczanie();
  }

  if (digitalRead(pinPrzycisk) == LOW && !rozpoczetoOdliczanie && poprzedniStanPrzycisku == HIGH && digitalRead(pinRozpoczecie) == LOW) {
    rozpocznijOdliczanie();
    poprzedniStanPrzycisku = LOW;
  } else if (digitalRead(pinPrzycisk) == HIGH) {
    poprzedniStanPrzycisku = HIGH;
  }

  if (rozpoczetoOdliczanie) {
    if (uplywCzasu < opoznienieAutomatycznegoStartu) {
      wyswietlTekst("Rozpoczynam za:", floatNaTekst((opoznienieAutomatycznegoStartu - uplywCzasu) / 1000.0, 1));
    } else {
      // Obliczanie czasu
      unsigned long czasTrwania = obecnyCzas - czasRozpoczecia;
      int godziny = czasTrwania / 3600000; // 1 godzina = 3600 sekund * 1000 (przekształcone na milisekundy)
      int minuty = (czasTrwania % 3600000) / 60000; // Pozostały czas po odjęciu godzin, dzielony przez 60 sekund * 1000
      int sekundy = ((czasTrwania % 3600000) % 60000) / 1000; // Pozostały czas po odjęciu godzin i minut, dzielony przez 1000

      wyswietlTekst("Czas oraz Punkty:", String(godziny) + "h " + String(minuty) + "m " + String(sekundy) + "s");

      // Liczenie punktów
      if (digitalRead(pinPrzycisk) == LOW) {
        punkty++;
        buzz();
        delay(165);
      }

      lcd.setCursor(13, 1);
      lcd.print(punkty / 100);
      lcd.setCursor(14, 1);
      lcd.print((punkty % 100) / 10);
      lcd.setCursor(15, 1);
      lcd.print(punkty % 10);
    }
  }
}

void rozpocznijOdliczanie() {
  czasRozpoczecia = millis();
  rozpoczetoOdliczanie = true;
  czasPoczatkowyLiczenia = millis(); // Ustawienie początkowego czasu liczenia punktów
  punkty = 0;
}

void wyswietlTekst(String linia1, String linia2) {

  lcd.setCursor(0, 0);
  lcd.print(linia1);

  if (linia2 != "") {
    lcd.setCursor(0, 1);
    lcd.print(linia2);
  }
}

String floatNaTekst(float wartosc, int miejscaPoPrzecinku) {
  char bufor[10];
  dtostrf(wartosc, 1, miejscaPoPrzecinku, bufor);
  return String(bufor);
}

void buzz() {
  tone(pinBuzzer, 4000); // Włącz buzzer na częstotliwości 850 Hz
  delay(200); // Poczekaj 0.5 sekundy
  noTone(pinBuzzer); // Wyłącz buzzer
}
 
Odpowiedź
#2
Jest to możliwe, ale i tak programy zajmą cały wymagany flash i RAM wymagany dla wszystkich trzech. Napisz sobie program, który ustawia w setup zmienną uint8_t wybor na 1,2,3 w pętli while( ! wybor) - czyli dopóki wybór jest 0, potem w loop wstawiasz switch case wybor, w każdym case 1 do 3 wszystko z danego programu 1 do 3.
Jeśli nie ma jakiś specjalnych funkcji wymagających kręcenia całym loop to można w danym case uwięzić program w petli while(1), ale można też dodać odczyt przycisku również w loop, który zmieni numer case i przeskoczy z jednego programu do kolejnego.
Miło być decenianym https://buycoffee.to/kaczakat
 
Odpowiedź
#3
Zasadniczo to, co masz przed funkcją setup() musisz zebrać z wszystkich trzech programów i wyeliminować zdublowane linie (np. #include <LiquidCrystal_I2C.h> wystarczy tylko raz, deklaracje zmiennych również).

W setup() również musisz połączyć setupy z trzech programów, znowu eliminując powtarzające się linie.

Funkcje dodatkowe np. buzz(). wyswietlTekst(String linia1, String linia2) mogą znaleźć się w programie zbiorczym tylko raz (pod warunkiem, że we wszystkich programach składowych mają taką samą treść).

A jak uporasz się z tym wszystkim to każdy loop() z każdego z programów musisz potraktować np. jako loop1(), loop2() i loop3() i przełączanie pomiędzy nimi wykonać w taki sposób jak napisał kolega @kaczakat.

Ogólnie zabrałeś się do tego od złej strony i na pewno użycie ChatGPT w tym wypadku nie pomaga - owszem napisał on programy, które działają (jak sądzę), ale z optymalizacją mają niewiele wspólnego. Takie połączenie może być niezłym potworkiem i sklejając program z trzech bugi mogą pojawiać się w nieoczekiwanych miejscach.
 
Odpowiedź
#4
Dzięki za pomoc, ale uporałem sie z tym w inny sposób otóż mam zamiar rozbudować mocniej te 3 programy a już brakuje obu pamięci. Więc dodałem 2 kolejne arduino mini na każdym program osobno i kiedy potrzebuje to przełączam sobie zasilanie na inną płytke, wszystko hula jak narazie dzięki.
 
Odpowiedź
#5
Nie wiem jak bardzo zamierzasz rozbudować te programy, ale z tego co tu pokazałeś, to zwykłe UNO pomieściło by takich 10, zajmuje to teraz 10kb Flash i 330 RAM, ale większość pozostałaby wspólna, dochodzą ewentualne dodatkowe komunikaty, napisy które można zapisać we flash, więc zużycie RAM może zostać na takim poziomie. Płytka ESP32 pomieściłaby tego 1000.
Nie mniej jednak, jeśli i tak nie zamierzasz się uczyć programować, a znalazłeś sposób by praca została wykonana, to gratuluję, sukces w pełni został osiągnięty.
Miło być decenianym https://buycoffee.to/kaczakat
 
Odpowiedź
  


Skocz do:


Przeglądający: 1 gości