PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : UART-Empfang von PC: Wieviel Zeit bleibt zum Verarbeiten?



cyberdennis
07.08.2007, 13:59
Hallo Leute,

ich empfange über den UART meines ATmega8 Daten vom PC mit 4800 Baud (asynchron via Interrupt). Der MC läuft mit 3,686MHz (externer Quartz).
Wenn ich viele Bytes gleichzeitig schicke gehen leider welche verloren, der ATmega empfängt nur den Anfang des Streams. Wenn ich in der Client-Anwendung nach jedem Byte ein Delay von 5ms einfüge funktioniert alles wunderbar.
Mein Verdacht ist nun, dass ich im Interrupt-Handler zu viele Zyklen verbrate. Frage: wie viele Zyklen stehen mir pro empfangenem Byte zur Verfügung? Bitte sagt mir, ob diese Rechnung richtig ist:
4800 Baud: 4800 interrupts pro Sekunde, 3686000 Zyklen/s
= ca. 768 Zyklen pro empfangenes Byte.
Das sollte locker reichen. Ich brauche maximal 200!

Fällt euch was dazu ein? Ich freue mich über jeden Hinweis!!!

Danke schonmal und viele Grüße,
Dennis

izaseba
07.08.2007, 14:56
4800 Baud: 4800 interrupts pro Sekunde
Bist Du Dir da sicher ?
Ich meine ein UART_RX Interrupt wird ausgelöst, wenn ein Byte empfangen wurde.

da Du 4800 Baud hast werden 4800 Bits in der Sekunde übertragen.
Wenn Du jetzt ein Start und ein Stop Bit noch mitschickst müssen insgesammt 10 Bits übertragen werden, also 4800/10 ergibt 480 Interrupts in der Sekunde

Tja mal schauen ob meine Rechnung stimmt ;-)

Gruß Sebastian

cyberdennis
07.08.2007, 15:28
Genau das war meine Frage: wie viele Interrupts habe ich pro Sekunde, unter den gegebenen Umständen? Ich würd es ja auch ausprobieren, kann aber kein on-device-debugging machen. Weiß es jemand sicher?

uwed
07.08.2007, 17:06
Die Rechnung von izaseba stimmt. In welcher Sprache programmierst du denn, bei meinem letzten Projekt hab ich mit 6MHz 38400 Baut empfangen ohne Probleme, allerdings in Assembler. Ich weis ja nicht was du machen willst, (lad dein Programm eventuell hoch), Wenn du nicht dauernd empfangen willst
nehm dir ein Anfangs und ein End zeichen z.B "[" "]" und kontrolliere das empfangene Byte auf diesen Askiiwert wenn es das Anfangszeichen ist setze einen Zeiger auf ein Array und schreibe die empangenen Werte nacheinander hinein. erst wenn dein Endzeichen kommt führst du die Große Operation aus.
villeicht hilfts ja.

Uwe

cyberdennis
07.08.2007, 17:12
Danke für eure Hilfe!
Das MC-Programm ist in Assembler geschrieben, deshalb kann ich sicher sagen, dass es zwischen 100 und 200 Zyklen braucht pro empfangenes Byte. Die Frage ist jetzt, warum ich clientseitig trotzdem ein Delay zwischen den Bytes brauche.
@Uwe: das mit dem puffern werde ich mal ausprobieren!

uwed
07.08.2007, 17:31
Um die Kleine Assemblerfront zu stärken. Hi Hi
Wenn du dirs etwas leichter machen willst, es ist sogar relatv gut dokumentiert. du musst die Variable Zeiger noch definieren Irgeneine Ram adresse die 0 als high byte hat (bei mir ist es ox70 gewesen). ind der steht dann der Wert an welcher Stelle des Strings er gerade ist, die länge ist glaub ich auf 15 begrenzt, dass nicht fer ganze Ram volgemüllt wird, wenn kein neues Startzeichen kommt. Musst du halt deinen Bedingungen anpassen ebenso wie das was er machen soll wenn er ein Abschlusszeichen empfängt.
ich schreibs als Text da ich das mit dem Programmkästchen nicht kann.

