Bascom Woran erkenne ich das über RS485 komplett gesendet wurde

schadeng

Neues Mitglied
12. Mai 2012
14
0
1
45
Sprachen
Hallo!

mit folgendem Fragment sendet ein AtMega8 mit einem Max485 Daten:
Code:
  Rs485_senden = 1
  Waitms 10
  Print "@" + Geraete_adresse_str + Datastring
  Waitms 10
  Rs485_senden = 0

Mir geht es nun um die zwei Zeilen "Waitms 10"
Angeblich reichem dem Max485 zum umschalten 30ns (maximal 60ns)
Alles unter Waitms 5 geht nur mit vielen Fehlern; Waitms 10 ist stabil. Bei 1MHz Taktfrequenz des Mega8 (er macht sonst nichts) verstehe ich das nicht.

Viel gravierender ist aber die zweite Zeile mit "Waitms 10"
Diese Wartezeit benötige ich, da sonst der Datenstrom abreist. Ist ja auch logisch, da zum senden der gepufferten Daten etwas Zeit benötigt wird, der Max485 aber schon wieder in den "Lese" Modus gesetz wird.
Diese 10ms sind aber jetzt nur geschätzt und laufen derzeit bei mir stabil (aber: der Datenstrom hat immer die selbe Länge)

Nun stellt sich mir die Frage, woran man erkennen kann, dass alles komplett gesendet wurde und der Datenpuffer leer ist.
Eigentlich soll das so funktionieren:
Code:
  Rs485_senden = 1
  Waitms 10
  Print "@" + Geraete_adresse_str + Datastring
  While USR.TXC <> 1
  Wend
  Rs485_senden = 0

Aber gerade das funktioniert nicht: Das Programm bleibt in der schleife hängen.
Und nu?

Grüße
 
Ohne jetzt im Datenlatt nachzuschauen:
Bist sicher, dass das hier richtig ist?
While USR.TXC <> 1
Wend


Das <>1 kommt mir merkwürdig vor. Bei <>0 würde ich nicht stutzen.

Aber zu den beiden waitmas 10:
Die dürften eigentlich gar nicht erforderlich sein, meine ich.
Der Sender haut raus und fertig. Dazu braucht er genau so lange, wie er braucht und dann macht er mit der Abarbeitung der Zeilen darunter weiter. Nix waitms.

Frage daher: Was ist denn Dein Empfänger? Ich vermute das Problem eher dort.
Bist Du sicher, dass der Empfänger die Daten schnell genug wegstecken kann?
Oder ist der Empfänger ein PC? Dann dürfte kaum was schief gehen.

Wenn der Empfänger aber ein AVR ist, dessen Empfangsroutine "blöd" programmiert ist, dann kann es Kummer geben. Gerade die direkt vorgesehenen Bascom-Befehle halte ich für reichlich suboptimal.
Das Verfahren: Meinstring=Meinstring + Zeichen sollte vermieden werden, bzw. nur dann eingesetzt werden, wenn viel Zeit zur Verfügung steht; also nach Übertragung aller Daten.

Bessere Erfahrungen habe ich damit gemacht, dass der Empfänger beim Eintrudeln eines seriellen Bytes per Interrupt dieses eine Zeichen abholt, in ein Array speichert und die Interrupt-Routine sofort wieder verlässt.
Erst wenn die Übertragung abgeschlossen ist, wird dann aus dem Array ein String zusammengebastelt.


Auch ein String ist übrigens ein Array. Aber wenn man das so behandelt, dann anders vorgehen, als mit einem Zeichen für Zeichen wachsenden String.
Also nicht: Meinstring=Meinstring+Zeichen.
Lieber einzeln die Zeichen im vorhandenen String mit den eintrudelnden Zeichen überschreiben, an wachsender Positon.
Der String hat also beispielsweise 20 Zeichen Länge. Nun Zeichen für Zeichen darin überschreiben, mit den eintrudelnden Bytes.
 
Hallo,
Eigentlich soll das so funktionieren:
Code:
  Rs485_senden = 1
  Waitms 10
  Print "@" + Geraete_adresse_str + Datastring
  While USR.TXC <> 1
  Wend
  Rs485_senden = 0

ich kenne mich leider mit Bascom nicht so aus, vielleicht kann ich aber trotzdem helfen.

Bei dem ATmega8 gibt es aber drei USART Control Register: UCSRA, UCSRB und UCSRC.

Das Flag TXC (USART Transmit Complete) befindet sich im Register UCSRA, es ist das Bit 6.

Du verwendest USR, es wird hier vielleicht nicht das Register UCSRA adressiert?!

Um das Flag manuell zu löschen (bei Verwendung vom Interrupt macht das die Hardware), schreibt man eine "1" rein.

Gruß,
Dirk
 
