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 » 09 paź 2012, 11:13

Sorry za opóźnienia - wieczorem dam znać co dalej.

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

Post autor: dondu » 10 paź 2012, 6:02

Ustawiłeś preskaler na 256 - OK
Ustawiłeś tryb CTC (mode 4) dla OCR1A -OK

Włączyłeś przerwania od porównania OCR1B, a powinieneś włączyć od OCR1A.
Patrz tabelka ustawiania trybów: Table 47. Waveform Generation Mode Bit Description
oraz: Figure 40. 16-bit Timer/Counter Block Diagram

Z tego samego powodu wektor przerwania ma być od porównania A a nie B.

--------

Dlaczego ustawiasz wartość początkową licznika na 31250?
Z tego wynika, że niestety nie rozumiesz trybu CTC.

W tym trybie licznik ma liczyć od zera w górę.
Dochodząc do momentu w którym licznik zrówna się z OCR1A, nastąpi jego wyzerowanie i wygenerowanie przerwania.
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.
Czyli OCR1A musi mieć wartość przy której ma to nastąpić. A u Ciebie jest ciągle wartość domyślna, wynikająca z ustawienia bitów w tym rejestrze podczas włączenia mikrokontrolera.

Zamiast tego w przerwaniu ustawiasz wartość licznika, który właśnie się wyzerował i zgłosił przerwanie.

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

Post autor: maxxxior » 10 paź 2012, 10:48

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_COMPA_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[godz];	// zapal segmenty dla odpowiednij liczby
				wysw = 0;
				break;
		
			default:
			break;
			}
			cnt=0;


		
		if(min>9)
		{
		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<<OCIE1A);			// zezwolenie na przerwanie od porownania
	TCCR1B |= (1<<WGM12);			// tryb CTC Timer1
	TCCR1B |= (1<<CS12);			// prescaler 256				
	
	sei();
	
	while(1);
	
	return 0;

}


Teraz jest dobrze?
Nie rozumiem tylko dlaczego w TIMSK ustawiam przerwania od "trybu" A a prescaler i tryb CTC ustawiam w "trybie" B ?? Czemu to jest takie zagmatwane? no chyba że to jest źle i powinno byc TCCR1A, ale w tym rejestrze nie można ustawić prescalera...

OK, co dalej?

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

Post autor: dondu » 10 paź 2012, 23:35

Przeczytaj jeszcze raz mój poprzedni post i zastanów się także nad funkcją obsługi przerwania, a nie tylko fragmentem main() ustawiającym timer.

TCCR1A i TCCR1B nie są odpowiednikami OCR1A i OCR1B, ale niestety często dochodzi do takiego rozumienia jak Twoje. Trochę mylące są te literki A i B.

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

Post autor: maxxxior » 11 paź 2012, 9:27

Czyli muszę ustawić na sztywno OCR1A = 31250, a TCNT1 inkrementować ??OCR1A ustawiam w main tak? a co z TCNT1? czy wystarczy że w obsłudze przerwania będzie tylko cnt++ ?

Wklejam kod:

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_COMPA_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[godz];	// zapal segmenty dla odpowiednij liczby
				wysw = 0;
				break;

			default:
			break;
			}

		if(min>9)
		{
		min=0;
		godz++;

			if(godz>5)
			{
			godz=0;
			min=0;
			}
		}
		//cnt=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<<OCIE1A);			// zezwolenie na przerwanie od porownania
	TCCR1B |= (1<<WGM12);			// tryb CTC Timer1
	TCCR1B |= (1<<CS12);			// prescaler 256
	OCR1A = 31250;

	sei();

	while(1);

	return 0;
}







ODPOWIEDZ