;Interuproutine für Serielle Schnittstelle
;-----------------------------------------------------------------
; Interruptroutine: wird ausgeführt sobald ein Byte über das UART empfangen wurde
;----------------------- ------------------------------


int_rxc:
push Temp ; temp auf dem Stack sichern
push temp1
push temp2



clr ZH
ldi ZL, Zeiger ;zum Laden Des Zeigers
ld temp2,Z
;-----------------------------------------------------------------
;Anfangszeichen Empfangen Pointer wird auf erste Stelle gesetzt
;-----------------------------------------------------------------
in Temp, UDR
cpi Temp, '['
brne Zahl
ldi temp2, 0x01 ;Wenn ein Klammer auf erkannt wird, wird der Zeiger auf 1 gesetz
;um die Klammer in 0x71 zu schreiben

Zahl:
cpi Temp, ']' ;die Position(im Programm) Zahl und Zahl1 bedeuten dass
brne Zahl1 ; kein Steuerzeichen empfangen wurde
;-----------------------------------------------------------------
;Abschlusszeichen Empfangen Wert wird errechnet
;-----------------------------------------------------------------

clr ZH
ldi ZL,String1 ;Anfangswert des Zu Berechnenden Registers
rcall Dezimalstring5 ;die Umrechnung wird 2x mit den jeweiligen Adressen aufgerufen

sbrs Temp,0 ;Da Dezimalstring wenn die Umrechnung gültig ist eine 1
rjmp ERROR_Konvert ;in Temp zurückgibt wird diese Überprüft
ldi ZL,Wert1H ;wenn die eins nicht kommt wirde Error ausggeben
st Z+,Erg1
st Z,Erg0

ldi ZL,String2 ;Anfangswert des Zu Berechnenden Registers
rcall Dezimalstring5

sbrs Temp, 0 ;Da Dezimalstring wenn die Umrechnung gültig ist eine 1
rjmp ERROR_Konvert ;in Temp zurückgibt wird diese Überprüft
ldi ZL,Wert2H ;wenn die eins nicht kommt wirde Error ausggeben
st Z+,Erg1
st Z,Erg0




; rcall Senden ;kann Zur Kontrolle aktiviert werden
rcall Dig_out ;gibt den Empfangenen String mit errechneten werten zurück

rjmp int_rxc_end ;wenn die Rechnung erfolgt ist, wird die Berechnung beendet

;-----------------------------------------------------------------
; Zahl Empfangen
;-----------------------------------------------------------------

Zahl1: add ZL,temp2 ;Wenn kein Steuerzeichen erkannt Wurde, wird der Zeiger
st Z,Temp ;zum Zpointer addiert und der empfangene
;Wert dort abgelegt
inc temp2 ;dann Wird der Zeiger incrementier und wieder gesichert
cpi temp2,0x0F ;Es wird Überprüft ob der Zeiger größer als 15 ist,
brlo Zeiger_OK ;falls dies der Fall ist wird er wieder decrementiert
dec temp2 ;um zu verhindern dass er den ganzen RAM beschreibt, ab dann
;wird nur noch die Speicherzelle String1+Zeiger Beschrieben
Zeiger_OK: ;bis wieder ein "[" ankommt
ldi ZL,Zeiger ;
st Z,temp2


int_rxc_end:
pop temp2
pop temp1
pop temp


reti O:) O:)

cyberdennis
07.08.2007, 17:49
Cool, danke! Ich werd das testen, um erstmal zu sehen, ob der Fehler überhaupt in meinem Assemblerprogramm steckt oder evtl. doch im PC-Programm.
Grüße
Dennis

cyberdennis
08.08.2007, 10:10
So, Fehler gefunden!
Beim Abzählen der benötigten Prozessorzyklen habe ich mich verrechnet.
Nach jedem empfangenen Byte habe ich erstmal eine Log-Message mit 5-10 Zeichen/Bytes auf die serielle ausgegeben - synchron!! Dass das Ausgeben auch abhängig von der Baudrate ist habe ich fröhlich unter den Teppich gekehrt. Deshalb ist alles durcheinandergekommen.
Jetzt bin ich schlauer und gebe nur noch max. ein Byte aus ;)