/******************************************************************** * Autor: Artur Cichowski * * Program demonstujący wykorzystanie przerwania od Timera, w którym * * obslugiwane są cztery przyciski. Program realizuje także obsługę * * w sposób cykliczny czterech wyświetlaczy siedmisegmentowych. * ********************************************************************/ #include // funkcje sei(), cli() #include #include "main.h" #define HAPSIM 0 volatile unsigned char kl_ENTER = 0; //przycisk ENTER (KEY0) volatile unsigned char kl_UP = 0; //przycisk UP (KEY1) volatile unsigned char kl_DOWN = 0; //przycisk DOWN (KEY2) volatile unsigned char kl_CANCEL = 0; //przycisk CANCELv(KEY3) volatile signed char cyfry[4]; //wartości tablicy modyfikowane są przyciskami signed char cyfry_kopia[4]; char dzielnik_f; char miganie; char menu=0x00; //deklaracje funkcji void init_TIMER0 (void); void init_pins (void); char BCD_to_7_seg(char cyfra); void display_7seg(void); int main(void); // Timer 1 void init_TIMER1 (void){ #if HAPSIM TCCR1B = _BV(CS10)|_BV(WGM13)|_BV(WGM12); #else TCCR1B = _BV(CS12)|_BV(WGM13)|_BV(WGM12); #endif ICR1=62499; TCNT1=0x0000; TIMSK |= _BV(TICIE1); }; //Timer0 jest zainicjalizowany w celu generowania przerwań od jego przepełnienia. void init_TIMER0 (void) { #if HAPSIM TCCR0 = _BV(CS00); //fclk/1, #else TCCR0 = _BV(CS02)|_BV(CS01)|_BV(CS00); //fclk/1024, #endif TCNT0 = 0x00; //wartość zliczona przez licznik TIMSK = _BV(TOIE0); //selektywne zezwolenie na przerwania od przepełnienia licznika0 TOIE0=1, przepełnienie co 256*64us=16,38ms, dla HAPSIM co 0,128ms }; union { //do obsługi przycisków -> w przerwaniu ISR struct { unsigned char ENTER:1; //LSB unsigned char UP:1; unsigned char DOWN:1; unsigned char CANCEL:1; unsigned char ENTER_PREV:1; unsigned char UP_PREV:1; unsigned char DOWN_PREV:1; unsigned char CANCEL_PREV:1; //MSB } flags; char byte; } key; union { //do obsługi przycisków -> w przerwaniu ISR struct { unsigned char ENTER:1; //LSB unsigned char UP:1; unsigned char DOWN:1; unsigned char CANCEL:1; unsigned char ENTER_PREV:1; unsigned char UP_PREV:1; unsigned char DOWN_PREV:1; unsigned char CANCEL_PREV:1; unsigned char ENTER_PREV1:1; unsigned char UP_PREV1:1; unsigned char DOWN_PREV1:1; unsigned char CANCEL_PREV1:1; unsigned char ENTER_PREV2:1; unsigned char UP_PREV2:1; unsigned char DOWN_PREV2:1; unsigned char CANCEL_PREV2:1; //MSB } flags; int word; } falling_slope; ISR (TIMER0_OVF_vect) { //przerwanie wywoływane co ok. 16,4 ms sei(); key.byte=(key.byte<<4);// przesuwając w lewą stronę bity z dołu uzupełniane są zerami //ustawienie jedynek na pozycjach od 0 do 3 w przypadku odczytania zer z odpowiednich wejść KEYx key.byte|=((bit_is_clear(PINKEY,KEY0))|(bit_is_clear(PINKEY,KEY1) << 1)|(bit_is_clear(PINKEY,KEY2) << 2)|(bit_is_clear(PINKEY,KEY3) << 3)); falling_slope.word=(falling_slope.word<<4); if(key.flags.ENTER){ //czy wciśnięty jest przycisk ENTER? if(!key.flags.ENTER_PREV) falling_slope.flags.ENTER=1; //Czy wykryto zbocze opadające if(falling_slope.flags.ENTER_PREV2) kl_ENTER = 1; //Czy od chwili wykrycia zbocza opadającego upłynęły 3 przerwania z wciśniętym przyciskiem } else{ falling_slope.word&=0xEEEE; //wyzerowanie flag dla przycisku ENTER potwierdzających wykrycie zbocza opadającego }; if(key.flags.UP){ //czy wciśnięty jest przycisk UP? if(!key.flags.UP_PREV) falling_slope.flags.UP=1; //Czy wykryto zbocze opadające if(falling_slope.flags.UP_PREV2) kl_UP = 1; //Czy od chwili wykrycia zbocza opadającego upłynęły 3 przerwania z wciśniętym przyciskiem } else{ falling_slope.word&=0xDDDD; //wyzerowanie flag dla przycisku UP potwierdzających wykrycie zbocza opadającego }; if(key.flags.DOWN){ //czy wciśnięty jest przycisk DOWN? if(!key.flags.DOWN_PREV) falling_slope.flags.DOWN=1; //Czy wykryto zbocze opadające if(falling_slope.flags.DOWN_PREV2) kl_DOWN = 1; //Czy od chwili wykrycia zbocza opadającego upłynęły 3 przerwania z wciśniętym przyciskiem } else{ falling_slope.word&=0xBBBB; //wyzerowanie flag dla przycisku DOWN potwierdzających wykrycie zbocza opadającego }; if(key.flags.CANCEL){ //czy wciśnięty jest przycisk CANCEL? if(!key.flags.CANCEL_PREV) falling_slope.flags.CANCEL=1; //Czy wykryto zbocze opadające if(falling_slope.flags.CANCEL_PREV2) kl_CANCEL = 1; //Czy od chwili wykrycia zbocza opadającego upłynęły 3 przerwania z wciśniętym przyciskiem } else{ falling_slope.word&=0x7777; //wyzerowanie flag dla przycisku CANCEL potwierdzających wykrycie zbocza opadającego }; dzielnik_f++; if(dzielnik_f==15){ //częstotliwość migania modyfikowanej cyfry //16e6/(1024*256*(2*XXXX)) ok. 2Hz dzielnik_f=0; miganie=!miganie;}; }; ISR(TIMER1_CAPT_vect) { cyfry[3]--; if (cyfry[3]<0) { cyfry[3]=9; cyfry[2]--; if(cyfry[2]<0) { cyfry[2]=5; cyfry[1]--; if(cyfry[1]<0) { cyfry[1]=9; cyfry[0]--; if(cyfry[0]<0) { cyfry[0]=5; } }; }; }; }; void init_pins (void) { /*ustawienie odpowiednich pinów mikrokontrolera jako wyjść dla portu, do którego podłączono diody LED*/ DIRLED |= (_BV(LED0)|_BV(LED1)|_BV(LED2)|_BV(LED3)); /*ustawienie odpowiednich pinów mikrokontrolera jako wejść dla portu, do którego podłączono przyciski KEY*/ DIRKEY &= ~(_BV(KEY0)|_BV(KEY1)|_BV(KEY2)|_BV(KEY3)); /*ustawienie odpowiednich pinów mikrokontrolera jako wejść dla portu, do którego podłączono przełączniki SW*/ DIRSWITCH &= ~(_BV(SW0)|_BV(SW1)|_BV(SW2)|_BV(SW3)); /*ustawienie wyjść dla portu, do którego podłączono katody wyświetlacza*/ DIRHEX = 0xFF; /*ustawienie odpowiednich pinów mikrokontrolera jako wyjść dla portu, do którego podłączono anody wyświetlacza*/ DIRHEXA |= (_BV(HEXA0)|_BV(HEXA1)|_BV(HEXA2)|_BV(HEXA3)); /*ustawienie pinu PB0 (dot. BUZ) w stamn wysoki - aktywowany stanem niskim */ PORTBUZ |= (_BV(BUZ)); }; //funkcja transkodera kodu BCD na kod wyswietlacza siedmiosegmentowego char BCD_to_7_seg(char cyfra){ char katody = 0xFF; //domyślnie wszystkie segmenty wyłączone switch(cyfra){ case 0 : katody=0xC0; //0b11000000 break; case 1 : katody=0xF9; break; case 2 : katody=0xA4; break; case 3 : katody=0xB0; break; case 4 : katody=0x99; break; case 5 : katody=0x92; break; case 6 : katody=0x82; break; case 7 : katody=0xF8; break; case 8 : katody=0x80; break; case 9 : katody=0x90; break; }; return katody; }; //funkcja obsługi wyswietlacza siedmiosegmentowego //funkcja uaktywnia cyklicznie poszczególne wyświetlacze void display_7seg(void) { static char select = 1; //zmienna o zakresie od 1 do 4 PORTHEXA |= (_BV(HEXA0)|_BV(HEXA1)|_BV(HEXA2)|_BV(HEXA3)); //wyłączenie wszystkich wyświetlaczy select++; //wskazanie na kolejną cyfrę if(select>4) select=1; //cykliczne aktywowanie wyświetlaczy 7-seg switch(select) { case 1 :PORTHEX = BCD_to_7_seg(cyfry[0]); //wizualizacja cyfry[0] PORTHEXA &= ~_BV(HEXA0); //aktywacja 1 wyświetlacza break; case 2 :PORTHEX = BCD_to_7_seg(cyfry[1]); //wizualizacja cyfry[1] PORTHEXA &= ~_BV(HEXA1); //aktywacja 2 wyświetlacza break; case 3 :PORTHEX = BCD_to_7_seg(cyfry[2]); //wizualizacja cyfry[2] PORTHEXA &= ~_BV(HEXA2); //aktywacja 3 wyświetlacza break; case 4 :PORTHEX = BCD_to_7_seg(cyfry[3]); //wizualizacja cyfry[3] PORTHEXA &= ~_BV(HEXA3); //aktywacja 4 wyświetlacza break; }; }; void display_7seg_kopia(void) { static char select = 1; //zmienna o zakresie od 1 do 4 PORTHEXA |= (_BV(HEXA0)|_BV(HEXA1)|_BV(HEXA2)|_BV(HEXA3)); //wyłączenie wszystkich wyświetlaczy select++; //wskazanie na kolejną cyfrę if(select>4) select=1; //cykliczne aktywowanie wyświetlaczy 7-seg switch(select) { case 1 :PORTHEX = BCD_to_7_seg(cyfry_kopia[0]); //wizualizacja cyfry[0] if((miganie) || (menu!=0x10)) PORTHEXA &= ~_BV(HEXA0); //aktywacja 1 wyświetlacza break; case 2 :PORTHEX = BCD_to_7_seg(cyfry_kopia[1]); //wizualizacja cyfry[1] if((miganie) || (menu!=0x20)) PORTHEXA &= ~_BV(HEXA1); //aktywacja 2 wyświetlacza break; case 3 :PORTHEX = BCD_to_7_seg(cyfry_kopia[2]); //wizualizacja cyfry[2] if((miganie) || (menu!=0x30)) PORTHEXA &= ~_BV(HEXA2); //aktywacja 3 wyświetlacza break; case 4 :PORTHEX = BCD_to_7_seg(cyfry_kopia[3]); //wizualizacja cyfry[3] if((miganie) || (menu!=0x40)) PORTHEXA &= ~_BV(HEXA3); //aktywacja 4 wyświetlacza break; }; }; void display_7seg_kopia1(void) { PORTHEXA |= (_BV(HEXA0)|_BV(HEXA1)|_BV(HEXA2)|_BV(HEXA3)); //wyłączenie wszystkich wyświetlaczy // pętla while(1){ PORTBUZ &= ~(_BV(BUZ)); PORTHEXA &= ~(_BV(HEXA0)|_BV(HEXA1)|_BV(HEXA2)|_BV(HEXA3)); //włączenie?? }; }; int main(void) { key.byte=0xFF; //inicjalizacja flag stanami nieaktywnymi falling_slope.word=0x0000; //inicjalizacja flag stanami nieaktywnymi PORTHEX = 0xFF; //wyłączenie wszystkich segmentów PORTHEXA |= (_BV(HEXA0)|_BV(HEXA1)|_BV(HEXA2)|_BV(HEXA3)); //wyłączenie wszystkich wyświetlaczy init_pins(); //inicjalizacja kierunkowości wyprowadzeń init_TIMER0(); //inicjalizacja Timera0 init_TIMER1(); sei(); //globalne zezwolenie na przerwania while(1) //nieskończona pętla { //modyfikacje poszczególnych cyfr pod wpływem wciśnięcia danego przycisku switch(menu){ case 0x00 : if(kl_ENTER == 1){ cyfry_kopia[0]=cyfry[0]; cyfry_kopia[1]=cyfry[1]; cyfry_kopia[2]=cyfry[2]; cyfry_kopia[3]=cyfry[3]; menu=0x10; kl_ENTER=0; }; break; case 0x10 : if(kl_ENTER == 1){ menu=0x20; kl_ENTER=0; }; if(kl_UP == 1){ cyfry_kopia[0]++; if (cyfry_kopia[0] > 5) cyfry_kopia[0] = 0; kl_UP = 0; }; if(kl_DOWN == 1){ cyfry_kopia[0]--; if (cyfry_kopia[0] < 0) cyfry_kopia[0] = 5; kl_DOWN = 0; }; if(kl_CANCEL == 1){ menu=0x00; kl_CANCEL = 0; }; break; case 0x20 : if(kl_ENTER == 1){ menu=0x30; kl_ENTER=0; }; if(kl_UP == 1){ cyfry_kopia[1]++; if (cyfry_kopia[1] > 9) cyfry_kopia[1] = 0; kl_UP = 0; }; if(kl_DOWN == 1){ cyfry_kopia[1]--; if (cyfry_kopia[1] < 0) cyfry_kopia[1] = 9; kl_DOWN = 0; }; if(kl_CANCEL == 1){ menu=0x00; kl_CANCEL = 0; }; break; case 0x30 : if(kl_ENTER == 1){ menu=0x40; kl_ENTER=0; }; if(kl_UP == 1){ cyfry_kopia[2]++; if (cyfry_kopia[2] > 5) cyfry_kopia[2] = 0; kl_UP = 0; }; if(kl_DOWN == 1){ cyfry_kopia[2]--; if (cyfry_kopia[2] < 0) cyfry_kopia[2] = 5; kl_DOWN = 0; }; if(kl_CANCEL == 1){ menu=0x00; kl_CANCEL = 0; }; break; case 0x40 : if(kl_ENTER == 1){ cyfry[0]=cyfry_kopia[0]; cyfry[1]=cyfry_kopia[1]; cyfry[2]=cyfry_kopia[2]; cyfry[3]=cyfry_kopia[3]; menu=0x00; kl_ENTER=0; }; if(kl_UP == 1){ cyfry_kopia[3]++; if (cyfry_kopia[3] > 9) cyfry_kopia[3] = 0; kl_UP = 0; }; if(kl_DOWN == 1){ cyfry_kopia[3]--; if (cyfry_kopia[3] < 0) cyfry_kopia[3] = 9; kl_DOWN = 0; }; if(kl_CANCEL == 1){ menu=0x00; kl_CANCEL = 0; }; break; }; if(menu==0) display_7seg(); //wizualizacja cyfr else display_7seg_kopia(); //wizualizacja cyfr if (cyfry[0]==0 && cyfry[1]==0 && cyfry[2]==0 && cyfry[3]==0) display_7seg_kopia1(); //brzęczenie i miganie }; return 0; }