Sicheres Multiplexen?

OP #4668539
Lesenswert?

Ich muss bei einer Schaltung multiplexing einsetzen, und zwar mittels 4x 
8bit-Shiftreistern.

Das Timing sieht wie folgt aus:

"shiftOut32(val);" - Wert wird gesetzt
"delayMicroseconds(150);" - 150uS warten
"blankOutputs();" - 0 setzen aller Ausgänge
"delayMicroseconds(150);" - 150uS warten
"shiftOut32(val);" - Nächster wert

So läuft das denn dauerhaft weiter.


Mein Problem ist nun. Der AtMega328 hat sonst noch einges zu tun und 
deshalb befürchte ich folgendes, da ja "nur 300uS für andere Operationen 
zur Verfügung stehen":

1.) Zeitliche Probleme mit der Wartezeit

und noch schlimmer

2.) Verzögerung oder Abbruch des eigentlichen "shift-vorgangs" durch 
andere "Prozesse"


Nun habe ich zwei Ideen.

Einen Attiny oder ähnlich einstzen, der mit alle 150uS ein Signal 
aussendet, das ich am Interrupt des 328er benutzen kann (Interrupts 
sperren ja alle anderen Aktionen).

Wenn schon ein zweiter uC benötigt wird, könnte man diesen doch direkt 
per I2C einbinden, und ihm das Multiplexen überlassen. Per I2C werden 
dann die absoluten Werte übergeben.

Oder gäbe es noch andere/bessere Varianten?
Gast #4668792
Lesenswert?

Johnny S. schrieb:
> aber ich weiss nicht ob sowas
> durch "delay();" beinflusst wird.

Was meinst du mit "sowas"? Und welche delay's sind gemeint?
Vielleicht zur kurzen Erläuterung. Du stellst dir einen Timer, der in 
einem bestimmten Zeitraster tickt. Damit ruft er eine ISR auf. Und in 
dieser ISR machst du dein Multiplexing (eine Stelle aus, weitergehen zur 
nächsten Stelle, anzuzeigende Ziffer holen, diese Stelle an). Ganz grob 
erklärt.
Damit hast du keinerlei Anlaß, irgendwelche Zeiten mit delay zu 
erzeugen!
Moderator (Firma: Titel) Persönliche Seite #4668798
Lesenswert?

Johnny S. schrieb:
> "delayMicroseconds(150);" - 150uS warten
> "blankOutputs();" - 0 setzen aller Ausgänge
> "delayMicroseconds(150);" - 150uS warten
> "shiftOut32(val);" - Nächster wert
> So läuft das denn dauerhaft weiter
Und braucht 100% der Rechenleistung.
Das ist die lange Schreibweise für "Programmierfehler".

> Mein Problem ist nun. Der AtMega328 hat sonst noch einges zu tun
Du wirst das Multiplexen in einen Timerinterrupt verlegen müssen. Und 
zum Testen nimmst du einfach solche Vorwiderstände, dass die LEDs nicht 
abfackeln, wenn du in einem Breakpoint statisch auf einer Zeile stehen 
bleibst...

> Nun habe ich zwei Ideen.
> Einen Attiny oder ähnlich einstzen, der mit alle 150uS ein Signal
> aussendet, das ich am Interrupt des 328er benutzen kann (Interrupts
> sperren ja alle anderen Aktionen).
Hört sich in etwa an wie:
Ein Loch ins Knie bohren und Kugeln einfüllen...

> Wenn schon ein zweiter uC benötigt wird
Wofür denn der jetzt?
Du kennst diese Laufschriften mit vielen LEDs? Das kann auch ein 
einziger uC. Und nebenher noch die Fernbedienung decodieren und die 
serielle Schnitte versorgen, eine Uhr laufen lassen und Schaltzeiten 
verwalten. Ich vermute also, dass dein Softwareansatz nicht ausgegoren 
ist. Das delay() deutet darauf hin...
#4668799
Lesenswert?

