przerwanie od UARTU ATMega32

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!
ODPOWIEDZ
doctor
-
Posty: 9
Rejestracja: 24 lip 2006, 18:06
Lokalizacja: Tarnowskie Gory

przerwanie od UARTU ATMega32

Post autor: doctor » 04 gru 2006, 13:50

Witam serdecznie,

mam do napisania program na uC, który w zależności co odbierze z PC przez UART to wykona odpowiednią funkcję / skoczy do innego fragmentu programu. Rozwiązalem to tak:
**************************
int main(void) {
USART_Init(MYUBRR);
while(1)
{
char znak = USART_Receive();
if(znak == '1') { funkcja 1; }
if(znak == '2') P funkcja 2; }
}
}
**************************
problem jest nastepujacy: dana sterujaca programem (znak) wysylam raz na jaksi czas, a w linijce char znak ... program przestaje byc wykonywany AŹ odbierze jakiś znak. Jak to rozwiązać? A może obsługa przerwania? Ale jak umieszcze jakiś kod w SIGNAL(SIG_UART_RECV) { kod } to sie wogóle nie wykonuje. Co robie źle?
Prosze o pomoc, z góry dziękuję i pzodrawiam.

tasza
Użytkownik
Posty: 1391
Rejestracja: 21 lut 2005, 15:02

Post autor: tasza » 04 gru 2006, 14:52

Zakładając, że masz taką funkcję USART_Receive() jak poniżej:

Kod: Zaznacz cały

unsigned char USART_Receive( void )  { 
    while ( !( UCSRA & (1<<RXC) ) ); 
    return UDR; 
}
to zauważ, że ona czeka w pętli while aż w buforze będzie gotowy znak do odebrania,
czyli ciągle obserwuje bit RXC rejestru UCSRA...

można spróbować coś takiego - to wersja nieczekająca:

Kod: Zaznacz cały

unsigned char USART_Receive_NoWait( void )  { 
    if  ( UCSRA & (1<<RXC) ) {
    	return UDR; 
    }
    else {
          return 0x00;
    }
}
funkcja zwróci 0x00 gdy znaczka jeszcze nie ma lub odebrany ostatnio znak
ale na nic nie będzie czekać, po prostu sprawdzi co jest w USART i poleci dalej...
doctor pisze: Ale jak umieszcze jakiś kod w SIGNAL(SIG_UART_RECV) { kod }
to sie wogóle nie wykonuje. Co robie źle?
a czy odblokowałeś przerwania?
tak globalnie oraz to, które jest zgłaszane przy odbiorze znaku przez USART?

tasza

doctor
-
Posty: 9
Rejestracja: 24 lip 2006, 18:06
Lokalizacja: Tarnowskie Gory

Odblokowlem

Post autor: doctor » 05 gru 2006, 12:55

Witaj, odblkokowalem przerwania. zrobilem to funkcja sei(), z tego co sie orientuje to jest to samo co SREG |= 1 << 7; Jeszcze cos, odczytalem rejestr SREG po wywolaniu sei(), wynosi 130d, czyli 10000010, 7 bit jest ustawiony, czyli globalnie przerwania sa odblokowane. Zaraz sprawdze ta funkcje no_wait, wielkie dzieki za nia. Dodam jeszcze ze probuje ten program w najprostszy sposob, tj chce aby po odebraniu 1 znaku przez USART zapalila sie dioda. Dolaczam moj kod programu, Pozdrawiam
Załączniki
signal.zip
Kod programu
(914 Bajtów) Pobrany 339 razy

tasza
Użytkownik
Posty: 1391
Rejestracja: 21 lut 2005, 15:02

Post autor: tasza » 05 gru 2006, 13:22

Kod: Zaznacz cały

SIGNAL(SIG_USART_RECV)
{
PORTA |= 1 << PA2; //powinno zapalac diode
_delay_ms(100);
}
ałć...no, to tak nie należy pisać, w procedurach obsługi przerwań ma być tylko to co niezbędne,
mają się wykonywać szybko i zwinnie, ponieważ jak 'ugrzęźniesz' w takim handlerku
jakimś delay-em ( jak u Ciebie _delay_ms(100); ) to jest szansa, że program nie zareaguje na nowe przerwanie...

najlepiej to chyba zrobić zapalającą/gasnącą co znaczek diodę, czyli coś takiego:

Kod: Zaznacz cały

unsigned char bLedState = 0;

SIGNAL( SIG_USART_RECV ) {
    bLedState ^= 1;
    if ( bLedState ) {
        PORTA |= (1 << PA2); //powinno zapalac diode
    } 
    else {
        PORTA &= ~(1 << PA2); //powinno gasić diode
    }
} // of SIGNAL
(piszę z głowy, sprawdź proszę czy to ruszy....)
i oczywiście diodka zapięta przez rezystor do masy...zapalana stanem H.

