UART senden per interrupt mit atmega8

Gast #2822017
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.
#2822043
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.
#2822051
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.
Gast #2822137
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
Gast #2822139
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 ;-)
     }
}
Gast #2835570
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
}
#2835594
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
Gast #2838303
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.
#2839292
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

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren