Bascom Led matrix

guten abend,

ich geb zu es klappt nicht. mit timer 1, eventuell muss ich hier tatsächlich mit den Registern arbeiten.
aber vorher noch ne Frage, macht es sinn mein an und aus der leds zu drehen, bin ich überhaupt auf dem richtigen weg ??

kannst du mir sagen, warum meine lösung nicht ideal ist (nicht weil ich ja so toll bin sondern um den sinn zu verstehen)
wenn ich übrigens ocr1a erhöhe ändert sich die Helligkeit nicht, aber die anzeige flackert. die Helligkeit kann mit ocr1b geregelt werden.
ist immer noch Voodoo im Moment.

da ich aber mal nach dcf geschaut habe, ist timer1 ja eh blöd, den benötigt ja dcf.
also hier mein code mit timer2.

Code:
'Meine erste matrix
'ATMEGA8 mit 8mhz int quarz

$regfile = "m8def.dat"
$crystal = 8000000
$hwstack = 100
$swstack = 100
$framesize = 100

'--------------  ports init ---------------------                                  '
Lcdport Alias Portb
Matrixsp Alias Portd
Config Matrixsp = Output
Matrixzei Alias Portc
Config Matrixzei = Output
Taster1 Alias Pinb.6
Config Taster1 = Input
Portb.6 = 1



'------------------timer init--------------------
Config Timer2 = Timer , Prescale = 256 , Clear Timer = 0
On Compare2 Ledsoff
On Timer2 Ledson
Enable Compare2
Enable Timer2
Ocr2 = 1023
Enable Interrupts



'------------------lcd init -----------
Config Lcdpin = Pin , Db4 = Lcdport.3 , Db5 = Lcdport.2 , Db6 = Lcdport.1 , _
   Db7 = Lcdport.0 , E = Lcdport.5 , Rs = Lcdport.4

Config Lcd = 16 * 1
Cursor Off , Noblink


Dim I As Byte
Dim Offset As Byte
Dim Ledmuster(4) As Byte

For I = 1 To 4
Offset = I - 1
Ledmuster(i) = Lookup(offset , Spalten)
Next
'Offset = 0
Dim Zeilen(4) As Byte

Zeilen(1) = &B00000001
Zeilen(2) = &B00000010
Zeilen(3) = &B00000100
Zeilen(4) = &B00001000

Dim Sz As Byte
Dim Zz As Byte

Sz = 1
Zz = 1

'---------------------------------------------------

  Cls
  Lcd "hallo duda " ; Offset                                ' nur um zu sehen ob sich was tut


Do

   Debounce Taster1 , 0 , Newbild , Sub


Loop

End




Ledson:

   Matrixzei = Zeilen(zz)
   Matrixsp = Ledmuster(sz)
   Incr Zz
   Incr Sz
   If Zz = 5 Then Zz = 1
   If Sz = 5 Then Sz = 1

   Timer2 = 100
    Return


Ledsoff:


   Matrixzei = 0


   Return


Newbild:




      For I = 1 To 4
      If Offset = 127 Then
            Offset = 0
            Goto Hops
      End If
      If Offset < 127 Then Incr Offset
Hops:
      Ledmuster(i) = Lookup(offset , Spalten)

      Next



Return


$data

Spalten:
Data &B11101111 , &B11111111 , &B11111111 , &B11101111
Data &B01111111 , &B01111111 , &B01111111 , &B01111111
Data &B00111111 , &B00111111 , &B00111111 , &B00111111
Data &B00011111 , &B00011111 , &B00011111 , &B00011111
Data &B00001111 , &B00001111 , &B00001111 , &B00001111
Data &B00000111 , &B00000111 , &B00000111 , &B00000111
Data &B00000011 , &B00000011 , &B00000011 , &B00000011
Data &B00000001 , &B00000001 , &B00000001 , &B00000001
Data &B00000000 , &B00000000 , &B00000000 , &B00000000
Data &B10000000 , &B10000000 , &B10000000 , &B10000000
Data &B11000000 , &B11000000 , &B11000000 , &B11000000
Data &B11100000 , &B11100000 , &B11100000 , &B11100000
Data &B11110000 , &B11110000 , &B11110000 , &B11110000
Data &B11111000 , &B11111000 , &B11111000 , &B11111000
Data &B11111100 , &B11111100 , &B11111100 , &B11111100
Data &B11111110 , &B11111110 , &B11111110 , &B11111110
Data &B11111111 , &B11111111 , &B11111111 , &B11111111
Data &B11111110 , &B11111110 , &B11111110 , &B11111110
Data &B11111100 , &B11111100 , &B11111100 , &B11111100
Data &B11111000 , &B11111000 , &B11111000 , &B11111000
Data &B11110000 , &B11110000 , &B11110000 , &B11110000
Data &B11100000 , &B11100000 , &B11100000 , &B11100000
Data &B11000000 , &B11000000 , &B11000000 , &B11000000
Data &B10000000 , &B10000000 , &B10000000 , &B10000000
Data &B00000000 , &B00000000 , &B00000000 , &B00000000
Data &B00000001 , &B00000001 , &B00000001 , &B00000001
Data &B00000011 , &B00000011 , &B00000011 , &B00000011
Data &B00000111 , &B00000111 , &B00000111 , &B00000111
Data &B00001111 , &B00001111 , &B00001111 , &B00001111
Data &B00011111 , &B00011111 , &B00011111 , &B00011111
Data &B00111111 , &B00111111 , &B00111111 , &B00111111
Data &B01111111 , &B01111111 , &B01111111 , &B01111111



die Idee hinter dem prescale 256 ist, den isr so selten wie möglich zu machen, damit der rest des programms nicht so oft unterbrochen wird.
das vorladen auf 100 damit es grade nicht flackert, so meine Ideen.

gruß
 
Hallo Gino,

ich habe nicht alles mitverfolgt, aber was mir gerade aufgefallen ist, du verwendest Timer2. Achtung, das ist ein 8bit Timer (0..255). Dies geht hier nicht:

Ocr2 = 1023

Möglich dass in OCR2 dann 255 steht (low byte von 1023d). Es gibt dann wahrscheinlich bei 255 immer ein Compare, wie auch ein Overflow Ereignis.

Dirk :ciao:
 
...ich behaupte mal du hast das wirklich verstanden und nicht nur auswendig gelernt, liest sich zumindest so...
Nein, ich habe da gar nichts auswendig gelernt - ich habe höchstens mal versucht(!), die Funktionsweise des Timers zu verstehen. Das Prinzip ist dann bei allen Timern (der AVR) nahezu gleich. Der eine kann dann mal mehr, der andere weniger - die Register oder Bits heißen vielleicht mal anders, die Hardware ist hier mal komplexer, dort weniger, aber im wesentlichen ist das immer dasselbe. Der Rest ist dann im wesentlichen aus dem Datenblatt "abgeschrieben" - oder besser: übersetzt

...clear timer 1 setzt den timer bei ocr1a wieder auf null, ist mir bereits aufgefallen, wenn ich dieses auf 0 stelle waren mir die isr zu langsam...
Ich weiß nicht, was der Parameter konkret bewirken soll - in der Onlinehilfe (wenn sie denn mal geht) finde ich nichts dazu. Wie ist das nun mit dem CTC?
Du begrenzt die Reichweite des Timers. der zählt also nicht mehr bis max(=0xFFFF), sondern weniger weit, bis er überläuft. Bis wohin? Bis zum gewählten Begrenzungsregister. OCR1A in dem Fall. Um die Quizfrage zu beantworten: Was bewirkt das? Ganz einfach, daß die Überlauffrequenz steigt (in Deinem konkreten Fall wirkt sich das also auf die Zeilenfrequenz aus. Und somit indirekt auch auf die Bildwiederholfrequenz) - der Timer läuft in derselben Zeit öfter über (weniger increments pro Überlauf). Du hast also neben dem Prescaler (mit eher wenigen groben diskreten Werten - Grobtuning der Interruptfrequenz) zusätzlich die Begrenzung der Reichweite (mit eher vielen, feinen Werten - Feintuning).
Das OCR1B reguliert hingegen das An-Aus-Verhältnis inneralb eines jeden Timerdurchlaufes - also effektiv die gefühlte Helligkeit.
Du hast da eigentlich schon so umgesetzt, wie ich es gedacht hatte, lediglich die Werte (600, 200 und gf der Prescaler) sind etwas unglücklich gewählt gewesen.
Was hätte ich noch anders gemacht? Nun:
...ich habe in summe bei timer1 3 isr Möglichkeiten, das wird mir nun klar.

1. compare1b (timer läuft aber weiter)
2. compare1a (timer kann weiterlaufen ,tuts bei mir aber grad net)
3. timer1 Overflow.
...
Das stimmt eben nicht ganz.
Erstens tritt im CTC Modus mMn kein Überlauf-Interrupt mehr auf, da dieser laut Datenblatt durch den Überlauf von MAX (also 0xFFFF) nach 0 (0x0000) ausgelöst wird. Der Timer erreicht aber im allgemeinen 0xFFFF nicht, da er ja bereits bei OCR1A überläuft. Das ist aber auch egal, da OCR1A ja eh an dessen Stelle steht, also der Compare-Interrupt hier verwendet werden kann.
Zweitens kann man mit dem Input Capture Event (genauer dem Input Capture Match) und dessen IRQ einen weiteren Interrupt am Timer1 nutzen, WENN eben das Input Capture Register zur Begrenzung des Timers nimmt (das ist auch ein CTC-Modus - vielleicht setzt hier der Parameter an?).
Wa
ist der Unterschied? Nun, eigentlich gibt es keinen. Die Begrenzung erfolgt genauso. Benutzt Du OCR1A, kannst Du diesen Kanal natürlich nicht mehr zur Generation eines PWM verwenden, bzw den Interrupt für irgendwas anderes (deswegen hast Du den von Kanal B verwendet). Benutzt Du das ICR1 zur Begrenzung, kannst Di das Input Capture Unit eben nicht mehr als solches verwenden. Dafür bleiben hier beide Output Compare Units frei.
Ich opfere hier eher IC-Unit, als ein OC-Unit, aber das zu ändernwenn mans mal braucht, ist ja auch kein Thema...

Vielleicht hätte ich vor der Erklärung der Register mal 'ne Übersicht der (15) Operationsmodi erstellen/erklären sollen - hmm werd ich wohl noch nachreichen. Du bist zwar (wegen dem Zeitgeber) mit dem Multiplexing auf Timer2 umgestiegen, aber auch hier ist es ja wieder weitgehend dasselbe. Timer2 ist allerdings wesentlich weniger potent.
Daß es ein 8bit-Timer ist, hat Dirk ja inzwischen gesagt. Timer2 besitzt nur ein OutputCompare, und kein InputCapture. Wenn Du das mit der Helligkeitsregelung behalten willst, hast Du also nur den Überlauf- und den (einen) OutputCompare-Interrupt.
Folglich kannst Du die Helligkeit nur über OCR2 regeln, die Überlauffrequenz (Zeilenfrequenz) wird allein über den Prescaler (und den Systemtakt) festgelegt, oder eben zu Fuß, indem Du selbst die Reichweite begrenzt. MachstDu ja bereits
Ich hatte hier schonmal irgendwo eine Android-App hochgeladen, die diverse Timings der Timer und so berechnet hat. Dirk hatte für Windows auch einige Tools online gestellt - ob da was für Timer bei war, kann ich nicht sagen...

Der hohe Preload bringts nicht, mit weniger Restschritten erfolgt der IRQ ja auch wieder eher...
Das mit dem Flackern und der Verweilzeit in den ISR könnte man ja mal grob überschlagen.
pro Überlauf wird eine Zeile dargestellt.
Am Ende sollen es 12 sein.
Der Timer macht pro Überlauf 256 Schritte, der Systemtakt liegt bei 8MHz.
Mit Prescaler=128 komme ich auf 4,096ms pro Zeile, bzw ca 50ms pro "Bild". Wäre 'ne Bildwiederholfrequenz von ca 20Hz reicht das?
Oder besser Prescaler=64? -> 2,048ms pro Zeile, 25ms pro Bild, 40Hz.
Dann stehen dem Controller pro Überlauf immerhin 16384 Takte zur Verfügung.
Ob der Timer weniger größere Schritte machen soll, oder mehr kleinere spielt ja keine Rolle - mit flackerfrei forderst Du 'ne bestimmte Anzahl an Überläufen pro Sekunde (und eben auch an Compare-Interrupts). Der Preload macht also nur da Sinn, wo ein Prescaler nicht hinreichend flackerfrei ist, der nächstkleinere aber bereits zuviel (geschätzte) Zeit in ISRs verbringt (eben da die Bildwiderholfrequenz jetzt unnötig hoch wird) - Feintuning eben.

Die LEDSON-ISR sollte man so (ohne Preload) auf etwas weniger als 100 Takte bekommen können (mit Words für Zeilen und Spalten gerechnet), wenn man da mit ASM selbst Hand anlegt, die LEDSOFF-ISR beschränkt sich ja fast schon auf den Ein- und Austritt. Ein Register und das SREG retten/wiederherstellen, 1 CLR, eine (bzw 2) Ausgabe - sollte mit 30 Takten oder so passen.
Wie Gut Bascom das macht, ist 'ne andere Frage, aber selbst die 16K Takte sollten da pro Durchlauf bleiben...
'Ne höhere Taktfrequenz ist nicht drin?
Mit den Schieberegistern wird das dann nochmal 'n Zack enger, da man ja nicht so einfach ein Word rausschicken kann... ein Byte ist kein Ding. Aber bei 2 Bytes muß man dann auf das erste warten... vielleicht kann man in der ISR aber dann was sinniges in der Wartezeit machen... hmm... kniffelig

Achso, In Deinem Programm schaltest Du die neue Zeile an, während in an den Spalten noch die alten Werte anliegen, bevor Du auch da die neuen lädst und zuweist. Andersrum wäre das besser (Zeilen sind ja noch abgeschaltet), also erst die Spalten mit dem neuen Muster beladen, dann die neue Zeile anschalten. Ich schätze die Leuchtdauer der falschen Pixel auf 'ne gute µs (also sicher vernachlässigbar, aber ....)
 
Hi
Sorry, wenn ich mich als Assembler_freak in einen Bascom-Thread einklinke, aber ich denke, ich kann was dazu beitragen. Zuerst, ich hab nicht alles gelesen, also nich übel nehmen, wenn was doppelt erklärt wird.
Das Prinzip ist klar. Im letzen Beitrag ist mir aber aufgefallen, das die Anzeige nicht erst ausgeschaltet wird, bevor die neue Reihe aufgelegt wird.
Also, ganz wichtig bei Multiplex ist die Reihenfolge jedesmal bei einem Zeitinterrupt:

Reihe abschalten
Nächste Reihe adressieren ( nicht einschalten)
zugehörige Spalteninfo auflegen
Reihe einschalten

Das sind nicht viele Schritte und genau diese werden von der ISR getriggert. Ich setz mir dazu ein Bit in der Timer-ISR, die jede mSek. im CTC Mode aufgerufen wird. Dieses Bit wird in der Main abgefragt und wenn gesetzt, die Bearbeitung aufgerufen und das Bit gelöscht. Man könnte es als ein Event-Bit betrachten. Du kannst natürlich auch direkt in der ISR die paar Schritte durchführen. Die Zeit ist allemal. Damit das funktioniert, ist es erst mal wichtig, mit einem Timer umzugehen. Da solltest du deine primäre Energie einbringen und dafür sorgen, eine entsprechende Zeitbasis damit zu schaffen. Ist dir das gelungen, das du jede mSek. einen Interrupt bekommst, ist jede beliebige Zeit davon ableitbar.
Ich schaffe mit in der Timer-ISR immer ein paar Zeitflags in der beschriebenen Art, die dann für Zeitsteuerungen herangezogen werden. Zusammen mit Eventbits der IO wird das Programm mehr oder weniger "Ereignisgesteuert", was die Hauptschleife und damit die Zykluszeit klein hält.
Ich hoffe, du kannst damit etwas anfangen und in BASCOM umsetzen.
Gruß oldmax
 
Hi oldmax,

die Idee hier war, durch Multiplexing die jeweils nächste Zeile und die Spaltenleitungen anzuschalten, und zwar im Überlauf des Timers, bzw beim CTC im IRQ des verwendeten Vergleichsevents. Ja, dazu muß vor der Aktivierung der nächsten Zeile die ältere abgeschaltet werden. Mein Vorschlag war es nun, das CompareMatch (des 2ten PWM-Kanals) dazu zu verwenden, alle(!) Zeilen abzuschalten. Dadurch braucht man sich also um das abschalten der Leitungen nicht mehr (weiter) kümmern, außerdem hat man so nebenbei gleich die Möglichkeit, die Helligkeit zu regeln.

Danach hatte gino aber bemerkt, daß er noch einen DCF77 mit anbinden will, und dafür gern die Bascom-internen Funktionen/Befehle verwenden will (Du könntest das natürlich selbst machen, ich vielleicht auch - abgesehen davon, daß wir das in ASM machen würden, aber gino will sicher selbst programmieren...)
Die Bascom-Bibliothek krallt sich dafür aber zwingend Timer1 - ok, dabei fällt 'ne Zeitbasis mit ab, aber die ist mit 1s nicht mehr fürs Multiplexing verwendbar.

Daraufhin ist gino selbst auf Timer2 umgestiegen, der hat aber nur ein OC-Unit (->Dimmen), und kein IC-Unit. Also kein CTC, Um- bzw Anschalten der Zeilen und Spalten im Überlauf-Interrupt.

