Skocz do zawartości

[atmega][c] Wyświetlacz 7 segmentowy


kfh13

Pomocna odpowiedź

Mam taki oto kod powstały na podstawie strony wkrętaka

#include <avr\io.h>
#include <inttypes.h>
#include <avr\signal.h>
#include <avr\interrupt.h>
#include <avr\pgmspace.h>
#include <w7s.h>

#define LED_DDR DDRB   //stan wyjście albo wejście
#define LED_PORT PORTB //0-włączenie leda
#define WYSW_1 0
#define WYSW_2 1
#define WYSW_3 2
#define WYSW_4 3
#define WYSW_5 4
#define WYSW_6 5


#define WYSW_DDR DDRC   //stan wyjście albo wejście
#define WYSW_PORT PORTC //0-włączenie wysw

uint8_t akt_wysw[6]=
{
~(1<<WYSW_6),
~(1<<WYSW_5),
~(1<<WYSW_4),
~(1<<WYSW_3),
~(1<<WYSW_2),
~(1<<WYSW_1)
};

volatile uint8_t wysw;
unsigned int godziny, minuty, sekundy,dziesiatki,jednosci;

int main(void)
{
   TCCR1B |= (1 << WGM12); // Ustawia timer1 w tryb CTC
   OCR1A = 3333; // Ustawia wartość pożądaną na 100Hz dla preskalera 1
   TCCR1B |= (1 << CS10); // Ustawia timer z preskalerem Fcpu/1
   TIMSK |= (1 << OCIE1A); // Zezwolenie na przerwania dla CTC
   sei(); // Zezwolenie globalne na przerwania/

LED_DDR = 0xff;
WYSW_DDR = 0xff;

sekundy=33;
minuty=22;
godziny=11;
       dziesiatki=sekundy/10; 
       jednosci=sekundy%10;

for(;;)
{
}
return 0; 
}


ISR(TIMER1_COMPA_vect)
{
switch (wysw)
   {
       case 0:
		WYSW_PORT=akt_wysw[0];
           LED_PORT=znaki_wysw[jednosci];
           wysw++;
       break;

	case 1:
		WYSW_PORT=akt_wysw[1];
           LED_PORT=znaki_wysw[dziesiatki];
           wysw++;
       break;

	case 2:
		WYSW_PORT=akt_wysw[2];
           LED_PORT=znaki_wysw[1];
           wysw++;
       break;

	case 3:
		WYSW_PORT=akt_wysw[3];
           LED_PORT=znaki_wysw[minuty/10];
           wysw++;
       break;

	case 4:
		WYSW_PORT=akt_wysw[4];
           LED_PORT=znaki_wysw[godziny-(godziny/10)*10];
           wysw++;
       break;

	case 5:
		WYSW_PORT=akt_wysw[5];
           LED_PORT=znaki_wysw[godziny/10];
           wysw=0;
       break;
   }
}

Nie wiem dlaczego program nie chce wyświetlić poprawnie liczby. W "caseach" mam kilka metod moich prób i działa jedynie ta w której sztywno wpisałem liczbę (case 2). Przy reszcie świecą wszystkie diody, czyli jakby nie znalazł odpowiedniej liczby w tabeli. Ma ktoś jakiś pomysł co robię źle ?

Link do komentarza
Share on other sites

Przy przypisywaniu wartości do zmiennych nie masz spacji:

sekundy=33; 
minuty=22; 
godziny=11; 

+ przy deklarowaniu tych zmiennych to samo:

unsigned int godziny, minuty, sekundy,dziesiatki,jednosci; 

Nie jestem pewien czy w tym tkwi błąd (czystego C uczę się od kilku godzin) ale sprawdź 🙂

edit:

Jeszcze tutaj masz głupi błąd:

jednosci=sekundy%10;
Link do komentarza
Share on other sites

A co program wyświetla?

[ Dodano: 14 Lut 10 10:34 ]

Próbowałeś w case 2: wyświetlać inne cyfry?

[ Dodano: 14 Lut 10 10:34 ]

Możesz jeszcze dodać volatile do deklaracji zmiennych, czyli

volatile unsigned int godziny, minuty, sekundy,dziesiatki,jednosci; 
Link do komentarza
Share on other sites

Zarejestruj się lub zaloguj, aby ukryć tę reklamę.
Zarejestruj się lub zaloguj, aby ukryć tę reklamę.

jlcpcb.jpg

jlcpcb.jpg

Produkcja i montaż PCB - wybierz sprawdzone PCBWay!
   • Darmowe płytki dla studentów i projektów non-profit
   • Tylko 5$ za 10 prototypów PCB w 24 godziny
   • Usługa projektowania PCB na zlecenie
   • Montaż PCB od 30$ + bezpłatna dostawa i szablony
   • Darmowe narzędzie do podglądu plików Gerber