...Nun stellt sich mir die Frage, woran man erkennen kann, dass alles komplett gesendet wurde und der Datenpuffer leer ist.
Eigentlich soll das so funktionieren:
Code:
  Rs485_senden = 1
  Waitms 10
  Print "@" + Geraete_adresse_str + Datastring
  While USR.TXC <> 1
  Wend
  Rs485_senden = 0
...
Nein, das kommt darauf an, wie Bascom TXC durch "PRINT" verwendet.
Vereinfacht gesagt arbeitet der UART im µC byteweise, also immer nur ein Zeichen nach dem anderen.
Es gibt einen Transmit-Buffer, in den dieses eine Byte geschrieben werden kann (wenn er leer ist - UDREn-Flag).
Es gibt ein Transmit-Schieberegister, welches (wenn es leer ist) ein Byte aus dem Buffer übernimmt, und "rausschiebt". Wenn der Buffer auch leer ist, wird danach das TXCn-Flag gesetzt.
Also UDREn wird 1 sobald das byte ins Schieberegister übernommen wurde. UDREn kann einen Interrupt triggern, um ein weiteres byte zu puffern - während das Schieberegister schiebt. (inwiefern das Flag beim schreiben nach UDRn automatisch gelöscht wird, geht aus meinem DB nicht richtig hervor, würde aber so am meisten Sinn machen. Wenn UDREn 0 ist, und man ein byte nach UDRn schreibt, wird es ignoriert).
Das TXCn wird erst gesetzt, wenn das Schieberegister "fertig geschoben hat", und der Buffer leer ist (UDREn=1). TXCn kann auch einen entsprechenden Interrupt triggern. Wird dieser ausgeführt, wird das Flag automatisch gelöscht, ansonsten kann man es "per Hand" selbst tun (->Dirk).

Soweit war Dir das wahrscheinlich bereits klar.
Jetzt ist die Frage, wie Bascom das alles mit "Print" umgesetzt wird. Print ist ja quasi eine Subroutine. Erst wenn diese komplett(!) abgearbeitet ist, macht das Programm mit Deiner Schleife weiter, wo Du das TXC pollst. Ich vermute(!), daß von Print keine Interrupts verwendet, sondern die Flags gepollt werden. Wenn Print also selbst das Flag löscht (ordentlich aufräumen halt), kannst Du in der Schleife ewig warten.
 
Hallo und danke :)
Soweit so gut. Und nu?

Da die Daten teilweise schnell hintereinander mit der Routine gesendet werden, die Routine also kurz hintereinander aufgerufen wird, kommt es genau dann zu Fehlern.
Wie würdet ihr es denn anders machen? Bzw wie komme ich denn an ein verwertbares TXC?

Ich denke derzeit eher über eine Änderung der "Busstruktur" nach:
Bisher hatte ich geplant, dass jeder jederzeit senden darf und von dem angesprochenem Gerät eine "Alles-klar"-Antwort erhält. Kommt diese nicht weiß ich, dass etwas schief gelaufen ist und sende erneut.

Ich denke ich werde eher zu einem Master-Slave-Bus wechseln. Der Master fragt dann nach der Reihe jedes Gerät nach seinem Status (pollen) und nur dann darf das Gerät darauf eine Antwort schicken. Die Antwort würde dann einfach den gesamten Status beinhalten und nicht (wie bisher) nur das was sich geändert hat. Somit würden die schnell aufeinander folgenden Datenpakete entfallen und es kann nicht zu "Unfällen" auf dem Bus kommen.
Was mir daran nicht gefällt ist aber, dass ich nur mit kleinen Latenzen die Daten bekomme und auf "Alarm-Meldungen" nur verzögert reagieren kann.

Dennoch würde mich interessieren, wie man denn verlässlich an ein TXC kommt, da ich das zumindest im Master benötig.

Danke und Grüße
 
Hallo und danke :)
Soweit so gut. Und nu?...
Entweder Du schaust Dir mal an, was Print genau macht (also ein Programm in dem quasi nur eine Print-Anweisung steht durch das AVR-Studio reassemblieren lassen), und/oder Du schreibst Dir eine eigene Print-Routine, in der Du selbst das Flag überwachst.
Andere Frage: Du läßt den Mega8 mit 1MHz laufen (mit internem Oszillator@8MHz und aktivierter CKDIV8-Fuse?) - Welche Baudrate hast Du wie eingestellt?
 
Hallo LotadaC

