Hallo zusammen!,
ich habe folgendes Problem:
Ich möchte gerne für eine Eisenbahnsteuerung eine PC-uC(AtMega32)
Verbindung haben...soweit kein Problem.
Der uC soll am Ausgang ein Taktsignal mit 0-30 Impulsen liefern. Die
Impulse (Zustand 1) selber sollen 355ms lang sein, dazwischen 405ms
pause (0).
Nun werden je nach Befehl nur bestimmte Impulse freigegeben. Die Ersten
zehn Impulse stllen die Adresse dar, die weiteren 20 die Aktion, welche
der Aktor ausführen soll.
Ich habe das bis jetzt so versucht zu realisieren, dass das Signal vom
PC (C#) in ein Array auf dem uC geschrieben wird.
Dieses Array hat dementsprechend so viele Zeilen wie das Singal in ms
aufgeteilt ergibt. Sprich 22800 Zeilen.
Nun habe ich auf dem uC den Timer0 entsprechend eingestellt, dass er
jede ms in die ISR springt und einen Vergleich durchführt. Ist im Array
an entsprechender Stelle eine 1 gesetzt wird der Ausgang 1 gesetzt, bei
einer 0 an dieser Stelle bleibt der Ausgang auf 0.
Nun habe ich allerdings das Problem, dass das Array nicht mit den 22800
Zeilen deklariert werden kann, da Speicher zu klein.
Auch eine Aufteilung in Bytes kommt nicht in Frage, da Speicher zu
gering.
Vermutlich bin ich auch auf dem Holzweg und denke zu kompliziert.
Hättet ihr einen Tipp für mich wie Ihr sowas realisieren würdet?
Zusammengefasst:
Auf dem PC wird ein Impulsmuster mit 1en und 0en berechnet, dieses
Muster soll am uC Zeitdiskret ausgegeben werden. Die Übertragung ist
kein Problem, sondern der Zeitdiskrete Ausgabe.
Mit delays möchte ich nicht arbeiten...was aber so halbwegs
funktionieren würde...
Vielen Dank schonmal!
PS. Ich erwarte keine Programmcodes.
TheGee schrieb:> Die> Impulse (Zustand 1) selber sollen 355ms lang sein, dazwischen 405ms> pause (0).
Das hab ich nicht verstanden. Pause ist das gleiche wie Zustand 0?
Nerd B schrieb:>> Impulse (Zustand 1) selber sollen 355ms lang sein, dazwischen 405ms>> pause (0).>> Das hab ich nicht verstanden. Pause ist das gleiche wie Zustand 0?
Ich auch nicht, aber ich glaube bei Log.1 gibt es 355ms Zustand1 und
dann 405ms Zustand0, bei Log.0 gibt es 760ms Zustand0.
Ist das so ?
Wenn dein Signal aus 30 Impulsen besteht, warum schickst du dann nicht
einfach diese 30 Bits vom PC zum uC? Oder der Einfachheit halber 32 Bits
also 4 Bytes. Da brauch man doch nicht jede Millisekunde zu übertragen,
wenn man weiß, wie lang Pausen und Signale sind.
Marc V. schrieb:> Ich auch nicht, aber ich glaube bei Log.1 gibt es 355ms Zustand1 und> dann 405ms Zustand0, bei Log.0 gibt es 760ms Zustand0.
Dann braucht also ein Befehl 22,8 Sekunden?
Das Problem ist, dass das Signal zusammenhängend ausgegeben werden muss.
Wenn ich nun über den PC sende und gleichzeitig ausgebe, unterbricht der
PC wegen dem Multitasking (durch öffnen anderer Programme) die Sendung,
bzw. sendet geringfügig verzögert.
Deswegen wollte ich das Signal erst auf dem uC zwischenspeichern und
dann per Befehl ausgeben. Da wird dann nixmehr unterbrochen.
/Ich auch nicht, aber ich glaube bei Log.1 gibt es 355ms Zustand1 und
dann 405ms Zustand0, bei Log.0 gibt es 760ms Zustand0.
Ist das so ?/
Genau, so soll es sein.
Nerd B schrieb:> Wozu brauchst du denn den PC? Und wozu brauchst du das Array? Und> warum> willst du nicht mit der delay Funktion arbeiten?
Über das PC Programm sollen die verschiedenen Befehle visuell gesteuert
werden. Drückt man den Button "Beleuchtung ein" generiert das C#
Programm das Bitmuster und sendet es an den Mikrocontroller.
Dies ist natürlich auch direkt am uC möglich...das PC Programm soll aber
mit der Zeit Umfangreicher werden und mehr Funktionen erhalten.
Ich möchte dies nunmal gerne über Timer lösen, da ich so meiner Meinung
nach flexibler bin für spätere Bitmuster-Anderungen
Nerd B schrieb:> Dann braucht also ein Befehl 22,8 Sekunden?TheGee schrieb:> Genau, so soll es sein.
Was willst du denn auf deiner Modellbahn damit schalten? Mehr als das
abendliche Einschalten der Straßenbeleuchtung kann man doch in diesem
Tempo kaum machen. <nachdenk>
TheGee schrieb:> Deswegen wollte ich das Signal erst auf dem uC zwischenspeichern und> dann per Befehl ausgeben. Da wird dann nixmehr unterbrochen.
1 Byte PC==>uC mit 38400B dauert 260us.
MEGA32 dekodiert diesen Byte und fuhrt entsprechende Aktion aus.
Wozu diese 22.8s und diese Slowmotion Impulse gut sein sollen, ist
mir absolut unklar.
Marc V. schrieb:> 1 Byte PC==>uC mit 38400B dauert 260us.>> MEGA32 dekodiert diesen Byte und fuhrt entsprechende Aktion aus.
Ja gut, dann hätte ich 1 Byte. Wenn die nächsten Bytes aber nicht
Zeitdiskret übertragen werden, passt es wieder nicht.
Oder meine Denkweise mit dem "Zwischenspeichern" im Array ist falsch.
Da ich die Empfänger auch selber erstellen will, sollen die Impulse
erstmal länger sein um sie für mich besser auswertbar zu machen.
Keine Frage...es geht schneller und effizienter...für einen C Neuling
ist dies aber noch zu hoch finde ich. Deswegen erstmal die langsamere
Variante.
TheGee schrieb:> Der uC soll am Ausgang ein Taktsignal mit 0-30 Impulsen liefern. Die> Impulse (Zustand 1) selber sollen 355ms lang sein, dazwischen 405ms> pause (0).
Sichher das das ms (Millisekunden) sind? Ich hätte hier Micro Sekunden
(µs) erwartet.
Aber selbst bei µs hat man noch genügent freie Taktzyklen für ein paar
einfache Rechenaufgaben im Timer, d.h. Du erzeust die eigentlichen
Signale erst im Timer Interrupt.
Jim M. schrieb:> TheGee schrieb:>> Der uC soll am Ausgang ein Taktsignal mit 0-30 Impulsen liefern. Die>> Impulse (Zustand 1) selber sollen 355ms lang sein, dazwischen 405ms>> pause (0).>> Sichher das das ms (Millisekunden) sind? Ich hätte hier Micro Sekunden> (µs) erwartet.>> Aber selbst bei µs hat man noch genügent freie Taktzyklen für ein paar> einfache Rechenaufgaben im Timer, d.h. Du erzeust die eigentlichen> Signale erst im Timer Interrupt.
Bis jetzt habe ich in der ISR ja nur einen Vergleich zwischen Zählwert
(welcher auch gleichzeitig der Zeitwert in ms ist) und ob in dem Array
an dieser Stelle eine 1 oder 0 ist...dementsprechend wird der Ausgang in
der ISR dann gesetzt.
Das Problem dabei ist, dass ich den uC eigendlich universell gestallten
will und dann bei Taktänderungen nicht umprogrammieren muss.
Ich habe auch schon an die Variante gedacht einfach einen Zahlencode
statt der einzellnen Bits zu senden, sprich es sollen zB die Bits
2,3,7,8,10 auf high gesetzt werden, dann sendet der PC nur diese Zahlen
und in der ISR werden dann die entsprechenden Zeiten high gesetzt.
Dies würde Speicherplatz-mäßig gehen...da harperts mir aber noch an der
Umsetzung. Da ich gedanklich immer an der Umsetzung mit einem
Array-Vergleich hänge...
TheGee schrieb:> Ja gut, dann hätte ich 1 Byte. Wenn die nächsten Bytes aber nicht> Zeitdiskret übertragen werden, passt es wieder nicht.>> Oder meine Denkweise mit dem "Zwischenspeichern" im Array ist falsch.
Ja.
Beispiel:
Beleuchtung ein = 0x81
Beleuchtung aus = 0x01 (Bit 7 = 1 für ein und 0 für aus)
Ventilator ein = 0x82
Ventilator aus = 0x02 (Bit 7 = 1 für ein und 0 für aus)
Somit hast du 127 verschiedene Befehle mit nur einem Byte und
praktisch ohne Verzögerung.
Das sich etwas erst nach 23s ein- oder ausschaltet ist ein klein
bisschen zu langsam, findest du nicht ?
@ TheGee
Ich vermute, dass ist so ein Fall, in dem die Lösung komplizierter als
nötig ist.
Falls und soweit ich Deine Beschreibungen recht verstehe, dann ist
folgendes:
> Der uC soll am Ausgang ein Taktsignal mit 0-30 Impulsen liefern. Die> Impulse (Zustand 1) selber sollen 355ms lang sein, dazwischen 405ms> pause (0).> Nun werden je nach Befehl nur bestimmte Impulse freigegeben. Die Ersten> zehn Impulse stllen die Adresse dar, die weiteren 20 die Aktion, welche> der Aktor ausführen soll.
so zu deuten.
1. Es werden "Telegramme" übertragen. D.h. es gibt eigenständige Teile,
die für sich genommen vollständig sind. Nicht ein fortlaufender
Bitstrom, der ständig vorliegen muss.
2. Die Telegramme bestehen aus Adresse und Kommando
3. Eine Adresse besteht aus 10 kleinsten Informationseinheiten.
4. Ein Kommando besteht aus 20 kleinsten Informationseinheiten.
Und jetzt bin ich mir nicht sicher, ob ich Dich richtig verstehe:
5. Eine kleinste Informationseinheit dauert bei der Übertragung 355 +
405 = 760ms. Richtig?
Es wird entweder. 760ms lang ein Low-Pegel übertragen oder 355ms lang
ein High-Pegel gefolgt von 405 ms Low-Pegel. Richtig?
Die kleinste Informationseinheit ist vermutlich entweder 0 oder 1. Die 0
wird vermutlich mit den 760ms Low-Pegel übertragen, die 1 vermutlich mit
dem beschrieben Pegelwechsel. Richtig?
Daraus folgt, dass es 2^10 verschiedene Adressen und 2^20 verschiedene
Kommandos gibt. Siehst Du das auch so?
Daraus scheint mir der, - zunächst naive -, Ansatz zu folgen:
a) Es wird vom PC eine Folge von 2 Bytes für die Adresse übertragen.
b) Es wird anschliessedn eine Folge von 3 Bytes für das Kommando
übertragen.
c) Der uC puffert Adresse und Kommando bis beides vorhanden ist. Evtl.
puffert er auch mehrere solcher Tupel.
d) Der uC erzeugt z.B. interruptgesteuert aus diesen beiden Daten, eine
entsprechende Impulsfolge. Dabei wird nicht zunächst die Impulsfolge
also Folge von 0 und 1 berechnet und gespeichert. Es ist nicht ganz klar
ob eine gewisse Adresse, z.B. 0x17 auch in seiner binären Darstellung
gerade die Bitfolge wiedergibt, aber das wäre der naheliegendste oder
einfachste Fall.
Das ganze liest sich bis auf das Timing wie eine einfache serielle
Übertragung wie RS232 oder IIC oder so. Eigentlich nicht wirklich
kompliziert zu machen. Wegen des Timings wird man das aber vermutlich
wie einen Software-UART angehen.
Also so:
1. Nimm das erste Bit mit einer Maske.
2.a. Ist es 1, erzeuge die 1-Folge der kleinsten Informationseinheit
(also 355ms High und 405ms Low)
2.b. Ist es 0, erzeuge die 0-Folge (also 760ms lang Low-Pegel)
3. Falls noch nicht das letzte Bit (also 10 bzw. 20) erzeugt wurde,
schiebe die Bitmaske eine Bit weiter und gehe zu 1.
4. Ende
Nützt Dir das was?
Hanswurst schrieb:> @ TheGee>> Ich vermute, dass ist so ein Fall, in dem die Lösung komplizierter als> nötig ist.>> Also so:>> 1. Nimm das erste Bit mit einer Maske.> 2.a. Ist es 1, erzeuge die 1-Folge der kleinsten Informationseinheit> (also 355ms High und 405ms Low)> 2.b. Ist es 0, erzeuge die 0-Folge (also 760ms lang Low-Pegel)> 3. Falls noch nicht das letzte Bit (also 10 bzw. 20) erzeugt wurde,> schiebe die Bitmaske eine Bit weiter und gehe zu 1.> 4. Ende>> Nützt Dir das was?
Ja genau, hast alles richtig verstanden. Das mit dem verschieben hilft
mir weiter! Dann könnte ich die 30 Zustände in ein Array übertragen und
diese mit der Maske nacheinander abfragen...je nachdem ob der Zustand
dann high oder low sein soll wird dann das entsprechende Signal
generiert.
Da werde ich mich morgen gleich mal reinhängen...Vielen Dank!
TheGee schrieb:> Ja genau, hast alles richtig verstanden. Das mit dem verschieben hilft> mir weiter! Dann könnte ich die 30 Zustände in ein Array übertragen und> diese mit der Maske nacheinander abfragen...je nachdem ob der Zustand> dann high oder low sein soll wird dann das entsprechende Signal> generiert.
Auweia.
Du hast aber nichts verstanden...
TheGee schrieb:> Ja genau, hast alles richtig verstanden. Das mit dem verschieben hilft> mir weiter! Dann könnte ich die 30 Zustände in ein Array übertragen und> diese mit der Maske nacheinander abfragen...je nachdem ob der Zustand> dann high oder low sein soll wird dann das entsprechende Signal> generiert.>> Da werde ich mich morgen gleich mal reinhängen...Vielen Dank!
HALT! HALT! HALT! Ich denke Du hast das falsch verstanden.
Ein Array kommt nur als Puffer für die Daten vom PC vor.
Aber NICHT, so wie Du es oben schriebst, für die zu sendenden Bitmuster.
Das wäre total ineffizient in Bezug auf Übertragungsgeschwindigkeit und
Speicherplatz. Oder habe ich jetzt was falsch verstanden?
Die Kernfrage ist, wie die 10 Adressen und die 20 Kommandos bei der
Übertragung vom PC kodiert sind.
Dazu solltest Du was schreiben. Und zur Redundanz noch den Empfänger
nennen oder beschreiben, der diese Impulsfolge letztlich empfängt.
@ TheGee
Um mal klarzustellen, wo ich eine ungünstige Überlegung bei Dir vermute:
Angenommen es ginge um Adresse 0x201 und Kommando 0x8001
(Die Daten sind absichlich so gewählt, dass lange Reihen von 0
entstehen).
Dann würde Dein Array, dass in Millisekunden-Äuflösung das zu sendende
Bitmuster enthält so aussehen:
Es wäre, wie Du schon schriebst, 22800 Bit lang. Also 22800 / 8 = 2850
Byte
Der überwiegende Teil der Daten würde, wegen der Pausen, aus Nullen
bestehen.
char Bitmuster [] {0x80, 0, 0, 0, ..., 0, 0, 1};
Eine enorme Platz und Zeitverschwendung.
Mit der Bitmaske hat das nichts zu tun.
Vielmehr soll Dein Array so aussehen (mal abgesehen von einigen Details,
die man anders machen würde).
struct Telegramm {
uint16_t Adresse;
uint32_t Kommando;
};
#define ANZAHL_TELEGRAMME 10
struct Telegramm Buffer [ANZAHL_TELEGRAMME];
Deine Uart-Empfangsroutine füllt diesen Buffer (Ringpuffer).
Das ist wesentlich kürzer, als Dein Monster-Array.
Bitmasken wendest Du auf Adresse und Kommand an.
Also 0x800 bzw. 0x80000. Und DIE schiebst Du über Adresse und Kommando.
Die Pegel-Dauer erzeugst Du jeweils daraus, ob das Bit 1 oder 0 ist.
Hoffe ich habe noch rechtzeitig geschrieben, ehe Du diese Monster
implementierst.
Hanswurst schrieb:> @ TheGee> Hoffe ich habe noch rechtzeitig geschrieben, ehe Du diese Monster> implementierst.
Guten Morgen,
nein so war das nicht gemeint...würde ja dann mein Problem nicht lösen.
Ich war in Gedanken daran die 30 einzellnen Zahlen vom PC->uC zu
übertragen...wie sonst auch...ist ineffizient, reicht mir aber erstmal,
da die Übertragungsdauer vom PC zum uC erstmal zweitrangig ist.
Es ist im Prinzip (in C#) eine for Schleife welche die Zustände (high,
low) der Zahlen 1,2,3,4,5,...,30 einzelln über die Schnittstelle sendet.
Auf dem uC wird die Schnittstelle durch die ISR(USART_RXC_vect)
abgefragt und nach jeder Sendung ein Zähler hochgezählt. So weis der uC
an welcher Stelle (1,2,3,4,5,...,30 ) das high oder low ins Array
eingetragen werden muss.
Nun habe ich durch deinen Tipp überlegt statt ein Array für 22800
Zustände anzulegen, eines für die 30 Zustände zu erstellen. In der ISR
vom Timer0 käme dann ein switch case rein der je nachdem ob high oder
low gesendet werden soll, die Zeiten generiert. Beim Ende bin ich mir
aber noch nicht so sicher...ich werds mal versuchen...
TheGee schrieb:> Nun habe ich durch deinen Tipp überlegt statt ein Array für 22800> Zustände anzulegen, eines für die 30 Zustände zu erstellen. In der ISR> vom Timer0 käme dann ein switch case rein der je nachdem ob high oder> low gesendet werden soll, die Zeiten generiert. Beim Ende bin ich mir> aber noch nicht so sicher...ich werds mal versuchen...
Und nochmal:
Wie wäre es mit einem einzigen Byte von PC und direktem ausführen
gleich danach ?
Wozu die 30 Zustände, wozu die "Geschwindigkeit" von 1,3Hz ?
TheGee schrieb:> Der uC soll am Ausgang ein Taktsignal mit 0-30 Impulsen liefern.
OK. Eigentlich aber nicht Ok. Was willst du mit einem Taktsignal? Der µC
muss ein Datensignal liefern.
> Die Impulse (Zustand 1) selber sollen 355ms lang sein, dazwischen 405ms> pause (0).
Wie kommen diese Zeiten zustande? Abgesehen von der Länge, wieso 355 und
405?
> Nun habe ich auf dem uC den Timer0 entsprechend eingestellt, dass er> jede ms in die ISR springt und einen Vergleich durchführt.
Warum? Du weisst doch, daß mind. 355ms nichts passiert. Warum also alle
ms nachgucken?
> Vermutlich bin ich auch auf dem Holzweg
Aber sowas von...
> Mit delays möchte ich nicht arbeiten...
Dein einziger richtiger Ansatz.
Du überträgst Daten mit einer PWM. PWM definiert sich über die Zeit. Um
zwei Zustände zu unterscheiden brauchst du also 2 Zeiten. Das ist jetzt
trivial. Also nur, damit das klar ist.
Die eine Zeit ist t, die andere 2t. Damit lässt sich das auch vernünftig
unterscheiden:
Eine logische 1 hat die Länge t eine 0 die Länge 2t. Das ist jetzt
willkürlich festgelegt, aber bleiben wir dabei.
Um eine logische 1 zu senden, setzt du den Leitungspegel auf High und
schaltest ihn nach der Zeit t wieder auf Low. Bei einer logischen 0 wird
der Leitungspegel ebenfalls auf High, aber erst nach 2t wieder auf Low
gesetzt.
Wichtig ist, daß die Leitung auch auf Low geht!
Denn der Empfänger wird mit der steigenden Flanke des Highpegels
getriggert und guckt timergesteuert nach 1,5t auf die Leitung. Ist der
Pegel jetzt Low, wurde eine eine logische 1 empfangen, ist er (immer
noch) High, steht eine logische 0 an.
Das nächste Bit beginnt wieder mit einer steigenden Flanke auf der
Leitung. Die Dauer des dazwischen liegenden Lowpegels ist vollkommen
egal. Das können ein paar µs, ein paar ms oder auch ein paar Wochen
sein.
Zum Senden werden die Datenbytes bitweise ausgewertet.
Dazu sieht man sich je nach Bitorder das oberste oder unterste Bit an
und verschiebt das Byte danach entweder nach links oder rechts. Nichts
mit switch und case, sondern einfach if und else.
Dann wird zuerst der Ausgangspegel auf High gesetzt und entsprechend des
Bitwertes nach t oder 2t wieder auf Low. Das erledigt der Timer mit
seiner Hardware. Zur Not auch im Interrupt.
Übrigens: Der Timer kann seinen korespondierenden Pin nicht nur zyklisch
toggeln, sondern auch nach Ablauf der eingestellten Zeit auf High oder
Low setzen. Auch wenn es sich bei der Übertragung um eine PWM handelt,
ist CTC der richtige Timermodus.
Und mach die Zeiten kürzer.
Naja. Das ist zwar speichersparender, aber Du musst immer noch rund 240
Byte übertragen anstatt 4 oder 5 wie bei meiner Methode.
Ich weiss aber nun auch nicht mehr woran es liegt, dass Du das partout
nicht verstehen oder eben nicht so machen willst. Ich weiss auch nicht
wie ich das noch deutlicher erklären könnte. Deutlicher geht es
eigentlich nicht mehr.
Ich bezweifle, dass die Spezifikation richtig ist.
Wie sollen zum Beispiel die Befehle 0x0001, 0x0002, 0x0004 usw
unterschieden werden? In allen Fällen kommt nur ein Impuls von 355 ms.
Um welche Eisenbahnmarke und welche Bauteile handelt es sich denn, die
du ansteuern möchtest?