Zobacz również » Film z fabryki PCBWay

Tak wygląda tablica znaki_wysw, teraz już znaki.

prog_uint8_t znaki[11] PROGMEM =
{
 ~(1<<LED_A | 1<<LED_B | 1<<LED_C | 1<<LED_D | 1<<LED_E | 1<<LED_F),           //0
 ~(1<<LED_B | 1<<LED_C),                                                         //1
 ~(1<<LED_A | 1<<LED_B | 1<<LED_G | 1<<LED_E | 1<<LED_D),                       //2
 ~(1<<LED_A | 1<<LED_B | 1<<LED_G | 1<<LED_C | 1<<LED_D),                      //3
 ~(1<<LED_F | 1<<LED_G | 1<<LED_B | 1<<LED_C),                                  //4
 ~(1<<LED_A | 1<<LED_F | 1<<LED_G | 1<<LED_C | 1<<LED_D),                      //5
 ~(1<<LED_A | 1<<LED_F | 1<<LED_G | 1<<LED_C | 1<<LED_D | 1<<LED_E),           //6
 ~(1<<LED_A | 1<<LED_B | 1<<LED_C),                                             //7
 ~(1<<LED_A | 1<<LED_B | 1<<LED_C | 1<<LED_D | 1<<LED_E | 1<<LED_F | 1<<LED_G),//8
 ~(1<<LED_A | 1<<LED_B | 1<<LED_C | 1<<LED_D | 1<<LED_F | 1<<LED_G),             //9
 ~(1<<LED_DP),
}; 

uint8_t wysw_znak(uint8_t cyfra)
{
return pgm_read_byte(&znaki[cyfra]);
}

Zapomniałem, że ta tablica jest typu progmen, więc jej wartości odczytuje się inaczej.

Wynikł następny problem... przerobiłem "kajsy" na:

switch (wysw)
   {
       case 0:
		WYSW_PORT=akt_wysw[0];
           LED_PORT=wysw_znak(sekundy%10);
           wysw++;
       break;

	case 1:
		WYSW_PORT=akt_wysw[1];
           LED_PORT=wysw_znak(sekundy/10);
           wysw++;
       break;

	case 2:
		WYSW_PORT=akt_wysw[2];
           LED_PORT=wysw_znak(minuty%10);
           wysw++;
       break;

	case 3:
		WYSW_PORT=akt_wysw[3];
           LED_PORT=wysw_znak(minuty/10);
           wysw++;
       break;

	case 4:
		WYSW_PORT=akt_wysw[4];
           LED_PORT=wysw_znak(godziny%10);
           wysw++;
       break;

	case 5:
		WYSW_PORT=akt_wysw[5];
           LED_PORT=wysw_znak(godziny/10);
           wysw=0;
       break;
   }

Jakoś dziwnie liczby się "przebijają". Tzn. jęśli ustawie wyświetlacz na 654321. To widać na 1 jak przebija 6, na 2 przebija 1, na 3 przebija 2 itd.

Dołączam foto:

20100214156.thumb.jpg.c1ec5d98ba46fbc5f89d199fcb84faaf.jpg

Link do komentarza
Share on other sites

To co mi przychodzi do głowy:

1) zmień częstotliwość multipleksowania

2) nie wygaszasz poprzedniego wyświetlacza zanim podasz następną cyfrę

3) za mała wartość rezystora na bazie tranzystorów

Ja robiłem tak i nie miałem tej poświaty, co prawda tylko 2 wyświetlacze, bez użycia tablic, ale poglądowo:

switch (w)
{
	case 0:
			PORTD =0xFF;    // wyzerowanie portu D - zgaszenie wszystkich lini
				sbi(PORTB,0); //zgaszenie segmentu 2
		led7(x);
				cbi(PORTD,7); // zapalenie segment 1
				w++;
				break;

	case 1:		
			PORTD =0xFF;     	
				sbi(PORTD,7); ///zgaszenie segmentu 1
		led7(y);

				cbi(PORTB,0);	// zapalenie segment 2
				w=0;
				break;		
}
}
Link do komentarza
Share on other sites

@regrom

1) Zwiększenie częstotliwości pogarsza problem, a zmniejszenie powoduje miganie a poświata nadal występuje.

2) To samo robi moja tablica. Obecnie nie używa się sbi i cbi tylko

PORTB|=_BV(4) // bit ustawiony (1)

PORTB&=~_BV(4) // bit wyzerowany

To i tak nic nie daje!

