Frackowiak Napisano Sierpień 31, 2010 Udostępnij Napisano Sierpień 31, 2010 Zaczynam zabawę w programowanie uC pod C. Swą przygodę zacząłem od tego kursu. Jako, ze C znam w miarę dobrze to nie miałem problemów ze zrozumieniem struktury aplikacji, i w miarę rozumiałem zadania. Teraz postanowiłem zrealizować swój pomysł na wykorzystanie uC, ale do tego potrzebuje wiedzy na temat licznika i timer. Wiele naczytałem się na elektrodzie i tutaj też, ale wielu rzeczy nie rozumiem. Nie wiem o co chodzi z preskalerem, nie rozumiem kiedy timer startuje i gdzie są przechowywane info na temat tego ile czasu zliczył (generalnie jestem zagubiony w temacie bardziej niż jak zacząłem szukać). Ja chciałbym użyć timera do zliczania czasu trwania sygnału wysokiego/niskiego na wejściu uC (będą to raczej krótkie czasy rzędu ms) oraz licznika do zliczania ile razy na wejściu uC pojawił się stan wysoki/niski. Generalnie wydaje mi się, ze na początek wystarczyłby mi jakiś przykład z dobrymi komentarzami żeby temat rozjaśnić, a w miarę potrzeb w przypadku braku zrozumienia jakiś kwestii dopytywałbym się szanownych kolegów o szczegóły. Z góry dzięki za pomoc! Pozdrawiam!
Frackowiak Wrzesień 2, 2010 Autor tematu Udostępnij Wrzesień 2, 2010 W zasadzie wielu rzeczy dowiedziałem z tego Tutoriala na temat timerów. Teraz Chciałem się dowiedzieć jak by ta wiedzę dostosować do moich potrzeb. Chodzi o to by rozpocząć zliczanie timera w momencie pojawienia się sygnału na jakimś wejściu i wyłączeniu timera i przepisanie jego wart. do jakiejś zmiennej gdy sygnał na wejściu zniknie. Myślałem o przerwaniu zewnętrznym na wejście INT0 i gdy ono wystąpi uruchomienie timera, ale nie do końca wiem czy dobrze kombinuje. Proszę o pomoc jeśli można!
Chechli Wrzesień 2, 2010 Udostępnij Wrzesień 2, 2010 No to zacznij pisać, i wtedy pytaj, co nie działa, a nie boisz się, że nie zadziała, zanim napisałeś Weź może właśnie przerwanie zewnętrzne, reakcję na odpowiednie zbocze sygnału powodującą przerwanie, albo reakcja na jakiekolwiek zbocze, albo zmiana zbocza, na które reaguje po każdym przerwaniu, zależnie od potrzeb, w obsłudze przerwania odczytujesz wartość timera, zapisujesz, zerujesz i liczysz ponownie. I dajesz największy preskaler z takich, które udają satysfakcjonującą Cię dokładność, żeby nie było problemów, że nie nadążasz z odczytem timera.
Frackowiak Wrzesień 3, 2010 Autor tematu Udostępnij Wrzesień 3, 2010 No więc idąc za radą Chechli zacząłem pisać (dużo się nie napisałe ) i powstało coś takiego: volatile int licznik = 0; void main() { DDRB |= _BV(0); // wyjście DDRB |= _BV(1); // wyjście PORTB &= ~_BV(0); PORTB &= ~_BV(1); DDRD &= ~_BV(PD2); // wejście przerwania INT0 PORTD |= _BV(PD2); // podciągnięcie do jedynki GICR |= _BV(INT0); // włączenie przerwania INT0 MCUCR |= _BV(ISC00); // ustawienie wyzwolenia przerwania na zbocze opadające sei(); // zezwolenie na obsługę przerwań while(1) { for ( int i = 0 ; i < licznik ; i++ ) { PORTB |= _BV(0); _delay_ms(100); PORTB &= ~_BV(0); licznik--; } } } ISR(INT0_vect) { TCCR1B |= _BV(CS10) | _BV(CS11); // preskaler 64 if ( TCNT1 >= 15625 ) { licznik++; } PORTB |= _BV(1); } W zamyśle program miał po naciśnięciu guzika zacząć zliczać czas z dokładnością do sekundy i co sekundę zwiększać licznik, by po skończeniu obsługi przerwania w pętli for mrugnąć diodą tyle razy ile sekund trzymany był guzik. Niestety nie do końca tak się dzieje. Po wciśnięciu guzika na około 2-3 sek dioda mająca mrugać zapala się i gaśnie tylko raz. Będę wdzięczny za wytknięcie mi błędów w rozumowaniu. Pozdrawiam! [ Dodano: 03 Wrz 10 03:49 ] OK Panowie i Panie ten problem został rozwiązany Pozdrawiam!!!
Chechli Wrzesień 4, 2010 Udostępnij Wrzesień 4, 2010 Zwykle program ne działa od razu, jakiś drobny błąd logiczny się zrobi albo jakiś znak zmieni, trzeba poszukać i dopiero potem na forum z tym
Karol R Wrzesień 6, 2010 Udostępnij Wrzesień 6, 2010 Cześć, w jaki sposób zapisać przerwanie które z założenia miałoby uruchomić się tylko raz, po czym zatrzymać timer i nie uruchamiać się ponownie ? Mój kod wygląda następująco, ale przerwanie wykonuje się cyklicznie, mimo "cli()" zamieszczonego w jego treści. int main (void) { TCCR1B |= (1 << WGM12); TIMSK |= (1 << OCIE1A); sei(); OCR1A = 11718; } ISR(TIMER1_COMPA_vect) { PORTD ^= (1<<PD0) KRYTERIUM_CZAS = 1; cli(); }
Kuraś Wrzesień 6, 2010 Udostępnij Wrzesień 6, 2010 mogę się mylić, ale nie masz w funkcji main pętli głównej, na której mógłby "zawiesić się" program prawdopodobnie efekt cyklicznego załączania był taki, że po dojściu do końca funkcji main przez pewien czas szukał w pamięci programu kolejnych instrukcji (a napotykał tylko puste wiersze), po czym po dojściu do końca pamięci wracał na początek i wykonywał na nowo funkcję main. int main (void) { TCCR1B |= (1 << WGM12); TIMSK |= (1 << OCIE1A); sei(); OCR1A = 11718; while(1); //teraz tutaj nastąpi zawieszenie w wykonywaniu - program na mikrokontrolerze nie powinien występować bez pętli głównej } ISR(TIMER1_COMPA_vect) { PORTD ^= (1<<PD0) KRYTERIUM_CZAS = 1; cli(); }
Karol R Wrzesień 6, 2010 Udostępnij Wrzesień 6, 2010 niechcący wprowadziłem Cię w błąd to tylko fragment programu odpowiedzialny za działanie timera, dalej znajduję się nieskończona pętla która realizuje odczyt z przetwornika A/C. Nie zamieszczałem całości z uwagi na przejrzystość. Oto pozostała część programu w funkcji main: while(1) { if(PIND & (1<<PD4)) { TCCR1B |= ((1 << CS10) | (1 << CS12)); while (1) { for (i=0;i<16;i++) { ADCSRA |= (1<<ADSC); while (ADCSRA & (1<<ADSC)); wartosc2 += ADCW; } wartosc2 >>= 4; if (wartosc2 > wartosc1) { MAX_AMPL = wartosc2; } if (MAX_AMPL >= 600 && KRYTERIUM_CZAS && wartosc2 <= 512) { PORTB |= ((1<<PB0) | (1<<PB1)); } wartosc1 = wartosc2; wartosc2 = 0; } } } }
Kuraś Wrzesień 6, 2010 Udostępnij Wrzesień 6, 2010 Więc problem tkwi w samym przerwaniu. Według pierwszej lepszej instrukcji od Atmegi88 na stronach dotyczących obsługi przerwań można wyczytać: When an interrupt occurs, the Global Interrupt Enable I-bit is cleared and all interrupts are dis-abled. The user software can write logic one to the I-bit to enable nested interrupts. All enabled interrupts can then interrupt the current interrupt routine. The I-bit is automatically set when a Return from Interrupt instruction – RETI – is executed. Co oznacza, że flaga zezwolenia globalnego na przerwanie zostanie ustawiona automatycznie po wyjściu z jego obsługi. Bez względu co byśmy z nią robili (w momencie włączenia przerwania flaga I jest zerowana, ręczne ustawienie pozwala podobno na zagnieżdżone przerwania.) Ja na Twoim miejscu wyczyściłbym po prostu w ten sposób, powinno pomóc: int main (void) { TCCR1B |= (1 << WGM12); TIMSK |= (1 << OCIE1A); sei(); OCR1A = 11718; [...] } ISR(TIMER1_COMPA_vect) { PORTD ^= (1<<PD0) KRYTERIUM_CZAS = 1; TIMSK &= ~(1 << OCIE1A); //wyłączenie obsługi przerwania od trybu porównywania timera } 1
Pomocna odpowiedź
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ę »