Skocz do zawartości

szejkop

Użytkownicy
  • Zawartość

    15
  • Rejestracja

  • Ostatnio

Informacje

  • Płeć
    Mężczyzna
  • Zawód
    Student ZUT

Osiągnięcia użytkownika szejkop

Odkrywca

Odkrywca (4/19)

  • Za 5 postów
  • To już rok!
  • To już 5 lat!

Odznaki

0

Reputacja

  1. Niestety po zmianie warunków program nie działa prawidłowo (nie wysyła nawet informacji do monitora szeregowego).
  2. Tak 🙂 Bardzo dziękuję za odpowiedź. Program przeszedł kolejne modyfikacje. Tutaj zastosowałem dodatkową zmienna impuls, która przedstawia "proces impulsu" Jeśli impuls=0, to znaczy, że jeszcze nie wystąpił impuls. Jeśli impuls=1, to znaczy, że wystąpiło zbocze narastające, czyli impuls trwa dalej i się jeszcze nie zakończył. Jeśli impuls=2, to znaczy, że wystąpiło zbocze opadające i impuls zakończył się. Od owej zmiennej uwarunkowałem funkcję sondująca odpowiedzialna za sygnał sondujący, oraz funkcję pomiar, która wysyła informacje tylko w odpowiednich momentach, czyli w momencie kiedy wystąpiło już zbocze opadające echa i sygnał się zakończył. Zmniejszyłem również okres występowania przerwań od Timera 2, fclk=16Mhz, ftimera=10kHz i wartość OCR2=200; stąd okres 100us. Owy program poniżej: #include <avr/io.h> #include <stdint.h> #include <util/delay.h> //#define trigPin arudino12 pb4 //#define echoPin arudino3 pd3 #include <avr/interrupt.h> volatile uint8_t czas; volatile double licznik; volatile uint8_t flaga=0; volatile double odl1=0; volatile double impuls=0; /////////////////////////////////////////////////////////// //INICJALIZACJA void InitInterrupt(void) { DDRB = 0b11111111;//trigg na wyjscie DDRD = 0b00000000;//echo na wejscie int EIMSK=0b00000010; EICRA=0b00001100; // TCNT2 = 0x00; //Zerowanie rejestru TCNT2 (Rejestr jednostki zegara) TCCR2A = (1<<WGM21); //Ustawia timer2 w tryb CTC bez preskalera TCCR2B=(1<<CS21); //Czestotliwość 16Mhz/8=2MHz OCR2A = 200; //Górna wartość licznika wynosi 200 //Przerwania będą następować co 100us sei(); } /////////////////////////////////////////////////////////// //PRZERWANIE OD TIMERA //F-cja przerwania od Timera2 ISR(TIMER2_COMP_vect) { licznik=licznik+1; // co 100us dodawana jest jedynka } /////////////////////////////////////////////////////////// //PRZERWANIE OD INT1 ISR(INT1_vect) { if(flaga=0) { TIMSK2 = (1<<OCIE2A); //włącza Timer2 w trybie dopasowania (START) EIMSK=0b00000000; EICRA = 0x00; //Przerwanie zostanie wywołane zboczem opadającym EICRA = (1<<ISC11); //na wejściu INT1 EIMSK=0b00000010; flaga=1; } else if(flaga=1) { TIMSK2 &=~(1<<OCIE2A); //zatrzymuje Timer2 (STOP) EIMSK=0b00000000; EICRA = 0x00; //Przerwanie zostanie wywołane zboczem rosnącym EICRA = (1<<ISC11)|(1<<ISC10); //na wejściu INT1 EIMSK=0b00000010; flaga=0; odl1=licznik; odl1/=20; licznik=0; } impuls=impuls+1; } /////////////////////////////////////////////////////////// //SYGNAL SONDUJACY void sonda(void) { PORTB &= ~(1 << 4); _delay_us(2); PORTB |= (1 << 4); // przypisanie jedynki _delay_us(10); PORTB &= ~(1 << 4); } /////////////////////////////////////////////////////////// //POMIAR WIELKOSCI void pomiar(void) { Serial.println(odl1); impuls=0; } /////////////////////////////////////////////////////////// //FUNKCJA GLOWNA int main(void) { Serial.begin (9600); void InitInterrupt(void); //deklaracja InitInterrupt(); //wywolanie void sonda(void); //deklracja void pomiar(void); //deklaracja while(1) { if(impuls=0) { sonda(); //wywolanie } if(impuls=2) { pomiar(); //wywolanie } _delay_ms(200); } } Mam nadzieję, że jestem coraz bliżej 🙂 [ Dodano: 28-12-2015, 13:05 ] Zauważyłem, że zamiast wykonania instrukcji warunkowej, program podstawia za impuls wartość 2, niestety to nie jedyny problem.
  3. Stosunkowo uzupełniłem swoją wiedzę i stworzyłem program wykorzystujący przerwania od timera2. Pierwsza funkcja: void InitInterrupt(void) Funkcja inicjalizująca dane wstępne,parametry portów oraz timera2 (ustawienie preskalera oraz tryb jego pracy CTC). Posiadam rezonator o f=16MHz i ustawiłem podział przez 1 oraz rejestr OCR2A = 0x10,aby uzyskać przerwania równe co 1us. Następnie zadeklarowałem przerwanie od Timera2 w momencie zrównania się rejestrów, licznik powinien zwiększyć się o 1. (cały czas przy założeniu, że przerwania występują co 1us.) Następnie jest proces deklaracji przerwania zewnętrznego w którym sprawdzane są warunki. Jeśli nie było flagi to ustawiamy rejestr odpowiedzialny na obsługę przerwania (zrównanie się rejestrów) czyli jest to związane z włączeniem timera,następnie przestawiamy rejestr EICRA na zbocze opadające i ustawiamy flage na 1 czyli,wystawienie informacji, że wystapiło zbocze narastające. Teraz oczekujemy na zbocze opadające, stąd przerwanie, w którym jest to sprawdzane. Zachodzi reakcja na zbocze opadające i sprawdzamy wcześniej ustawiona flage. Następuje wyłączenie przerwania od timera2(stop timera), zmiana rejestru EICRA na zbocze narastające (proces zaczyna sie powtarzać), ustawienie flagi. Ostatnia faza to przypisanie zliczonych przerwań, które występowały co 1us. Ostatecznie przeskalowuje owy czas na dystans i przesyłam wartość do monitora szeregowego. W funkcji pomiar wysłam sygnał sondujący, który tworzy echo. #include <avr/io.h> #include <stdint.h> #include <util/delay.h> //#define trigPin arudino12 pb4 //#define echoPin arudino3 pd3 #include <avr/interrupt.h> volatile uint8_t czas; volatile double licznik; volatile uint8_t flaga; volatile double odl1; /////////////////////////////////////////////////////////// void InitInterrupt(void) { DDRB = 0b11111111;//trigg na wyjscie DDRD = 0b00000000;//echo na wejscie int EICRA=0b00001100; // TCNT2 = 0x00; //Zerowanie rejestru TCNT2 (Rejestr jednostki zegara) TCCR2A = (1<<WGM21); //Ustawia timer2 w tryb CTC bez preskalera TCCR2B=(1<<CS20); //Czestotliwość 16Mhz/1=16MHz OCR2A = 0x10; //Górna wartość licznika wynosi 16 //Przerwania będą następować co 1us sei(); } /////////////////////////////////////////////////////////// //F-cja przerwania od Timera2 ISR(TIMER2_COMP_vect) { licznik=licznik+1; } ISR(INT1_vect) { if(flaga=0) { TIMSK2 = (1<<OCIE2A); //włącza Timer2 w trybie dopasowania (START) EIMSK=0b00000000; EICRA = 0x00; //Przerwanie zostanie wywołane zboczem opadającym EICRA = (1<<ISC11); //na wejściu INT1 EIMSK=0b00000010; flaga=1; } else if(flaga=1) { TIMSK2 &=~(1<<OCIE2A); //zatrzymuje Timer2 (STOP) EIMSK=0b00000000; EICRA = 0x00; //Przerwanie zostanie wywołane zboczem rosnącym EICRA = (1<<ISC11)|(1<<ISC10); //na wejściu INT1 EIMSK=0b00000010; odl1=licznik; //Zapisuje wartość licznika do zmiennej "odl" odl1/=20; //oraz skaluje go licznik=0; //Zerowanie licznika flaga=0; } } double s_pomiar(void) { EIMSK=0b00000010; PORTB |= (1 << 4); // przypisanie jedynki _delay_us(10); PORTB &= ~(1 << 4); _delay_us(2); EIMSK=0b00000000; return odl1; } int main(void) { void InitInterrupt(void); double s_pomiar(void); while(1) { Serial.begin (9600); InitInterrupt(); s_pomiar(); Serial.println(odl1); _delay_ms(200); } } Myslę, że idea programu jest prawidłowa 🙂 Jednak jest tutaj jakieś niedociągnięcie. Program wysyła impulsy prawidło do czujnika i odpowiada odpowiednią długością impulsu, ale jednak nie otrzymuje wartości licznika. Proszę o pomoc
  4. Stworzyłem funkcje, program stał się bardziej przejrzysty. Niestety warunki w przerwaniu oraz negacja nie działa prawidłowo. Jestem dopiero początkującym i callback oraz flagi nie są aż tak mi znane, dlatego też zwracam się z prośbą. #include <avr/io.h> #include <stdint.h> #include <util/delay.h> //#define trigPin arudino12 pb4 //#define echoPin arudino3 pd3 #include <avr/interrupt.h> volatile uint8_t czas; int main(void) { DDRB = 0b11111111;//trigg na wyjscie DDRD = 0b00000000;//echo na wejscie int TCCR0B = (1 << CS00);//256 preskalera Serial.begin (9600); void sonda(); void initprzerwanie(); initprzerwanie(); while (1) { sonda(); Serial.println(czas); _delay_ms(200); } } //////////Inicjalizacja przerwania/////////////// void initprzerwanie(void) { EIMSK=0b00000010; //aktywowanie przerwania od int1 EICRA=0b00001100; // reagowanie na narastajace zbocze na int1 sei(); } //////////Sygnal sondujacy/////////////// void sonda(void) { PORTB &= ~(1 << 4); //przypisanie zera _delay_us(2); PORTB |= (1 << 4); // przypisanie jedynki _delay_us(10); PORTB &= ~(1 << 4); } //////////Obsluga przerwania/////////////// ISR( INT1_vect ) //przerwanie { if(EICRA & 0x04) //sprawdzenie ustawionego bitu { TCNT0=0; //przerwanie od zbocza narastajacego czyli start timera } else { czas=TCNT0; // przerwanie od zbocza opadajcego czyli zczytanie wartosci timera } EICRA^=0x4; // negacja bitu odpowiedzialna za odpowiednia reakcje na zbocze }
  5. Dziękuje za odpowiedź. Tak jak powiedziałeś, ustawiłem na "spokojnie" reakcje na zbocze narastające. W przerwaniu zgaszam flagę(dla pewności) oraz zmieniam reakcje ze zbocza narastającego na opadające. #include <avr/io.h> #include <stdint.h> #include <util/delay.h> //#define trigPin arudino12 pb4 //#define echoPin arudino3 pd3 #include <avr/interrupt.h> volatile uint8_t czas; int main(void) { EIMSK=0b00000010; //aktywowanie przerwania od int1 EICRA=0b00001100; // reagowanie na narastajace zbocze na int1 Serial.begin (9600); DDRB = 0b11111111;//trigg na wyjscie DDRD = 0b00000000;//echo na wejscie int TCCR0B = (1 << CS00);//256 preskaler sei(); while (1) { PORTB &= ~(1 << 4); //przypisanie zera _delay_us(2); PORTB |= (1 << 4); // przypisanie jedynki _delay_us(10); PORTB &= ~(1 << 4); _delay_ms(200); Serial.println(EICRA); } } ISR( INT1_vect ) //przerwanie { TCNT0=0; /start timera EIFR=0b00000010; //gaszenie flagi EICRA=0b0001000; // opadajace } W jaki sposób teraz powrócić do przerwania(realizowanego przez zbocze opadające) i zapisac wartość timera do zmiennej,a potem znowu zmienić reakcje na zbocze narastające.
  6. Udało mi się rozwiązać problem z sei() w arduino, przerwanie reaguje odpowiednio na pojawienie się zbocza narastającego. Teraz chciałbym przejść realizacji zadania zgodnie z podpowiedzią marka1707. Mam problem jak stworzyć drugie przerwanie. ISR( INT1_vect ) //przerwanie od zbocza narastajacego { TCNT0=0;// start timera EICRA=0b00001000;//zmiana na opadajace zbocze } Jak wywołać teraz przerwanie od zbocza opadajacego? Nie moge użyc znów ISR( INT1_vect) Myślałem również, żeby po prostu negować ten bit w rejestrze i sprawdzać jego warość: ISR( INT1_vect ) //przerwanie { if(EICRA & 0x04) //sprawdzenie ustawionego bitu { TCNT0=0; //przerwanie od zbocza narastajacego czyli start timera } else { czas=TCNT0; // przerwanie od zbocza opadajcego czyli zczytanie wartosci timera } EICRA^=0x4; // negacja bitu odpowiedzialna za odpowiednia reakcje na zbocze } Niestety ta negacja nie działa, patrząc po szeregowym rejstrze,który dalej wskazuje wartosc 12.
  7. Ogólnie rzecz biorąc porty były źle ustawione oraz napotkałem inny problem: //program testowy// #include <avr/io.h> #include <stdint.h> #include <util/delay.h> //#define trigPin arudino12 pb4 //#define echoPin arudino3 pd3 #include <avr/interrupt.h> volatile uint8_t czas; int main(void) { sei(); Serial.begin (9600); DDRB = 0b11111111;//trigg na wyjscie DDRD = 0b00000000;//echo na wejscie int TCCR0B = (1 << CS02);//256 preskaler EIMSK=0b00000010; //aktywowanie przerwania od int1 EICRA=0b00000011; // reagowanie na narastajace zbocze na int1 while (1) { czas=0; PORTB &= ~(1 << 4); //przypisanie zera _delay_us(2); PORTB |= (1 << 4); // przypisanie jedynki _delay_us(10); PORTB &= ~(1 << 4); Serial.println(czas); _delay_ms(100); } } Zauważyłem, że istnieje powiązanie pomiędzy globalnym odblokowaniem, a rejestrem EMISK odpowiedzialnym za odblokowanie przerwania zewnętrznego. Kiedy wyrażenie sei(); nie jest zakomentowane program nie działa, dopiero po usunięciu deklaracji globalnego odblokowania program rusza tzn. są przesyłane wartości czasu (0) do monitora szeregowego w przeciwnym wypadku program nie przesyła żadnej wartości. Jak mogę to rozwiązać? __________ Komentarz dodany przez: Treker Kody programów należy umieszczać w tag'ach . Tym razem już poprawiłem, pamiętaj na przyszłość 🙂
  8. Dziękuje za odpowiedź. Mam problem właśnie z pomiarem długości impulsu. Mój program nie działa i stanąłem w miejscu. Jestem dopiero początkującym w C stąd prosiłbym o kod, który będę mógł przeanalizować , bądź o podpowiedź.
  9. Witam Chciałbym zwrócić się z prośbą o pomoc w obsłudze czujnika odległosci w jezyku C. W Arduino IDE jest wręcz banalne i zrobiłem to tak jak na kursie: funkcja odpowiedzialna za to: int zmierzOdleglosc() { long czas, dystans; digitalWrite(trigPin, LOW); delayMicroseconds(2); digitalWrite(trigPin, HIGH); delayMicroseconds(10); digitalWrite(trigPin, LOW); czas = pulseIn(echoPin, HIGH); dystans = czas / 58; return dystans; } Ustawienie poszczególnych pinów oraz opóżnień w C jest dosyć łatwe, natomiast chodzi mi o realizacje funkcji pulseIn czyli funkcji odpowiedzialnej za pomiar długości impulsu. Posiadam: Atmega328p oraz zewnętrzny rezonator 16Mhz - czyli po prostu programuje arduino pisząc program w C. Ogólnie chciałbym skorzystać z przerwania zewnętrznego, dlatego też echo pin podłączyłem do INT1. W trakcie kiedy wykryje zbocze narastające, ma zostać uruchomiony timer i ma on mierzyć czas do momentu zmiany wartości syganłu na zero. Następnie przypisać owy czas do pewnej zmiennej,która następnie przetworzymy na odleglość. #include <avr/io.h> #include <stdint.h> #include <util/delay.h> //#define trigPin arudino12 pb4 //#define echoPin arudino3 pd3 #include <avr/interrupt.h> volatile uint16_t czas; int main(void) { sei(); Serial.begin (9600); DDRB = 0b0000000;//trigg na wejscie DDRD = 0b11111111;//echo na wyjscie int TCCR0B = (1 << CS02);//256 preskaler EIMSK=0b00000010; //aktywowanie przerwania od int1 EICRA=0b00000011; // reagowanie na narastajace zbocze na int1 while (1) { PORTB &= ~(1 << 4); //przypisanie zera delayMicroseconds(2); PORTB |= (1 << 4); // przypisanie jedynki delayMicroseconds(10); PORTB &= ~(1 << 4); } } ISR( INT1_vect ) //przerwanie { TCNT0 = 0; while (PD3); //dopoki echo jest w stanie wysokim zatrzymaj się w tym miejscu czas=TCNT0; } Piny przypisałem zgodnie ze zdjęciem,które zostało tutaj załączam.
  10. Po modyfikacji programu( wal silnika kreci tylko w jednym kierunku) silnik nie startuje. Przewody musialy stykac, poniewaz nie bylo zadnych wibracji pochodzacych z obrotu - silnik od poczatku juz nie reagowal. A uklad dzialal, poniewaz dioda swiecila sie na stale.
  11. Postanowiłem zrobić tak jak doradziliście, podłączyłem diodę i dopisałem w setup kod programu oznaczającą inicjalizację programu. Procesor nie restartuje się... dioda świeci tylko raz, a sam silnik wykonuje owe "odpoczynki"po określonej liczbie cykli. Zmodyfikowałem jednak kod programu i ustawiłem, aby silnik stale kręcił się w prawo - zero reakcji... Tak samo jest w przypadku z lewą stroną. Kilka razy wgrywałem program i zauważyłem, że czasami wał silnika wykona obrót o 10 stopni i na tym koniec, kiedy natomiast podłączam go bezpośrednio do baterii 1.5V, działa bez zarzutu.
  12. Przesyłam zdjęcia mojego układu oraz schematu(który został przeze mnie poprawiony): Ogólnie rzecz biorąc nastąpił postęp, ponieważ silnik zaczął reagować,ale nie w pełni. Silnik wykonuje obrót na 3 sekundy prawo , następnie w lewo, prawo i robi sobie "odpoczynek" na trzy sekundy. Ilość cykli natomiast się zmienia. Czasami odpoczynek następuję już po dwóch cyklach, a czasami po czterech. Zauważyłem również,ze jak podłącze silnik, to diody gasną na płytce prototypowe,a także dioda na arduino zaczyna słabiej swiecić. Silnik podłączony jest niebieskim oraz pomarańczowym przewodem zaznaczonym na zdjęciu.
  13. Witam Stworzyłem owy układ do sterowania silnikiem dc (przypadek nr1. - sterowanie kierunkiem obrotów, gdzie v=const). Układ zadziałał - diody świeciły się tak jak powinny. Poszedłem o krok dalej i podłączyłem mały silnik DC - opis ze strony z producenta - "silnik jest zwykłym szczotkowym silnikiem prądu stałego. Napięcie zasilania 1.5V do 4.5V, max. prędkość obrotowa 12000 obr/min. Prąd z obciążenie 350 mA". Układ w praktyce niestety nie działa, kiedy natomiast podłączam silnik bezpośrednio do baterii to wał się kręci. Proszę o odpowiedź
×
×
  • 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.