aha, w void USART_Init(unsigned int ubrr) brakuje mi zezwolenia, aby UART zgłaszał
przerwanie, jak odbierze znaczek...
czyli linijka

Kod: Zaznacz cały

UCSRB = (1 << RXEN) | (1 << TXEN);
powinna wyglądać tak:

Kod: Zaznacz cały

UCSRB = (1 << RXEN) | (1 << TXEN) | (1 << RXCIE);
no i jak korzystasz z przerwań, to wywołanie funkcji USART_Receive(); w petli for
jest niepotrzebne, zakomentuj je...

tasza

[ Dodano: 2006-12-05, 13:46 ]
na tej stronce: https://elportal.pl/index.php?module=Co ... y&ceid=145 masz źródła aplikacji,
która odbiera znaczki w przerwaniach: https://elportal.pl/tasza/lxt/led_tree_avr.zip
może też tam zerknij....

tasza

doctor
-
Posty: 9
Rejestracja: 24 lip 2006, 18:06
Lokalizacja: Tarnowskie Gory

Pomoglo

Post autor: doctor » 05 gru 2006, 13:53

Dziekuje za rady. juz sie dioda wlacza jak odbierze dowolny znaczek. Niestety nie idzie jej wylaczyc. Oto kod

***************
char bLedState = 0;

SIGNAL(SIG_USART_RECV)
{
bLedState = !bLedState;
if( !bLedState )
PORTA |= 1 << PA2; //powinno zapalac diode
else
PORTA &= ~(1 << PA2);
}
***************

wiem ze w winavr nie ma zmiennych boolowskich, sprubuje na intach jeszcze

tasza
Użytkownik
Posty: 1391
Rejestracja: 21 lut 2005, 15:02

Post autor: tasza » 05 gru 2006, 14:07

jak cytujesz kod, używaj proszę tagów CODE, dzięki...

no to tak:

Kod: Zaznacz cały

typedef unsigned char BOOL;
#define FALSE 0
#define TRUE  1

BOOL bLedState = FALSE; 

unsigned char anyChar = 0x00;

SIGNAL( SIG_USART_RECV )  { 

    //dodane...
    anyChar = UDR;

    bLedState ^= TRUE; // to co wywołanie zmieni się: true/false/true/false....   
 
    if( bLedState == TRUE ) {
        PORTA |= 1 << PA2; //powinno zapalac diode 
    }
    else {
        PORTA &= ~(1 << PA2); 
    }
}
i to powinno działać....

tasza

doctor
-
Posty: 9
Rejestracja: 24 lip 2006, 18:06
Lokalizacja: Tarnowskie Gory

No prawie juz

Post autor: doctor » 05 gru 2006, 14:15

Za to zrobilem program który klawiszem '5' zapala ta diode, a pozostalymi ja gasi. To juz mnie wlasciwie satysfakcjonuje, ale to ciekawe z jednej strony, bo w przykladzie wyzej tylko ja zapalal, wiec cos bylo ztypem zmiennej, mimo iz byla zadeklarowana globalnie.

*******************
unsigned char keycode;

SIGNAL(SIG_USART_RECV)
{
keycode = UDR;
if( keycode == '5')
PORTA |= 1 << PA2; //powinno zapalac diode
else
PORTA &= ~(1 << PA2);
}
*******************

Pozdrawiam

tasza
Użytkownik
Posty: 1391
Rejestracja: 21 lut 2005, 15:02

Post autor: tasza » 05 gru 2006, 14:33

http://www.atmel.com/dyn/resources/prod ... oc2503.pdf
strona 152, topic: Receive Complete Flag and Interrupt
reasumując: przy obsłudze odbierania w przerwaniach, trzeba w procedurze
obsługi odczytywać nadesłany znaczek z rejestru UDR, inaczej nie skasuje się
flaga RXC i nowe przerwanie wywoła się natychmiast po zakończeniu poprzedniego...
i to prawdopodobnie był problem....

oj, coś kiepsko ze mną :oops:

pa,
tasza

doctor
-
Posty: 9
Rejestracja: 24 lip 2006, 18:06
Lokalizacja: Tarnowskie Gory

Wszystko gra

Post autor: doctor » 05 gru 2006, 15:01

W datasheecie stoi:
przerwanie od USATR'a bedzie wykonywane tak długo dopóki flaga RXC jest ustawiona.
Mowiac prosciej należało po każdym wystąpieniu przerwania czytać rejestr UDR aby czyścić flagę RXC.

Dzięki wilelkie za pomoc Tasza, megaszacunek.

Pozdrawiam

ODPOWIEDZ