- /********************************************************************
- * 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 <avr/interrupt.h> // funkcje sei(), cli()
- #include <util/delay.h>
- #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;
- }