Zegar na wyświetlaczach 7-segmentowych - Obsługa Timera
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.
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.
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!
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!
Ok, nie mogłem sobie poradzić z przerwaniem od porównania, lecz wykombinowałem od przepełnienia takie coś:
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ć...
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);
}
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ć...
Około 21:00 będę dostępny to się odezwę.
EDIT:
Zacznijmy od tego, że masz ostrzeżenia, które ignorujesz:
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:
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
EDIT:
Zacznijmy od tego, że masz ostrzeżenia, które ignorujesz:
Wytłuściłem dwa najważniejsze.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...
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:
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.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.
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
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.
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.
Ok, wrzucam cały kod, z przerwaniem od timer1 tryb CTC prescaler 256.
I co dalej?
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;
}