Zegar na wyświetlaczach 7-segmentowych - Obsługa Timera

To forum jest dla wszystkich pasjonatów mikrokontrolerów AVR Atmela. Wymiana doświadczeń i pomoc dla początkujących w pisaniu programów zarówno w C, Asemblerze jak i BASCOM. Zapraszam znawców tematu, aby pomogli wszystkim początkującym!
maxxxior
Użytkownik
Posty: 210
Rejestracja: 19 mar 2010, 21:27
Lokalizacja: Skierniewice

Zegar na wyświetlaczach 7-segmentowych - Obsługa Timera

Post autor: maxxxior » 22 wrz 2012, 22:02

Witam, wziąłem się za zrobienie prostego zegara na 4 wyświetlaczach 7-segmentowych. Kod piszę na Atmega32, w języku C. Napisałem właśnie taki że tak powiem "niechlujny" sposób, za pomocą pętli i delay'ów lecz wiadomo, to mi dobrze czasu nie zmierzy. Jak to zrobić na timerze? jak go skonfigurować i jak wyliczyć wartości aby mi zmieniał stan wyświetlaczy co 1 sekundę ?

Awatar użytkownika
dondu
Użytkownik
Posty: 211
Rejestracja: 24 maja 2005, 9:47
Lokalizacja: Śląskie
Kontakt:

Post autor: dondu » 22 wrz 2012, 22:35

Ponieważ nie pokazujesz schematu, to na początek musisz odpowiedzieć na pytania:
- czy ma to być zegar który ma być dość dokładny (powiedzmy kilka sek, w miesiącu),
- czy robisz projekt tylko dla nauki i na razie wystarczy mniejsza dokładność.
Od tego zależy w jaki sposób zbudujesz zegar pod względem schematu jak i programu.

maxxxior
Użytkownik
Posty: 210
Rejestracja: 19 mar 2010, 21:27
Lokalizacja: Skierniewice

Post autor: maxxxior » 22 wrz 2012, 23:14

wystarczy mniejsza dokładność... .właśnie czytałem przykład jak skonfigurować Timer1 aby dioda migała co 1sekundę... że trzeba ustawić tryb CTC, że do OCR1 trzeba wpisać wartość 31250, ale, jak to wykorzystać w moim programie? nie rozumiem praktycznego wykorzystania tych linijek w programie... Ok, mam skonfigurowany Timer, i teraz skąd program ma wiedzieć że ma liczyć według tego timera? jak to wykorzystać w tym programie, tzn chodzi mi o to w którym miejscu umieścić przerwanie i jak to zrobić...

maxxxior
Użytkownik
Posty: 210
Rejestracja: 19 mar 2010, 21:27
Lokalizacja: Skierniewice

Post autor: maxxxior » 22 wrz 2012, 23:16

najlepiej jak byś mi tutaj wstawił szkielet poglądowy programu...

Awatar użytkownika
dondu
Użytkownik
Posty: 211
Rejestracja: 24 maja 2005, 9:47
Lokalizacja: Śląskie
Kontakt:

Post autor: dondu » 22 wrz 2012, 23:49

CTC - właściwy kierunek.

Zapoznaj się z przykładem LED'a sterowanego za pomocą przerwania i timera, choć to nie tryb CTC, to da Ci pojęcie co musisz napisać: http://mikrokontrolery.blogspot.com/201 ... timer.html

Dla trybu CTC flaga przerwania będzie inna niż ta w funkcji ISR() z przykładu.
Jaka? Znajdziesz tutaj: http://www.nongnu.org/avr-libc/user-man ... rupts.html

maxxxior
Użytkownik
Posty: 210
Rejestracja: 19 mar 2010, 21:27
Lokalizacja: Skierniewice

Post autor: maxxxior » 24 wrz 2012, 15:21

flaga przerwania - tzn co? w tym pierwszym przykładzie co jest tą flagą przerwania?

a nie mogę do tego mojego programu skorzystać z tego przykładu z pierwszego linka, i nie korzystać z CTC ?

Niestety nie za bardzo wiem jak to zrobić: poniżej zamieszczam swój program, w którym wykorzystałem konfiguracje timera z pierwszego linka, z drugiego przykładu.

Kod: Zaznacz cały

#include <avr/io.h>
//#define F_CPU 1000000
#include <util/delay.h>
#include<avr/interrupt.h>
#define A (1<<PA0)
#define B (1<<PA1)
#define C (1<<PA2)
#define D (1<<PA3)
#define E (1<<PA4)
#define F (1<<PA5)
#define G (1<<PA6)
#define DP (1<<PA7)

#define timer_start 6

volatile uint8_t cnt = 0;

