Forum: Mikrocontroller und Digitale Elektronik uC Taktsignal Zeitdiskret ausgeben


von TheGee (Gast)


Lesenswert?

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.

von Nerd B (Gast)


Lesenswert?

Wozu brauchst du denn den PC? Und wozu brauchst du das Array? Und warum 
willst du nicht mit der delay Funktion arbeiten?

von Nerd B (Gast)


Lesenswert?

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?

von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

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 ?

von ElektroNick (Gast)


Lesenswert?

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.

von Nerd B (Gast)


Lesenswert?

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?

von TheGee (Gast)


Lesenswert?

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.

von TheGee (Gast)


Lesenswert?

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

von Huh (Gast)


Lesenswert?

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>

von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

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.

: Bearbeitet durch User
von TheGee (Gast)


Lesenswert?

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.

von Jim M. (turboj)


Lesenswert?

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.

von TheGee (Gast)


Lesenswert?

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...

von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

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 ?

von Hanswurst (Gast)


Lesenswert?

@ 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?

von TheGee (Gast)


Lesenswert?

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!

von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

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...

von Hanswurst (Gast)


Lesenswert?

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.

von Hanswurst (Gast)


Lesenswert?

@ 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.

von TheGee (Gast)


Lesenswert?

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...

von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

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 ?

von Thomas E. (thomase)


Lesenswert?

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.

von Hanswurst (Gast)


Lesenswert?

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.

von Nerd B (Gast)


Lesenswert?

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?

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.