Timingtechnisch ist anzumerken, daß der Mega8 mit 8MHz läuft, und die LEDMatrix später auf 12x12 aufgestockt werden soll. Mindestens eine Dimension soll dabei seriell durch Schieberegister angesteuert werden - leider welche ohne OutputEnable (Dimming) und CS-Pin (falls beide Dimensionen). Und flackerfrei soll das ganze natürlich auch bleiben...

Zur Verwendung der Timer hatte ich ansonsten schon was geschrieben, auch wie Bascom wo welche Register beschreibt. Aber zu den WGM wollte ich noch'ne Übersicht machen. Damit die Tabelle im Datenblatt auch für Bascom'ler verständlicher wird. Der Bascom-Befehl ermöglicht so nicht alle (15 des Timer1), aber man kann ja selbst auf die I/Os zugreifen..
 
Hi
nun ja, das ich's in ASM machen würde is klar, aber ich hab deswegen ja auch keinen Code, sondern nur eine Beschreibung liefern wollen. Es muss zum Multiplexen ja nicht der timer1 genommen werden. Es reicht, einen 8 Bit-Timer mit einem Register zu verheiraten um einen ungefähren msek. Takt abzuleiten. Die 2 Befehle sprengen nicht das ganze Konzept. Aber ich kenn den Weg in BASCOM nicht. In Assembler würd ich ein Register "freischaufeln", mit INC bei jedem Interrupt hochzählen und wenn so ca. 1 msek. erreicht ist, das beschriebene Bit setzen. Bei 8 Mhz wär das etwa ein Wert von ... hmm .... 35, wenn der Timer im Overflow läuft und der Interrupt tritt alle 0,03 mSek. auf. Wenn der Controller sonst nicht allzuviel zu schaffen hat, könnt das funktionieren. In Assembler würd das alle 32 µSek
ca. 1 µSek. schlucken. Nich schön, aber machbar.
Wie bereits in meinem Post angedeutet, alles, was irgendwie mit Zeiten zu tun hat, läuft über Timer und damit sollte, nee muss man sich auskennen. Aber ihr macht das schon, denk ich. Übrigends, noch ein gutes und erfolgreiches 2014 an alle.
Gruß oldmax
 
Hi,
wie versprochen, reiche ich hier mal 'ne Übersicht der Betriebsmodi (waveform Generation modes) von Timer1 des Mega8 nach:
Timer1.png
Zur Erklärung:
In den Quadraten der letzten Zeile steht Nummer des jeweiligen Betriebsmodus. Das ist der Betriebsmodus, der Waveform Generation Mode. Der WGM. Die Dezimalzahl, die durch die 4 WGM-Bits in den beiden TCCR1-Registern binär abgelegt ist.
Die Zeile darüber enthält die Reichwerte des Timers (in hexadezimaler Form, bzw das Register, welches die Reichweite festlegt).

Als erstes kann man zwischen PWM- und nonPWM-Modi unterscheiden.
In nonPWM-Modi sind die OCR1x-Register nicht gepuffert (abgesehen vom 16bit-Zugriff) - Veränderungen wirken sich sofort aus.
Alle nonPWM sind singleSlope-Modi, dh der Timer inkrementiert immer, und läuft irgendwo über. Wo? Nun, das steht in der letzten Zeile (mit den Kreisen).
WGM=0, also Überlauf bei max=0xFFFF=216 ist der normalMode, WGM=4, also Überlauf bei OCR1A ist der CTC. (WGM=12 ist natürlich auch ein CTC)
In nonPWM-Modi können über die COM-Bits (TCCR1A) folgende Manipulationen der OC-Pins durch CompareMatches eingestellt werden:
  • keine (Pin nicht mit OC-Unit verbunden)
  • Pin wird getoggelt
  • Pin wird gelöscht
  • Pin wird gesetzt
Der Überlauf-Interrupt dürfte hier (laut Datenblatt immer bei MAX) nur bei WGM=0 auftreten, wenn OCR1A oder ICR1 die Reichweite auf einen kleineren Wert begrenzen, wird max ja nie erreicht...

Bei den PWM-Modi kann zwischen Modi mit singleSlope (wie schon bei den nonPWM) und dualSlope Modi unterschieden werden.
Im SingleSlope-PWM (oder auch FastPWM) wird der Timer nur inkrementiert, und läuft irgendwann über (bzw wird zurückgesetzt).
Abweichend zum nonPWM werden hier Veränderungen von OCR1n gepuffert, und erst beim nächsten Überlauf (Top->bottom) wirksam.
Auch die COM-Bits wirken hier anders beim OC-Match:
  • keine
  • keine, außer bei WGM=15, da wird KanalA getoggelt (entspricht also bei jedem Überlauf)
  • Pin wird beim OC-Match gelöscht, beim Überlauf gesetzt (nichtinvertierrender PWM)
  • Pin wird beim OC-Match gesetzt, beim Überlauf gelöscht (invertierender PWM)

