Witam,
ostatnio zająłem się pisaniem stosunkowo prostej aplikacji na AVR ATmega8, potrzebnej mi na studia. Na celu miałem też trochę lepsze poznanie AVR.
W czym problem : W moim programie chciałem przetestować typowe zachowanie uC, napisałem kilka prostych funkcji, włączyłem przerwania, zrobiłem pętle nieskończoną w której na moim wyświetlaczu 7 segmentowym przemyka 0 . (są 4 wyświetlacze). Następnie zrobiłem symulacje uśpienia uC przez naciśniecie PD (0) , na teraz jest to tylko bardzo duże opóźnienie. Oczywiście będąc w pętli nieskończonej uC reaguje na przerwania od TIMERA, INT0 oraz INT1. Zdaję sobie sprawę ze znak_LED jest zrobiony trochę "na dziko". Ale taka wersja na pewno działa.
PROBLEM 1 :
ATmega w ogóle nie reaguje na wciśnięcie przeze mnie przycisku PD2 (INT0), natomiast wciśnięcie przycisku PD3 (INT1) działa znakomicie. Działa także przerwanie od TIMERA. Zastanawiające. Czy zrobiłem gdzieś błąd w programie? W konfiguracji? Czy może nie wiem o czymś krytycznym?
PROBLEM 2:
Następną sprawą jest problem z funkcją error1();. Zaraz po jej wywołaniu uC działa jak należy - wyświetla z lewej strony aktualną wartość K , a potem z prawej na 3 wyświetlaczach napis Err i tak sobie mryga aż k=10, wtedy wychodzi, zeruje wyświetlacz, no i ... właśnie powinien wrócić do pętli nieskończonej w której na wyświetlaczu przemykają zera. Ale u mnie na wyświetlacz gaśnie, i nic się dalej nie dzieje. Przynajmniej ja nie wiem jak to sprawdzić. A zależy mi oczywiście na poprawnym powrocie z przerwania. Dodam jeszcze że gdy obsługę przerwania INT1 zostawię pustą - to program poprawnie wraca z przerwania.
Czy ktoś widzi moje błędy? Bo już od kilku godzin siedzę i nie mogę znaleźć błędu.
ostatnio zająłem się pisaniem stosunkowo prostej aplikacji na AVR ATmega8, potrzebnej mi na studia. Na celu miałem też trochę lepsze poznanie AVR.
W czym problem : W moim programie chciałem przetestować typowe zachowanie uC, napisałem kilka prostych funkcji, włączyłem przerwania, zrobiłem pętle nieskończoną w której na moim wyświetlaczu 7 segmentowym przemyka 0 . (są 4 wyświetlacze). Następnie zrobiłem symulacje uśpienia uC przez naciśniecie PD (0) , na teraz jest to tylko bardzo duże opóźnienie. Oczywiście będąc w pętli nieskończonej uC reaguje na przerwania od TIMERA, INT0 oraz INT1. Zdaję sobie sprawę ze znak_LED jest zrobiony trochę "na dziko". Ale taka wersja na pewno działa.
PROBLEM 1 :
ATmega w ogóle nie reaguje na wciśnięcie przeze mnie przycisku PD2 (INT0), natomiast wciśnięcie przycisku PD3 (INT1) działa znakomicie. Działa także przerwanie od TIMERA. Zastanawiające. Czy zrobiłem gdzieś błąd w programie? W konfiguracji? Czy może nie wiem o czymś krytycznym?
PROBLEM 2:
Następną sprawą jest problem z funkcją error1();. Zaraz po jej wywołaniu uC działa jak należy - wyświetla z lewej strony aktualną wartość K , a potem z prawej na 3 wyświetlaczach napis Err i tak sobie mryga aż k=10, wtedy wychodzi, zeruje wyświetlacz, no i ... właśnie powinien wrócić do pętli nieskończonej w której na wyświetlaczu przemykają zera. Ale u mnie na wyświetlacz gaśnie, i nic się dalej nie dzieje. Przynajmniej ja nie wiem jak to sprawdzić. A zależy mi oczywiście na poprawnym powrocie z przerwania. Dodam jeszcze że gdy obsługę przerwania INT1 zostawię pustą - to program poprawnie wraca z przerwania.
Czy ktoś widzi moje błędy? Bo już od kilku godzin siedzę i nie mogę znaleźć błędu.
// HARDWARE:
// PORTB :
// PB0 - A
// PB1 - B
// PB2 - C
// PB3 - D
// PB4 - E
// PB5 - F
// PB6 - G
// PB7 - DP
// PORTC :
// PC0 - A0
// PC1 - A1
// PC2 - A2
// PC3 - A3
// PC4 -
// PC5 -
// PC6 -
// PC7 -
// PORTD :
// PD0 - SW0
// PD1 - SW1
// PD2 - SW2 // int0
// PD3 - SW3 // int1
// PD4 - SW4
// PD5 - SW5
// PD6 - SW6
// PD7 - SW7
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/sleep.h>
#define F_CPU 1000000 // 1Mhz
#include <util/delay.h>
// definicja wyboru wyświtlacza 7seg.
#define A_0 1
#define A_1 2
#define A_2 4
#define A_3 8
// TABLICA ZMIENNYCH DO WYSWIETLACZA LED 7SEG
unsigned char liczba_LED[10]={0xC0, 0xF9, 0xA4, 0xB0, 0x99, 0x92, 0x82, 0xF8, 0x80, 0x90};
unsigned char znak_LED[4]={0x06,~(0x50),~(0x20),~(0x20)};
// znaki= E , r , - , - ,
// PRZERWANIA:
ISR (INT0_vect) // przerwanie od INT0
{
// jakies tam instrukcje
}
ISR (INT1_vect) // przerwanie od INT0
{
error1();
wyswietl_7seg_zostaw(0,A_0|A_1|A_2|A_3);
_delay_ms(250);
}
ISR (TIMER1_OVF_vect) // przerwanie od przepełnienia licznika
{
// jakieś tam instrukcje
}
ISR (BADISP_vect){} // jeśli wystapi jakiekolwiek inne przerwanie - to to ratuje sytuacje przed resetem
void AVR_init(void)
{
DDRB = 0xFF; // PORTB WYJSCIOWY
DDRC = 0xFF; // PORTC wYJSCIOWY
DDRD = 0x00; // PORTD WEJSCIOWY
}
void wyswietl_7seg_zostaw (int liczba, int PORT_A_LCD)
{
PORTB = liczba_LED[liczba];
PORTC = 0x00+~(PORT_A_LCD);
_delay_ms(100);
}
void wyswietl_7seg_znak (int liczba, int PORT_A_LCD)
{
PORTB = znak_LED[liczba];
PORTC = 0x00+~(PORT_A_LCD);
_delay_ms(5);
}
void error1(void)
{
for(int k=0;k<10;k++)
{
for(int ki=0;ki<100;ki++)
{
wyswietl_7seg_znak (0, A_2); // wyswietlam znak E
wyswietl_7seg_znak (1, A_1); // wyswietlam znak r
wyswietl_7seg_znak (1, A_0); // wyswietlam znak r
}
wyswietl_7seg_zostaw(k,A_3); // wyswietlam k
_delay_ms(100);
}
wyswietl_7seg_zostaw(0,A_0|A_1|A_2|A_3);
_delay_ms(250);
}
// MAIN:
int main(void)
{
// INICJALIZACJA AVR
AVR_init();
PORTB = 0xC0; // zero na wyświetlaczu
// PRZERWANIA
GICR = _BV(INT0); // włączenie przerwania od INT0 ; mogłoby być GICR = _BV(INT0|INT1);
GICR = _BV(INT1);
MCUCR = 0; // włączenie reakcji na opadające zbocze.
TCCR1B = _BV(CS11); // preskaler X8 = 524280 = troche ponad 1/2 sek
TIMSK = _BV(TOIE1); // włacz obsługę przerwania przepełnienia TIMER 1
//-- WŁĄCZ GLOBALNĄ OBSŁUGE PRZERWAŃ --
sei();
//PĘTLA NIESKOŃCZONA
for( ; ; )
{
if(bit_is_clear(PIND, 0)) atmega_sleep();
wyswietl_7seg_zostaw (0, A_3); // mimo że jest napisane zostaw - to naturalnym jest że
wyswietl_7seg_zostaw (0, A_2); // zera przelatują, każda kolejna funkcja
wyswietl_7seg_zostaw (0, A_1); // kasuje poprzednie ustawienie PORTC
wyswietl_7seg_zostaw (0, A_0);
}
return 0;
}