PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : UART mit INTERRUPT in C



Nemesis
05.10.2007, 16:18
Hi,

ich habe ein echtes Problem mit dem UART. Ich möchte Daten zwischen meinem PC und dem Atmega 32 austauschen.

Da ich nicht möchte das der Atmega 32 in der schleife fest steckt bis er etwas über die Comport Leitung vom PC empfängt. Dachte ich mir das ich das mit einem Interrupt versuche.

Ich kann den Interrupt jedoch nicht aktivieren/einstellen.
Hab schon alles mögliche versucht aber nix ging.

Hab dann auch etwas auf der roboternetz Seite gefunden das einem zeigt wie genau mann vor zu gehen hat. Um mit dem UART-Interrupt arbeiten zu können.

Das soll dann so fuktionieren:
1) Konfiguriere Interrupt
2) generell Interrupts zulassen
3) schalte speziell den InterruptXXX ein
4) verzweige bei InterruptXXX zu SprungXXX

Das ganze ist hier zu finden:
https://www.roboternetz.de/wissen/index.php/Bascom_Interrupts

Mit den Punkten 1 und 3 komme ich nicht zurecht hab keine ahnung wie mann das macht.
Mein Programm sieht etwa so aus:


#include <avr/io.h>
#include <avr/interrupt.h>
#define USART_RXC_vect _VECTOR(14)

#include <avr/delay.h>

/* USART-Init beim ATmega16 */
#ifndef F_CPU
#define F_CPU 16000000 /* Oszillator-Frequenz in Hz */
#endif
// Hilfsmakro zur UBRR-Berechnung ("Formel" laut Datenblatt)
#define UART_UBRR_CALC(BAUD_,FREQ_) ((16000000)/((19200)*16L)-1)
#define UART_BAUD_RATE 19200


char c = 97;
int main(void)
{
///////////////////////////////////////////interrupt für uart einstellen
/*1*/
/*2*/sei();
/*3*/
/*4*///steht oben
////////////////////////////////////////////

///////////////////////////////////////////UART einstellungen
UCSRB |= (1<<TXEN); // UART TX einschalten
UCSRC |= (1<<URSEL)|(3<<UCSZ0); // Asynchron 8N1
UBRRH = (uint8_t)( UART_UBRR_CALC( UART_BAUD_RATE, F_CPU ) >> 8 );
UBRRL = (uint8_t)UART_UBRR_CALC( UART_BAUD_RATE, F_CPU );
//////////////////////////////////////////////////

while(c != 300)
{
UCSRB |= (1<<TXEN); // UART TX einschalten
UDR = c;
_delay_ms(200);
}
}

ISR(USART_RXC_vect) /* veraltet: SIGNAL(SIG_UART_RECV) */
{
while (!(UCSRA & (1<<RXC))) // warten bis Zeichen verfuegbar
c = UDR;
}

Zum Code(so soll es sein):
Ich schicke zu beginn ein kleines a vom controller zum PC (welches ich auch ohne Probleme am PC empfangen kann), danach sende ich ein irgent ein zeichen z.b. ein x vom PC zum Controller. Dieses Zeichen soll der Controller dann mit hilfe des Interrupts aufnehmen(damit er nicht in der Schleife für das Daten Empfangen fest hängt) und dann wieder zum PC zurück schicken.

Das einziegste was der Controller macht, ist mir immer nur das a zu schicken.

Ich hoffe es kann mir jemand dabei helf damit es richtig funktioniert.

Gruß Nemesis

gummi_ente
05.10.2007, 16:37
Hallo nemesis,

hier ist eine gute Anleitung zum Compiler und zum AVR:
http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial

Grüße

izaseba
05.10.2007, 16:40
Hallo,
wie willst Du was empfangen, wenn Du den Empfänger nicht einschaltest ;-)

das geht so,


UCSRB = (1<<RXEN)|(1<<TXEN)|(1<<RXCIE);

Jetzt kannst Du senden,empfangen und der Interrupt ist eingescheltet, der für den Empfang zuständigt ist.
Im einfachstem Fall machst Du ein Echo:


