Forum: Mikrocontroller und Digitale Elektronik UART senden per interrupt mit atmega8


von tobi (Gast)


Lesenswert?

Hallo ich bin gerade danbei ein wenig mit der UART herumzuspielen und 
nutze dazu den atmega8

ich habe nun eine Frage ich möchte per interrupt senden

kann ich dazu folgendes machen:
1
 
2
#include "interrupt.h"
3
unsigned char  character;
4
5
void sendCharByInt(unsigned char);
6
7
8
9
void sendCharByInt(unsigned char sendchar){
10
UCSRA =(1<<TXC);
11
character=sendchar;
12
}
13
14
ISR (TXC_Vector ){
15
16
UDR = character;
17
18
}
19
sendCharByInt
20
main(){
21
while(1){}
22
23
}

würde das gehen?

falls ich irgendwo ein Zeichen vergessen haben sollte oder der vektor in 
der ISR nicht 100%tig stimmt bitte ich mir das nachzusehen. Manche Leute 
suchen hier "schönheitsfehler" in den posts damit sie was zu meckern 
haben.

von tobi (Gast)


Lesenswert?

tobi schrieb:
> sendCharByInt

 der Aufruf soll natürlich in die main inklusive  eines Zeichens z.B.

sendCharByInt('a');

von H.Joachim S. (crazyhorse)


Lesenswert?

Hm, bringt irgendwie nichts...
Ohne Sendepuffer kannst du gleich beim polling bleiben.

von tobi (Gast)


Lesenswert?

H.joachim Seifert schrieb:
> Hm, bringt irgendwie nichts...
> Ohne Sendepuffer kannst du gleich beim polling bleiben.

aber ist mein sendepuffer quasi nicht die globale variable?
müsste sie vll auch noch als synchronized definieren fällt mri gerade 
ein aber ansonsten müsste es doch gehen oder

von Karl H. (kbuchegg)


Lesenswert?

tobi schrieb:
> H.joachim Seifert schrieb:
>> Hm, bringt irgendwie nichts...
>> Ohne Sendepuffer kannst du gleich beim polling bleiben.
>
> aber ist mein sendepuffer quasi nicht die globale variable?
> müsste sie vll auch noch als synchronized definieren fällt mri gerade
> ein aber ansonsten müsste es doch gehen oder

Schon. Aber was bringts?

Per Interrupt senden macht dann Sinn, wenn du einen String verschickst. 
Den String schiebst du in einen globalen Buffer, das erste Zeichen ins 
UDR und wenn der UART wieder ein Zeichen aufnehmen kann, meldet er sich 
mit einem Interrupt 'Ich brauch wieder Daten'. In der ISR schiebt man 
dann das nächste Zeichen ins UDR.

Für ein einzelnes Zeichen bringt das nichts.

von H.Joachim S. (crazyhorse)


Lesenswert?

Überleg mal, was du da machst:
-Du willst ein Byte senden
-übergibst dieses Byte an eine Funktion
-diese tut nichts anderes, als das Byte in eine globale Variable zu 
schreiben und den Interrupt freizugeben
-nun kommt der Interrupt, holt sich dieses Byte und sendet es

Wo ist der Nutzen? Kannst es auch gleich ins UDR schreiben, der Interupt 
bringt dir gar nichts.

Überlicherweise verwendet man einen Ringbuffer. Die Ausgaberoutinen 
schreiben in diesen Buffer. Ein TxC-Interrupt schaut nach, ob es noch 
was zu senden gibt. Wenn ja das nächste Byte holen. Wenn nein fertig.
Dazu braucht man 4 Variablen. Den Buffer selbst  (Grösse nach Bedarf), 
einen Schreib- und einen Lesezeiger sowie einen Zähler der noch zu 
sendenden Bytes.
Nebenbei musst du noch aufpassen, dass der Buffer nicht überläuft.

von tobi (Gast)


Lesenswert?

Karl Heinz Buchegger schrieb:
>> H.joachim Seifert schrieb:
> Schon. Aber was bringts?
>
> Per Interrupt senden macht dann Sinn, wenn du einen String verschickst.
> Den String schiebst du in einen globalen Buff wieer, das erste Zeichen ins
> UDR und wenn der UART wieder ein Zeichen aufnehmen kann, meldet er sich
> mit einem Interrupt 'Ich brauch wieder Daten'. In der ISR schiebt man
> dann das nächste Zeichen ins UDR.
>
> Für ein einzelnes Zeichen bringt das nichts.

Ok das mir dem einzelnen char war vll ungeschickt. Im prinzip wollte ich 
es so machen wie heinz geschrieben hat. Wollte erstmal nur das einfache 
bsp wählen

von tobi (Gast)


Lesenswert?

Es würde also auch folgendes gehen
1
unsigned char characerArr[9]

