_LM_ Październik 15, 2021 Udostępnij Październik 15, 2021 Zapytaj kolegi @farmaceuta ćwiczyliśmy jakiś czas temu różne warianty timerów, gdzieś są jego posty 😉 Cytuj Link do komentarza Share on other sites More sharing options...
_LM_ Październik 15, 2021 Udostępnij Październik 15, 2021 (edytowany) 7 minut temu, farmaceuta napisał: Ja bym tu bardziej byl sklonny zwalic winne na czujniki...wkoncu czego sie spodziewac po module za piatke?😉 Nawet gdyby tak było, to poprawnie napisany program musi uwzględnić taką sytuację i odpowiednio na nią zareagować, zawieszenie się mikrokontrolera jest chyba najgorszą z opcji. Np budujesz sobie czujnik parkowania w garażu ... program się wysypuje a lampa wciąż pokazuje że "spoko ziomeczku cofaj śmiało, zmieścisz się :D" Edytowano Październik 15, 2021 przez _LM_ Cytuj Link do komentarza Share on other sites More sharing options...
farmaceuta Październik 15, 2021 Udostępnij Październik 15, 2021 1 minutę temu, _LM_ napisał: Zapytaj kolegi @farmaceuta ćwiczyliśmy jakiś czas temu różne warianty timerów, gdzieś są jego posty 😉 Łooo....to byla walka prawie na smierc i zycie...😅 niestety w tym temacie nic nie pomoge bo Input Capture nie byl przez nas testowany...a i wiedzy teoretyczniej tez nie ogarnalem w tym temacie...😕 1 Cytuj Link do komentarza Share on other sites More sharing options...
farmaceuta Październik 16, 2021 Udostępnij Październik 16, 2021 To idzie mniej wiecej tak... if (TCCR1B & (1 << ICES1)) Tutaj tylko sprawdzasz na jakie zbocze ustawiles pin, czyli na jakie zbocze ma zareagowac przerwanie...1 na narastajace, 0 na opadajace...i teraz tak, jesli miales stan nisKi i nagle wystapilo wykrycie zbocza narastajacego zostaje wywolane przerwanie, nastepuje sprawdzenie powyzszego if'a ktory jest prawdziwy i w tym momencie zaczynamy liczyc czas..(powiedzmy ze interesuje nas stan wysoki). Teraz zerujemy TCNT1 = 0; (bo to w nim w rzeczywistosci nastepuje liczenie) i odrazu ustawiamy bit tak zebysmy mogli wykryc zbocze opadajace TCCR1B &= ~(1 << ICES1); czyli moment w ktorym przechodzimy z high na low...(miedzy czasie nasz timer ciagle liczy i aktualizuje TCNT1). Nastepuje zmiana czyli wykrylismy nasz opadajace zbocze, i wywolanie przerwania...sprawdzamy warunek if, ale ten juz nie jest prawdziwy bo zmienilismy bit zbocza, wiec wykona sie else...i tak TCCR1B |= (1 << ICES1); znowu zmieniamy bit zeby wykryc zbocze narastajace...i pobieramy wynik bo nasz pomiar stanu wysokiego sie zakonczyl... wynik = ICR1; To co znajduje sie w rejestrze ICR1 jest przekopiowana wartoscia z TCNT1...dlatego zerowanie tego rejestru na poczatku stanu ktory mierzymy jest wazne (liczymy wtedy od zera)...z tego co jeszcze wyczytalem to nie zaleca sie korzystac z jakiegokolwiek trybu podczas korzystania z IC...uzywamy zwylkego trybu licznika..mozna jeszcze dodac jakas opcje zmniejszajaca szumy (zaklocenia)...wtedy wystapienie przerwania jest opoznione o 4 cykle zegara (zgodnie z ustawionym preskalerem)...nie wiem czy Ci to cokolwiek pomoglo, czy takiej odpowiedzi chciales, no ale napisalem...juz przepadlo😅 (jak cos to mnie prostowac..) Cytuj Link do komentarza Share on other sites More sharing options...
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
Krawi92 Październik 16, 2021 Udostępnij Październik 16, 2021 Przespałem się z tym wszystkim i zakumałem. Teraz piszę jakby troche uporządkowaną bibliotekę, może nie po swojemu, na wzór tego co tu było ale postaram się pare rzeczy dodać, postaram się uwzględnić też ilość przepełnień, gdybym chciał mierzyć większą odległość, choć nie wiem czy dla tego czujnika to ma sens. Jak skończe to wrzuce gotowe pliki, może się komuś przyda jako gotowiec pod HC-SR04 Cytuj Link do komentarza Share on other sites More sharing options...
_LM_ Październik 16, 2021 Udostępnij Październik 16, 2021 Jeśli będziesz pisał libsa to powinieneś uwzględnić taktowanie mikrokontrolera, bo nie wszyscy wiedzą że może być inne niż 16Mhz 😉 biblioteka powinna również uwzględnić możliwość zawieszenia się samego modułu - pisałem o tym wcześniej. Gdy ją zbudujesz i pokażesz, spróbuj napisać taką samą ale tak aby sterować tym modułem z jednego pinu a jest to możliwe. Dzięki @farmaceuta że opisałeś działanie moich wypocin 😉 Cytuj Link do komentarza Share on other sites More sharing options...
farmaceuta Październik 16, 2021 Udostępnij Październik 16, 2021 7 minut temu, Krawi92 napisał: postaram się uwzględnić też ilość przepełnień, gdybym chciał mierzyć większą odległość, choć nie wiem czy dla tego czujnika to ma sens. Dla tego czujnika pewnie przepelnie nigdy nie zostanie osiagniete, ale jak najbardziej mozna kombinowac...wtedy jest to uniwersalne dla roznych przypadkow np. guzikow gdzie juz mozna trzymac dlugo wcisniety...ale to akurat proste..dodac przerwanie od przepelnienia i dodawac max wartosc jaka miesci sie w rejestrze TCNT1 do wyniku... Cytuj Link do komentarza Share on other sites More sharing options...
Krawi92 Październik 16, 2021 Udostępnij Październik 16, 2021 Czy przepełnienie nastąpi to zależy od prescalera. Mnie przy większej odległości się przepełniał, sygnalizowała to dioda, dlatego żeby nie nastąpiło to zwiększyłem prescaler do np: 64. Ja akurat jade na oscylatorze 8mhz bo mam tylko 1 kwarc na chacie już zajęty 😄 Przy prescalerze 8 lekko migotał LCD, wiadomo, zmniejszyła sie niby precyzja, ale dla takiego czujnika to akurat mała różnica. Akurat wrzuciłem fajna możliwość zmiany portu i pinu w 1 miejscu dla pinow trig i echo. Postaram się jak najbardziej uniwersalnie to zrobić. Cytuj Link do komentarza Share on other sites More sharing options...
_LM_ Październik 16, 2021 Udostępnij Październik 16, 2021 (edytowany) 14 minut temu, farmaceuta napisał: Dla tego czujnika pewnie przepelnie nigdy nie zostanie osiagniete Będzie jeśli sygnał nie powróci lub częstotliwość timera będzie wysoka. Im większa częstotliwość pracy timera tym większa rozdzielczość pomiarowa* i np: zamiast na mieć na 1000mm 1000 zliczeń można ich mieć 10000 itd. *Rozdzielczość != dokładność Edytowano Październik 16, 2021 przez _LM_ Cytuj Link do komentarza Share on other sites More sharing options...
Krawi92 Październik 16, 2021 Udostępnij Październik 16, 2021 Ok, na razie wrzucę co mam, liczę na podpowiedzi co by tu ulepszyć. Jeszcze nie zabrałem się za obsługę przepełnień i muszę pomyśleć jak rozwiązać w jakiś uniwersalny sposób przeliczanie na cm. Jest to uzależnione od prescalera i taktowania. Tutaj na sztywno zrobiłem dla 8Mhz i prescalera 64. Użyłem timera programowego, żeby sobie HC tykał. Proszę wytknąć ew błędy. hcsr04.c #include <avr/io.h> #include <avr/interrupt.h> #include <util/delay.h> #include "hcsr04.h" volatile uint16_t result; // zmienna przechowywująca wynik volatile uint8_t start_meas; // zmienna pomocnicza volatile uint8_t timer; // timer programowy void hc_Init(void){ // Kierunki Pinów DDR(PORT_TRIG) |= (1 << TRIG); // Trig jako wyjście DDR(PORT_ECHO) &=~ (1 << ECHO); // Echo jako wejście PORT(PORT_TRIG) &=~ (1 << TRIG); // Stan niski na Trig PORT(PORT_ECHO) |= (1 << ECHO); // Podciągnięcie do VCC Echo // Konfiguracja przerwań TCCR1B |= (1 << CS11)|(1 << CS10); // prescaler 64.. 1 impuls 8uS TIMSK1 |= (1 << ICIE1); // przerwanie input capture // Konfiguracja timera dla timera programowego TCCR0A |= (1 << WGM01); // CTC Timer0 TCCR0B |= (1 << CS00)|(1 << CS02); // Prescaler 1024 OCR0A = (F_CPU/1024UL/31UL)-1; // Przerwanie co ok 30ms TIMSK0 |= (1 << OCIE0A); // zezwolenie na przerwanie od przepełnienia } void meas(void){ // Funkcja wywołująca pomiar // Rozpoczęcie pomiaru z użyciem timera programowego if (!timer){ // jesli timer jest 0 if(!start_meas){ // i jesli zmienna start_meas jest 0 PORT(PORT_TRIG) |= (1 << TRIG); // Stan wysoki na trig przez 10us _delay_us(15); PORT(PORT_TRIG) &=~ (1 << TRIG); TIFR1 &= ~(1 << ICF1); // kasowanie flagi przerwania na wypadek gdyby sie "uchowalo" TIMSK1 |= (1 << ICIE1); // zezwolenie na przerwanie od przechwytu TCNT1 = 0; // zerowanie licznika TCCR1B |= (1 << ICES1); // Przerwanie na zboczu narastającym start_meas = 1; // zakonczono wywolanie pomiary timer = 10; // czasookres pomiaru .. ok 300ms } } } uint16_t meas_result(){ return result/7; // rezultat funkcji w cm } ISR(TIMER1_CAPT_vect){ if (TCCR1B & (1 << ICES1)){ // jesli zbocze narastajace TCNT1 = 0; // zerujemy licznik TCCR1B &=~ (1 << ICES1); // czekamy na zbocze opadajace TIMSK1 |= (1 << TOIE1); // wlaczamy przerwanie od przepelnienia }else{ // jesli wystapilo zbocze opadajace TIMSK1 &=~ (1 << TOIE1); // wylaczamy przerwanie od przepelnienia TIMSK1 &=~ (1 << ICIE1); // wylaczamy przerwanie od przechwytu TCCR1B |= (1 << ICES1); // znow czekamy na zbocze narastajace result = ICR1; // zapisujemy wartosc ICR1 do zmiennej result start_meas = 2; // pomiar gotowy do odczytania } } ISR(TIMER0_COMPA_vect){ // Timer programowy if(timer)timer--; } hcsr04.h #ifndef HCSR04_H_ #define HCSR04_H_ //PORTy #define PORT(x) SPORT(x) #define SPORT(x) (PORT##x) //PINy #define PIN(x) SPIN(x) #define SPIN(x) (PIN##x) // Kierunek #define DDR(x) SDDR(x) #define SDDR(x) (DDR##x) #define PORT_TRIG D // PORT pinu trigger #define TRIG 5 // nr pinu #define PORT_ECHO B // PORT pinu ECHO (pin ICP) #define ECHO 5 // nr pinu void hc_Init(void); // Inicjalizacja modułu i przerwań void meas(void); // wywołanie pomiaru uint16_t meas_result(); // zwrot pomiaru extern volatile uint16_t result; // specyfikator extern by zmienne byly widoczne w innych plikach extern volatile uint8_t start_meas; #endif /* HCSR04_H_ */ przykładowe rozwiązanie w main.c #include <avr/io.h> #include <avr/interrupt.h> #include <util/delay.h> #include "hcsr04.h" #include "lcd.h" int main (void){ lcd_init(); // inicjalizacja lcd hc_Init(); // inicjalizacja HC SR04 lcd_locate (0,3); lcd_str("Odleglosc"); sei(); // zezwolenie na przerwania globalne while(1){ meas(); // wywolanie funkcji uruchamiajacej pomiar if(start_meas == 2){ // Jesli wykonano pomiar lcd_locate(1,5); lcd_int(meas_result()); // Wyswietl rezultat fukncji lcd_str("cm "); start_meas=0; // zacznij pomiar od nowa } } } Cytuj Link do komentarza Share on other sites More sharing options...
Krawi92 Październik 21, 2021 Udostępnij Październik 21, 2021 Wrzucam lekko poprawioną wersje. Niestety nie ogarnąłem na razie jak to zrobić uniwersalnie dla każdego taktowania. Gdyby ktoś chciał inne taktowanie niż 8Mhz to musi ustawić prescaler tak, żeby miał czas impulsu 1uS 😛 Jedynie co to porty Trig i Echo można w pliku nagłówkowym sobie zmienić. hcsr04.c #include <avr/io.h> #include <avr/interrupt.h> #include <util/delay.h> #include "hcsr04.h" volatile uint16_t result; // zmienna przechowywująca wynik volatile uint8_t start_meas=0; // zmienna pomocnicza volatile uint8_t timer; // timer programowy void hc_Init(void){ // Kierunki Pinów DDRB |= (1 << PB1); DDR(PORT_TRIG) |= (1 << TRIG); // Trig jako wyjście DDR(PORT_ECHO) &=~ (1 << ECHO); // Echo jako wejście PORT(PORT_TRIG) &=~ (1 << TRIG); // Stan niski na Trig PORT(PORT_ECHO) |= (1 << ECHO); // Podciągnięcie do VCC Echo // Konfiguracja przerwań TCCR1B |= (1 << CS11); // prescaler 8..Przy 8Mhz = 1 impuls 1uS // prescaler 8 przy 8Mhz = 1uS TIMSK1 |= (1 << ICIE1); // przerwanie input capture TCCR1B |= (1 << ICES1); // Przerwanie na zboczu narastającym // Konfiguracja timera dla timera programowego TCCR0A |= (1 << WGM01); // CTC Timer0 TCCR0B |= (1 << CS00)|(1 << CS02); // Prescaler 1024 OCR0A = (F_CPU/1024UL/31UL)-1; // Przerwanie co ok 30ms 8000000/1024/31-1 TIMSK0 |= (1 << OCIE0A); // zezwolenie na przerwanie od porównania } void meas(void){ // Funkcja wywołująca pomiar // Rozpoczęcie pomiaru z użyciem timera programowego if (!timer){ // jesli timer jest 0 if(!start_meas){ // i jesli zmienna start_meas jest 0 PORT(PORT_TRIG) |= (1 << TRIG); // Stan wysoki na trig przez 10us _delay_us(10); PORT(PORT_TRIG) &=~ (1 << TRIG); start_meas = 1; // zakonczono wywolanie pomiary timer = 10; // czasookres pomiaru .. ok 300ms } } } uint16_t meas_result(){ return (result+9)/56UL; // rezultat funkcji w cm(Operacja w nawiasie w celu dokladnej kalibracji) } ISR(TIMER1_CAPT_vect){ // procedura obslugi przerwania od przechwytu if(TCCR1B & (1 << ICES1)){ // Jesli zbocza narastające TCNT1=0; // zerujemy liczenik TCCR1B ^= (1 << ICES1); // zmieniamy bit ICES1 na przeciwny }else{ // jesli jednak zobacze opadające result = ICR1; // zapisujemy zawartosc ICR1 do zmiennej TCCR1B ^= (1 << ICES1); // zmieniamy bit ICES1 na przeciwny start_meas = 2; // flaga informuje ze pomiar gotowy do wyswietlenia } } ISR(TIMER0_COMPA_vect){ // Timer programowy if(timer)timer--; } main.c #include <avr/io.h> #include <avr/interrupt.h> #include <util/delay.h> #include "hcsr04.h" #include "lcd.h" int main (void){ lcd_init(); // inicjalizacja lcd hc_Init(); // inicjalizacja HC SR04 lcd_locate (0,4); lcd_str("Dalmierz"); sei(); // zezwolenie na przerwania globalne _delay_ms(20); // Opoznienie 20ms, brak opóźnienia powoduje czasem zawieszenie sie czujnika while(1){ meas(); // wywolanie funkcji uruchamiajacej pomiar if(start_meas == 2){ // Jesli wykonano pomiar lcd_locate(1,0); lcd_str(" "); lcd_locate(1,5); lcd_int(meas_result()); // Wyswietl rezultat funkcji lcd_str("cm "); if(meas_result() > 400){ // Jeśli pomiar przekroczy 400cm lcd_locate(1,0); lcd_str("Za daleko !!!!!!"); } if(meas_result() < 3){ // Jesli pomiar poniżej 3 cm lcd_locate(1,0); lcd_str("Za blisko !!!!!!"); } start_meas=0; // zacznij pomiar od nowa } } } Może komuś się kiedyś przyda, jak będzie chciał odpalić sobie czujniczek 😛 Cytuj Link do komentarza Share on other sites More sharing options...
_LM_ Październik 22, 2021 Udostępnij Październik 22, 2021 11 godzin temu, Krawi92 napisał: Gdyby ktoś chciał inne taktowanie niż 8Mhz to musi ustawić prescaler tak, żeby miał czas impulsu 1uS 😛 chyba 10µS chodzi Ci o ten kawałek kodu? if (!timer){ // jesli timer jest 0 if(!start_meas){ // i jesli zmienna start_meas jest 0 PORT(PORT_TRIG) |= (1 << TRIG); // Stan wysoki na trig przez 10us _delay_us(10); PORT(PORT_TRIG) &=~ (1 << TRIG); start_meas = 1; // zakonczono wywolanie pomiary timer = 10; // czasookres pomiaru .. ok 300ms } Cytuj Link do komentarza Share on other sites More sharing options...
Krawi92 Październik 22, 2021 Udostępnij Październik 22, 2021 Nie, o inicjalizacje prescalera dla timera tj tccr1b |= (1 << cs11) prescaler 8.. 8000000/8=1000000 1/1000000 =1 us Cytuj Link do komentarza Share on other sites More sharing options...
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!