In meinem BootLoader speichere ich die Zeichen ab die ich über die RS232
bekomme. Da geht auch recht gut. Nun habe ich mir mein Programm noch mal
angeschaut und bin der Meinung das ich das Abspeichern umständlich
mache.
lds Dummy1,RS232Zeiger ; den RS232-Zeiger aus dem Speicher holen
8
inc Dummy1 ; Zeiger um eins weiterschieben
9
cpi Dummy1,69 ; Auf Speichergrenze von 68 Byte testen
10
brne SOK ; Noch keine 20 Byte
11
ldi Dummy1,1 ; 68 Byte überschritten wieder bei 1 anfangen
12
SOK:
13
sts RS232Zeiger,Dummy1
14
ZeigerStellen:
15
adiw xl:xh,1 ; Zeiger erhöhen
16
dec Dummy1
17
brne ZeigerStellen
18
st x,EZeichen
19
rjmp EndeInRs232
Umständlich finde ich es den Zeiger mit adiw xl:xh,1 in einer Schleife
hoch zu zählen. In Dummy1 steht der Wert um wieviel der Zeiger erhöht
werden muss.
Ich komme einfach nicht darauf. Könnte mir jemand auf die Sprünge
helfen?
Hi
>erhöht automatisch nach dieser ausführung den Zeiger um eine Position!
Hatte ich auch gedacht (nicht richtig gelesen). Das von Dussel (Gast)
passt schon.
MfG Spess
Geschickter ist es, den Speicher von RS232Buffer so zu definieren, dass
kein Überlauf im High-Byte stattfinden kann. Rs232Zeiger enthält dann
direkt das Low-Byte der Adresse. In etwa so:
Also in RS232Zeiger habe ich die Anzahl der schon empfangenden Zeichen
und in RS232Buffer sind die Zeichen.
Bekomme ich nun ein Zeichen so speichere ich das in den
RS232Buffer+RS232Zeiger.
Mein RS232Buffer liegt bei 0x0101
Mein RS232Zeiger liegt bei 0x0100
Kommt das erste Zeichen schreibe ich in RS232Zeiger die 1
Danach setze ich x auf RS232Buffer-1
Danach zähle ich Rs232Zeiger runter bis es null ist
bei jedem dec erhöhe ich x
Also: Erste Zeichen
RS232Zeiger=1
RS232Buffer=0x0100
Loop:
RS232Zeiger-1
RS232Buffer+1
RS232Zeiger=0 ZeichenSpeichern in RS232Buffer
RS232Zeiger nicht 0 gehe zu Loop
Somit kommt das Zeichen immer an die richtige stelle.
Nur wenn ich schon 50 Zeichen abgespeichert habe. So muss ich beim
nächsten zeichen 51 mal die schleife durchlaufen das kostet doch Zeit.
Hier wollte ich eigentlich
adiw xl:xh, RS232Zeiger machen. Was aber nicht geht :-(
Hi
>Hier wollte ich eigentlich>adiw xl:xh, RS232Zeiger machen. Was aber nicht geht :-(
Na dann mache es doch so:
Beitrag "Re: Kurze Hilfe in ASM"
MfG Spess
Ahh mit add xl,Dummy1 erhöhe ich XL um den wert Dummy1. Sollte dabei ein
Übertrag entstehen so wird dieses durch adc xh,rxx übernommen da rxx 0
ist und das Carry gesetzt. Ergab es kein übertrag ist rxx 0 und kein
Carry. Richtig?
clr Dummy2
ldi Dummy1,RS232Zeiger
ldi xl,low(RS232Buffer) ; X Pointer laden
ldi xh,high(RS232Buffer)
so ist x=0x0100
Nehmen wir an Dummy1 (RS232Zeiger) wäre 0x44 so würde
add xl,Dummy1 = 0x44 sein
adc xh,Dummy2 = 0x01 da kein Übertrag entstanden ist
Richtig?
Hi
>Die schnellste und kürzeste form den Ringspeicher zu füllen?> ldi xl,low(RS232Buffer-1) ; X Pointer laden> ldi xh,high(RS232Buffer-1) ;> ...> ldi Dummy1,1
Warum fängst du nicht, wie allgemein ülich, bei Null an?
MfG Spess
spess53 schrieb:> Warum fängst du nicht, wie allgemein ülich, bei Null an?
Weil ich doch mein Zeiger erhöhe und somit min. eine 1 darin steht. Um
nun auf RS232Buffer zu kommen muss ich doch wegen dem add eins weniger
haben.
Klaus2m5 schrieb:> Nein! - aber Deine Aufgabenstellung ist erfüllt.
Wie könnte ich es noch besser machen.
Hi
>Weil ich doch mein Zeiger erhöhe und somit min. eine 1 darin steht. Um>nun auf RS232Buffer zu kommen muss ich doch wegen dem add eins weniger>haben.
Dann erhöhe den Zeiger nach dem addieren.
MfG Spess
Macht von der Geschwindigkeit und vom Speicherplatz aber nix aus.
Geht das ganze, ein empfangendes Zeichen in einen Ringbuffer zu
schreiben noch kürzer bzw. noch schneller?
Hi
Mal andersherum gefragt: An welcher Stelle siehst du ein Problem. Der
Code-Teil wird, bei 8 MHz, in ca. 2µs abgearbeitet. Bei 9600Bd dauert
ein Zeichen ca. 1ms.
MfG Spess
Holger P. schrieb:> Macht von der Geschwindigkeit und vom Speicherplatz aber nix aus.>> Geht das ganze, ein empfangendes Zeichen in einen Ringbuffer zu> schreiben noch kürzer bzw. noch schneller?
Ja - aber für RS232 spielt das jetzt nicht wirklich eine Rolle, es sei
denn, Du arbeitest mit sehr hohen Baudraten und niedriger AVR-Clock.
Den Ringpuffer zu füllen, ist allerdings noch nicht mal die halbe Miete.
Du musst den Ringpuffer ja auch leeren und vor Überlauf schützen. Wenn
es dann klemmt, kannst Du Dir immer noch Gedanken über Optimierungen
machen.
So wie ich das nun getestet habe, lief mein Code auch gut im BootLoader.
Als ich aber diese Speicherung in meinem Hauptprogramm eingesetzt habe
musste ich feststellen das wenn ich eine Zeichenkette aus dem PC
versende z.B. "LED gelb an" dieser Satz nicht im Buffer stand.
Wenn ich aber "L" "E" "D" " " "g" "e" "l" "b" " " "a" "n" tippte ging
das.
Alos hinter einander senden der Buchstaben geht. Als String nicht. Was
mir sagte das meine Routine wohl zu langsam ist. Bei einer Baudrate von
38400. Also schaute ich mir mein Code an und dachte das da was zu machen
sei.
War es auch und ich habe mein fehler verstanden.
Jetzt frage ich mich ob es noch schneller geht.
Hi
> Als String nicht. Was>mir sagte das meine Routine wohl zu langsam ist. Bei einer Baudrate von>38400. Also schaute ich mir mein Code an und dachte das da was zu machen>sei.
Wozu braucht man dafür 38400Bd?
MfG Spess
Hi
>Ich möchte eine schnelle Kommunikation zwischen PC->µC und 38400 ist>schneller als 19200 :-)
Und du meinst du merkst das. Benutzt du den RX-Complete-Interrupt? Wenn
nicht, hängt es wahrscheinlich an einer ganz anderen Stelle.
MfG Spess
Holger P. schrieb:> Denke ich mir schütze ich den Buffer vor dem Überlauf.>> Leeren tu ich den Buffer so
Das ist natürlich kein Ringpuffer. Ich frage mich allerdings, wozu Du
beim Empfang bei mehr als 68 Bytes wieder auf den Anfang des Puffers
schreibst? Das ist dann der Überlauf und vorher Empfangenes würde
überschrieben.
Klaus 2m5 schrieb:> Das ist dann der Überlauf und vorher Empfangenes würde>> überschrieben.
Jo genau und somit das gesendete ungültig.
Sendet der PC "LED gelb an"+chr(13) schreibe ich alles was kommt in
diesen Buffer. Kommt Enter werte ich den Buffer aus und vergleiche auf
hinterlegte befehle. Geht gut!. Kommt "LED gelb an und das sehr schnell
auf los geht es los 123456789012345 alles klar" so steht im Buffer " und
das sehr schnell auf los geht es los 123456789012345 alles klar" und der
vergleich mit "LED gelb an" geht schief. Genauso alles andere was von
"LED gelb an" abweicht.
So habe ich unter
.db "LED gelb an"
.db "LED rot an"
.db "LED gelb aus"
u.s.w.
meine Befehle gelegt und vergleiche wie getippt den Buffer mit den
Wörtern nachdem ich ein ENTER bekommen habe welches ich nicht
abspeicher.
spess53 schrieb:> Benutzt du den RX-Complete-Interrupt?
reti ; $011 SPI Serial Transfer Complete
rjmp InRS232 ; $012 USART Rx Complete
reti ; $013 USART, Data Register Empty
ja diesen benutze ich
Holger P. schrieb:> Jo genau und somit das gesendete ungültig.
O.K. - ungewöhnlich, aber kann man so machen. Hat mich nur dazu
verleitet, zu glauben, dass es sich um einen Ringpuffer handelt.
Nungut so benutzte ich das falsche Wort. Sorry bin halt noch Anfänger.
Aber zurück zu meiner Frage:
Schneller geht das abspeichern nicht oder? Das ist jetzt schon Optimal
so?
Hi
>Habe ich in dem Interupt nicht für notwendig empfunden. Ist es das? Bei>Ja warum?
Das ist eine der wichtigsten Sachen. Stell dir mal vor, das der
Interrupt zwischen den beiden Befehlen ausgelöst wird:
cpi r16,5
breq blabla
Und jetzt überlege, was passiert wenn der Interrupt das Z-Flag (befindet
sich in SREG) ändert.
MfG Spess
Leuchtet mir ein das es knallt. Aber ich mache doch nix in meinem Loop
ODER kann ein ; $012 USART Rx Complete auch ausgelöst werden wenn ich in
der Routine bin?
Das würde eventuell erklären warum ich Zeichen verliere wenn ich sie an
einem Stück aussende. So müsste ich den Interrupt ausschalten wenn ich
in der abarbeitung des Interrupt's bin.
Aber das SReg zu sichern in diesem fall will mir noch nicht einleuchten.
Klar vorsorge tragen damit bei einer erweiterung keine Probleme kommen
können. Aber so zum spielen?
Nein ich benutze noch die Internen 8Mhz.
Zu dem was du mir geschrieben hast.
Das ganze Auswerten ausserhalb des Interrupts zu machen denke ich ist
keine gute Idee.
Wenn ich es im Interrupt mache sind weitere Interrups erst mal gesperrt
und mir kann nix dazwischen hauen. Würde sonst ein Zeichen gesendet in
der Zei ich den Buffer durchsuche könnte es ja sein das schon wieder was
andere drin steht.
In deinem Beispiel schaust du auch nicht ob ich mehr als 69 Zeichen im
Buffer habe. Wobei mir klar ist das dieses keine fertige lösung sein
soll sondern nur ein aufzeigen wie ich es auslagere.
Also besten Dank.
Warum ich Zeichen verliere wenn ich es im PC auf ein schlag versende
verstehe ich noch nicht. Sende ich zeichen für Zeichen aus einer
Schleife aus dem PC geht alles
Also ein ComPort1.WriteStr(Dummy); geht nicht
Wobei ein
For I:=1 to Length(Dummy) do
begin
ComPort1.WriteStr(Dummy[I]);
end;
Super geht.
Mein Progrämmelchen läuft klasse ohne Problem geht alles 100%
Danke
P.S. Nun ist aber schluss mit der Spielerei, suche jetzt mal ein
richtiges Projekt.
UART habe ich glaube ich verstanden.
SPI habe ich glaube ich verstanden.
ADC habe ich glaube ich verstanden.
SRam, EEPROM und Flash habe ich glaube ich verstanden.
I/O natürlich auch.
Was noch fehlt ist PWM und I2C. PWM weiß nicht ob das so interessant ist
i2C fehlen mir noch geräte die ich damit steuern könnte.
Hast du eine Idee?
Hi
>Nein ich benutze noch die Internen 8Mhz.
Du liebst Glücksspiele. Damit bekommst du keine dauerhaft stabile
Verbindung.
>In deinem Beispiel schaust du auch nicht ob ich mehr als 69 Zeichen im>Buffer habe.
Wie kommst du eigentlich auf die 68? Mit 2er-Potenzen geht manches
leichter:
1
RS232Buffer: .Byte 64
2
3
.cseg
4
....
5
inc Dummy1
6
andi Dummy1,0b11000000 ; kann nicht größer 63 werden
Wie groß können eigentlich am Stück gesendet Strings werden?
>Also ein ComPort1.WriteStr(Dummy); geht nicht>Wobei ein> For I:=1 to Length(Dummy) do> begin> ComPort1.WriteStr(Dummy[I]);
MfG Spess
> end;
Sieht nach Delphi aus. Welch Komponente benutzt du?
Ja aber wenn es 68 Byte sind soll es wieder bei 0 anfangen. Die 68 Byte
habe ich von meinem BootLoader übernommen. 2Byte für die Pageadresse
64Byte für die Daten und 2Byte für den CRC.
Ja es ist Delphi habe ich bei einem Bekannten bei dem ich eine Art
Praktikum mache. Dort habe ich es auf einem PC, leider nicht daheim. Es
ist die Version Delphi 4. Die Komponente ist die TComPort component ver.
2.01 von Dejan Crnila
Holger P. schrieb:> Warum ich Zeichen verliere wenn ich es im PC auf ein schlag versende> verstehe ich noch nicht. Sende ich zeichen für Zeichen aus einer> Schleife aus dem PC geht alles
wenn du die Zeichen einzeln sendest, dann kann sich der AVR bei jedem
Zeichen anhand des Startbits synconisieren und die Abweichung die durch
die Ungenauigkeit des interen Oszillators entsteht ist auf die 10Bit
vernachlässigbar. Sendest du aber eine größere Anzahl nacheinander, so
werden die Bits alle mit der syncronisation des 1.Startbits eingelesen
und die Abweichung wird bei jedem Byte größer bis Fehler kommen. Du
solltest in deiner ISR die Fehlerbits (OVR,FE) auswerten.
> Das ganze Auswerten ausserhalb des Interrupts zu machen denke ich ist> keine gute Idee.> Wenn ich es im Interrupt mache sind weitere Interrups erst mal gesperrt> und mir kann nix dazwischen hauen. Würde sonst ein Zeichen gesendet in> der Zei ich den Buffer durchsuche könnte es ja sein das schon wieder was> andere drin steht.
eher umgekeht - wenn du die eingehenden Zeichen nicht aus dem UDR
ausliest und abspeicherst gehen sie verloren! Der AVR kann nur eine
Byte puffern.
Sascha
Sascha Weber schrieb:> eher umgekeht - wenn du die eingehenden Zeichen nicht aus dem UDR>> ausliest und abspeicherst gehen sie verloren! Der AVR kann nur eine>> Byte puffern.>>>> Sascha
Ich habe ja ein Buffer und fülle diesen. Kommt der Abschluss so werte
ich den Buffer in dieser Routine gleich aus. Damit mir der Buffer nicht
versaut wird.
Aber das mit den Zeichen einzeln und auf einmal versenden leutet mir
ein. Werde es mal mit einem Externen Clock versuchen. Danke.