Johnny S. schrieb:
> Nunja, Timer1 währe schon eine möglichkeit aber ich weiss nicht ob sowas
> durch "delay();" beinflusst wird.

Du [Schimpfwort von MOD gelöscht] sollst gar kein delay() verwenden. 
Sondern einen Timer so programmieren, daß er alle 150µs einen Interrupt 
auslöst. In der ISR mußt du dann nur im Wechsel einen neuen Wert 
rausschieben oder die Ausgänge auf 0 stellen.
Gast #4668828
Lesenswert?

Dein Timer sollte im Raster von 150µs ticken. In der ISR schreibst du 
sinngemäß:

if step==1  Wert setzen, step=2 -> exit

elseif step==2  alle Ausgänge löschen, step=1, nächsten Wert holen -> 
exit

Die beiden Zeilen werden damit aller 150µs aufgerufen. Ganz ohne Delay.
OP #4668945
Lesenswert?

Vielen Dank für den Tipp mit dem Timerintterupt, dies funktioniert 
grundsätzlich gut :-)

Was ich nun feststellen musste, ist das der AtMega sowiso zu langsam 
ist, denn er nicht mit dem Shiften fertig, weil dies länger dauert wie 
150uS.

Da muss wohl etwas schnelleres her, da die orginale shiftOut(); funktion 
nicht benutzt werden kann, weil sie nicht kompatibel ist.
Angehängte Dateien:
Gast #4668962
Lesenswert?

Johnny S. schrieb:
> das der AtMega sowiso zu langsam ist,
Das glaube ich nicht, der langweilt sich eher...

Johnny S. schrieb:
> Da muss wohl etwas schnelleres her, da die orginale shiftOut(); funktion
> nicht benutzt werden kann, weil sie nicht kompatibel ist.
Was heißt "originale shiftOut()"? Wo kommt die her? Kann man dieser 
Funktion nicht mitteilen, wie schnell sie schieben soll?
Gast #4669002
Lesenswert?

Johnny S. schrieb:
> Was ich nun feststellen musste, ist das der AtMega sowiso zu langsam
> ist, denn er nicht mit dem Shiften fertig, weil dies länger dauert wie
> 150uS.

In Bascom geschrieben ?

Selbst C sollte das schaffen. Obwohl, wenn man ganz kranken Code 
schreibt kann man alles langsam machen. Wer hat denn shiftout 
geschrieben ? Bremst er sie absichtlich ? Denn in Assembler dauert das 
2us.

Johnny S. schrieb:
> blankOutputs();" - 0 setzen aller Ausgänge

Man sollte offenbar Schieberegister verwenden, die einen OE oder CLR 
Eingang haben und damit durch 1 Ausgabeoperation sofort alle Ausgänge 
abschalten können. Die richtige Hardwareauswahl kann also auch beim 
Programmieeren helfen.
OP #4669029
Lesenswert?

Ich hatte zum test nur mal 16bit benutzt und folgenden Code:

for(int i=1; i<=16; i++){
digitalWrite(DATA, bitRead(value, i));
digitalWrite(CLK, HIGH);
digitalWrite(CLK,LOW);
digitalWrite(DATA,LOW);
       }


die variable "value" ist der Wert in einer 32bit variable.

Die Standard "shiftOut();" setzt zuerst CLK high, und setzt dann DATA.

Mein Spezial-IC HV66,
http://ww1.microchip.com/downloads/en/DeviceDoc/HV66%20C070313.pdf

benötigt den DATA aber vor dem CLK im richtigen Zustand.

und zwar mindestens 25ns vor CLK
#4669051
Lesenswert?

@Johnny SGT (sgt_johnny)

>Ich hatte zum test nur mal 16bit benutzt und folgenden Code:

>for(int i=1; i<=16; i++){
>digitalWrite(DATA, bitRead(value, i));
>digitalWrite(CLK, HIGH);
>digitalWrite(CLK,LOW);
>digitalWrite(DATA,LOW);
>       }

