C LED Matrix 8 x 8

Ich weiß nicht, ob die Timereinstellung nun so stimmt. Jetzt ist es plötzlich auch wieder Timer0 und OCIE0 Interrupt, leider habe ich keine Zeit hier im Datenblatt nachzulesen.

@LotadaC:
Die Variable static ... ist nicht global, sondern lokal, also innerhalb der ISR verfügbar. Sie wird nach dem Reset initialisiert und bleibt immer bestehen, auch wenn die Routine/ISR verlassen wird.
 
global, lokal,.... Hochsprachen-Zugriffsrechtequerelen;) Der Inhalt der Variable überlebt aber auch außerhalb der ISR, also zwischen 2 ISR-Aufrufen (auch wenn das Hauptprogramm den Namen, die Adresse dann nicht kennt). Init nach dem Reset. Alles klar.

Zu den 100Hz - das ist die Frequenz, mit der der IRQ auftritt, welcher aber immer nur eine von 8 Spalten zeigt, Ich dachte, daß wäre inzwischen klar. Da das ganze Bild aus 8 Spalten besteht, ist die Bildwiederholfrequenz halt bei ca. 12Hz.

Das hatte ich doch in mehreren Beiträgen hier schon exakt vorgerechnet - nicht im CTC, sondern im normalMode oder eben im fastPWM...
 
global, lokal,.... Hochsprachen-Zugriffsrechtequerelen;) Der Inhalt der Variable überlebt aber auch außerhalb der ISR, also zwischen 2 ISR-Aufrufen (auch wenn das Hauptprogramm den Namen, die Adresse dann nicht kennt). Init nach dem Reset. Alles klar.

Zu den 100Hz - das ist die Frequenz, mit der der IRQ auftritt, welcher aber immer nur eine von 8 Spalten zeigt, Ich dachte, daß wäre inzwischen klar. Da das ganze Bild aus 8 Spalten besteht, ist die Bildwiederholfrequenz halt bei ca. 12Hz.

Das hatte ich doch in mehreren Beiträgen hier schon exakt vorgerechnet - nicht im CTC, sondern im normalMode oder eben im fastPWM...


Stimmt, Lotaadc du hast natürlich Recht!
Ich habe den "fastPWM" Mode vernachlässigt.
Nun habe ich den eingestellt. Aber dann darf ich ja auch nicht dort die komplette "Routine" zum Multiplexen rein schrreiben, sondern wie du es schon gesagt hast....

ist der einen ISR : alle spalten anschalten mit zähler und co....
in der nächsten ISR : alle spalten wieder ausschalten...

Code:
/* TIMER0 CompareMatch */
    TCCR0 |= (1<<WGM01) | (1<<WGM00) | (1<<CS01) | (1<<CS00);
    TIMSK |= (1<<OCIE0);
 
Hier mal ein kleines Bildchen ^^

2014-08-02 11-43-07.821.jpg

So sah es mit der alten Multiplexroutine aus.
 
Ich würde einfach mal mit debuggen anfangen:

Den Ihnalt der ISR in die while(1) Schleife von main() einfügen (Interrupt natürlich abschalten) und da zusätzlich noch ein _delay_ms(2) dazu. Vor der while(1) Schleife noch dieses vram füllen und dann schauen, ob das nun funktioniert oder nicht. Das zu ändern dauert etwa 10 Sekunden und um es auszutesten etwa 30 Sekunden.
 
Was mir direkt mal auffällt... Die 8 te Zeile / Spalte wird nicht mit eingeschaltet... So wie es aktuell ist, blinkt die Anzeige... ( ich habe das delay ein bisschen höher geschraubt )