Naja, an den Fuse-Bit hab ich (noch) nichts verändert. Der Atmel läuft ohne externen Quarz mit 1MHz (Werkseinstellung?!). Das Projekt ist noch sehr rudimentär und es geht derzeit noch um grundlegende Randbedingungen und Vorgehensweisen.
Aus Platzmangel (die Platine darf höchstens 6cm Durchmesser haben) muss ich wohl auf den externe Quarz verzichten. Geplant ist, dass ich den Takt intern auf 8Mhz einstelle (CKSEL=0100). Damit sollte dann die Fehlerquote bei bis zu 19200baut auf 0,16% fallen.

Eingestellt sind die Werte mittels und zu Beginn des Code:
$regfile = "M8def.dat"
$crystal = 1000000
$baud = 9600

Grüße
 
Oh, bei 1MHz hast Du bei 9600baud (und ohne U2X-Flag) laut Datenblatt 'n Fehler von -7%. Durch das " Double the USART transmission speed"-Bit (U2X) im USART Control and Status Register A (UCSRA) kannst Du im Prinzip die Auflösung des Baudrate-Registers verdoppeln. Ich weiß nicht, ob Bascom mit der $Baud-Direktive das Flag mit einbezieht. Du kannst das Flag aber auch selbst setzen. Dann läuft der UART mit doppelter Geschwindigkeit (wie der Name ja sagt). Wenn Du also Bascom vorher(!) anweist, die Baudrate auf 4800 zu setzen, und danach das U2X setzt, läuft der UART mit 9600Baud, hat aber die Abweichung, als wenn er mit 4800 (und ohne U2X) laufen würde.
Alternativ kannst Du natürlich auch nur de 4800 einstellen (lassen - durch Bascom).
Oder den UART komplett zu Fuß konfigurieren - durch direktes beschreiben der Register...

Zur Taktfrequenz: Das hatte ich wohl mit dem Mega88 verwechselt (der hat einen internen 8MHz Oszillator, für den man zur Laufzeit einen sogenannten MainClockPrescaler umschalten lassen kann - also durch das Programm. Vor dem Umschalten läuft der Controller entweder mit Prescaler 1, also 8MHz, oder mit Prescaler 8 (1MHz). Vorgeben kann man das durch die erwähnte CKDIV8-Fuse.)
Du hast aber einen Mega8. Da müßtest Du tatsächlich die Frequenz durch die CKSEL-Fuses vorgeben. Bei 8MHz wären dann aber sogar 76k8Baud drin, mit U2X (0,2%).
 
Hallo zusammen,

also UARTs haben bei ihrem Versorgungstakt so ihre Eigenheiten ;)

Sehr gut erklärt wurde das mal in einem Bucht über die IO-Bausteinen des Z80 von Sybex.
Du hast einen Zähler für die einzelnen Bits die hereinkommen. Vor diesem Zähler sitzt ein weiterer Zähler der eine Abtastung der Empfangsleitung von etwa 1/16 Datenbit ermöglicht. Beim Z80-SIO konnte man diesen "Vorzähler" auch halbieren wie beim UART des Atmels. Dieser Vorzähler ist dafür da, das der Empfänger sich auf den ankommenden asynchronen Datenstrom aufsynchronisieren kann. Wenn man ihn also um ein Bit verringert, dann fällt das aufsynchronisieren schwerer und man kann schneller mal die Synchronisation verlieren.

Wenn man das Prinzip auf den Atmel übernimmt dann wäre dieser Teiler /2 (U2X) also Teil des Vorzählers für die Synchronisation. Man sollte also möglichst die volle Teilerkette eingeschaltet lassen und eher mit höherem Prozessortakt arbeiten.

Man müßte das eventuell mal weiter recherchieren und etwas genauer unter die Lupe nehmen.

Gruß
Dino
 

Über uns

  • Makerconnect ist ein Forum, welches wir ausschließlich für einen Gedankenaustausch und als Diskussionsplattform für Interessierte bereitstellen, welche sich privat, durch das Studium oder beruflich mit Mikrocontroller- und Kleinstrechnersystemen beschäftigen wollen oder müssen ;-)
  • Dirk
  • Du bist noch kein Mitglied in unserer freundlichen Community? Werde Teil von uns und registriere dich in unserem Forum.
  •  Registriere dich

User Menu

 Kaffeezeit

  • Wir arbeiten hart daran sicherzustellen, dass unser Forum permanent online und schnell erreichbar ist, unsere Forensoftware auf dem aktuellsten Stand ist und der Server regelmäßig gewartet wird. Auch die Themen Datensicherheit und Datenschutz sind uns wichtig und hier sind wir auch ständig aktiv. Alles in allem, sorgen wir uns darum, dass alles Drumherum stimmt :-)

    Dir gefällt das Forum und unsere Arbeit und du möchtest uns unterstützen? Unterstütze uns durch deine Premium-Mitgliedschaft!
    Wir freuen uns auch über eine Spende für unsere Kaffeekasse :-)
    Vielen Dank! :ciao:


     Spende uns! (Paypal)