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?
Die dritte Variante wäre, dass Multiplexing mittels einem Interrupt zu erledigen, der alle 150 µs aufgerufen wird.
Ich weiß zwar nicht, was Shiftreistern sind - eventuell eine sehr misslungene Denglisch Variation, allerdings köingt die Aufgabenstellung wirklich sehr nach (Timer-)interrupt.
Oh, ich meinte natürlich "Shiftregistern" Nunja, Timer1 währe schon eine möglichkeit aber ich weiss nicht ob sowas durch "delay();" beinflusst wird.
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!
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
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
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.
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.
> 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...
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
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?
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...
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...
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?
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?
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.
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 ...
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
MaWin schrieb: > Wer hat denn shiftout > geschrieben ? Bremst er sie absichtlich ? Denn in Assembler dauert das > 2us. 32bit in 2µs? Sicher?
@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!
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.
@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.
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.
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
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.
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?
@ 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.
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...
@ 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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.