ISR (USART_RXC_vect) {
uint8_t tmp = UDR;
UDR = tmp;
}
Du brauchst hier auf nichts zu warten, weil das Zeichen schon da ist ;-)
Wichtig ist nur, das UDR auch ausgelesen wird!
willst Du aus dem Hauptprogramm was senden, mußt Du UDRE testen:


while(!(UCSRA & (1<<UDRE)));
UDR = 'a';

Gruß sebastian

Nemesis
05.10.2007, 18:03
Hallo Sebastian,

hab eben ausprobiert was du geschrieben hast und nun funktioniert es.
Da rauf wäre ich so schnell wohl nicht gekommen, vielen dank.

Allerdings gibt es noch ein kleines problem. Und zwar habe ich eine globale Variable "char c = 'a'; ". Wenn der Interrupt ausgelöst wird, wird das Hauptprogramm gestopt und der Controller sprinkt in die Funktion vom Interrupt.
In dieser Funktion lasse ich mir dann das Zeichen welches ich vom PC gesendet habe (z.b. x) zurück zum PC schicken. Wie schon gesagt das klappt jetzt bestens. Aber ich möchte das das x nun das a in der Variablen c ersetzt. Das funktioniert jedoch nicht und ich hab keine ahnung warum nicht.

Vielleich hat dafür jemand ne Lösung.

Gruß Nemesis

uwegw
05.10.2007, 18:07
Ist c als volatile deklariert?

Nemesis
05.10.2007, 18:29
Hab zwar keine ahnung was volatile macht aber nun geht alles. O:)

izaseba
05.10.2007, 18:38
Das ist aber schlecht,
Als (angehender) C Programmierer sollte man es schon wissen ;-)

Zugegeben, bei PC Programmierung sieht man volatile seltener, aber google hilft hier weiter:
http://www.google.com/search?client=opera&rls=en&q=volatile+%2Bc+programmierung&sourceid=opera&ie=utf-8&oe=utf-8
wühl Dich da mal durch...

Gruß Sebastian

uwegw
05.10.2007, 18:39
volatile sagt dem Compiler, dass die Variable von anderen Stelle aus geändert werden kann. Es greifen ja das Hauptprogramm und der Interrupt darauf zu. Ohne volatile denkt der Compiler, dass die Variable immer gleich bleibt, wenn sie nicht im Hauptprogramm geändert wird. Er lädt sie darum zb nicht immer aus dem RAM, sondern puffert sie vielleicht in einem Register. Wenn das Hauptprogramm nie was an c ändert, kann der Compiler daraus sogar ne Konstante machen. Egal wie er hier optimiert, das Ergebnis ist, dass das Hauptprogramm nicht mitbekommt, dass im Speicher für c schon ein neuer Wert steht.

Nemesis
05.10.2007, 19:01
Naja bin eigentlich E-Techniker und hatte erst 2 Semester C-Programmierung.
Doch da kam sowas nicht vor. Aber gut das ich es nun weis.

Ihr habt mir Heute echt gut und schnell geholfen vielen Dank nochmal.

Gruß Nemesis

roboterheld
06.10.2007, 12:11
....Zugegeben, bei PC Programmierung sieht man volatile seltener, .....

es ist keine schande , wenn man nicht weiss, wo man volatile setzen muss.
auch c-fachleute scheitern daran, weil jeder c-compiler die werte anders handhabt. mal bleiben die werte der variablen erhalten, mal sind sie weg...lol... das ist c.

gerade das scheiss winavr-c lässt ein manchmal im stich, hier ist es angebracht, fast alles volatile zu setzen um diese fehlerquelle erst einmal auszuschliessen.


mfg

izaseba
06.10.2007, 12:37
Aha, unser Troll meldet sich wieder zu Wort...
Ich hab Dir schon einmal gesagt, wenn man keine Ahnung hat, soll man mal die Fresse halten !

Gruß Sebastian

P.S.
Deine Art erinnert mich an einen User, der Küchenbretter mag, und schon zweimal gesperrt wurde, bist Du etwa seine Reinkarnation ?