Bei den dualSlope-Modi hingegen läuft der Timer zwischen 0 und einem Top-Wert hin und her.
Die Com-Bits bewirken hier bei OC-Matches:
  • keine
  • keine, außer bei WGM=9 oder 11 (die 14 im DB muß falsch sein) - da wird KanalA getoggelt (was da dem Umkehrpunkt entspricht
  • Pin ist gelöscht genau dann wenn TCNT>OCR1n
  • Pin ist gesetzt genau dann wenn TCNT>OCR1n
Jaja, genau genommen stimmt das so nicht ganz - der Pin wird im CompareMatchEvent gesetzt bzw gelöscht.
Dadurch werden sie phasenkorrekt.
Das Überlaufflag wird hier beim erreichen des unteren Umkehrpunktes (Bottom) gesetzt.
Natürlich werden auch hier die OCR1n-Register gepuffert.
Die Synchronisation erfolgt bei den nicht frequenzkorrekten Modi beim oberen Umkehrpunkt, bei den phasen- und frequenzkorrekten am unteren Umkehrpunkt, was hier auch schon der wesentliche Unterschied ist.
 
Zuletzt bearbeitet:
:yu: Heftig, besser hätte es Atmel selbst nicht erklären können!
 
Moin,

Ihr wisst schon, das Ihr mich da mit Infos überhäuft. Aber trotzdem danke ich versuchs aufzunehmen.

aktueller Stand (es geht jetzt langsamer, Urlaub ist beendet).

LED Matrix noch unverändert, aber mit der widerholfrequenz werde ich spielen.

DCF hab ich mal eingebaut und hat auch schlagartig funktionier, lesen bildet.

in dem Sekunden ISR gebe ich die Zeit auf einem LCD Display aus, das dauert aber so lange, das die Matrix nun im Sekundentakt flackert.

Ich denke da muss ich noch nacharbeiten.

irgendwann bekomme ich da schon noch ein Gefühl für.

Höhere Frequenz ist sicherlich möglich, dann bastel ich wenn nötig einen Quarz dran.

ich wollte halt diesen Schaltplan verwenden, ist die Wordclock aus der CT Zeitung. Die habe ich gebaut und tut auch aber mit PASCAl Programmiert.

Und nun möchte ich die Software gerne selber schreiben als nur dran rumzufrickeln. Also das ganze auch verstehen.
Seit 1-2 Monaten spiel ich nun mit Steckbrett, Mega8, LEDs und allem möglich rum. Ein Thermometer ist schon dabei rausgekommen.
Und nun übe ich eben weiter mit der Uhr, mal sehen wohin das alles führt, eins nach dem anderen.

gruß
 

Anhänge

  • schem_Wordclock_strip.pdf
    29,1 KB · Aufrufe: 21
...in dem Sekunden ISR gebe ich die Zeit auf einem LCD Display aus, das dauert aber so lange, das die Matrix nun im Sekundentakt flackert...
Genau das ist das Problem. Auf das Display gesendete Daten sind ja eher statisch - die bleiben da so lange stehen, bis Du neue sendest. Das erledigt der Display-Controller.
Um das Multiplexing der LEDs muß sich Dein Programm aber selbst kümmern. Also sollte das Vorrang bekommen.

Ich spekuliere mal: Du hast den DCF77 angeklemmt, und nutzt die Bascom-Routinen/Bibliothek. Insbesondere verwendest Du also auch die Möglichkeit, den (verwendeten) Timer1 einen IRQ je Sekunde erzeugen zu lassen. In dieser ISR läßt Du nun (unter anderem?) irgendwas auf dem Display ausgeben. diese Displayausgabe dauert aber zu lange - folglich gibt es jede Sekunde 'ne merkliche Störung des Multiplexing.

Warum?
Weil der Timer1-Interrupt, solange er aktiv ist, andere Interrupts (also insbesondere die des Multiplexing) unterdrückt/verzögert.
(Man könnte zwar die Timer1-ISR auch unterbrechbar machen, aber das ist eher speziell - falls Du was dazu wissen möchtest, gib bescheid. Hier ist das aber nicht nötig.)
Die Frage ist: braucht Du denn die Displayausgabe unbedingt in der/einer ISR? Ich denke eher: Nein. Der IRQ generiert Dir einen sauberen Sekundentakt - ob die Displayausgabe da mal'ne zehntel Sekunde früher, oder 'ne tausendstel später kommt, ist dann doch egal, oder?
Den Weg hat Oldmax ja bereits erklärt: Du brauchst 'ne Statusvariable die Dir die "'ne Sekunde ist rum"-Info von der Timer-ISR in Dein Hauptprogramm mitteilt. Ein Flag. 'N Memo. 'N Knoten im Taschentuch.
In der ISR machst Du den Knoten rein, und verläßt die ISR flott. Dann minimiert sich die Störung/Verzögerung des Multiplexing.
In der Hauptprogrammschleife kannst Du nun bei jedem Durchlauf 'n Blick aufs Taschentuch werfen - is'n Knoten drin, schiebste die neuen Daten aufs Display, und dröselst den Knoten wieder auf...

Zum Takt: mit der doppelten Taktfrequenz haste natürlich auch doppelt soviel Zeit für kritische Sachen...
Der Mega8 erlaubt maximal 16MHz, der Nachfolger des Mega8 ist der Mega88. Der ist Pinidentisch, hat aber deutlich mehr Hardware unter der Haube. Außerdem kann er bis 20MHz betaktet werden. (In ASM gibt's noch einige Unterschiede, die Dich aber nicht interessieren sollten).
Des weiteren gibt es in der Serie noch unterschiedliche Speicherausstattungen - Mega48/88/168/328. Quasi derselbe Controller.

Zu der Schaltung:
PortD und PortC steuern hier die Spalten an. Da dazu je der ganze Port verwendet wird, kann man das ganze schön parallel ausgeben (also PortC=bla, PortD=blub).
Halt, was ist mit C4, C5, C6? C4 und C5 werden für HW-TWI verwendet, sobald das TWI aktiviert wird (TWI Enable Bit (TWEN) im TWI Control Register (TWCR) oder so), werden die Beinchen vom I/O abgekoppelt, das TWI übernimmt die Kontroller über die Pins. Folglich kannst Du in die Register-Bits schreiben, was Du willst. Es hat keinen Effekt. Und C6? der ist als Reset-Pin auch von der I/O-Logik abgekoppelt (RSTDSBL-Fuse oder so).
Die Zeilendaten werden aber seriell rausgeschoben. Über (hoffentlich) HW-SPI. Das dauert dann aber immer.
Die SPI-Clk kann mit max einem viertel des Systemtaktes laufen. Folglich dauert das senden eines Bytes mindestens 32 Takte. Du kannst zwar das ganze Byte auf einmal an die Hardware übergeben (und dann was anderes machen), aber für das 2te Byte mußt Du eben diese 32 Takte warten. Ok, man kann versuchen, möglichst viel des Krams, den man eh in der ISR machen muß/will eben in diese Zeit zu packen (inkrementiererei der Zeiger in's SRAM, einige Register wiederherstellen usw).

Dein Display kannst Du bei dem Plan aber dann vergessen - wenns kein TWI ist. Selbst via SPI ist ja nicht möglich, da Deine Schieberegister nicht über !CS-Pins selektiert werden können.
 
Hallo,

das lcd soll dann auch nicht mehr dran sein, das habe ich aktuell nur um mir programmdaten anzuzeigen.
also irgendwelche variablen ausgeben, debuggen halt. ich hätte aber nicht gedacht, das die ausgabe so lange dauert, versuch macht gluch.

so bau ich mir teil für teil zusammen bis das ganze mal tut.

als nächstes löt ich mal die matrix 12x12 und bastel die schieberegister dran.
dann die muster für die ausgabe erstellen. und noch ein bischen logik für um die uhrzeit in die ausgabe zu wandeln.

klingt eigentlich net schwer. es gibt ja noch mindestens 2 weiter projekte im forum, da hab ich auch die eine oder andere idee geklaut.

den rtc baustein werde ich weglassen bzw. entlöten da mir dcf viel besser gefällt. Spart auch die Batterie für puffer.
folglich brauch ich auch keine taster und abfragen für das stellen der uhr. dafür kommt ein fotowiderstand dran um die helligkeit zu dimmen.

gruß
 
ach ja das mit dem flag find ich gut, werde ich auf jedenfall einbauen.
vor allem bei der worduhr. bei meiner variante ändert sich ja aller aller höchstens pro minute die anzeige.

mein grober plan ist.

per flag (reicht eigentlich zu jeder 59. sekunde) die uhrzeit in matrix wandeln. flag wird im sekunden isr incr. und in der hauptscheife ausgewertet.

in der hauptschleife die uhrzeit in matrix muster zu wandeln (zu jeder 59. sekund) , wenn diese sich ändern, und nur dann, die muster neu laden.

in dem ISR von Timer2 wird die multiplex ausgabe gemacht.

das sollte doch alles sein oder ??

das müsste heißen, mein UC macht eigenlich ca. 58 sekunden nichts anderes als die LED zu multiplexen und die Uhrzeit höchzuzählen.
dann die Matrix neu berechnen und das Array neu laden.

gruß
 
Im Prinzip schon. Allerdings wird des mit der seriellen Ausgabe über Hardware-SPI noch etwas fordernder (schätze ich jetzt mal) in der ISR. Das in der Hauptschleife zu machen, wird aber auch nicht so recht gehen, wenn grad Daten auf's Display... ok, das wäre ja dann raus, aber trotzdem.
Wieviel Zeit Bascom sich für die DCF-Routinen nimmt, kann man auch nicht so einfach sagen -> Multiplexing bleibt mitsamt der seriellen Ausgabe im IRQ.
Wenn der SPI-Takt also schnellstmöglich gewählt wird (wie schnell erlauben Deine Schieberegister da eigentlich?), lohnt es sich auch nicht, den SPI-ist-fertig-IRQ zu verwenden.
Du kannst das ja erstmal in Bascom versuchen (also mit den Bascom-Befehlen), wenn nötig kann man natürlich auch da wieder über die I/O-Register direkt an die Hardware gehen...
Notfalls läßt sich da mit eingebettetem Assembler noch was rauskitzeln.

Hmm... ich seh mich hier schon noch so'ne Übersicht machen... grml....
 
wenn ich grad so nachdenke,

warum eigenlich nicht die zeilen schaltung per schieberegister und die spalten per direktem IO port.

für jede zeile werden die Spalten LEds parrallel ausgegeben und ein bit im schieberegister wird weitergeschoben. sind alle zeilen durch,
kommt das "zeilenbit" "vorne" wieder rein und wird durchgeschoben. das geht doch wesentlich schneller und grad seh ich keinen nachteil.

dann muss ich eben nicht für jede zeile immer 12 bit in die schieberister schieben.
 
Hatten wir ja schon vorgeschlagen:
Hi,
Dino, Deine Idee hat nicht zufällig was damit zu tun, 'ne irgendwie(?) einmal ins Schieberegister gelangte 1 von vorn bis hinten durchzuclocken? Und den 12ten Ausgang dann auf den Eingang zu legen?


Mist! :rolleyes: erwischt :p

Ich hätte den Dateneingang des Schieberegisters auf eine sowieso benötigte Spaltenleitung vom Atmel gelegt. Dann muß man beim 1-durchtakten nur auf den richtigen Pegel dieser Leitung achten. Sollte aber kein Problem sein :D

Gruß
Dino
Aber ich wollte Dich erstmal ein wenig mit dem Multiplexing spielen lassen.
Was Du nun als Spalten, und was als Zeilen betrachtest, ist ja egal.

Dann mußt Du in der Compare-ISR die parallelen Leitungen abschalten, und in der Überlauf-ISR erst (!) einmal die Register schieben, danach die neuen parallelen Leitungen anlegen. Trotzdem mußt Du immer noch erstmal 'ne 1 in das (verdoppelte) Schieberegister bekommen...

Nachtrag: Ich würde an Deiner Stelle zum ansteuern der Schieberegister trotzdem die SPI-Pins verwenden - nur eben nicht HW-SPI.
MOSI auf den Dateneingang des ersten Schieberegisters, SCK auf den Clock-Eingang beider HC164.
Zum Init generierst Du die 1 und einen CLK-Strobe (damit ist die erste Zeile (oder eben Spalte) aktiv.
Danach wird MOSI tristate (Eingang, low). Die Verbindung des letzten Ausganges auf den Eingang realisierst Du mittels einek 4k7 oder 10k-Widerstandes.
Beim seriellen programmieren sollte das keine Rolle spielen (käme aber möglicherweise auf den Programmer an).

Willst Du das mit den PNP-Transistoren und den Darlington-Arrays (die können die Ausgänge AFAIK gegen Gnd ziehen) so beibehalten, oder würden Dir die 20mA pro LED reichen (max 20mA pro Pin, max 100mA über PortC (wären 80mA+ca 2mA für die Pullups (falls Du die hättest. Der Reset zählt extra?)) Der Rest zusammen max 200mA (160mA für die LEDs+1mA für R29 und R30 zusammen. Die würde ich sogar rauslassen, und stattdessen die internen Pullups nehmen.)

Auf keinen Fall die Kerkos an Vcc/Gnd und AVcc/Agnd vergessen - ich würde da vielleicht sogar je 2 Kerkos hinsetzen, und'n kleinenElko dazu (irgendwas im ein- bis zweistelligen µ-Bereich... aber da ist Dinos Bauch besser als meiner...
 
Hi,

Und ich dachte ich hätte den stein des weisen gefunden.

Schade.

Danke für die Antworten, es kommen beim testen bestimmt noch fragen dazu.
 
Haste ja auch... nachdem wir ihn in #15 liegengelassen haben...
Viel Erfolg, in halt uns auf dem laufenden...
 
guten abend,

hier meine Ergebnisse, erste Tests mit den bascom befehlen spiout und shiftout habe ich schnell wieder verworfen, da kann ich ja nur ein Byte rausschieben :-(
also allen Mut zusammengenommen und das mal selber probiert und siehe da es tut :).
ist jetzt ja auch net so schwierig.

sieht zwar so aus als habe ich grad keinen dcf empfang mehr, seit ich die schieberegister dran hab aber das kann net viel sein ;-)

Code:
'Meine erste matrix
'ATMEGA8 mit 8mhz int quarz

$regfile = "m8def.dat"
$crystal = 8000000
$hwstack = 100
$swstack = 100
$framesize = 100

'--------------  ports init ---------------------                                  '
Lcdport Alias Portc
Ledspalte Alias Portd
Config Ledspalte = Output
'Zeile Alias Portb
'Config zeile = Output
Taster1 Alias Pinb.6
Config Taster1 = Input
Portb.6 = 1

'--------------------dcf init-------------------------------

Config Dcf77 = Pinb.7 , Timer = 1 , Debug = 1 , Check = 1 , Gosub = Sectic
Config Date = Dmy , Separator = Dot


'------------------timer init für multiplex --------------------
Config Timer2 = Timer , Prescale = 64 , Clear Timer = 0
On Compare2 Ledsoff
On Timer2 Ledson
Enable Compare2
Enable Timer2
Ocr2 = 253
Enable Interrupts



'------------------lcd init -----------
Config Lcdpin = Pin , Db4 = Lcdport.3 , Db5 = Lcdport.2 , Db6 = Lcdport.1 , _
   Db7 = Lcdport.0 , E = Lcdport.5 , Rs = Lcdport.4

Config Lcd = 16 * 1
Cursor Off , Noblink

'------------------ init (schieberegister)------------------
Daten Alias Portb.4
Clock Alias Portb.5
Config Daten = Output
Config Clock = Output






'--------------------------variablen definieren ---------------------------
Dim Setdimm As Byte
Setdimm = 50
Dim I As Byte
Dim Offsetsekunden As Byte
Dim Offsetminuten As Byte
Dim Ledmuster(4) As Byte

Dim Sz As Byte
Dim Zz As Byte
Dim Tick As Bit
Dim Tack As Bit

Zz = 1

'---------------------------------------------------

  Cls



Do

   Debounce Taster1 , 0 , Setdimmer , Sub                   ' zum gugga obs tut
   If Tick = 1 Then                                         'lcd nur wenn neue sekunde und tick tack anzeige matrix umschalten.
        Locate 1 , 1
        Lcd Time$ ; " " ; Date$ ; " " ; Setdimm
        Tick = 0
        If Tack = 0 Then Offsetsekunden = 2
        If Tack = 1 Then Offsetsekunden = 0
        Gosub Newbild
   End If
   Select Case _min                                         ' minuten auswerten für matrix zum testen in meine 8 x 4 matrix
    Case 0 To 2 : Offsetminuten = 0
    Case 2 To 3 : Offsetminuten = 2
    Case 3 To 5 : Offsetminuten = 4
    Case 5 To 7 : Offsetminuten = 6
    Case 7 To 9 : Offsetminuten = 8
    Case 9 To 10 : Offsetminuten = 10
    Case 10 To 12 : Offsetminuten = 12
    Case 12 To 14 : Offsetminuten = 14
    Case 14 To 15 : Offsetminuten = 16
    Case 15 To 17 : Offsetminuten = 18
    Case 17 To 20 : Offsetminuten = 20
    Case 20 To 25 : Offsetminuten = 22
    Case 25 To 27 : Offsetminuten = 24
    Case 27 To 30 : Offsetminuten = 26
    Case 30 To 32 : Offsetminuten = 28
    Case 32 To 35 : Offsetminuten = 30
    Case 35 To 38 : Offsetminuten = 32
    Case Else : Offsetminuten = 0
    End Select





Loop

End




Ledson:



   If Zz = 1 Then Daten = 1                                 ' für erste zeile eine 1 ins schieberegister
   If Zz <> 1 Then Daten = 0                                ' mit 0 die obige eins weiterschieben.
   Clock = 1 : Clock = 0                                    ' clk impuls
   Ledspalte = Ledmuster(zz)                                ' daten für die jeweilige zeile anlegen
   Incr Zz                                                  ' nächste zeile (sind bis jetzt nur 4)

   If Zz = 5 Then Zz = 1



    Return


Ledsoff:

                                                               ' daten aus (dimmen und Geisterbilder)
   Ledspalte = &B11111111


   Return


Newbild:                                                    ' neues LED muster laden




      For I = 1 To 2                                        ' obere 2 zeilen zum test tick tack
      Ledmuster(i) = Lookup(offsetsekunden , sekundenmuster)
      Incr offsetsekunden
      Next
      For I = 3 To 4                                        ' zeile 3 und 4 minuten anzeige
      Ledmuster(i) = Lookup(offsetminuten , Minutenmuster)
      Incr Offsetminuten
      Next


Return


Sectic:

   Tick = 1                                                 ' tick tack bit
   Toggle Tack

Return

Setdimmer:

     Setdimm = Setdimm + 50
     If Setdimm > 250 Then Setdimm = 0

     Ocr2 = Setdimm
Return



$data

sekundenmuster:
Data &B11110000 , &B11111111
Data &B00001111 , &B11111111
Data &B11111111 , &B11111111
Data &B11111111 , &B11111111
Data &B11111111 , &B11111111
Data &B11111111 , &B11111111
Data &B11111111 , &B11111111
Data &B11111111 , &B11111111
Data &B11111111 , &B11111111
Data &B11111111 , &B11111111




Minutenmuster:
Data &B11111111 , &B11111110
Data &B11111111 , &B11111100
Data &B11111111 , &B11111000
Data &B11111111 , &B11110000
Data &B11111111 , &B11100000
Data &B11111111 , &B11000000
Data &B11111111 , &B10000000
Data &B11111111 , &B00000000
Data &B11111110 , &B00000000
Data &B11111100 , &B00000000
Data &B11111000 , &B00000000
Data &B11110000 , &B00000000
Data &B11100000 , &B00000000
Data &B11000000 , &B00000000
Data &B10000000 , &B00000000
Data &B00000000 , &B00000000
 
Das Mulitplexing geht aber soweit erstmal, ja?
Derzeit prüfst Du ja in jeder Überlauf-ISR, ob Dein Zeilenzähler 0 ist oder nicht. Entsprechend legst Du 'ne 0 oder 1 auf die Datenleitung, und clockst die ein ("schieb").
Statt der 2 If's kannst Du auch einmal If-Then-Else nehmen.
Oder Du denkst nochmal hierrüber nach:
...Nachtrag: Ich würde an Deiner Stelle zum ansteuern der Schieberegister trotzdem die SPI-Pins verwenden - nur eben nicht HW-SPI.
MOSI auf den Dateneingang des ersten Schieberegisters, SCK auf den Clock-Eingang beider HC164.
Zum Init generierst Du die 1 und einen CLK-Strobe (damit ist die erste Zeile (oder eben Spalte) aktiv.)
Danach wird MOSI tristate (Eingang, low). Die Verbindung des letzten Ausganges auf den Eingang realisierst Du mittels einek 4k7 oder 10k-Widerstandes...
Dann brauchst Du in der ISR nur noch Clk-Impulse generieren - die Daten (alles Nullen, bis auf eine eins) sind ja bereits im Register, und drehen sich über den Widerstand (DataOut vom Controller ist Tristate) nur noch im Kreis.
Spart hier die If's komplett.
Das Rücksetzen des Zählers brauchst Du natürlich trotzdem (wobei man in ASM hier stattdessen auch den Zustand der Datenleitung verwenden könnte (die, wo tristate ist) - statt des Vergleiches mit einer Zahl und einem daraus folgendem bedingten Sprunges könnte man mittels Skip direkt auf den Pin reagieren, und das Reset des Zählers überspringen. - Nur so am Rande, ASM halt)

An Deiner Stelle würde ich nicht auf "Zz=5" prüfen, sondern auf "Zz>4", und die "4" dann durch'ne Konstante oben ersetzen. An etwaigen anderen Stellen auch (also Anzahl der LEDs) - dann kannst Du den Code später einfacher auf'ne andere LEDzahl ändern.

Zum DCF und so kann ich erstmal nichts weiter sagen - versuch mal, das Enable Interrupts hinter die Config des DCF zu packen...
Du hattest den DCF mit Sectic und LCD erfolgreich am laufen?
Ich würde soweit ersmal alles weglassen, also erstmal nur den DCF mit sectic, und 'ne LED in der Sectic-Routine togeln lassen.
Wenn das geht, das Display miteinbinden, und die Zeiten aufs Display ausgeben. (wie hier, also mittels Flag im Sectic, welches im Hauptprogramm gepollt wird).
Wenn das geht, das Multiplexing mit rein, aber erstmal nur ein statisches Bild erzeugen lassen.
Wenn Du hier angekommen bist, kannst Du Dir Gedanken um das laden der Bilddaten usw machen.

Nachtrag: Ist zwar im Moment grad ganz oben, ober sicherheitshalber (insbesondere für zukünftige "Sucher") verweise ich mal auf Thomas's Hinweise zur Empfindlichkeit der Zeitzeichenempfänger...
mit dem schalten des Multiplexing hast Du natürlich 'ne Verunreinigung der Versorgungsspannung, ob das der Grund ist, weiß ich nicht. Aber die Stabilisierung des Empfängers schadet sicher nicht...
 

Über uns

  • Makerconnect ist ein Forum, welches wir ausschließlich für einen Gedankenaustausch und als Diskussionsplattform für Interessierte bereitstellen, welche sich privat, durch das Studium oder beruflich mit Mikrocontroller- und Kleinstrechnersystemen beschäftigen wollen oder müssen ;-)
  • Dirk
  • Du bist noch kein Mitglied in unserer freundlichen Community? Werde Teil von uns und registriere dich in unserem Forum.
  •  Registriere dich

User Menu

 Kaffeezeit

  • Wir arbeiten hart daran sicherzustellen, dass unser Forum permanent online und schnell erreichbar ist, unsere Forensoftware auf dem aktuellsten Stand ist und der Server regelmäßig gewartet wird. Auch die Themen Datensicherheit und Datenschutz sind uns wichtig und hier sind wir auch ständig aktiv. Alles in allem, sorgen wir uns darum, dass alles Drumherum stimmt :-)

    Dir gefällt das Forum und unsere Arbeit und du möchtest uns unterstützen? Unterstütze uns durch deine Premium-Mitgliedschaft!
    Wir freuen uns auch über eine Spende für unsere Kaffeekasse :-)
    Vielen Dank! :ciao:


     Spende uns! (Paypal)