logo elektroda
logo elektroda
X
logo elektroda
REKLAMA
REKLAMA
Adblock/uBlockOrigin/AdGuard mogą powodować znikanie niektórych postów z powodu nowej reguły.

[ATMEGA8][C] problem z wyświetlaczem LED

DawidDabrowski 17 Maj 2010 12:53 1350 3
REKLAMA
  • #1 8085714
    DawidDabrowski
    Poziom 2  
    Witam.

    Bawię się uC Atmega8 oraz czterocyfrowym wyświetlaczem LED ze wspólną anodą, cyfry siedmiosegmentowe + kropka, 12 wyprowadzeń.

    Napisałem prosty program na multipleksację wyświetlacza:

    
    #define F_CPU 8000000L
    
    #include <avr/io.h>
    #include <util/delay.h>
    #include <avr/interrupt.h>
    
    int i,j;
    
    int size[]={6,2,5,5,4,5,6,3,7,6};
    
    volatile int nr;
    
    int t[][8]=
    {
    	{0,1,2,4,5,6},
    	{2,6},
    	{4,1,3,6,0},
    	{4,6,3,2,1},
    	{5,3,6,2},
    	{4,3,1,5,2},
    	{5,4,3,2,0,1},
    	{4,6,2},
    	{0,1,2,3,4,5,6},
    	{4,5,3,6,2,1},
    };
    
    void show_digit(int d,int dt) {
    	PORTB=(1<<8)-1;
    	for(j=0; j<size[d]; ++j) PORTB^=_BV(t[d][j]);
    	if(dt) PORTB^=_BV(7);
    }
    
    // PORTD - nr wyswietlacza
    // PORTB - segmenty
    
    int dig[4]={5,0,9,2};
    int dot[4]={0,0,1,0};
    
    int main(void) {
    	DDRD=(1<<8)-1;
    	//PORTD=(1<<8)-1;
    	DDRB=(1<<8)-1;
    	PORTB|=(1<<8)-1;
    	TCCR1B|=(1<<WGM12)|(1<<CS10);
    	OCR1A=40000;
    	TIMSK|=(1<<OCIE1A);
    	sei();
    	while(1) {
    	}
    }
    
    ISR(TIMER1_COMPA_vect) {
    	nr=(nr+1)%4;
    	PORTD=(1<<nr);
    	show_digit(dig[nr],dot[nr]);
    }
    


    Wyświetla on "29.05". Działa dobrze.

    Jednak jeśli chcę dodać w pętli while coś z użyciem funkcji _delay_ms(), to się kopie. Domyślam się, że przerwanie się za bardzo wtrąca do _delay_ms() i wydłuża czas oczekiwania.

    Jak temu zaradzić? Chciałbym zrobić zegarek, tak więc czas tu gra kluczową rolę :)

    Proszę o pomoc,
    Dawid.
  • REKLAMA
  • #2 8085729
    tadzik85
    Poziom 38  
    delay nie powinno mieć takiego wpływu. zamiast modulo w przerwani zrób anda z 0x03; wykonuje się szybciej.
  • REKLAMA
  • #3 8086635
    DawidDabrowski
    Poziom 2  
    W tej chwili mój program wygląda tak:

    
    #define F_CPU 8000000L
    
    #include <avr/io.h>
    #include <util/delay.h>
    #include <avr/interrupt.h>
    
    int i,j;
    
    int size[]={6,2,5,5,4,5,6,3,7,6};
    
    volatile int nr;
    
    int t[][8]=
    {
    	{0,1,2,4,5,6},
    	{2,6},
    	{4,1,3,6,0},
    	{4,6,3,2,1},
    	{5,3,6,2},
    	{4,3,1,5,2},
    	{5,4,3,2,0,1},
    	{4,6,2},
    	{0,1,2,3,4,5,6},
    	{4,5,3,6,2,1},
    };
    
    void show_digit(int d,int dt) {
    	PORTB=(1<<8)-1;
    	for(j=0; j<size[d]; ++j) PORTB^=_BV(t[d][j]);
    	if(dt) PORTB^=_BV(7);
    }
    
    // PORTD - nr wyswietlacza
    // PORTB - segmenty
    
    int dig[4]={5,0,9,2};
    int dot[4]={0,0,1,0};
    
    int main(void) {
    	DDRD=(1<<8)-1;
    	//PORTD=(1<<8)-1;
    	DDRB=(1<<8)-1;
    	PORTB|=(1<<8)-1;
    	TCCR1B|=(1<<WGM12)|(1<<CS10);
    	OCR1A=40000;
    	TIMSK|=(1<<OCIE1A);
    	sei();
    	while(1) {
    		dig[0]=5; dig[1]=0; dig[2]=9; dig[3]=2;
    		_delay_ms(5000);
    		dig[0]=0; dig[1]=1; dig[2]=6; dig[3]=1;
    		_delay_ms(5000);
    	}
    }
    
    ISR(TIMER1_COMPA_vect) {
    	nr=(nr+1)%4;
    	PORTD=(1<<nr);
    	show_digit(dig[nr],dot[nr]);
    }
    


    Od poprzedniego różni się jedynie zawartością pętli while(1). Ten program ma za zadanie co pewien czas (5s) zmieniać zawartość wyświetlacza. Działa on następująco: na początku wyświetla się pierwsza zawartość "29.05", po 5s zmienia się na "16.10", a następnie staje... zamiast zmieniać się po 5s z powrotem na "29.05". Co może być powodem?...

    P.S. dzięki za fajną sztuczkę z & bitowym :) pozwala modulować przez 2^k - fajne :)
  • #4 8087173
    OlekM
    Poziom 17  
    Co do możliwej przyczyny problemu, to:

    
    volatile int dig[4]={5,0,9,2};
    volatile int dot[4]={0,0,1,0}; 
    


    Procedura show_digit - jest znacznie bardziej skomplikowana, niż mogłaby być.
    Proponuję podejście w takim stylu:

    
    
    //poniższe wartości są tylko przykładowe :-)
    #define SEG_A _BV(0)
    #define SEG_B _BV(1)
    #define SEG_C _BV(2)
    #define SEG_D _BV(3)
    #define SEG_E _BV(4)
    #define SEG_F _BV(5)
    #define SEG_G _BV(6)
    #define SEG_DP _BV(7)
    
    char cyfra[10] = {
    SEG_A | SEG_B | SEG_C | SEG_D | SEG_E | SEG_F, // cyfra 0
    SEG_B | SEG_C, // cyfra 1
    
    //itd.
    
    }
    
    void show_digit(int d,int dt) {
       PORTB = ~cyfra[d];
       if(dt) PORTB^= SEG_DP;
    } 
    
REKLAMA