Komentator 87 Napisano Czerwiec 1, 2015 Udostępnij Napisano Czerwiec 1, 2015 Zgodnie z rozpoczętym cyklem pora na kolejne zadanie. Stawka jest wysoka, bo do rozdania mam jeszcze 9 Proxxonów FBS 240/E.Dziś rusza następne zadanie, czyli okazja do zdobycia kolejnej szlifierko-wiertarki! UWAGA, to tylko wstęp! Dalsza część artykułu dostępna jest na blogu.Przeczytaj całość »Poniżej znajdują się komentarze powiązane z tym wpisem. Cytuj Link to post Share on other sites
Bobby 306 Czerwiec 1, 2015 Udostępnij Czerwiec 1, 2015 Klasy w C++ (Arduino) też wchodzą w grę? Cytuj Link to post Share on other sites
Treker 2830 Czerwiec 2, 2015 Udostępnij Czerwiec 2, 2015 Bobby, pytanie, czy będzie to zrozumiałe i przydatne dla początkujących? Cytuj Link to post Share on other sites
Treker 2830 Czerwiec 2, 2015 Udostępnij Czerwiec 2, 2015 Jednocześnie przypominam wszystkim o trwającej ankiecie, która wyłoni zwycięzcę poprzedniego zadania! Cytuj Link to post Share on other sites
Polecacz 101 Zarejestruj się lub zaloguj, aby ukryć tę reklamę. Zarejestruj się lub zaloguj, aby ukryć tę reklamę. Szukasz producenta PCB? Sprawdź firmę JLCPCB. Dlaczego warto? • Prototypy PCB 2-warstwowe za 2$ (gotowe w 24 godziny) • Prototypy PCB 4-warstwowe za 5$ • Montaż SMT od 7$ • Produkcja w profesjonalnej fabryce (zobacz film) Sprawdź też » Jak powstaje PCB? Wycieczka po fabryce
Bobby 306 Czerwiec 2, 2015 Udostępnij Czerwiec 2, 2015 Treker, myślę, że tak. Generalnie wszystkie biblioteki arduino praktycznie są napisane typowo jako kasy - servo, stepper, serial. Napisałem ostatnio np. klasę do obsługi średniej kroczącej (zero sprzętu), wtedy po zaincludowaniu pliku .h kod wygląda tak: deklaracja: SMA average(L); //konstruujemy obiekt klasy SMA, parametrem konstruktora jest ilość próbek średniej używanie: average.add(probka); //dodajemy próbkę do bufora, reszta zostaje automatycznie przesunięta zmienna = average.get(); //odczytujemy średnią z ostatnich L próbek Sama średnia obsługuje na razie tylko twory mojej innej klasy, Cartesian, która to przechowuje współrzędne w układzie kartezjańskim, ale nic nie stoi na przeszkodzie, by oprzeć klasę o szablon - wtedy będzie mogła liczyć średnią z dowolnych zmiennych. Właśnie obiektowość w Arduino jest świetna - tak mi teraz przemknęło przez myśl, by napisać może jakiś odcinek kursu arduino o klasach właśnie. Pozwala to na nieporównywalnie prostszą względem czystego C skalowalność kody, staje się on też prostszy w wykorzystaniu na inne platformy (jeśli tylko znajdzie się dla nich kompilator C++, na przykład STMy). Cytuj Link to post Share on other sites
aixI 47 Czerwiec 2, 2015 Udostępnij Czerwiec 2, 2015 Chciałbym Wam przedstawić funkcję do obsługi przycisku (ang. switch) w przerwaniu INT0 na pinie PD2 portu D mikrokontrolera AVR firmy ATMEL ATmega8. Kod źródłowy napisany jest w języku C dla 8-bitowych mikrokontrolerów AVR. Podstawowe informacje o tym mikrokontrolerze można znaleźć w jego nocie katalogowej (ang. datasheet) wpisując w przeglądarkę internetową frazę "ATmega8 datasheet". Takie rozwiązanie pozwala na użycie tegoż przycisku jako przycisk ON/OFF naszego robota lub innego urządzenia Przedstawię teraz konfigurację przycisku i zmiennej globalnej do obsługi przerwania: // Definiujemy przycisk, który znajduje się na pinie 2 portu D, czyli PD2. #define Przycisk_PIN (1<<PD2) #define Przycisk (PIND & Przycisk_PIN) volatile int jazda = 0; Teraz przechodzimy do "Głównej funkcji programu" i ustawiamy pin PD2 jako wejście, ponieważ będzie on odbierał sygnały, które "wygeneruje" przycisk (stan bliski VCC (+5V), czyli logiczna jedynka (1) lub stany bliskie GND, czyli logiczne zero (0)). Musimy też pamiętać, że aby korzystać z przerwań musimy włączyć globalne przerwania --> sei(); //--- Główna funkcja programu --- int main(void) { DDRD &= ~Przycisk_PIN; // Wejcie - Przycisk PORTD |= Przycisk_PIN; // Pull-Up wewnętrzny (rezystor podciągający do VCC, dlatego nie trzeba stosować fizycznego rezystora podciągającego) sei(); // Włączenie globalnych przerwań } Przejdźmy teraz do obsługi przerwania INT0 na pinie PD2: //--- Obsługa przerwania z INT0 --- ISR(INT0_vect) { GICR &= ~(1<<INT0); // Wyłączamy obsługę przerwania na PD2 - drgania styków spowodowałyby wielokrotne jego wywołanie jazda ^= 1; // Zmieniamy stan flagi GICR |= (1<<INT0); // Włączamy z powrotem obsługę przerwania } Jeszcze napiszemy uproszczony kod źródłowy do obsługi tego przerwania: // --- Pętla nieskończona programu --- while(1) { if(jazda) { // Sprawdzamy czy "jazda" jest 1-ką lub 0-em _delay_ms(50); // Eliminacja drgania styków if(jazda) { LED1_ON; // Dioda LED świeci }else{ LED1_OFF; // Dioda LED nie świeci } } } Drgań styków możemy się jeszcze pozbyć sprzętowo, przez realizację podłączenia przycisku do mikrokontrolera. Mianowicie przez użycie odpowiednich rezystorów jak i kondensatorów - na Forum było to omawiane wiele razy (a nawet w #3 odsłonie tego konkursu). Mam nadzieję, że ta prosta funkcja do obsługi przycisku w przerwaniu jako przycisk ON/OFF pozwoli wielu początkującym okiełznanie swojego robota Pozdrawiam, Adam (aixI). Cytuj Link to post Share on other sites
piotreks-89 163 Czerwiec 2, 2015 Udostępnij Czerwiec 2, 2015 aixI, delay w przerwaniu? "Trochę" to się mija z ideą przerwania... Cytuj Link to post Share on other sites
aixI 47 Czerwiec 2, 2015 Udostępnij Czerwiec 2, 2015 Tak, wiem. Ale wżywamy tego przycisku jak włącznik ON/OFF i tyle - nic więcej ma nie robić, tylko spełniać swoją funkcję, a taki drobny "delay" przy tym nie przeszkadza. Cytuj Link to post Share on other sites
piotreks-89 163 Czerwiec 2, 2015 Udostępnij Czerwiec 2, 2015 Nawet jeśli, to nie tłumaczy to użycia delay'a w przerwaniu. To jest po prostu zły nawyk i nie należy go powielać. Mam nadzieję, że to zmienisz. Ja daję autodelet'y na swoje posty, bo szkoda tutaj śmiecić. Cytuj Link to post Share on other sites
aixI 47 Czerwiec 2, 2015 Udostępnij Czerwiec 2, 2015 W sumie jakby się tak dobrze zastanowić, to jeżeli mają to być jakieś dobre, pomocne funkcje, które mają nauczać początkujących i wpajać im od samego początku dobre nawyki, to jest to prawdą, że jednak nie powinno się stosować "delay'a" w przerwaniu - sam wiem, że się go tam nie powinno stosować, ale niestety nie usprawiedliwia mnie to. Poprawiłem i ustawiłem autodel. Pozdrawiam, Cytuj Link to post Share on other sites
piotreks-89 163 Czerwiec 2, 2015 Udostępnij Czerwiec 2, 2015 Nie chcę być namolny, ale usuwając tego delay'a i nie zastępując go inną metodą eliminacji drgań styków (a są takie ), problemu wcale się do końca nie pozbywasz. Owszem, kod staje się nieco poprawniejszy, ale inny problem powraca. Cytuj Link to post Share on other sites
Treker 2830 Czerwiec 2, 2015 Udostępnij Czerwiec 2, 2015 Bobby, ok w takim razie dopuszczam również takie rozwiązania. aixI, zwracam też uwagę, że to rozwiązanie nie do końca jest funkcją. Jest to kilka "rozrzuconych" kawałków kodu. Oczywiście rozumiem, że tutaj inaczej ciężko byłoby to rozwiązać, ale proszę, aby wszyscy pamiętali, że należy ograniczać takie rozdrabnianie. aixI, piotreks-89, nie wygaszajcie postów, niech zostaną widoczne dla wszystkich. Cytuj Link to post Share on other sites
Hudyvolt 102 Czerwiec 2, 2015 Udostępnij Czerwiec 2, 2015 int8_t uchyb(uint8_t pomiary[], uint8_t czujniki, uint8_t prog) { static int8_t wagi[8]; //tablica zawierajaca wagi poszczególnych czujników if (wagi[0] == 0) //wyliczenie wag czujników przy pierwszym wywołaniu funkcji { for (uint8_t i=0; i<(czujniki/2); i++) { wagi[i] = 1 << ((czujniki / 2) - i); wagi[czujniki-i-1] = -wagi[i]; } } int8_t uchyb = 0; uint8_t ile = 0; for (uint8_t i=0; i<czujniki; i++) { if (pomiary[i] < prog) //kierunek znaku nierówności zależy od reakcji czujnika na kolor podłoża { // < dla sytuacji gdy linia daje niskie wartości z ADC uchyb += wagi[i]; // > dla sytuacji gdy linia daje wysokie wartości z ADC ile++; } } if (ile>1) uchyb /= ile; return uchyb; } Funkcja zwraca wartość uchybu dla regulatora P(ID) na podstawie tablicy z wartościami z przetwornika ADC. Argumentu funkcji: 1. nazwa tablicy z pomiarami z ADC 2. liczba czujników 4. próg rozpoznawania kolorów przyjąłem 2 założenia: 8-bitowy odczyt ADC i max. 8 czujników Podaję też cały program wykorzystujący tę funkcję, a także z kodem do generowania tablicy z pomiarami ADC w przerwaniach. Poniższy kod jest przeznaczony dla mikrokontrolerów ATmega innych niż: ATmega8, ATmega8A, ATmega128, ATmega406. Z oczywistych względów nie będzie działał tez na mikrokontrolerach, które nie są wyposażone w ADC. #include <avr/io.h> #include <avr/interrupt.h> #define SENSORS 8 //liczba czujników [max. 8] volatile uint8_t reading[SENSORS]; //tablica przechowująca odczyty ADC void Init_ADC(); uint8_t potega(uint8_t podstawa, uint8_t wykladnik); int8_t uchyb(uint8_t pomiary[], uint8_t czujniki, uint8_t prog); int main(void) { Init_ADC(); int8_t error; while (1) { error = uchyb(reading, SENSORS, 128); } } void Init_ADC() { ADMUX |= (1<<REFS0); //VCC jako napięcie odniesienia z pinem AREF podłączonym do GND przez kondensator ADMUX |= (1<<ADLAR); //przesunięcie wyniku do lewej -> 8-bitowy odczyt wyniku ADCSRA |= (1<<ADPS2) | (1<<ADPS1); //prescaler = 64 -> przy 16MHz daje to 250kHz dla ADC ADCSRA |= (1<<ADIE); //włączenie przerwań od ADC ADCSRA |= (1<<ADEN); //włączenie przetwornika ADC ADCSRA |= (1<<ADSC); //start konwersji sei(); //globalne zezwolenie na przerwania } ISR(ADC_vect) { static uint8_t i; // reading[i] = ADCH; i++; i%=SENSORS; ADMUX = (ADMUX & 0b11111000) | i; ADCSRA |= (1<<ADSC); } int8_t uchyb(uint8_t pomiary[], uint8_t czujniki, uint8_t prog) { static int8_t wagi[8]; //tablica zawierajaca wagi poszczególnych czujników if (wagi[0] == 0) //wyliczenie wag czujników przy pierwszym wywołaniu funkcji { for (uint8_t i=0; i<(czujniki/2); i++) { wagi[i] = 1 << ((czujniki / 2) - i); wagi[czujniki-i-1] = -wagi[i]; } } int8_t uchyb = 0; uint8_t ile = 0; for (uint8_t i=0; i<czujniki; i++) { if (pomiary[i] < prog) //kierunek znaku nierówności zależy od reakcji czujnika na kolor podłoża { // < dla sytuacji gdy linia daje niskie wartości z ADC uchyb += wagi[i]; // > dla sytuacji gdy linia daje wysokie wartości z ADC ile++; } } if (ile>1) uchyb /= ile; return uchyb; } @Edit 14-07-2015: poprawiłem potęgowanie ze znaku ^, który w języku C jest operacją XOR, na przesunięcie bitowe. Podziękowania dla Elvisa za wyłapanie błędu i propozycję rozwiązania. Ja zaproponowałem funkcję liczącą potęgę jednak rozwiązanie Elvisa jest dużo prostsze. uint8_t potega(uint8_t podstawa, uint8_t wykladnik) { if (wykladnik == 0) return 1; else return podstawa * potega(podstawa, (wykladnik - 1)); } Warto zwrócić uwagę, że ta funkcja przyjmuje i zwraca zmienne 8-bitowe bez znaku, czyli wartości 0-255. Tak jak wykorzystana jest ona w funkcji głównej będzie działać poprawnie dla maks. 15 czujników. Cytuj Link to post Share on other sites
Wojciech 25 Czerwiec 3, 2015 Udostępnij Czerwiec 3, 2015 Hudyvolt, zamiast ciągle uruchamiać od nowa konwersję: ADCSRA |= (1<<ADSC); Można ustawić przetwornik w tryb 'Free run' (podczas jego inicjalizacji) poprzez ustawienie bitu 'ADFR', w taki sposób: ADCSRA |= (1<<ADFR); Cytuj Link to post Share on other sites
Hudyvolt 102 Czerwiec 3, 2015 Udostępnij Czerwiec 3, 2015 Wojciech, a w którym momencie zmieniać kanał w muxie i skąd mieć pewność wartość z którego kanału odczytuję z rejestru ADCH? Cytuj Link to post Share on other sites
Polecacz 101 Zarejestruj się lub zaloguj, aby ukryć tę reklamę. Zarejestruj się lub zaloguj, aby ukryć tę reklamę. 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
Pomocna odpowiedź
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!