Code:
volatile uint8_t VRAM[8]= {0xFF,0xFF,0x01,0xFF,0x01,0xFF,0x01,0xFF};

    while(1)
    {    
    


        PORTC |= (1<<PC7) | (1<<PC6) | (1<<PC5) | (1<<PC4) | (1<<PC3);
        PORTB |= (1<<PB2) | (1<<PB1) | (1<<PB0);
        
         static volatile uint8_t spalte = 0;
           PORTA = VRAM[spalte];
        
        _delay_ms(1000);
        
        switch (spalte)
        {
            case 0: PORTC &= ~(1<<PC3);
            break;
            case 1: PORTC &= ~(1<<PC4);
            break;
            case 2: PORTC &= ~(1<<PC5);
            break;
            case 3: PORTC &= ~(1<<PC6);
            break;
            case 4: PORTC &= ~(1<<PC7);
            break;
            case 5: PORTB &= ~(1<<PB2);
            break;
            case 6: PORTB &= ~(1<<PB1);
            break;
            case 7: PORTB &= ~(1<<PB0);
            break;
            default: break;
        }

        spalte++; // nächste Spalte        
        if (spalte >= 7) spalte = 0; // Spalten 0..7

    }
    
}
 
Natürlich kannst Du auch alles in dieselbe ISR schreiben. Hattest Du ja bereits, nur eben mit 12Hz Bildwiederholfrequenz.
Was soll der Timer machen?
Das Warten rausnehmen, indem er den Code (in der ISR) eben nur soundso oft pro Sekunde aufruft.
Um die Interrupt-Frequenz ze beeinflussen, kannst Du erstmal den geeigneten Prescaler wählen (Grobtuning). Da der Prescaler nur wenige diskrete Werte annehmen kann, kann(!) es sein, daß das nicht hinreichend genau trifft, dann (!) kann man die Reichweite des Timers begrenzen, indem man einenTeil der Schritte wegschneidet. Entweder manuell (Preload in der ISR), oder automatisch mittels eines entsprechenden zurücksetzen in einem compare-match.

Dirk hat ja inzwischen die Katze aus dem Sack mit den 2 Interrupten gelassen.
Bisher ist es so, bei jedem Timerdurchlauf wird einmal (und zwar in dieser Reihenfolge):
Code:
alle Spalten gelöscht
der neue Inhalt auf die Zeilen gelegt
die neue Spalte aktiviert
Zwischen den einzelnen ISR-Aufrufen "ruht" das Programm, bzw macht irgendwas anderes.
Man kann das also so sehen, daß die Anzeige zwischen 2 ISR.Aufrufen mit einer leuchtenden Spalte "wartet".

Wenn Du diese Schritte jetzt auf 2 verschiedene Interrupts verteilst, also das Spaltenlöschen und Zeilensetzen auf den Compare-IRQ, und das Spaltensetzen auf den TOV-IRQ, ändert das doch nichts an der Reihenfolge der Schritte:
Bei jedem(!) Timerdurchlauf wird genau ein OCR-IRQ und genau ein TOV-IRQ fällig. (Das eventuelle mehrfache Auftreten des OCR-matches bei verändern des OCR während eines durchlaufes vermeidet die Wahl des fastPWM, da sind OCR-Manipulationen gepuffert/mit dem TOV synchronisiert)
Im OCR gehen dann also die Lichter aus, und die Zeilen werden vorbereitet...
Danach(!) geht im TOV die nächste Spalte an.

