morthell Napisano Wrzesień 8, 2013 Udostępnij Napisano Wrzesień 8, 2013 Witam. Niedawno zaopatrzyłem się w mikrokontroler atmega8, postanowiłem więc trochę się pobawić w rożne projekty. Próbuje zbudować program który jest podobny do systemu automatycznego oświetlenia w domu na czujkach PIR. Otóż, chcę aby przyciski wirtualizowały czujkę w taki sposób że naciśnięcie przyciska jest równo znaczne z wykryciem ruchu przez czujkę. Chcę aby program zapalał diodę led po przyciśnięciu przycisku na 10s. Jeśli jeszcze raz nacisnę przycisk odliczanie 10s powinno się resetować a dioda wciąż palić. Jednak jeśli jednak 10s minie to dioda ma zgasnąć. Zbudowałem program na timerze, jednak nie działa on tak jak powinien: 1. Dioda gaśnie po określonym czasie, lecz po kolejnym takim samym czasie znów się zapala; 2. Puszczenie przycisku powoduje że dioda pozostaje na stanie w jakim była przez wyłączeniem jej tj. jeśli się paliła to dalej się pali, jeśli zgasła to jest zgaszona. I tu jest moje pytanie, gdzie jest błąd w moim myśleniu i co powinienem zmienić by program zaczął działać zgodnie z założeniami? #include <avr/io.h> #include <avr/interrupt.h> #define F_CPU 12000000UL #define LED1 PB2 #define LED2 PB3 #define LED3 PB4 //definicja początkowej wartości timera #define timer_start 0 //zmienna pomocnicza-licznik używana w przerwaniu volatile uint8_t cnt=0; int main(void) { int licznik; //########### I/O ########### //port D jako wejscie DDRD &= ~(1<<PD2); DDRD &= ~(1<<PD3); DDRD &= ~(1<<PD4); DDRB |= (1<<LED1) | (1<<LED2) | (1<<LED3); //Ustawienie pinów sterujących diodami PORTD = 0xFF; //########################## //######## konfiguracja timera ############## TIMSK |= (1<<TOIE0); //Przerwanie overflow (przepełnienie timera) TCCR0 |= (1<<CS02) | (1<<CS00); // źródłem CLK, preskaler 1024 TCNT0 = timer_start;// //Początkowa wartość licznika //########################################### sei();//Globalne uruchomienie przerwań while(1);//główna pętla programu } //############ Procedura obsługi przerwania od przepełnienia timera ############ ISR(TIMER0_OVF_vect) { TCNT0 = timer_start; //Początkowa wartość licznika cnt++; //zwiększa zmienną licznik if(cnt >=100) { if (!(PIND & (1<<PIND3))) { PORTB ^=(1<<LED1); } else { PORTB &=~ (1<<PB2); cnt=0; } //PORTB ^=(1<<LED3); //PORTB ^=(1<<LED2); } } Docelowo w programie chcę aby działały 3 diody stąd też tyle wejść i wyjść zdefiniowanych. Pozdrawiam. Link do komentarza Share on other sites More sharing options...
MirekCz Wrzesień 8, 2013 Udostępnij Wrzesień 8, 2013 Masz źle skonstruowany warunek - najpierw sprawdzasz, czy cnt>=100 - więc automatycznie przyciśnięcie klawisza gdy cnt<100 nic nie daje. Co więcej cnt po dojściu do 100 rośnie dalej do 255, a następnie przepełnia się zmienna i liczysz od 0. Przerwanie powinno wyglądać tak (nie wiem tylko kiedy klawisz masz wciśnięty i kiedy led się pali, bo nie ma schematu, ale opis jest w programie) TCNT0 = timer_start; //Początkowa wartość licznika if ((PIND & (1<<PIND3))) {//klawisz naciśnięty cnt=0; PORTB ^=(1<<LED1); //wlaczyliśmy LED1 } else {//klawisz nie jest naciśnięty if (cnt<100) cnt++; else PORTB &=~ (1<<LED1); //wyłącz LED1 } Jak widać zmienną cnt kasujemy tylko gdy jest wciśnięty przycisk, natomiast dodajemy do niej coś tylko jak przycisk nie jest wciśnięty - wtedy następuje faktyczne naliczanie czasu. Rozwinąć to na wiele ledów możesz najłatwiej poprzez zrobienie tablicy zmiennej cnt i LED (o ile są na tym samym porcie) i zrobić pętle for wywołującą w przerwaniu ten kod if/else dla każdej komórki w tablicy - nie będziesz musiał kopiować całego kodu. Link do komentarza Share on other sites More sharing options...
Sabre Wrzesień 9, 2013 Udostępnij Wrzesień 9, 2013 _pytanie Link do komentarza Share on other sites More sharing options...
Pomocna odpowiedź