Das ist Arduino und seine IO-Funktionen.

https://www.arduino.cc/en/Reference/ShiftOut

Diese Funktion greift ihrerseits auch wieder nur auf digitalWrite() zu. 
Das ist schnachlangsam! Ein einzelnes digitalWrite() dauert ~7us!!

Beitrag "Re: Suche jemanden mit Oszilloskop zum Optimieren von Signalleitungen"

>benötigt den DATA aber vor dem CLK im richtigen Zustand.

>und zwar mindestens 25ns vor CLK

Das ist trivial, einfach die Daten vor dem Takt ändern.

Entweder nimmst du das Hardware-SPI deines Arduinos oder du musst das 
Bitschieben als Soft-SPI old school programmieren. Aber das ist ein 
schööööne ÖÖÖÖÖbung fööööör den Schöööööler!
#4669085
Lesenswert?

@Johnny SGT (sgt_johnny)

>Dann benutze ich wohl Hardware SPI,

Gut.

>und mache dann lötbrücken, die ich
>nach dem programmieren überlöten kann damit das IC verbindung hat.

Muss man nicht. Wenn man an das CS Signal des SPI-Slave einen externen 
Pull-Up Widerstand schaltet, kann die Verbindung auch während des 
Programmierens bestehen bleiben.
OP #4669835
Lesenswert?

Das IC wird nicht für ein LCD benutzt, sondern für ein VFD, und eine 
Punktmatrix mit 3..5 Änderungen pro Sekunde ist sinnlos.

Ab etwa 200Hz kann man das denn "flicker"-frei anschauen. Und das 
element besteht aus 10 Teilen, bei 150uS ein/ 150us Aus, sind das pro 
element 300uS * 10 Elemente = 3mS
#4670064
Lesenswert?

Johnny S. schrieb:
> Das IC wird nicht für ein LCD benutzt, sondern für ein VFD

Auch dann sind die 150µs spielend zu schaffen.
Du kannst das SPI oder die UART im SPI-Mode nehmen. Mit der UART ist man 
noch etwas schneller, da keine Pausen zwischen den 4 Bytes.
Mit nem Pulldown an /BL bleibt das VFD dunkel während des 
Programmierens. Mit /BL kannst Du Dir auch das 0 schieben sparen.

Die Funktionsaufrufe digitalWrite(); müssen erst mühsam die 
Arduino-Nummer in den entsprechenden Pin-Zugriff ummappen, daher sind 
sie sehr langsam.
Direkte Portzugriffe (PORTx |= 1<<y bzw. PORTx &= ~(1<<y)) können direkt 
als SBI/CBI ausgeführt werden, d.h. sind im Vergleich dazu rasend 
schnell.
#4670108
Lesenswert?

@ Lothar Miller (lkmiller) (Moderator) Benutzerseite

>> Arduino-Nummer in den entsprechenden Pin-Zugriff ummappen, daher sind
>> sie sehr langsam.

Ja.

>Machen die eine Arbeit, die eigentlich der Compiler machen müsste,
>tatsächlich zur Laufzeit?

Nein. Denn die Argumente sind VARIABEL, das KANN der Compiler nicht 
vorher ausrechnen. Mögicherweise gibt es aber in C++ Möglichkeiten, 
durch Overloading 2 Funktionen bereitzustellen, ein digitalWrite() mit 
variabeln Parametern und eins mit konstanten, welche dann vom Compiler 
aufgelöst werden kann. In der Praxis wird man variable Portzugiffe 
deutlich weniger brauchen als konstante.
#4670145
Lesenswert?

@  Lothar Miller (lkmiller) (Moderator) Benutzerseite

>> die Argumente sind VARIABEL
>Ich möchte behaupten, dass annähernd 99,9% der Aufrufe von
>digitalWrite() zumindest bei der Pinadresse statisch sind...

Kommt das der Formulierung

"In der Praxis wird man variable Portzugiffe deutlich weniger brauchen 
als konstante."

ausreichend nah?

;-)

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren