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!
Awatar użytkownika
dondu
Użytkownik
Posty: 211
Rejestracja: 24 maja 2005, 9:47
Lokalizacja: Śląskie
Kontakt:

Post autor: dondu » 24 wrz 2012, 23:30

Jeżeli zrobisz wyświetlacz na jednym timerze, a zliczanie czasu na drugim, to nie łącz tych obliczeń. To będą dwa niezależne procesy, a wspólna będzie tylko zmienna (jakaś tablica) przechowująca informacje, jaka cyfra na jakim wyświetlaczu ma być aktualnie pokazana.

Dlatego wybierz drugi timer z trybem CTC i wykombinuj jak ustawić 1Hz albo 10Hz, jeżeli chcesz mieć możliwość wyświetlania dziesiątych części sekundy.

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

Post autor: maxxxior » 24 wrz 2012, 23:44

OK, tylko teraz ta częstotliwość odświeżania jest dużo mniejsza od 50Hz, jak co i gdzie ustawić aby to wyświetlanie było powyżej 50Hz ?

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

Post autor: dondu » 24 wrz 2012, 23:47

Nie pokazałeś jak policzyłeś ustawiłeś timer0 pomimo, że prosiłem:
dondu pisze:No to już jesteśmy prawie u celu. Ale podaj jeszcze Twoją propozycję ustawienia timera - obliczenia preskalera + ustawienie rejestrów.
Stąd nie mogę odpowiedzieć na Twoje pytanie .

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

Post autor: maxxxior » 24 wrz 2012, 23:51

no właśnie nie wiem jak go ustawić, ponieważ nie wiem jak policzyć tą jedną sekundę bądź te 50Hz dla jednego wyświetlacza.

Teraz mam tak:
TIMSK |= (1<<TOIE0)
TCCR0 |= (1<<CS02) | (1<<SC00)
TCNT0 = ???

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

Post autor: dondu » 24 wrz 2012, 23:54

Na razie masz tylko dwie cyfry wyświetlacza, czy więcej?

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

Post autor: maxxxior » 25 wrz 2012, 0:12

na razie dwie.

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

Post autor: maxxxior » 25 wrz 2012, 11:52

Nie wiem co robię źle. Zmieniłem częst. taktowania na 8Mhz,wektor przerwań na ISR(TIMER1_COMPB_vect)

i konfiguracje Timer1 tak:

TIMSK |= (1<<OCIE1B) // zezwolenie na przerwania od porównania
TCCR1B |= (1<<CS12) | (1<<WGM12); // tryb CTC oraz prekaler 256
OCR1B = 31250;

właśnie nie wiem co z tym rejestrem OCR1B czy go dobrze wybrałem, ponieważ czytałem w książce że trzeba ustawić dla tego timera rejestr OCRx lecz nie ma wogóle takiego rejestru więc wpisałem do tego tę wartość.

Co tu jest nie tak? przy takiej konfiguracji świeci się tylko liczba 0 na drugim wyświetlaczu.

I jeszcze jedno: Czy odliczanie sekund oraz odświeżanie wyświetlaczy będę musiał zrobić na dwóch osobnych timerach czy mogę to zrobić na jednym?? jak będzie prościej?
Dziś cały dzień siedzę nad tymi timerami i nic mi nie wychodzi, POMOCYYY!

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

Post autor: maxxxior » 25 wrz 2012, 21:35

Pomoże ktoś? już mi głowa pęka od tych timerów, a i tak nic nie działa :/

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

Post autor: dondu » 26 wrz 2012, 20:47

Wrzucaj aktualny program w całości.

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

Post autor: maxxxior » 29 wrz 2012, 13:13

Ok, nie mogłem sobie poradzić z przerwaniem od porównania, lecz wykombinowałem od przepełnienia takie coś:

Kod: Zaznacz cały

 #include <avr/io.h>
#define F_CPU 8000000
#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 200
volatile uint8_t cnt=0;
volatile char flaga;
volatile int wysw, godz=0, min=0;
volatile unsigned char liczba_LED[9] = {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};