Die Reihenfolge bleibt gleich (bei jedem Durchlauf.
Man hat jetzt aber zwischen den beiden Interrupten (also zwischen Licht aus und Licht an) eine weitere variable Pausenzeit ("warten").
Die Frequenz der Timerdurchläufe ändert sich nicht (Spaltenfrequenz), und damit auch nicht die Bildwiederholfrequenz.
Mit dem Teilen hast Du die Moglichkeit, die Lichter nicht erst direkt vor dem anzeigen der nächsten Spalte abzuschalten, sondern schon früher.
Statt alle 2 ms die neue Spalte anzeigen zu lassen, und eben fast 2ms lang leuchten zu lassen, kannst Du mit 2 Interrupten auch alle 2ms die neue Spalte anzeigen lassen, aber sie bereits (je) im Compare-IRQ wieder aus, also zu einem beliebig einstellbaren Zeitpunkt vor dem nächsten TOV.
Du kannst damit also einfach die AN-Zeit der (jeder) Spalte reduzieren.
 
Was mir direkt mal auffällt... Die 8 te Zeile / Spalte wird nicht mit eingeschaltet...

Das ist klar, du hast plötzlich schon wieder was geändert ...

so wäre es richtig:
if (spalte >= 8) spalte = 0; // Spalten 0..7

Bei dir gibts es den Fall (spalte == 7) garnicht.

vram[0..7] !
 
Was mir direkt mal auffällt... Die 8 te Zeile / Spalte wird nicht mit eingeschaltet...
Code:
...
        spalte++; // nächste Spalte        
        if (spalte [B]>= 7[/B]) spalte = 0; // Spalten 0..7
...
Es werden nur die Spalten 0 bis 6 (7 Stück), da Du nach der 6ten auf sieben inkrementierst,also sieben erreichst, und dann gleich auf 0 zurücksetzt.
 
Wenn ich das so schreibe wie du meinst, bleibt die Reihe einfach aus...

Code:
 if (spalte >= 9) spalte = 0; // Spalten 0..7

Leuchtet sie zwar, aber sehr schwach im gegensatz zu den anderen 7 Reihen.
 
Janiiix,

schau auch mal wo du das _delay_ms(1000) eingefügt hast.

Eigentlich dürfte man so garnichts sehen:

a. Spalten abschalten
b. Zeilen aktualisieren
c. 1 Sekunde warten
d. Spalten einschalten und sofort weider a
 
Jetzt sollte er doch Spalte einmal durch gehen oder sehe ich das falsch ?
Er macht das aber wie es aussieht nur bei jeder 2 ten...
 
Moment ich habe einen Fehler gesehen, Code kommt gleich ...


EDIT:
Spaltentreiber sind nicht invertiert. Hier der geänderte Code.

Code:
    /***********************************
    2ms Ereignis
    Framerate 8x2ms = 16ms
    ************************************/

    static volatile uint8_t spalte = 0;

    // alle Spalten abschalten:
    PORTC &= ~((1<<PC7) | (1<<PC6) | (1<<PC5) | (1<<PC4) | (1<<PC3));
    PORTB &= ~((1<<PB2) | (1<<PB1) | (1<<PB0));
    
    // neue Zeilendaten ausgeben
    
    PORTA = VRAM[spalte];

    // Spalte aktivieren
    switch (spalte) {
        case 0: PORTC |= (1<<PC3);
            break;
        case 1: PORTC |= (1<<PC4);
            break;
        case 2: PORTC |= (1<<PC5);
            break;
        case 3: PORTC |= (1<<PC6);
            break;
        case 4: PORTC |= (1<<PC7);
            break;
        case 5: PORTB |= (1<<PB2);
            break;
        case 6: PORTB |= (1<<PB1);
            break;
        case 7: PORTB |= (1<<PB0);
            break;
        default: break;
    }

    spalte++; // nächste Spalte
    if (spalte >= 8) spalte = 0; // Spalten 0..7
 
Beitrag 53 beachten


Ich würde da auch erst mal mit einer TimerISR arbeiten, erst wenn dies funktioniert ggf. verbessern mit einer zweiten ISR zum dimmen. Nicht gleich alles aufeinmal.


Wichtig: Wenn nochmal mit _delay_ms gestestet wird, dann muss das an anderer Stelle stehen, sonst sieht man garnix (da man zuletzt was gesehen hat, hat mich dies auch auf die Fehlerursache gebracht)
 
Beitrag 53 beachten


Ich würde da auch erst mal mit einer TimerISR arbeiten, erst wenn dies funktioniert ggf. verbessern mit einer zweiten ISR zum dimmen. Nicht gleich alles aufeinmal.


das ich auch son s***** nicht komme... Dirk & Lotaadc ich danke euch für eure herrvorragende hilfe.
 
@Lotaadc...

Das mit der Helligkeit kann ich so hin nehmen das sieht sehr gut aus (läuft gerade nur in einer ISR)
 
Ich habe meinen Zeichentabelle jetzt auch noch mal angepasst.
Das sind so die Zeichen die ich benötige.

Code:
const char charset[66][8] ={
     {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // an
     {0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF}, // aus
     {0x83,0x39,0x31,0x21,0x09,0x19,0x83,0xFF}, // null
     {0xCF,0x8F,0xCF,0xCF,0xCF,0xCF,0xCF,0xFF}, // eins
     {0x87,0x33,0xF3,0xC7,0x9F,0x3F,0x03,0xFF}, // zwei
     {0x87,0x33,0xF3,0xC7,0xF3,0x33,0x87,0xFF}, // drei
     {0xE3,0xC3,0x93,0x33,0x01,0xF3,0xF3,0xFF}, // vier
     {0x03,0x3F,0x07,0xF3,0xF3,0x33,0x87,0xFF}, // fünf
     {0xC7,0x9F,0x3F,0x07,0x33,0x33,0x87,0xFF}, // sechs
     {0x03,0xF3,0xF3,0xE7,0xCF,0xCF,0xCF,0xFF}, // sieben
     {0x87,0x33,0x33,0x87,0x33,0x33,0x87,0xFF}, // acht
     {0x87,0x33,0x33,0x83,0xF3,0xE7,0x8F,0xFF}, // neun
     {0xe7,0xdb,0xdb,0xdb,0xdb,0xc3,0xdb,0xdb}, // A
     {0x87,0xbb,0xbb,0xbb,0x87,0xbb,0xbb,0x87}, // B
     {0xC3,0x99,0x3F,0x3F,0x3F,0x99,0xC3,0xFF}, // C
     {0x87,0x93,0x99,0x99,0x99,0x93,0x87,0xFF}, // D
     {0x81,0x9F,0x9F,0x87,0x9F,0x9F,0x81,0xFF}, // E
     {0x81,0x9F,0x9F,0x87,0x9F,0x9F,0x9F,0xFF}, // F
     {0xC3,0x99,0x3F,0x3F,0x31,0x99,0xC1,0xFF}, // G
     {0x99,0x99,0x99,0x81,0x99,0x99,0x99,0xFF}, // H
     {0xE7,0xE7,0xE7,0xE7,0xE7,0xE7,0xE7,0xFF}, // I
     {0xF9,0xF9,0xF9,0xF9,0x99,0x99,0xC3,0xFF}, // J
     {0x99,0x99,0x93,0x87,0x93,0x99,0x99,0xFF}, // K
     {0x9f,0x9f,0x9f,0x9f,0x9f,0x9f,0x81,0x81}, // L
     {0x39,0x11,0x01,0x01,0x29,0x39,0x39,0xFF}, // M
     {0x39,0x19,0x09,0x21,0x31,0x39,0x39,0xFF}, // N
     {0xC3,0x99,0x99,0x99,0x99,0x99,0xC3,0xFF}, // O
     {0x83,0x99,0x99,0x83,0x9F,0x9F,0x9F,0xFF}, // P
     {0xC3,0x99,0x99,0x99,0x91,0xC3,0xF1,0xFF}, // Q
     {0x83,0x99,0x99,0x83,0x93,0x99,0x99,0xFF}, // R
     {0xC3,0x99,0x8F,0xC7,0xF1,0x99,0xC3,0xFF}, // S
     {0x81,0xE7,0xE7,0xE7,0xE7,0xE7,0xE7,0xFF}, // T
     {0x99,0x99,0x99,0x99,0x99,0x99,0xC1,0xFF}, // U
     {0x99,0x99,0x99,0x99,0x99,0xC3,0xE7,0xFF}, // V
     {0x39,0x39,0x39,0x29,0x01,0x11,0x39,0xFF}, // W
     {0x99,0x99,0xC3,0xE7,0xC3,0x99,0x99,0xFF}, // X
     {0x99,0x99,0x99,0xC3,0xE7,0xE7,0xE7,0xFF}, // Y
     {0x01,0xF9,0xF3,0xE7,0xCF,0x9F,0x01,0xFF}, // Z
     {0xFF,0xFF,0xC3,0xF9,0xC1,0x99,0xC5,0xFF}, // a
     {0x9F,0x9F,0x9F,0x83,0x99,0x99,0xA3,0xFF}, // b
     {0xFF,0xFF,0xC3,0x99,0x9F,0x99,0xC3,0xFF}, // c
     {0xF9,0xF9,0xF9,0xC1,0x99,0x99,0xC5,0xFF}, // d
     {0xFF,0xFF,0xC3,0x99,0x81,0x9F,0xC3,0xFF}, // e
     {0xE3,0xC9,0xCF,0x87,0xCF,0xCF,0xCF,0xFF}, // f
     {0xFF,0xFF,0xC5,0x99,0x99,0xC1,0xF9,0xC3}, // g
     {0x9F,0x9F,0x93,0x89,0x99,0x99,0x99,0xFF}, // h
     {0xE7,0xFF,0xE7,0xE7,0xE7,0xE7,0xE7,0xFF}, // i
     {0xF3,0xFF,0xF3,0xF3,0xF3,0x33,0x33,0x87}, // j
     {0x9F,0x9F,0x99,0x93,0x87,0x93,0x99,0xFF}, // k
     {0xE7,0xE7,0xE7,0xE7,0xE7,0xE7,0xE7,0xFF}, // l
     {0xFF,0xFF,0x39,0x11,0x01,0x29,0x39,0xFF}, // m
     {0xFF,0xFF,0x83,0x99,0x99,0x99,0x99,0xFF}, // n
     {0xFF,0xFF,0xC3,0x99,0x99,0x99,0xC3,0xFF}, // o
     {0xFF,0xFF,0xA3,0x99,0x99,0x83,0x9F,0x9F}, // p
     {0xFF,0xFF,0xC5,0x99,0x99,0xC1,0xF9,0xF9}, // q
     {0xFF,0xFF,0xA3,0x89,0x9F,0x9F,0x9F,0xFF}, // r
     {0xFF,0xFF,0xC1,0x9F,0xC3,0xF9,0x83,0xFF}, // s
     {0xCF,0xCF,0x83,0xCF,0xCF,0xCB,0xE7,0xFF}, // t
     {0xFF,0xFF,0x99,0x99,0x99,0x99,0xC5,0xFF}, // u
     {0xFF,0xFF,0x99,0x99,0x99,0xC3,0xE7,0xFF}, // v
     {0xFF,0xFF,0x39,0x29,0x01,0x01,0x93,0xFF}, // w
     {0xFF,0xFF,0x39,0x93,0xC7,0x93,0x39,0xFF}, // x
     {0xFF,0xFF,0x99,0x99,0x99,0xC1,0xF9,0xC3}, // y
     {0xFF,0xFF,0x81,0xF3,0xE7,0xCF,0x81,0xFF}, // z         
     {0x81,0x7E,0x5A,0x7E,0x42,0x66,0x7E,0x81} // Smiley
     };

Ist das soweit inordnung (gibt es bessere möglichkeiten)

Wenn ich jetzt die ganzen Zeichen einmal durchlaufen lassen will (ein Zeichen nach dem anderen darstellen lassen will)
Wie weiße ich mein VRAM dann das neue Zeichen zu ?

VRAM = charset[1]; ?
 
Ich habe meinen Zeichentabelle jetzt auch noch mal angepasst.

Ist das soweit inordnung (gibt es bessere möglichkeiten)
Tabellen würde ich ins Flash Memory legen.

Wenn ich jetzt die ganzen Zeichen einmal durchlaufen lassen will (ein Zeichen nach dem anderen darstellen lassen will)
Wie weiße ich mein VRAM dann das neue Zeichen zu ?

VRAM = charset[1]; ?

Nein, so nicht.

So könnte man es machen:
(vorausgesetzt die Anordnung der Bits im Array passt zu deinem Matrix-Konzept)

Code:
for (uint8_t i=0, i<67; i++)
{

  for (uint8_t d=0; d<8; d++) vram[d] = charset[i][d];
   _delay_ms(1000);

}
 

Ü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)