3) To raczej ominięcie problemu niż jego usunięcie. No chyba, że to czysto "sprzętowa dolegliwość" a nie wina software.

Znalazłem rozwiązanie ! Którego do końca nie rozumiem, ale co tam. Zastosowałem podwójne wygaszanie - czyli wygaszam wyświetlacze i diody. Poświata znikneła.

Oto przykład:

ISR(TIMER1_COMPA_vect)
{
WYSW_PORT= 0xff;
LED_PORT= 0xff;
switch (wysw)
   {
       case 0:
		WYSW_PORT&=akt_wysw[0];
           LED_PORT=wysw_znak(sekundy%10);
           wysw++;
       break;

	case 1:
		WYSW_PORT&=akt_wysw[1];
           LED_PORT=wysw_znak(sekundy/10);
           wysw++;
       break;

	case 2:
		WYSW_PORT&=akt_wysw[2];
           LED_PORT=wysw_znak(minuty%10);
           wysw++;
       break;

	case 3:
		WYSW_PORT&=akt_wysw[3];
           LED_PORT=wysw_znak(minuty/10);
           wysw++;
       break;

	case 4:
		WYSW_PORT&=akt_wysw[4];
           LED_PORT=wysw_znak(godziny%10);
           wysw++;
       break;

	case 5:
		WYSW_PORT&=akt_wysw[5];
           LED_PORT=wysw_znak(godziny/10);
           wysw=0;
       break;
   }
}
Link do komentarza
Share on other sites

regrom, miał rację. Pomogło wygaszanie przed przełączeniem do kolejnej cyfry.

Nie jest prawdą, że:

2) To samo robi moja tablica.

W programie najpierw przełączasz na kolejny segment:

WYSW_PORT&=akt_wysw[5];

co powoduje, że na bardzo krótko, ale zawsze zapalasz na nim cyfrę z poprzedniego.

Dopiero później wykonujesz:

LED_PORT=wysw_znak(godziny/10); 

co ustawia poprawną wartość.

Takie przełączanie jest krótkie, ale jak sam zaobserwowałeś widoczne.

Pomysł 3) wcale nie jest zły - efekt byłby o wiele mniej widoczny, gdyby tranzystor przełączał się szybciej.

Link do komentarza
Share on other sites

Tylko, że samo wygaszenie wyświetlacza nic nie dało. Dopiero połączenie z "zerowaniem" znaku daje całkowite zlikwidowanie poświaty.

Link do komentarza
Share on other sites

@Elvis

No rzeczywiście teraz działa. Całość kodu została zmieniona na:

WYSW_PORT= 0xff;

LED_PORT=wysw_znak(stan_wysw[numer_wysw]);
WYSW_PORT=akt_wysw[numer_wysw];

numer_wysw++;
if(numer_wysw==6)
{
numer_wysw=0;
}

Pozwoliło to na zaoszczędzenie około 90 bajtów i zrobiło się bardziej uniwersalne.

Link do komentarza
Share on other sites

Dokładnie o to mi chodziło, sam rozwiązywałem ten problem, jak widać w kodzie który podałem jest to samo:

PORTD =0xFF;    // wyzerowanie portu D - zgaszenie wszystkich lini
                   sbi(PORTB,0); //zgaszenie segmentu 2
           led7(x);
                   cbi(PORTD,7); // zapalenie segment 1 

najpierw wygaszenie wszystkich segmentów, odłączenie segmentu, funkcja led(7) ustawienie odpowiedniej kombinacji, i dopiero wtedy następuje zapalenie tego segmentu co powinno.

Pozdrawiam i życzę dalszych sukcesów 😉

  • Pomogłeś! 1
Link do komentarza
Share on other sites

Dołącz do dyskusji, napisz odpowiedź!

Jeśli masz już konto to zaloguj się teraz, aby opublikować wiadomość jako Ty. Możesz też napisać teraz i zarejestrować się później.
Uwaga: wgrywanie zdjęć i załączników dostępne jest po zalogowaniu!

Anonim
Dołącz do dyskusji! Kliknij i zacznij pisać...

×   Wklejony jako tekst z formatowaniem.   Przywróć formatowanie

  Dozwolonych jest tylko 75 emoji.

×   Twój link będzie automatycznie osadzony.   Wyświetlać jako link

×   Twoja poprzednia zawartość została przywrócona.   Wyczyść edytor

×   Nie możesz wkleić zdjęć bezpośrednio. Prześlij lub wstaw obrazy z adresu URL.

×
×
  • Utwórz nowe...

Ważne informacje

Ta strona używa ciasteczek (cookies), dzięki którym może działać lepiej. Więcej na ten temat znajdziesz w Polityce Prywatności.