ISR (TIMER1_OVF_vect)
{	
	TCNT1 = 34286;
	cnt++;
	
	switch(wysw)
			{
			case 0:
				PORTD &= ~(1<<4);
				PORTD |= (1<<5);		//wlacz wyswietlacz drugi
				PORTA = liczba_LED[min];	//liczba na wyswietlacz				+
				min++;
				wysw++;
				break;
				
			case 1:
				PORTD &= ~(1<<5);		//wlacz wyswietlacz pierwszy
				PORTD |= (1<<4);
				PORTA = liczba_LED[8];	// zapal segmenty dla odpowiednij liczby
				wysw = 0;
				break;
		
			default:
			break;
			}
			cnt=0;


		
		if(min>10)
		{
		min=0;
		godz++;
		
			if(godz>5)
			{
			
			godz=0;
			min=0;
			}
		}	
}
void main(void)
{
    //ustaw kierunki transmisji
    DDRD |= (1<<4) | (1<<5);
    DDRA = 0xFF;
	
	TIMSK |= (1<<TOIE1);			// zezwolenie na  przerwania od przepelnienia
	TCCR1B |= (1<<CS02);			// preskaler 256
	TCNT1 = 34286;					// 65536 - 31250 = 34286
	
	sei();
	
	while(1);

}


No i chyba wyświetlacze się odswieżają co sekundę. Co dalej? Jak dobrze zrobić odświeżanie wyświetlaczy oraz zliczanie na nich sekund?

A no i obliczyłem , że dla 100Hz, dla odświeżania wyświetlaczy trzeba wpisać do TCNT1 wartość 65223. Tylko wtedy te cyfry na drugim wyświetlaczu tak szybko się zmieniają że nic się nie da zobaczyć...

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

Post autor: dondu » 03 paź 2012, 16:11

Temat pchnąłeś do przodu, czy nadal stoisz?

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

Post autor: maxxxior » 03 paź 2012, 16:17

stoje w miejscu. Czekałem aż mi coś poradzisz jak to zrealizować... Jak zrobić opóźnienie tej jednej sekundy . No bo ok, to odświeżanie mógłbym zrobić tak jak napisałem w poprzednim poście tak? a to opóźnienie zmiany wyświetlacza?

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

Post autor: dondu » 03 paź 2012, 16:52

Około 21:00 będę dostępny to się odezwę.


EDIT:

Zacznijmy od tego, że masz ostrzeżenia, które ignorujesz:
Build started 3.10.2012 at 22:02:41
avr-gcc -mmcu=atmega32 -Wall -gdwarf-2 -std=gnu99 -Os -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums -MD -MP -MT dd.o -MF dep/dd.o.d -c ../dd.c
../dd.c:19: warning: excess elements in array initializer
../dd.c:19: warning: (near initialization for 'liczba_LED')
../dd.c:64: warning: return type of 'main' is not 'int'
avr-gcc -mmcu=atmega32 -Wl,-Map=PROBY.map dd.o -o PROBY.elf
avr-objcopy -O ihex -R .eeprom -R .fuse -R .lock -R .signature PROBY.elf PROBY.hex
avr-objcopy -j .eeprom --set-section-flags=.eeprom="alloc,load" --change-section-lma .eeprom=0 --no-change-warnings -O ihex PROBY.elf PROBY.eep || exit 0
avr-objdump -h -S PROBY.elf > PROBY.lss

AVR Memory Usage
----------------
Device: atmega32

Program: 412 bytes (1.3% Full)
(.text + .data + .bootloader)

Data: 18 bytes (0.9% Full)
(.data + .bss + .noinit)


Build succeeded with 3 Warnings...
Wytłuściłem dwa najważniejsze.

Pierwszy - policz ile jest elementów tablicy i porównaj z liczbą jaką podałeś podczas deklaracji zmiennej, liczba_LED.

Drugi mniej istotny, ale main() jest wyjątkiem i musi być typu int a nie void.
Szczegóły: http://mikrokontrolery.blogspot.com/201 ... klady.html


NIGDY NIE IGNORUJ WARNINGÓW - by w piekielu nie siedziec na stopniu 10

... a teraz popatrzę w Twój program i datasheet ...


EDIT2:

Z kodu widać, że chcesz użyć Timer1.
Taktujesz mikrokontroler zegarem 8MHz.
Zaproponowałeś preskaler 256.

No to liczymy: 8MHz /256 = 31250Hz
Czyli tak trzeba ustawić timer, by licząc od 0 w górę wyzerował się w momencie pojawienia się 31250-go taktu.

Tym trybem jest tryb CTC:


Patrzysz do tabelki:

In CTC mode the counter is cleared to zero when
the counter value (TCNT1) matches either the OCR1A (WGM13:0 = 4) or the ICR1 (WGM13:0 =12). The OCR1A or ICR1 define the top value for the counter, hence also its resolution. Thismode allows greater control of the compare match output frequency. It also simplifies the operation of counting external events.
Z powyższego dowiadujemy się, że timer wyzeruje się, gdy zrówna się z rejestrem OCR1A lub ICR1 w zależności czy wybierzemy odpowiednio mode 4 czy 12.

Teraz zerkamy do tabeli gdzie tryby są opisane: Table 47. Waveform Generation Mode Bit Description

gdzie widać, że mode 4 i 12 to faktycznie tryby CTC. Różnią się natomiast tylko tym, do którego z rejestrów licznik timer się porównuje OCR1A czy ICR1 (patrz kolumna TOP).

Wybierzmy więc mode, w którym porównywać się będziemy do rejestru OCR1A.
I tutaj czekam na Twoją pracę nad tym co napisałem powyżej, łącznie z podaniem który mode z tabeli wybrałeś i jak należy go ustawić (włączyć).

Dodatkowo ustal jak ustawić preskaler bo 256 ustawia się inaczej.
Patrz tabelka: Table 48. Clock Select Bit Description

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

Post autor: maxxxior » 04 paź 2012, 12:03

OK, zrobię to co napisałeś w przeciągu kilku godzin, ale:
Dlaczego nie mogę zostawić tego trybu NORMAL co jest aktualnie skonfigurowany w kodzie ?
Tzn ogólnie, chciałbym się nauczyć obsługiwać timer w trybie NORMAL, CTC i PWM... więc proponowałbym abyś mi pomógł w zrobieniu na przykład odświeżania wyświtlacza w trybie normal a zliczanie sekund w trybie CTC.

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

Post autor: maxxxior » 05 paź 2012, 16:54

Ok, wrzucam cały kod, z przerwaniem od timer1 tryb CTC prescaler 256.

Kod: Zaznacz cały

#include <avr/io.h>
#define F_CPU 8000000
#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 200
volatile uint8_t cnt=0;
volatile char flaga;
volatile int wysw, godz=0, min=0;
volatile 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};

ISR (TIMER1_COMPB_vect)
{	
	//TCNT1 = 65223;
	TCNT1 = 31250;
	cnt++;
	
	switch(wysw)
			{
			case 0:
				PORTD &= ~(1<<4);
				PORTD |= (1<<5);		//wlacz wyswietlacz drugi
				PORTA = liczba_LED[min];	//liczba na wyswietlacz				+
				min++;
				wysw++;
				break;
				
			case 1:
				PORTD &= ~(1<<5);		//wlacz wyswietlacz pierwszy
				PORTD |= (1<<4);
				PORTA = liczba_LED[8];	// zapal segmenty dla odpowiednij liczby
				wysw = 0;
				break;
		
			default:
			break;
			}
			cnt=0;


		
		if(min>10)
		{
		min=0;
		godz++;
		
			if(godz>5)
			{
			
			godz=0;
			min=0;
			}
		}	
}
int main(void)
{
    //ustaw kierunki transmisji
    DDRD |= (1<<4) | (1<<5);
    DDRA = 0xFF;
	
	//TIMSK |= (1<<TOIE1);			// zezwolenie na  przerwania od przepelnienia
	//TCCR1B |= (1<<CS02);			// preskaler 256
	//TCNT1 = 65223;					// 65536 - 31250 = 34286
	
	TIMSK |= (1<<OCIE1B);			// zezwolenie na przerwanie od porownania
	TCCR1B |= (1<<WGM12);			// tryb CTC Timer1
	TCCR1B |= (1<<CS12);			// prescaler 256
	TCNT1 = 31250;					
	
	sei();
	
	while(1);
	
	return 0;

}
I co dalej?

ODPOWIEDZ