int16_t min1, min2, sek1,sek2, m, licznik_sekund;
unsigned char liczba_LED[10] = {A|B|C|D|E|F, E|F, D|E|G|B|A, D|E|G|F|A, C|G|E|F, D|C|G|F|A, D|C|B|A|F|G, D|E|F, A|B|C|D|E|F|G, C|D|E|G|F|A};

int main()
{

	
	
    //ustaw kierunki transmisji
    DDRD = 0xFF;
    DDRA = 0xFF;
	
	TIMSK |= (1<<TOIE0);
	TCCR0 |= (1<<CS02) | (1<<CS00);
	TCNT0 = timer_start;
	
	sei();
	
	while(1);
}

ISR (TIMER0_OVF_vect)
{
	TCNT0 = timer_start;
	cnt++;
	if(cnt>3)
	{
	for(min1=0; min1<=9; min1++)
		for(min2=0; min2<=9; min2++)
			for(sek1=0; sek1<=9; sek1++)
				for(sek2=0; sek2<=9; sek2++)
					//for(m=1; m<=2950; m++)
				{	
					
					// wyswietlacz 4 - sekundy2
					PORTD=0b11111011;
					PORTA = liczba_LED[sek2];
					_delay_ms(50);
					
					// wyswietlacz 3 - sekundy1
					PORTD= 0b11110111;
					PORTA= liczba_LED[sek1];
					_delay_ms(50);
					
					
					   // wyswietlacz 2 = godz2
					    PORTD = 0b11101111;
						PORTA = (liczba_LED[min2]);
						_delay_ms(50);
					
						// wyswietlacz 1 - godz1 
						PORTD = 0b11011111;
						PORTA = (liczba_LED[min1]);
						_delay_ms(50);
					
						if(sek1>5)
						{
							min2++;
							sek1=0;
							sek1=0;
							if(min2>9)
							{
							min1++;
							min2=0;
								if(min1>5)
								{
									min1=0;
								}
							}
						
						
						}
				}
			cnt=0;
	}
}
Chciałem zrealizować na razie sekundnik, to znaczy ze pierwszych dwóch wyświetlaczach minuty, a na drugim i trzecim sekundy.
Nie wiem co zrobić z tymi delay'ami, i nie wiem czy w dobrym miejscu zeruje licznik cnt, oraz go inkrementuję. A, ta zakomentowana pętla m=0; ... to byłą pętla opóźniająca...

Awatar użytkownika
dondu
Użytkownik
Posty: 211
Rejestracja: 24 maja 2005, 9:47
Lokalizacja: Śląskie
Kontakt:

Post autor: dondu » 24 wrz 2012, 17:36

to jest funkcja obsługi przerwania:

Kod: Zaznacz cały

ISR (TIMER0_OVF_vect) {

}
a to wektor przerwania od przepełnienia timera0: TIMER0_OVF_vect
(błędnie napisałem: flaga przerwania - sorki).
Inne wektory przerwań znajdziesz w linku, który podałem wyżej.


Co do Twojego programu.
Przerwania muszą wykonywać się szybko. Albo robisz coś na timerze który odlicza czas i przerwaniach, albo używasz delay.

Zapoznaj się z tym: http://mikrokontrolery.blogspot.com/201 ... wania.html

maxxxior
Użytkownik
Posty: 210
Rejestracja: 19 mar 2010, 21:27
Lokalizacja: Skierniewice

Post autor: maxxxior » 24 wrz 2012, 19:09

no tak, dlatego napisałem że nie wiem co zrobić z tym delay'em. Co mam wstawić w jego miejsce ? czy może lepiej zastosować sposób stąd: http://diycenter.acid19.linuxpl.com/rea ... icle_id=19 ?

Awatar użytkownika
edwacc
Użytkownik
Posty: 163
Rejestracja: 14 paź 2008, 10:19
Lokalizacja: świętokrzyskie knieje

Post autor: edwacc » 24 wrz 2012, 19:30

Możesz użyć kwarcu 4.096MHz i użyć przerwania od przepełnienia T0. Preskaler dla T0 najlepiej z podziałem 8, czyli

Kod: Zaznacz cały

TCCR0 |= 1 << CS01;
Obsługa przerwania będzie wtedy wykonywana z częstotliwością:

Kod: Zaznacz cały

4.096 [MHz] / (256 * 8) = 2 [kHz]
Przy każdym zliczonym tysiącu przerwań możesz zmieniać stan diody, bedzie wtedy mrugała z częstotliwością 1 Hz.

maxxxior
Użytkownik
Posty: 210
Rejestracja: 19 mar 2010, 21:27
Lokalizacja: Skierniewice

Post autor: maxxxior » 24 wrz 2012, 19:36

