Forum: Mikrocontroller und Digitale Elektronik Sicheres Multiplexen?


von Johnny S. (sgt_johnny)


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?

von Tobias .. (bitfehler)


Lesenswert?

Die dritte Variante wäre, dass Multiplexing mittels einem Interrupt zu 
erledigen, der alle 150 µs aufgerufen wird.

von kennicknich (Gast)


Lesenswert?

Ich weiß zwar nicht, was Shiftreistern sind - eventuell eine sehr 
misslungene Denglisch Variation, allerdings köingt die Aufgabenstellung 
wirklich sehr nach (Timer-)interrupt.

von kennicknich (Gast)


Lesenswert?

*klingt ;-)

von Johnny S. (sgt_johnny)


Lesenswert?

Oh, ich meinte natürlich "Shiftregistern"

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

von Huh (Gast)


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!

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


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

: Bearbeitet durch Moderator
von Axel S. (a-za-z0-9)


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.

: Bearbeitet durch Moderator
von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Bitte keine allzu derben presönlichen Beifallsbekundungen!

von Markus S. (acepilot)


Lesenswert?

Versuche deine Applikation wann immer es geht ohne ein delay() zu 
programmieren. In 99.9% aller Fälle sind sperrende delays überflüssig 
und können auch anders gelöst werden.

von Huh (Gast)


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.

von Pandur S. (jetztnicht)


Lesenswert?

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


Es gibt von selbst keine anderen Prozesse. Wenn man die Zeit mit Delays 
verballert ist sie allerdings auch weg...

von Johnny S. (sgt_johnny)


Angehängte Dateien:

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.

: Bearbeitet durch User
von Huh (Gast)


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?

von Dominik R. (vision)


Lesenswert?

Das rausschieben von 32 Bit dauert länger als 150uSek? Ok... dann schau 
dir mal die Funktion an, die die Bits raus schubst. Ca. 5 uSek nur um 
ein Bit zu schieben ist schon arg viel...

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Dominik R. schrieb:
> Ca. 5 uSek nur um ein Bit zu schieben ist schon arg viel...
Ich tippe, da ist irgendwo noch ein delay() im Spiel...

von Peter D. (peda)


Lesenswert?

Johnny S. schrieb:
> denn er nicht mit dem Shiften fertig, weil dies länger dauert wie
> 150uS.

Bei 16MHz F_CPU dauern 4 Bytes ~4µs, was machst Du die restliche Zeit?

von Stefan (Gast)


Lesenswert?

Noch fraglicher ist für mich, warum man zur Ansteuerung der 
Schieberegister nicht einfach ein SPI Interface verwendet. Warum quält 
man den Prozessor mit sowas?

von MaWin (Gast)


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.

von Weinbauer (Gast)


Lesenswert?

kommt halt auf die Außenbschaltung an wie schneller er hinausschieben 
kann und/oder ob er softwaremäßig shiftet oder per SPI und auch wieviele 
Shiftregister er ansteuert ...

von Weinbauer (Gast)


Lesenswert?

PS: auch in Bascom kann man SBI CBI verwenden

von Johnny S. (sgt_johnny)


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

: Bearbeitet durch User
von Jack (Gast)


Lesenswert?

MaWin schrieb:
> Wer hat denn shiftout
> geschrieben ? Bremst er sie absichtlich ? Denn in Assembler dauert das
> 2us.

32bit in 2µs? Sicher?

von Falk B. (falk)


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!

von Johnny S. (sgt_johnny)


Lesenswert?

Dann benutze ich wohl Hardware SPI, und mache dann lötbrücken, die ich 
nach dem programmieren überlöten kann damit das IC verbindung hat.

von Falk B. (falk)


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.

von Peter D. (peda)


Lesenswert?

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

Das LCD wird weder in 150µs reagieren, noch kannst Du es so schnell 
ablesen.
Wozu also die Eile?
Ich mache Display-Ausgaben absichtlich langsam genug zum ergonomischen 
Ablesen, also max 3..5 Änderungen/s.

von Johnny S. (sgt_johnny)


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

von Peter D. (peda)


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.

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Peter D. schrieb:
> Die Funktionsaufrufe digitalWrite(); müssen erst mühsam die
> Arduino-Nummer in den entsprechenden Pin-Zugriff ummappen, daher sind
> sie sehr langsam.
Machen die eine Arbeit, die eigentlich der Compiler machen müsste, 
tatsächlich zur Laufzeit?

von Falk B. (falk)


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.

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

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

von Falk B. (falk)


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?

;-)

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.