• 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
Jak ustawić funkcje czasu wyjścia na określony i off
#11
(03-07-2019, 06:02)Jarewa0606 napisał(a):
(02-07-2019, 19:20)es2 napisał(a): To jedno z najprostszych ale i najgorszych rozwiązań 
A czemu millis to jedno z najgorszych rozwiazań??
Skoro pytasz, to masz małe doświadczenie w programowaniu i nie zrealizowałeś żadnego poważnego projektu a nawet na AVR czy 8051 jest to możliwe ale wymaga większego wkładu pracy niż w przypadku nowoczesnych rozwiązań (ARM, FPGA/CPLD).

Stopniowanie rozwiązań od najgorszego:
- Delay.
- Millis i inne rozwiązania realizowane w pętli głównej.
- Przerwania od timera.
- Wykorzystanie sprzętu.
W ostatnim przypadku najczęściej do wyboru są dwie opcje:
- Wykorzystanie układów peryferyjnych bez użycia DMA.
- Jak wyżej z DMA.

Najlepszym, najdokładniejszy, nieabsorbującym czasu procesora rozwiązaniem tego konkretnego przypadku jest wykorzystania timera w trybie one pulse (na AVR to sprzętowo chyba nie da się zrealizować).

Mills ma ta wadę, że gdy jakieś operacje wykonują się długo, przykładowo wysyłanie danych do LCD, poprzedzone odczytem 1-Wire przez beznadziejne arduinowskie biblioteki korzystające niepotrzebnie z float, do tego ładowanie pliku JPG z karty SD, to zdarzenie, może wykonać się z opóźnieniem prawie 3 sekund a nawet więcej.
Oczywiście, pojawią się głosy, że można robić po kawałku, odczytać 1-Wire, później plik z SD, po kawałku (kto to potrafi?), wysyłać dane do LCD po kawałku (kto próbował?) czyli narobić się a i tak, opóźnień nie da się wyeliminować. Prościej, skuteczniej, użyć przerwań od timera, bo w tym przypadku, sprzętowe sterowanie wyjścia timerem, to przerost formy nad treścią.

Ułomności "metody" delay chyba nie muszę uzasadniać?
 
Odpowiedź
#12
Myślałem że masz coś innego na myśli.. Raczej jak ktoś tworzy program na Ardunio to raczej nie potrzebuje wysokiej precyzji czasu a wysyłkę i odczyt uwzględnia.


W przypadku Przerwania od timera trzeba uwzględnić ze niektóre biblioteki na Ardunio z niego korzystają wtedy może pojawić się konflikt.
Arduino zostało wymyślone po to, by robić dobrze jedną prostą rzecz – migać diodą. 
 
Odpowiedź
#13
(04-07-2019, 05:55)Jarewa0606 napisał(a): Myślałem że masz coś innego na myśli..  Raczej jak ktoś tworzy program na Ardunio to raczej nie potrzebuje wysokiej precyzji czasu
Jeśli chcesz odmierzyć 6 sekund to dopuszczalna jest odchyłka o +50%?
Gdyby chodziło o minuty, to jest różnica pomiędzy jajkiem na miękko a na twardo.

(04-07-2019, 05:55)Jarewa0606 napisał(a): a wysyłkę i odczyt uwzględnia.
Najczęściej nie da się, bo czasy wykonania operacji mogą i przeważnie są różne przy każdym obiegu pętli głównej.

(04-07-2019, 05:55)Jarewa0606 napisał(a): W przypadku Przerwania od timera trzeba uwzględnić ze  niektóre biblioteki na Ardunio z niego korzystają  wtedy może pojawić się konflikt.
Po "pierwsze primo" uC maja kilka timerów, jak jest za mało to trzeba wybrać taki, który ma ich więcej. Jak AVR ma ich mało (max 6) to trzeba wybrać ARM STM32 gdzie 16 timerów to nie problem.
Po "drugie primo", ok 1ms przerwanie od T0 jest od przepełnienia, nie ma problemu aby wykorzystać jedno z dwu T0 od porównania.
Po "trecie primo", aby odmierzanie czasu działało dobrze, łatwiej to zrobić na przerwaniach czy sprzętowo niż w pętli głównej. Ponadto zmiany w programie nie wpływają na odmierzane czasy, no chyba, ze ktoś stosuje złe praktyki i zawiesza przerwania. Takim złym przykładem jest obsługa 1-Wire i WS2812 przez libs Arduino, metody wzorowane na Mirku K. Ile z tym kłopotu można poczytać na forach. Doprawdy niepojęte jest, jakie badziewie potrafią wymyśleć (nazywanie tego myśleniem to profanacja tego słowa) Arduinowcy i Mirek K i to w sytuacji, gdy do 1-Wire, poza dedykowanymi układami mastera np DS2482, Dallas-Maxim udostępnia AN opisujący wykorzystanie UART w roli układu master.
Mało UART w Arduino? Jaki problem wybrać uC z większą ich liczbą?
Kolejne kretyństwo w Arduino, to zabranie jedynego w UNO (i nie tylko UNO) popularnego UART na cele programowania i pseudo-debugowania (z którego większość arduinowców nie korzysta) jakby nie było FT201, FT220 i podobnych.
Na szczęście widać tręd odchodzenia w Arduino od AVR na rzecz ARM, czego nie robi "wszechwiedzący" Mirek K. (mam nadzieję, że się na tym przejedzie, gdy natomiast zmieni zdanie, będzie zmuszony setkom osób przyznać rację wielu przeprosić a to nie ten typ, on woli plajtę niż przyznanie się do błędu) gdzie nawet 12 UART, 4 I2C, 6 SPI nie jest problemem, mniej niż 4 timery w ARM nie widziałem + jeden systemowy, no i jest DMA, brakuje tylko czasem MMU. Niestety, szybkie uC są "zabijane" przez libs arduino prze "delay", "while( czekam_na_coś_tam)" i karygodne programowe SPI, I2C, 1-Wire, itd, przez co "para idzie w gwizdek".


PS
Widział ktoś AVR z FPU? Jak pamiętam nawet Xmega nie ma go.
 
Odpowiedź
#14
Zasadniczo, to można sobie pomieszać styl arduinowy ze stylem AVR-GCC.
Oczywiście te nazwy, to wytwór własny.

Potrzebne nam będą:

1) Funkcja włączająca Timer1.
Kod:
void timerStart()
{
    PRR &= ~(1 << PRTIM1);
    TCCR1A = (1 << WGM11); 
    TCCR1B = (1 << WGM13) | (1 << WGM12) | (1 << CS12) | (1 << CS10);
    ICR1   = 46875;
    TIMSK1 = 1 << OCIE1B;
    flaga = false;
    digitalWrite(Elektrozawor, HIGH);
}

2) Funkcja wyłączjąca Timer1.
Kod:
void timerStop()
{
    TCCR1B = (0 << CS12) | (0 << CS11) | (0 << CS10);
    digitalWrite(Elektrozawor, LOW);
}

3) Funkcja obsługi przerwania od porównania.
Kod:
ISR(TIMER1_COMPB_vect)
{    licznik++;
    if (licznik==2)
    {
    licznik = 0;
    timerStop();
    }
}

No i kilka globalnych zmiennych:

bool flaga = true;
volatile byte licznik;

W funkcji loop() w warunku if (distance <=  && distance >= 0), należy wpisać:
Kod:
if (flaga) timerStart();

Oczywiście zamiast tego wszystkiego, co obsługuje włączenie elektrozaworu, czyli wywal digitalWrite(Elektrozawor, HIGH);
Funkja timerStart() uruchamia nasz Timer1 w trybie Fast PWM, z preskalerem 1024.
Zezwala na przerwania od porównania i ustawia pin elektrozaworu na HIGH.
Licznik liczy 46875 tiknięć, co jak mi się wydaje, oznacza że minęły 3 sekundy.
Do sześciu sekund się nie da, ponieważ ICR1 może wynosić najwyżej 65535 (10bit).
Jest tam jeszcze reset flagi, co znaczy że do puki jej nie ustawimy, warunek z funkcji loop() się nie spełni i nie załączy nam liczenia czasu od nowa.
Gdy miną 3 sekundy, wyzwolone zostanie przerwanie.
Funkcja go obsługująca doda wtedy 1 do zmiennej licznik.
Następne przerwanie spowoduje spełnienie warunku if (licznik==2), czyli zerujemy licznik i wywołujemy funkcję timerStop(), która wyłącza źródło taktowania dla Timera1, oraz ustawia pin elektrozaworu na LOW.
Aby zresetować flagę zezwalającą na następne spełnienie warunku:
Kod:
if (distance <= 10 && distance >= 0) {

        if (flaga) timerStart();
        
    }


Należy w warunku:

Kod:
else
  {
    digitalWrite(Red, LOW);
    digitalWrite(Green, HIGH);
    digitalWrite(Elektrozawor, LOW);
    delay(300);
  }

Dopisać:

Kod:
flaga = true;

No i jeszcze takie pytanie:
Po co są te delaye? Wywal to w diabły!

A cha i jeszcze taka mała dygresja:
Na granicy dystansu jaki sobie tam obrałeś, elektrozawór będzie miał, jak by to określić, jakby trzaski. Coś w stylu drgań styków w przełącznikach, więc powinieneś się tym zająć.

Oczywiście powyższe funkcje, to taki mój szybki research w tym kierunku, więc należy to traktować z pewnym dystansem. Trzeba wziąć manuala do ręki i porządnie sobie wszystko zaplanować, bo nie wiem czy Fast PWM to będzie odpowiedni tryb.
No i można zamiast zliczać programowo do dwóch, wyzwalać sprzętowy licznik i całkowicie odciąć się od rdzenia i stosu.
Ale już mi się nie chciało grzebać, chociaż jeśli masz ochotę ta to rozwiązanie, to mogę coś naskrobać.
Jeśli masz problem z kodem lub sprzętem, zadaj pytanie na forum. Nie odpowiadam na PW, jeśli nie dotyczą one spraw forum lub innych tematów prywatnych.

[Obrazek: SsIndaG.jpg]
 
Odpowiedź
#15
(04-07-2019, 21:35)Robson Kerman napisał(a): Do sześciu sekund się nie da, ponieważ ICR1 może wynosić najwyżej 65535 (10bit).
Nie chce mi się grzebać w manualach więc nie wiem czy w każdym AVR PWM na timerze 1 może pracować w trybie 16-bit ale w Mega328 na pewno tak:
Cytat:16. 16-bit Timer/Counter1 with PWM
16.1 Features
• True 16-bit Design (i.e., Allows 16-bit PWM)
a to pozwala uzyskać czasy do ponad 4 sekund przy taktowaniu 16MHz i preskalerze 1024. Zmniejszając taktowanie do 8MHz czas zwiększy się do ponad 8 sekund z rozdzielczością 1,28ms.

Nie byłbym sobą, jak bym nie porównał AVR do ARM. W STM 32, nawet na 16-bit timerze, można uzyskać przy taktowaniu 16MHz, czasy do 268 sekund z rozdzielczością ok 4ms (preskaler można ustawić w zakresie 1..65535). Sygnał taktujący można dodatkowo podzielić przez 2 lub 4 wydłużając czas jeszcze bardziej. Wiele STM32 ma timery 32-bit ale w każdym, można dwa 16-bit połączyć w jeden 32-bit (w AVR tylko robiąc połączenie na zewnątrz układu). Timer 32-bit pozwala przy taktowaniu 180MHz, uzyskać czasy do 18dni z rozdzielczością niecałe 400ns a z dodatkowym podzielnikiem przez 2 lub 4 - sami policzcie.

Jak więc widać, nawet w banalnym projekcie, AVR wymaga większych nakładów czasu pracy nad softem aby uzyskać efekt, który w STM32 uzyskuje się kilkoma linijkami kodu.
 
Odpowiedź
#16
Cytat:No i jeszcze takie pytanie:

Po co są te delaye? Wywal to w diabły!


Jesli chodzi o delay to tam gdzie zapala się dioda zielona to tak chce zrobić, że podkładam szklankę czujnik ją wykrywa i zapala sie dioda i przerwa 3 sekundy otwiera się elektrozawór naleje np 6 sekund i zamknie się dlatego chciałbym ustawić go na okreslony czas i off.


Cytat:Ale już mi się nie chciało grzebać, chociaż jeśli masz ochotę ta to rozwiązanie, to mogę coś naskrobać.
Jeśli chciałbyś się podjąć to będę wdzięczny, bo zanim się oczytam i poznam więcej arduino to zajmie mi to czasu, a ten projekt chciałbym sobie zrealizować.
 
Odpowiedź
#17
(05-07-2019, 14:51)brendy napisał(a):
Cytat:No i jeszcze takie pytanie:
Po co są te delaye? Wywal to w diabły!
Jesli chodzi o delay to tam gdzie zapala się dioda zielona to tak chce zrobić, że podkładam szklankę czujnik ją wykrywa i zapala sie dioda i przerwa 3 sekundy otwiera się elektrozawór naleje np 6 sekund i zamknie się dlatego chciałbym ustawić go na okreslony czas i off.
Takie rzeczy robi się na przerwaniach od timera albo ostatecznie z użyciem millis https://forbot.pl/blog/kurs-arduino-ii-w...is-id18418.
 
Odpowiedź
#18
(04-07-2019, 22:17)es2 napisał(a):
(04-07-2019, 21:35)Robson Kerman napisał(a): Do sześciu sekund się nie da, ponieważ ICR1 może wynosić najwyżej 65535 (10bit).
Nie chce mi się grzebać w manualach więc nie wiem czy w każdym AVR PWM na timerze 1 może pracować w trybie 16-bit ale w Mega328 na pewno tak:
Cytat:16. 16-bit Timer/Counter1 with PWM
16.1 Features
• True 16-bit Design (i.e., Allows 16-bit PWM)
a to pozwala uzyskać czasy do ponad 4 sekund przy taktowaniu 16MHz i preskalerze 1024. 

Mój błąd. Napisałem 10 bit zamiast 16 bit.No ale jak policzyć, to 10 bit daje nam 1024, a ja napisałem 65535, więc od strony kodu nie ma pomyłki.
I tak jak piszesz, Mega 328 daje możliwość liczenia do 4 sekund, ale w tym przypadku trzeba policzyć do 6 sekund.
Dla tego więc w moim kodzie przerwanie jest co 3 sekundy.
Jeśli masz problem z kodem lub sprzętem, zadaj pytanie na forum. Nie odpowiadam na PW, jeśli nie dotyczą one spraw forum lub innych tematów prywatnych.

[Obrazek: SsIndaG.jpg]
 
Odpowiedź
#19
(06-07-2019, 09:18)Robson Kerman napisał(a): I tak jak piszesz, Mega 328 daje możliwość liczenia do 4 sekund, ale w tym przypadku trzeba policzyć do 6 sekund.
Jaki problem CLKPR ustawić na 1, do tego w opcjach kompilacji F_CLK czy jak się tam to zwie przypisać 8000000?

Często, amatorzy, aby zmienić domyślny dla większości AVRmega podzielnik przez 8, gdy pracują na wewnętrznym RC zmieniają FUSE. Gdy ma to być jedyna zmiana, nie wiedzą, że wystarczy zmienić CLKPR, bo ustawienie FUSE DIV8 nie robi nic innego, jak wpisuje do CLKPR 3.
W większych uC, aby nie "katować" użytkownika koniecznością ustawiania FUSE i wyeliminować możliwe błędy z tym związane, sprawdzam w programie FUSE, jeśli nie są takie jak chcę, to je zmieniam. Dzięki temu, nawet jak użytkownik zapomni ustawić bity LOCK, to program sam to zrobi.
 
Odpowiedź
#20
Można wpisać
Kod:
#ifdef F_CPU
#undef F_CPU
#define F_CPU 8000000L
#endif

Ale raczej to nic nie da, bo kompilator później zajrzy do boards.txt i to pozmienia . Trzeba raczej przeredagować wpis w boards.txt dla konkretnej płytki.

Kod:
uno.build.f_cpu=8000000L

Znowuż zmieniając preskaler zegara, trzeba pamiętać, że to Arduino i użytkownik nie ma wpływu na pracę innych peryferiów poustawianych przez producenta tegoż urządzenia. A te nie synchronizują się z zegarem, tylko patrzą na millis, nie wiem po co.
W każdym razie pewnie coś popsujemy i przestanie działać jakiś wyświetlacz, albo komunikacja Smile
Często się zastanawiam, dla czego Arduino ma tylu zwolenników, skoro pracując normalnie na rejestrach w normalnym IDE powyższe zadanie można zrobić szybciej, przyjemniej i bez stresu (z browarkiem w ręku)?
Jeśli masz problem z kodem lub sprzętem, zadaj pytanie na forum. Nie odpowiadam na PW, jeśli nie dotyczą one spraw forum lub innych tematów prywatnych.

[Obrazek: SsIndaG.jpg]
 
Odpowiedź
  


Skocz do:


Przeglądający: 1 gości