tylko ja nie chce zmieniać żadnego stanu diody tylko jak to wykorzystać w programie podanym przeze mnie ?

Awatar użytkownika
edwacc
Użytkownik
Posty: 163
Rejestracja: 14 paź 2008, 10:19
Lokalizacja: świętokrzyskie knieje

Post autor: edwacc » 24 wrz 2012, 20:00

Z całym szacunkiem ale program podany przez Ciebie to jakiś koszmar...
Nie wiem o co w nim chodzi, i nie mam czasu w to wnikać a tym bardziej doprowadzać do porządku :)

Podpowiem Ci tylko, że w przerwaniu od przepełnienia T0 wystarczy inkrementować jakiś licznik i sprawdzać czy jego wartość nie przekroczyła 2000.
W funkcji main() zastosuj pętle nieskończoną, w której będziesz sprawdzał wartość tego licznika i aktualizował wartość innego licznika reprezentującego aktualny czas (np. format zapożyczony z Unix - http://www.epochconverter.com/).
W pętli nieskończonej możesz też zaimplementować funkcje kalendarza i wyświetlania czasu na LED.
Ostatnio zmieniony 24 wrz 2012, 20:03 przez edwacc, łącznie zmieniany 2 razy.

Awatar użytkownika
dondu
Użytkownik
Posty: 211
Rejestracja: 24 maja 2005, 9:47
Lokalizacja: Śląskie
Kontakt:

Post autor: dondu » 24 wrz 2012, 20:02

W poprzednim moim poście podałem Ci link. Zaglądnij do niego jeszcze raz i przeczytaj punkt Flagi - rozwiązaniem problemu, który właśnie przed chwilą dopisałem (miałem to zrobić już dawno temu). Szukaj go pod koniec artykułu.

Na tej podstawie wykombinuj na razie jedynie wyświetlanie jakiejś liczby, bez żadnych innych funkcjonalności zegara. Chodzi o to, byś załapał jak posługiwać się przerwaniem oraz jak multipleksować wyświetlacz.

maxxxior
Użytkownik
Posty: 210
Rejestracja: 19 mar 2010, 21:27
Lokalizacja: Skierniewice

Post autor: maxxxior » 24 wrz 2012, 20:58

a mógłby ktoś mi w między czasie wytłumaczyć o co chodzi z tym dziesiatki = liczba/10 i jednosci = liczba%10 ?? nie rozumiem jak to działa :/

maxxxior
Użytkownik
Posty: 210
Rejestracja: 19 mar 2010, 21:27
Lokalizacja: Skierniewice

Post autor: maxxxior » 24 wrz 2012, 21:15

nie no, nie mam siły już... chciałem wgrać program z tego portalu: http://diycenter.acid19.linuxpl.com/rea ... icle_id=19

i chciałem wyświetlić tą liczbę 24, i teraz niby segmenty tej liczby palą się mocniej a reszta też się pali tylko słabiej. Co jest grane?

Awatar użytkownika
Ertew
Użytkownik
Posty: 1414
Rejestracja: 03 lip 2005, 10:36
Lokalizacja: Leszno
Kontakt:

Post autor: Ertew » 24 wrz 2012, 21:21

Podejście pierwsze:
Liczbę minut masz w jednej zmiennej, jak doliczysz do 60 to zaczynasz od zera i zwiększasz liczbę godzin. Logiczne, prawda?
Problem w tym że na jednym wyświetlaczu możesz wyświetlić tylko jedną cyfrę, nie liczbę.
Żeby z liczby wyodrębnić dwie cyfry, trzeba podzielić liczbę przez 10.

Nie mowa tu o matematycznym dzieleniu z ułamkiem ( 23/10=2,3 ) tylko o dzielenie z resztą
Pierwsze działanie zwraca liczbę całkowitą zaokrągloną w dół, więc 23/10=2
Drugie nie przejmuje się liczbą całkowitą, natomiast zwraca resztę z dzielenia: 23%10=3
Mając tak wyodrębnione cyfry można je wyświetlić na kolejnych pozycjach wyświetlacza.



Podejście drugie:
Masz dwie zmienne, jedna to jednostki minut, druga dziesiątki minut. Po doliczeniu do 10 jednostek, zerujesz jednostki i zwiększasz dziesiątki o jeden. Sprawdzasz przy tym czy dziesiątki nie doszły do 6, wtedy je zerujesz i zwiększasz jednostki godzin.
Wykrycie godziny 24 już jest trudniejsze :wink:
No i te całe if'y zabierają zdecydowanie więcej pamięci flash i czasu procesora niż konwersja zmiennych podczas wyświetlania. RAMu chyba też więcej wyjdzie.

ODPOWIEDZ