Im aufruf dann zb:
1
SendStringByInt("test");
2
Für
3
SendStringByInt(chararray temparr){
4
Characterarr temparr;
5
Udsra | (1<< txc);
6
7
}
8
9
ISR (TXC_vector){
10
int i=0;
11
If(!characterArr[i]){
12
    /* mir fällt der name vom bit im register des atmega8 nicht ein deswegen busybit */
13
     If(!busybit){
14
         UDR = characterArr[i];
15
        i=i+1;}
16
}
17
}

Würde das gehen?

Auch hier bitte ich ein wenig um nachsicht, bin mit handy on ;-)
     }
}

von Na Sowas (Gast)


Lesenswert?

Da fehlt noch einiges. Der letzte Vorschlag zB kann keine Null senden. 
Na gut, vielleich muss man auch nicht. Aber busy ist das Uart sicher 
nicht, sonst gaebs ja keinen Interrupt

von Na Sowas (Gast)


Lesenswert?

Und der Zaehler i muss natuerlich global sein

von Sascha W. (sascha-w)


Lesenswert?

und das erste Byte muss man immer außerhalb der ISR in UDR schreiben, da 
die ISR nur auslöst wenn der Puffer leer wird und nicht wenn er schon 
leer ist.

Sascha

von Tobi L. (Gast)


Lesenswert?

habe leider keinen atmega 8 zur stelle da ich längere zeit bei meiner 
freundin bin wie sieht das hiermit aus??
1
#define MaxTxLen 12;
2
3
char globalArr[MaxTxLen];
4
5
SendStringByInt("test");
6
unsigned int i=0;
7
8
9
SendStringByInt(char temp[]){
10
unsigned int cnt;
11
    for(cnt = 0;cnt < sizeof(temp) ; cnt++){
12
    globalArr[cnt] = temp[cnt];
13
    }
14
    UDR = globalArr[0];  
15
  cnt=cnt+1;
16
}
17
18
ISR (USART_TXC_vect){
19
(!(UCSRA & (1<<UDRE))){}
20
cnt=cnt+1;
21
UDR=globalArr[cnt];
22
}

von Sascha W. (sascha-w)


Lesenswert?

Tobi L. schrieb:
> habe leider keinen atmega 8 zur stelle da ich längere zeit bei meiner
> freundin bin wie sieht das hiermit aus??

Also zunächst muss cnt natürlich auch außerhalb von SendStringByInt 
verfügbar sein und da er auch in der ISR verwendet wird volatile!

Des weiteren brauchst du in der ISR eine Erkennung wenn alle Bytes 
versendet sind, also entweder ein /0 im Puffer wenn du nur Text 
versendest oder du musst dir die Länge merken oder cnt muss rückwärts 
zählen.

Als ISR ist der UDRE-INT zu verwenden, denn der löst aus wenn Platz im 
UDR ist, damit entfällt die Warteschleife (die in einer ISR sowieso blöd 
ist).
Achtung wenn das Senden beendet ist den UDRE-INT (UDRIE in UCSRB) wieder 
ausschalten!

Sascha

von Tobi (Gast)


Lesenswert?

Sascha Weber schrieb:



>Als ISR ist der UDRE-INT zu verwenden

den wollte ich ebenfalls zu erst verwenden^^

> Achtung wenn das Senden beendet ist den UDRE-INT (UDRIE in UCSRB) wieder
>
> ausschalten!

habe es dann aber aus dem grund nicht getan^^..

ist die frage was "besser" ist

von Tobi (Gast)


Lesenswert?

>Also zunächst muss cnt natürlich auch außerhalb von SendStringByInt
>verfügbar sein und da er auch in der ISR verwendet wird volatile!

damit hast du natürlich vollkommen recht! hab mal eben schnell das brett 
vorm kopf entfernt.

von Sascha W. (sascha-w)


Lesenswert?

Tobi schrieb:
> ist die frage was "besser" ist

wenn du den TXC nimmst, wird die ISR erst aufgerufen wenn das Zeichen 
fertig versendet ist, obwohl du ja während ein Zeichen raus geht das 
nächste schon in UDR reinschreiben kannst (1-Byte-FIFO). Nutzt du den 
UDRE bleibt der Puffer immer gefüllt und die Ausgabe macht keine 
"Pausen", die sonst durch den Aufruf der TXC-ISR nach dem Senden 
entstehen.
Hab noch mal im Datenblatt geschaut, es scheint so zu sein, das bei 
leerem UART-Puffer die UDRE-ISR wenn der INT freigegeben ist immer 
wieder aufgerufen wird. Dann sollte es eigentlich gegen, den Sendepuffer 
zu befüllen, und anschließend den UDRE freizugeben. Die Befüllung des 
UDR würde dann nur in der ISR erfolgen.
Wichtig - nach dem freischalten des UDRE nichts mehr verändern was auch 
in der ISR benötigt wird, da ja nach dem freischalten sofort die ISR 
angesprungen wird.

Sascha

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.