Guten Abend zusammen,
in einem Vorhaben sollen von einem Host (PC) Daten Seriel an ein
Knotenpunkt gesendet, bearbeitet und weitergeleitet werden. Meine Wahl
fiel auf den 2560 AVR da in dem Projekt einige Timer sowie ADC notwendig
sind.
Es bildet sich folgende Konstellation fuer den "Knotenpunkt" 2560:
UART0 - Host (PC mit eigenem Interface)
UART1 - Slaveteilnehmer 1
UART2 - Slaveteilnehmer 2
UART3 - Slaveteilnehmer 3
Ueber Interruptroutinen der Slaves werden "Identifikationbytes" an den
Host gesendet und anschließend die Nachricht aus dem Buffer des 2560,
somit werden die 3 Slaves identifiziert.
Dabei gilt:
0xA0 - Slave 1 Nachrichtanfang
0xA1 - Slvae 2 Nachrichtanfang
0xA2 - Slave 3 Nachrichtanfang
0xA3 - Slave 1 Nachrichtende
0xA4 - Slave 2 Nachrichtende
0xA5 - Slave 3 Nachrichtende
Info:
Der Bereich 0xA0 bis 0xAF ist fuer dieses Vorhaben reserviert, die
Nachrichten der Slaves enthalten diese nicht.
Folgende Zeilen habe ich schnell zusammen geschrieben zum Verstaendnis,
dieser Aufruf existiert natuerlich 3 mal:
1
USART1_INTERRUPT:
2
push r16
3
push r17
4
lds r16, UDR1
5
lds r17, 0xA0 ;Slaveteilnehmer 1 [MSB]
6
sts UDR0, r17 ;An UART0 (Host) senden
7
sts UDR0, r16
8
lds r17, 0xA3 ;Slaveteilnehmer 1 [LSB]
9
sts UDR0, r17 ;An UART0 (Host) senden
10
pop r17
11
pop r16
12
reti
Somit weiss Ich nun am Host von welchem Slave Nachrichten gesendet
wurden und kann die Bytes zwischen MSB und LSB in einem String
bearbeiten.
Es sollen Nachrichten vom Host an die Slaves versendet werden. Mein
Problem hier ist das die Zuordnung der Nachrichten vom Host zu den
einzelnen Slaves mit dem dazugehoerigen Daten nicht funktioniert.
Empfangene Identifikationsbytes:
0xAA - Slave 1
0xAB - Slave 2
0xAC - Slave 3
Versuch Nr. 1
Dafuer habe Ich nun eine Interruotroutine geschrieben, meine Idee war es
aehnlich wie Slave -> Host, ein Identifikationsbyte vor der Nachricht an
den 2560 zu senden und anschließend mit Verzoegerung die Nachricht an
den gerichteten Slave (siehe Codezeilen unten)
Versuch Nr. 2
Mit jeder Nachricht vom Host zum 2560 das Identifikationsbyte mit der
Nachricht zu versenden. Die Nachrichten selber sind immer
unterschiedlich lang, das erste Byte waere somit interessant. Ich habe
mich an die Befehle LSL und LSR gemueht um das erste Byte aus einem
register filtern zu koennen um Entscheiden zu treffen. Dabei muss das
Byte auch weggeschnitten werden bevor es zum Slave gesendet wird, wie in
Versuch Nr.1 beabsichtigt.
Wie wuerdet Ihr das loesen um maximale Performance zu halten (unnoetige
Delays vermeiden)?
Falls Jemand fragt - ja UART ist hier vorgegeben...
1
USART0_INTERRUPT:
2
push r16
3
lds r16, UDR0
4
cpi r16, 0xAA ;Empfangener Byte - String gerichtet an UART1?
5
brne NT1
6
rjmp SLAVE1_WORK
7
NT1:
8
cpi r16, 0xAB ;Empfangener Byte - String gerichtet an UART2?
9
brne NT2
10
rjmp SLAVE2_WORK
11
NT2:
12
cpi r16, 0xAC ;Empfangener Byte - String gerichtet an UART3?
Sascha W. schrieb:> lds r17,0xa0 //lade r17 mit Wert aus SRam-Addr 0xA0> ldi r17,0xa0 //lade r17 mit 0xa0BaeumeKommunizierenElektromagnetisch schrieb:> leider verstehe ich nicht ganz worauf die Anwort hinweisen soll..
r17 wird NICHT mit 0xA0 geladen, sondern mit dem WERT aus der
RAM-Addr 0xA0.
Deine Slaven senden wie folgt:
Sascha W. schrieb:> lds r17,0xa0 //lade r17 mit Wert aus SRam-Addr 0xA0> ldi r17,0xa0 //lade r17 mit 0xa0>> alles klar?>> SaschaMarc V. schrieb:> lds r17, 0xA3 ;Slaveteilnehmer 1 [LSB] - NEIN, Inhalt der> RAM-Addr[0xA3] wird gesendet !!!> sts UDR0, r17 ;An UART0 (Host) senden>> jetzt klarer ?
Guten Abend Sascha und Marc,
erstmal Danke fuer eure Antworten. Den Zusammenhang mit dem Problem der
Verstaendnisuebergabe habe ich nun erkannt.. Ihr beide habt Recht die
oben stehenden Zeilen sind nicht korrekt:
1
lds r17, 0xA0 ;Slaveteilnehmer 1 [MSB]
2
sts UDR0, r17 ;An UART0 (Host) senden
3
sts UDR0, r16
4
lds r17, 0xA3 ;Slaveteilnehmer 1 [LSB]
5
sts UDR0, r17 ;An UART0 (Host) senden
Das resultiert daraus das ich sie schnell aus dem Kopf heraus
geschrieben habe und kein C&P aus einem Projekt angewendet habe...
Ich versuche es anders zu uebermitteln:
a. Ich habe ein Interface programmiert welches ueber eine RS232
Schnittstelle Daten von einem 2560 mit 3 Slave´s empfaengt
b. Diese besagte Schnittstelle (PC mit Interface) wird mit UART0
realisiert, die 3 Slaves ueber UART1, UART2 und UART3
c. Wenn einer der 3 Slaves etwas ueber ihre RS232 Schnittstelle sendet
wird ein Interrupt beim 2560 ausgeloest -> Es wird ein
Identifizierungsbyte (LDI NICHT LDS Befehl zum laden eines Registers)
zum Host gesendet und im Anschluss die Nachricht sowie ein Abschlussbyte
d. Ich weiß durch die Identifizierungsbytes welcher Slave (1, 2 oder 3)
mir welche Nachricht gesendet hat -> Das Interface kann sie nun
bearbeiten
Naechste realisierung ¶warum der Thread existiert¶:
e. Ich wuerde gerne den Slaves sagen was sie tun sollen, sie sollen
Nachrichten vom Host empfangen..
f. Mein Interface versendet vom PC ueber RS232 an den 2560 (UART0) Daten
-> Interruptroutine vom 2560 wird ausgeloest.
>>>> Wie koennte man jetzt anhand den empfangenen Bytes entscheiden an welchen
Slave was gesendet wird?
Dazu schrieb ich oben bereits, siehe bitte USART0_INTERRUPT:
Folgendes habe ich festgestellt:
Wenn vom Interface das Byte 0xAA (gerichtet an UART1) und ein
X-beliebiges Byte gesendet wird dann funktioniert der oben stehende
Code, im Register r16 steht das zweitgesende Byte.
Wenn mehrere Bytes versendet werden nach 0xAA, dann wird das
zuletztgesendete Byte im Register r16 geladen.. die Funktionsweise ist
hier sehr interessant..
BaeumeKommunizierenElektromagnetisch schrieb:> Folgendes habe ich festgestellt:> Wenn vom Interface das Byte 0xAA (gerichtet an UART1) und ein> X-beliebiges Byte gesendet wird dann funktioniert der oben stehende> Code, im Register r16 steht das zweitgesende Byte.> Wenn mehrere Bytes versendet werden nach 0xAA, dann wird das> zuletztgesendete Byte im Register r16 geladen.. die Funktionsweise ist> hier sehr interessant..
Auch mit nur einem Datenbyte würde es nicht richtig funktionieren.
Das Problem besteht aus gleich fünf Teilproblemen, oder anders
ausgedrückt: da sind fünf Fehler drin:
1) Du liest in einer ISR zweimal aus UDR (ohne weitere Maßnahmen). Das
kann höchstens zufällig mal beim zweiten Byte den richtigen Wert
liefern.
2) Du hast keinen Merker für die Adresse verwendet. Mußt du aber, weil
halt in einer Instanz des Interrupts nur ein Byte empfangen werden kann.
Aber selbst wenn du zwei Bytes liest und erst dann die ISR verläßt: du
landest hier im unterbrochenen Code, der dann möglicherweise R16
verändert, womit deine Adresse für die nächste Instanz des Interrupts
verloren ist. Sowas geht nur dann, wenn R16 sozusagen reserviert ist.
3) Selbst wenn R16 reserviert ist und garantiert nicht außerhalb der ISR
geändert wird, so machst du den Wert trotzdem beim nächsten Eintritt in
die ISR selber kaputt, indem du das nächste empfangene Byte wieder nach
R16 liest.
4) Du springst in der ISR an drei Stellen zu Code, der den Stack kaputt
macht und die Interrupts gesperrt hinterläßt. Somit ist garkein weiterer
Empfang mehr möglich.
Hallo c-hater,
danke dir fuer deine Antwort, ich hatte fehlinterpretiert das der RX
Interrupt nur fuer jeden Byte ausgeloest wird, urspruenglich ausgehend
von der Annahme, dass ich die Bytes aus dem Internen Puffer herauslesen
koennte. Wie koennte man den Buffer nutzen?
Habe den Interruptteil vom UART0 angepasst womit es funktionieren
sollte, Nachteil ist hier das ein gesamtes Register (hier r17) fuer
restlichen Code des µC unangetastet bleiben muss, weil wie du sagtest
zwischen den Bytes beim Empfangen andere Interrupts diesen veraendern
koennten.
Habe das nun so gestaltet, werde es vielleicht noch etwas anpassen -
sollte gehen:
[ASM]
USART0_INTERRUPT:
push r16
lds r17, UDR0 ;In das "Entscheidungsregister" Byte einlesen
mov r16, r17 ;r16 wird gesendet falls kein Identifikationsbyte
cpi r17, 0xAA ;Empfangener Byte = Identifikationsbyte?
brne NT1
rjmp HOST_ENDE
NT1:
cpi r17, 0xAB ;Empfangener Byte = Identifikationsbyte?
brne NT2
rjmp HOST_ENDE
NT2:
cpi r17, 0xAC ;Empfangener Byte = Identifikationsbyte?
brne HOST_ENDE
lds r16, UDR0 ;Falls kein Definitionsbyte - in r16 laden
cpi r17, 0xAA
brne ET1
sts UDR1, r16
ET1:
cpi r17, 0xAB
brne ET2
sts UDR2, r16
ET2:
cpi r17, 0xAC
brne HOST_ENDE
sts UDR3, r16
HOST_ENDE:
pop r16
reti
[/ASM]
BaeumeKommunizierenElektromagnetisch schrieb:> [ASM]> ...> [/ASM]
Die Tags waren falsch, korrekt ist avrasm.
Was den Inhalt betrifft, sieht der schon sehr wesentlich besser aus, es
sind zumindest erstmal alle rein "technischen" Fehler ausgemerzt. Nur
die Logik passt noch nicht. Das liegt vor allem daran, dass du noch
nicht die ganze Bedeutung des "Entscheidungsbyte" erfasst hast und die
Möglichkeiten, die sich daraus zur korrekten Steuerung des Ablaufes über
mehrere Instanzen der ISR hinweg ergeben.
Was fehlt, sind einfach noch zwei Sachen: die korrekte Nutzung des
Endekennzeichens der Nachricht in der ISR und die Initialisierung des
"Entscheidungsbyte" vor der allerersten Auslösung des Interrupt.
Sinnvollerweise nämlich auf das Endekennzeichen.
---
In der ISR liest du das empfangene Byte ein und prüfst du dann erstmal
das "Entscheidungsbyte". Ist das "Endekennzeichen", bist du ausserhalb
einer Nachricht, ansonsten innerhalb und das Entscheidungsbyte enthält
die Zieladresse der Nachricht.
Entsprechend diesen zwei Fällen musst du verzweigen und zwei völlig
unterschiedliche Routinen abarbeiten. Wenn ausserhalb der Nachricht,
dann das empfangene Byte auf gültige Zieladresse prüfen und, falls ja,
dem "Entscheidungsbyte" zuweisen. Das war alles in diesem Zweig, es
folgt nur noch ordentlicher Exit aus der ISR.
Im anderen Zweig hingegen mußt du das empfangene Byte auf
Endekennzeichen prüfen. Wenn ja, dem "Entscheidungsbyte" zuweisen und
das war's, es folgt nur noch ordentlicher Exit aus der ISR.
Nur dann, wenn das empfangene Byte nicht das Endekennzeichen war, dann
kommt die Sache mit der Weiterleitung an den zuständigen Empfänger, also
das, was bisher der wesentliche Inhalt deiner ISR war...
>> [ASM]>> ...>> [/ASM]>> Die Tags waren falsch, korrekt ist avrasm.>
Improvisierend basierte Tastenfolge aus dem Kopf heraus resultierender
Fehler
Hallo c-hater,
danke Dir fuer deine Nachricht, ich habe sie aus mehreren Winkel
versucht zu interpretieren.
Zuerst einmal sollte ich die Aussage aendern das ein Register reserviert
sein muss fuer den obigen Code ->
a. r17 im Hauptprogramm nicht verwenden. Sollte eine ISR in verwenden
dann vor Beginn in Stack laden und beim Verlassen wiederherstellen.
außerdem war er fehlerbehaftet den mit jedem empfangenen Byte habe ich
mir r17 ueberschrieben, den Teil habe ich angepasst nun empfangen alle
Slaves das was vom Interface generiert wird:
1
USART0_INTERRUPT:
2
push r16
3
lds r16, UDR0 ;In das "Entscheidungsregister" Byte einlesen
4
5
cpi r17, 0xAA
6
brne NT1
7
mov r17, r16 ;in r17 nur Byte laden wenn = Identifikationsbyte
mov r17, r16 ;in r17 nur Byte laden wenn = Identifikationsbyte
17
brne HOST_ENDE
Mag zwar funktionieren doch plaediere ich die Optimierte Schiene zu
fahren. Mir liegen Verstaendnissteine im Wege den technischen Kontext
zu meinem Ansatz im vollen Umfang zu verarbeiten.
Mir ist bewusst, dass solche Sprungbefehle nicht gerne verwendet werden,
weil sie mehr Ressourcen benoetigen. Außerdem ist es nicht schoen, weil
das eine Form einer Asymmetritaet darstellt -> Bytes an Slave 3
gerichtet dauert laenger im Vergleich Slave 1.. Aus diesem Grund werde
ich den Teil ueberarbeiten in dem ich eine .db erstelle und diese durch
r30 und r31 mit lpm aus dem Flash vergleichen lasse. War das damit
gemeint:
> und die Initialisierung des> "Entscheidungsbyte" vor der allerersten Auslösung des Interrupt.> Sinnvollerweise nämlich auf das Endekennzeichen.
?
Eine weitere sekundaere Variante die ich hier rauslese ist es das ich
ein "Abschlussbyte" senden soll vom Interface um die Routine zu beenden.
Bei den drei Slaves ist es notwendig, da jeder Bytes in die Pipeline
feuern kann somit muss ich die ISR´s fuer die anderen 2 Slaves speeren
waehrend einer sendet und mit einem Abschlussbyte versehen um sie wieder
frei zugeben. Da in dieser Konstellation nur ein Host besteht der
sendet, wozu das Abschlussbyte?
> Entsprechend diesen zwei Fällen musst du verzweigen und zwei völlig> unterschiedliche Routinen abarbeiten.
Verstehe ich nicht ganz.. es wird die ISR beim Empfangen von Bytes
ausgeloest, soll ich mittels "rcall" eine weitere Routine aufrufen, wo
ist der Sinn dahinter wenn ich in der ISR alles erledigen kann?
> das war's, es folgt nur noch ordentlicher Exit aus der ISR.
Diesen Satz verfasstest Du zwei Mal. Mit dem Wiederherstellen aller
Register sowie "reti" ist fuer mich die ISR sauber beendet, laesst sich
dem etwas hinzufuegen?
Danke,
BkE
In der Hoffnung, die Aufgabenstellung überhaupt richtig verstanden zu
haben: hier ein Vorschlag für die (letztbehandelte) Richtung PC->slaves.
Ist zwar für einen AVR-Dx, und die Slaves heißen Kanal, sollte aber ja
egal sein.
von BaeumeKommunizierenElektromagnetisch schrieb:> Mir ist bewusst, dass solche Sprungbefehle nicht gerne verwendet werden,> weil sie mehr Ressourcen benoetigen. Außerdem ist es nicht schoen, weil> das eine Form einer Asymmetritaet darstellt -> Bytes an Slave 3> gerichtet dauert laenger im Vergleich Slave 1..
Das ist ein ziemlich sekundäres Problem, so lange du die Logik der
Weiterleitung nicht korrekt abbildest.
Merke: erstmal korrekte Funktion des Codes herstellen. Über mögliche
Optimierungen kann man danach immer noch nachdenken.
Die gibt es aber nicht unbedingt. Bei der geringen Zahl möglicher
Clients (begrenzt durch die Zahl der vorhandenen UARTS) lohnt es nicht,
groß über die Optimierung der Verteilung nachzudenken. Da ist nur wenig
bis gar kein Optimierungspotential drinne, verglichen mit der
Verzweigungslösung.
Die Verzweigung selber könnte man allerdings noch optimieren. In Asm
kann man nämlich nach einer einzigen Vergleichsoperation in drei
Richtungen verzweigen, also statt eines binären einen trinären Baum
aufspannen. Diese Optimierung ist simpel und lohnt schon ab drei
möglichen Zielen der Verzweigung. Also ist die Indikation für die
Anwendung dieser Optimierung in deinen Fall eindeutig positiv.