Hallo,
Ich habe ein kleines Problem mit meiner seriellen Schnittstelle. Und
zwar sende ich einen String von einem Terminalprogramm in meinen µC.
Dort angekommen wird dieser in einer Variable gespeichert und sofort
wieder an das Terminal zurückgegeben. Nur unterscheidet sich der
gesendete String sehr vom empfangengen, obwohl diese identisch sein
müssten. Es ist, als ob der µC den String "durcheinander würfelt". Auch
die Länge stimmt nicht überein. Was könnte da sein?
Ich programmiere den ATmega8 in BASCOM!
Vielen Dank für eure Hile!!
mfg
Andy
> Was könnte da sein?
Alles mögliche.
Angefangen von falschen Baudraten, einem Quarz der nicht
aktiviert ist, bis hin zu einem Programmfehler.
> Ich programmiere den ATmega8 in BASCOM!
Duck und wech.
Also, die Baudraten stimmen und der Quarz ist auch richtig aktiviert.
Der serielle Interrupt sieht folgendermaßen aus:
Onserial:
Daten = Inkey()
Buf = Buf + Chr(daten)
Print Buf
Return
Alos denkbar einfach. Aber wenn ich zum Beispiel den Text "qwertzuiop"
runtersende, kommt "qwertqweupqwepqwep" zurück. Komisch, oder gibt es
dafür eine logische Erklärung?
Was mir noch aufgefallen ist: Es kommt erst zu diesen Fehlern, wenn der
String länger als 6 Zeichen ist. Alles was darunter ist, wird korrekt
übertragen!
Was ist da los?
Inkey() wartet doch nur auf irgendein Zeichen, oder?
Dann ist klar, was läuft. Der AVR empfängt ein Zeichen, addierts in den
Buffer und gibts sofort wieder aus. Beim nächsten Zeichen das Gleiche -
nur dass er jetzt 2 Zeichen augibt, währenddessen kann er zwar eines
empfangen, aber das Zweite nicht usw.
Der Print-Befehl ist der Übeltäter, so kann das nicht funktionieren.
Welche Funktion erwartest Du von dem Programm? Dass es den Text exakt
zurücksendet und dabei speichert? Dann solltest Du nicht bei jedem
Aufruf den kompletten Text mit Print ausgeben, sondern nur das aktuelle
Zeichen.
Oder: Den ganzen String lesen und erst am Ende ausgeben.
Print sollte in diesem Falle eigentlich nicht das Problem darstellen
(abgesehen davon, dass es zeit verschlingt und in einer ISR nix zu
suchen hat).
Problematisch kann hingegen die Verwendung von Inkey() innerhalb einer
ISR sein, da fuer das Anlegen und Fuellen des inkey Buffers selbst eine
URXC-ISR genutzt wird. Allerdings setzt der Compiler den Aufruf dieser
internen ISR zwischen die Sicherung der Register und die User-ISR.
Sollte also dennnoch laufen. Ich tippe allerdings auf nebenbei laufende
Timer, deren ISRs zu lang sind. Sowas bringt Bascom leider sehr schnell
aus dem Takt und das Prog macht, was es will. Ich wuerde folgendes
machen:
1. Den kompletten Code hier posten...
2. Die ISR umbenennen. In Onserialx o.ae.
2. HWStack, SWStack und Framesize ueberpruefen. Sollte man testweise
alle auf >60 setzen, wenn mal gar nix laeuft.
3. Alle anderen Interrupts deaktivieren.
4. Ueberpruefen, ob in den Variablendeklarationen Overlay genutzt wird.
Diese Variablen testweise loeschen (nicht 0 setzen, sondern deren
Deklarationen loeschen).
Beste Gruesse
@ Marvin und André
Vielen Dank für eure ausführlichen Antworten. Ich habe nun den Tipp von
Marvin befolgt und das Print weggelassen und erst zum Schluss meine
Variable ausgegeben und... Es hat funktioniert. Anscheinend hat das
Print, wirklich dazu geführt, dass einzelne Zeichen "verschlungen"
wurden.
Naja, trotzdem vielen Dank für eure Bemühungen.
mfg
Andy
> Anscheinend hat das> Print, wirklich dazu geführt, dass einzelne Zeichen "verschlungen"> wurden.
Das Print selbst wahrscheinlich nicht.
Dein eigentliches Problem wird eher darin liegen,
dass du ohne Handshake auf der Leitung fährst. D.h.
der µC teilt dem PC nicht mit, dass er momentan beschäftigt
ist und daher zur Zeit nicht senden kann.
Der Print braucht seine Zeit. Da er aber innerhalb der ISR
augeführt wird, kann der µC in dieser Zeit nichts empfangen.
Nur: Das weiss der PC nicht und sendet weiter munter
drauflos. Da aber niemand die Zeichen abholt: -> Null-Device
Kannst du softwaremässig einen Interrupt auslösen?
Normalerweise macht man das so, dass man ein Flag
(also eine globale Variable) benutzt, die anzeigt
ob Daten komplett empfangen wurden oder nicht.
Innerhalb der Empfangsfunktion wird einfach nur
das nächste Zeichen von der UART geholt und in
den Buffer gestellt. Die Funktion stellt dann
noch fest, ob die Übertragung der Daten damit
vollständig ist oder nicht. Ist sie nicht
vollständig macht sie nichts weiter. Ist
sie aber vollständig, so wird das Flag (die
globale Variable) auf zb 1 gesetzt.
Im Hauptprogramm, also ausserhalb der Empfangsroutine
wird nun ständig diese globale Variable beobachtet.
Solange sie 0 ist, passiert nichts weiter. Wenn die
aber plötzlich 1 wird, dann hat die UART-Empfangsroutine
einen kompletten Datensatz empfangen und der muss verarbeitet
werden. Danach wird das Flag wieder auf 0 gesetzt und
wieder solange gewartet, bis diese 1 geworden ist, ...