Skocz do zawartości
macizet

Jak pisać biblioteki na Arduino?

Pomocna odpowiedź

20 minut temu, slon napisał:

Czy taki sposób będzie poprawny

Jeśli led faktycznie będzie obiektem to owszem.

No to teraz proszę bardzo - jako ćwiczenie napisać odpowiednią klasę. Podaję przykładowy interfejs

class BlinkingLed {
  public:
  	BlinkingLed(int pin);
  	BlinkingLed(int pin, int OnTime, int OffTime, int autostart = 0);
  	void setOnTime(int);
  	void setOffTime(int);
  	int getOnTime(void);
  	int getOffTime(void);
  	void start(void);
  	void stop(void);
  	void run(void);
};

  	

Zaproponować i zaimplementować inne metody które mogą być potrzebne.

Zaproponować inny interfejs i krótko opisać dlaczego jest lepszy.

A dla bardziej ambitnych - napisać to samo ale w C a nie w C++ 🙂

Kto chętny?

 

 

Udostępnij ten post


Link to post
Share on other sites

@ethanak dziękuje za dalsze podjęcie tematu oraz za podanie przykładowego interfejsu. Natomiast mam pytanie : czy dla podanej klasy BlinkingLed nie będę potrzebował definiować atrybutów? 

class BlinkingLed {
  private:
    int _pin
    int _onTime;
    int _offTime;
    int _autostart;
  public:
  	BlinkingLed(int pin);
  	BlinkingLed(int pin, int OnTime, int OffTime, int autostart = 0);
  	void setOnTime(int);
  	void setOffTime(int);
  	int getOnTime(void);
  	int getOffTime(void);
  	void start(void);
  	void stop(void);
  	void run(void);
};

 

Udostępnij ten post


Link to post
Share on other sites

Pewnie że musisz - ale to już kwestia Twojej implementacji, ja zaproponowałem wyłącznie publiczne metody interfejsu.

Takie pytanie: po co Ci atrybut _autostart?

 

Udostępnij ten post


Link to post
Share on other sites

Konstruktor przypisuje wartości początkowe do atrybutów

BlinkingLed(int pin, int OnTime, int OffTime, int autostart = 0);

czyli w tym wypadku do atrybutu _autostart domyślnie została by przypisana wartość zero. Tworząc nowy obiekt np:

BlinkingLed led1(13,1000,1000);

podaje wartości początkowe do pozostałych atrybutów.  Metoda start(); sprawdza warunek np:

start()
{
  if (autostart==1) 
  {
   // blink uruchomiony 
  } else 
  // czekamy
}

atrybut _autostart ma wartość 0 więc czekamy. Metoda run(); np:

run()
{
  autostar=1;
}

metoda stop();

stop()
{
 autostart=0; 
}

teraz gdybym chciał utworzyć kolejny obiekt 

BlinkingLed led2(3);

tutaj zastosowałem pierwszy konstruktor

BlinkingLed(int pin);

czyli na tą chwilę miał bym dwie diody na na pinach 3 i 13 gotowe do uruchomienia np:

led1.start(); led2.start(); 
led1.run(); led2.run();

czy to co napisałem jest poprawne zwłaszcza jeśli chodzi o zastosowanie konstruktora?

Udostępnij ten post


Link to post
Share on other sites

Hm... nic z tego nie rozumiem. Funkcja start nie startuje migania ledą... funkcja run to tylko sygnalizacja że start ma startować... a miganie odbywa się automagicznie za pomocą telepatii...

Biblioteka to nie tylko zestaw klas, metod i różnych innych przydatnych firdymałków - to również dokumentacja. Nawet taka najkrótsza - przy deklaracji metody jedno zdanie opisu co dana metoda robi i (jeśli nazwy parametrów nie określają jednoznacznie ich znaczenia) co znaczy który parametr. Bez tego użycie nawet najbardziej dopracowanej biblioteki będzie niemożliwe.

Poza tym pisząc bibliotekę musimy mieć na uwadze to, że ktoś ją będzie stosować i ten ktoś najprawdopodobniej nie będzie zaglądał do kodów źródłowych, a przede wszystkim będzie szukał biblioteki spełniającej jego oczekiwania. I znów nawet najpiękniejszy kod nie spowoduje tego, że biblioteka w której zabrakło jakiejś ważnej funkcji stanie się nagle używalna...

Wyobraźmy sobie jakiś nietrywialny program, który będzie korzystać z naszej biblioteki do migania ledami. Niech to będzie np. metronom.

Metronom wyposażony jest w przyciski start-stop, potencjometr regulujący tempo w zakresie 30..250 BPM, ledę sygnalizującą rytm oraz ledę pokazującą stan naładowania akumulatora.

Po wciśnięciu "start" metronom rusza, migając ledą sygnalizacyjną w określonym tempie, przy czym czas zapalenia ledy musi być równy czasowi zgaszenia. Tempo ustalane jest potencjometrem. Po wciśnięciu "stop" metronom się zatrzymuje, a leda gaśnie.

Druga leda pali się cały czas jeśli napięcie odczytane z akumulatora wynosi ponad 3.8V. Jeśli napięcie spada, leda zaczyna migać w stałym rytmie (raz na sekundę mniej więcej), z tym że mignięcia są coraz krótsze w miarę spadku napięcia do 3.2V. Od 3.2V w dół czas zapalenia ledy wynosi 1/10 okresu i już się nie zmniejsza.

Należy spróbować zaprojektować taki program używając funkcji z nieistniejącej jeszcze biblioteki - w ten sposób będziemy mieli całkiem nieźle określony interfejs (a przynajmniej jego fragment) i będziemy mogli wziąć się do tworzenia biblioteki.

Ktoś chętny?

Niekoniecznie do stworzenia biblioteki, ale właśnie programu metronomu i określenia swoich wymagań co do biblioteki migania ledami?

A może ktoś ma inną propozycję programu używającego takiej biblioteki?

 

 

Udostępnij ten post


Link to post
Share on other sites

Moją intencją nie było rozpisywanie pliku BlinkingLed.cpp czy , którejkolwiek z tych metod. Natomiast sam plik nagłówkowy BlinkingLed.h to w zasadzie mógł by wyglądać tak:

#ifndef BlinkingLed_h
#define BlinkingLed_h

#include "Arduino.h"

class BlinkingLed {
  private:
    int _pin;
    int _onTime;
    int _offTime;
    int _autostart;
  public:
  	BlinkingLed(int pin);
  	BlinkingLed(int pin, int OnTime, int OffTime, int autostart = 0);
  	void setOnTime(int);
  	void setOffTime(int);
  	int getOnTime(void);
  	int getOffTime(void);
  	void start(void);
  	void stop(void);
  	void run(void);
};

#endif

oczywiście , żeby to mogło działać to trzeba by było obydwa te pliki (BlinkingLed.cpp oraz BlinkingLed.h) przenieść do folderu BlinkingLed i umieścić w  folderze arduino Libraries (zakładając , że będziemy korzystać z arduino IDE) . Jeśli ktoś jest dalej zainteresowany tym tematem to zostaje do uzupełnienia plik BlinkingLed.cpp i rozpisanie poszczególnych metod.

#include "Arduino.h"
#include "BlinkingLed.h"

BlinkingLed::BlinkingLed(int p)
{

}

 

Udostępnij ten post


Link to post
Share on other sites
6 godzin temu, slon napisał:

zostaje do uzupełnienia plik BlinkingLed.cpp i rozpisanie poszczególnych metod.

No i tu jest pierwszy wielki błąd: przed napisaniem kodu należy dokładnie określić, co która metoda ma robić (np. że "start" ma wystartować miganie) i dopiero brać się za realizację założeń. Trudno realizować niesprecyzowane założenia, prawda?

Następny błąd to określanie z góry prywatnych atrybutów. Po co? Przecież użytkowników biblioteki nie interesują prywatne zmienne (no, chyba  że ktoś chce napisać bibliotekę pochodną i będzie klął autora w żywy kamień za użycie "private" zamiast "protected"). Te atrybuty wylezą dopiero w trakcie pisania. Pomyśl: czy pisząc program w C++ najpierw określasz wszystkie zmienne globalne, a potem się tego kurczowo trzymasz?

Jak widać, pisanie bibliotek nie jest taką prosta sprawą nawet jeśli to ma być najprostsza biblioteka do migania ledami 🙂

No ale może ktoś jeszcze spróbuje swoich sił?

 

Udostępnij ten post


Link to post
Share on other sites

Coz, to ja sie ucze.

Udostępnij ten post


Link to post
Share on other sites

Wracając do metronomu to zainteresowały mnie dwa założenia 

Cytat

potencjometr regulujący tempo w zakresie 30..250 BPM

Cytat

 czas zapalenia ledy musi być równy czasowi zgaszenia

wpasowałem to do funkcji, którą zamieściłem na pierwszej stronie

  potencjometr=analogRead(A1);
  potencjometr=map(potencjometr,0,1023,30,250);
  BPM=60000/potencjometr/2; 
  start(7,BPM,BPM);

działa całkiem  fajnie chociaż osobiście chyba bym wolał regulację BPM przyciskami "góra" , "dół".

Udostępnij ten post


Link to post
Share on other sites

A dla mnie najwygodniejszy by był enkoder obrotowy i wyświetlacz - przejście przyciskami od najwolniejszego do najszybszego będzie wymagało trochę klikania. Ale w sumie nie o to tu chodziło...

Po prostu sterowanie potencjometrem jest nieprecyzyjne ale najprostsze w realizacji (w sumie jedna linijka w programie), a chodziło o napisanie biblioteki a nie skupianie się nad wprowadzaniem danych do programu 🙂 Mając bibliotekę będziemy mogli napisać sobie metronom tak jak nam pasuje.

 

 

Udostępnij ten post


Link to post
Share on other sites

@slon żeby sterować przyciskami trzeba by zrobić pętlę for która co 0.5 sekundy będzie zwiększać wartość zmiennej o 1 a potem dać tą zmienną do tego twojego BPM (Sorry, ale nie bardzo wiem gdzie), a druga pętla for przy drugim przycisku odpowiadałaby za zmniejszanie wartości zmiennej.

Udostępnij ten post


Link to post
Share on other sites

Sterowania przyciskami nie sprawdzałem. Natomiast sprawdziłem jak wygląda sterowanie jasnością  z użyciem micros() na pinie 4. Dioda płynnie się rozjaśnia (kwestia doboru wartości).

Udostępnij ten post


Link to post
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ę »

×