C LED Matrix 8 x 8

Jetzt schiebt er meinen Character schon mal raus... nach links... Jedoch leuchtet jede Spalte / Reihe nach dem schieben...
Wenn der Character durch ist, ist das ganze Display an... Wie unterbinde ich das ? verODERN klappt nicht :/

Code:
uint8_t GetCharacterIndex(char a)
{

        uint8_t index = 1;    // alles aus

        if ((a >= '0') && (a <= '9'))
        index = a+2-48;  // erste Zahl ist Index in der Tabelle des ersten Zeichens, zweite Zahl ist Index in Ascii Code des ersten Zeichens
        else if ((a >= 'A') && (a <= 'Z'))
        index = a+12-65;
        else if ((a >= 'a') && (a <= 'z'))
        index = a+38-97;

        for (uint8_t d= 0 ; d < 8 ; d++)
        {
            VRAM[d] = pgm_read_byte(&charset[index][d]);
        }
        
                _delay_ms(300);
                
        for (uint8_t d= 0 ; d < 8 ; d++)
        {
            VRAM[0] <<= 1 | 0x01;
            VRAM[1] <<= 1 | 0x01;
            VRAM[2] <<= 1 | 0x01;
            VRAM[3] <<= 1 | 0x01;
            VRAM[4] <<= 1 | 0x01;
            VRAM[5] <<= 1 | 0x01;
            VRAM[6] <<= 1 | 0x01;
            VRAM[7] <<= 1 | 0x01;
            
            _delay_ms(100);
        }
        
        


        return index;

}
 
Das hat in der Funktion nichts zu suchen...
Die heißt "GetCharacterIndex" - rat mal warum...
 
Das hat in der Funktion nichts zu suchen...
Die heißt "GetCharacterIndex" - rat mal warum...

Das war auch nur zum Testen ob das so klappt mit dem darstellen ;)
Haut jetzt aber hin!

Muss natürlich :

VRAM[0] = VRAM[0] << 1 | 0x01;
... usw

lauten ;)
 
Jetzt habe ich mir eine Funktion geschrieben um einen String aus zu geben ;) Klappt!
Das mit dem links raus schieben klappt auch, nur sollte der nächste Buchstabe rechts wieder rein scrollen...
Das passiert aktuell noch nicht... Gibt es sowas wie im "Kreis schieben" ? Vill. sogar einen Befehl?
 
Oder gibt es eine bessere Idee als mit dem zweiten "VRAM"?
 
Ich würde so vorgehen, dass ich eine X Position (Bitposition bzw. Spaltenposition, nicht Character Position) der DisplayString Funktion übergebe. Die Stringlänge in Bits (Spalten) ist in deinem Fall 8 x strlen() plus ggf. Leerspalte zwischen den Zeichen. Mit der X Position hole ich mir die Grafikdaten eines Zeichens (bei X = 0, 8, 16 ...), oder eben zweier Zeichen (bei X != 0, 8, 16 ...). Im erten Fall bei einem Zeichen, passt dieses genau in vram im zweiten Fall sind beide Zeichen entprechend verschoben zusammen in vram.

Es gibt sicherlich auch andere Möglichkeiten und ich weiß auch nicht genau, wie flexibel oder komplex das alles werden soll :) Vielleicht bringt sich das ja auf Ideen.

Dirk :ciao:
 
Also erst den ganzen String in den VRAM laden & später zusammen ausgeben.
Mein Problem was ich imoment habe... Wie bekomme ich es hin das die Zeichen "rechts" anfangen und nicht direkt in der Mitte ?
 
Nein, nicht den ganzen String in vram laden. Sprichst du nun von einem String oder nur von einem einzelnen Zeichen? Vielleicht poste mal, was du bisher gelöst hast.
 
Hier wird der String via Pointer an "GetCharacterIndex" übergeben...

Code:
/* Übergibt den String der Routine "GetCharacterIndex" */
void StringtoCharacter(const char *s)
{
        while (*s)
        
    GetCharacterIndex(*s++);
}

Hiermit knalle ich die Zeichen in den "VRAM"

Code:
/* Erechnet den Index des aktuellen Zeichens */
uint8_t GetCharacterIndex(char a)
{


        uint8_t index = 1;    // alles aus

        if ((a >= '0') && (a <= '9'))
        index = a+2-48;  // erste Zahl ist Index in der Tabelle des ersten Zeichens, zweite Zahl ist Index in Ascii Code des ersten Zeichens
        else if ((a >= 'A') && (a <= 'Z'))
        index = a+12-65;
        else if ((a >= 'a') && (a <= 'z'))
        index = a+38-97;
        else if ((a == '.'))
        index = a+70-46;
        
        for (uint8_t d= 0 ; d < a ; d++)
        {
            VRAM[d] = pgm_read_byte(&charset[index][d]);
            check_usb();
        }
                
            _delay_ms(500);
         ShiftVRAM(0, 100);
        

            
        return index;

}
 
... Also nicht, daß wir Dir jetzt dabei helfen zu das programmieren (daß ein Zeichen angezeigt wird, dieses rausgeschoben wird, das 2te mit einem Schlag dargestellt wird. Und herausgeschoben wird. Und Insbesondere die Reihenfolge der Zeichen die ist, die im charset steht), und Du danach plötzlich doch beliebige String darstellen willst, und die plötzlich wirklich durchgeschoben werden sollen...
;)
Deine neue Multiplexroutine ist inzwischen in der Lage, interruptgesteuert permanent den Inhalt des VRAM auf der Matrix darzustellen.
Dirk hat Dir eine Routine geschenkt, die Aus einem vorgegebenem Character, also einer ASCII-Nummer den Index desselben Zeichens in Deiner Tabelle zu liefern (sofern vorhanden, sonst "Space").

Was Du willst ist, einen gegebenen String (also mehrere ASCII) als Lauftext darstellen - es ist Quatsch das in Dirks Routine einzubauen.
Du kannst Dirks Routine nutzen(!) um die Position der Daten im Charset zu erhalten, das kopieren der Daten sollte eine Andere Routine machen.

Überlege Dir doch erstmal (ohne das gleich zu implementieren) den Weg! Was ist denn der Lauftext?
Das pixelversetzte Neubeschreiben der Matrix, also des VRAM.
Du brauchst also eine Routine, die einen vorgegebenen String (also nur die nötigen Teile Spalten der entsprechenden Zeichen) unter Berücksichtigung der aktuellen Pixelversetzung (Verschiebung) nach VRAM schreibt.
Diese Routine wird nach inkrement des Versatzes mit einer festgelegten Frequenz aufgerufen (am einfachsten in der Hauptschleife mit 'nem Wartezyklus dazwischen, denkbar ist aber auch, daß an einen Timer (sogar indirekt an den Multiplexing Timer - aber eben nicht in der ISR selbst) zu binden.
Diese Routine muß für jede der 8 VRAM-Spalten errechnen, welche Spalte welcher Zeichennummer aus Deiner Tabelle in diese Spalte zu laden ist, und dies tun. Zur Ermittlung der Zeichennummer kannst Du dann z.B Dirks Methode Aufrufen (wenn Du erstmal den entsprechenden Character aus dem String errechnet hast..
Im Prinzip läuft das auf meinen Beitrag #25 hinaus, nur eben nicht im Multiplex-IRQ selbst und daß es eben nicht sofort ausgegeben wird, sondern ins VRAM geschrieben.
 
Also das ist doch alles überhaupt kein Problem.
Dann passt man den Index einfach an. Das geht ganz schnell, man muss nicht im String irgendwelche komischen Zeichen eingeben, um den richtigen Index zu erwischen und Maschinenzyklen oder Code ist das auch nicht die Welt, irgendwas muss der Controller ja auch machen ;-)

Hier mal eine Funktion, die eventuell weiterhilft.
Index ist korrigiert für 0..9, A..Z, a..z, alles andere gibt Index=1 alles aus.
Es fehlt noch der smilie und alles an.
(nicht getestet)
Code:
// http://www.torsten-horn.de/techdocs/ascii.htm

uint8_t GetCharsetIndex(char a)
{
    uint8_t index = 1;    // alles aus

    if ((a >= '0') && (a <= '9'))
        index = a+2-48;  // erste Zahl ist Index in der Tabelle des ersten Zeichens, zweite Zahl ist Index in Ascii Code des ersten Zeichens
    else if ((a >= 'A') && (a <= 'Z'))
        index = a+12-65;
    else if ((a >= 'a') && (a <= 'z'))
        index = a+38-97;

    // usw...

    return index;
}


Zunächst erstellt man sich eine Funktion, die sich nacheinander ein Zeichen vom String holt, bis zum Stringende. Hier hat man also eine Schleife, in dieser ...
1. ... holt man sich dann den richtigen Index = GetCharsetIndex(a)
2. Dann adressiert man das CharsetArray mit dem Index (besser wäre, das Array liegt nur im Flash Memory) und kopiert die Daten ins vram


Den aktuellen Wert von index kann ich nur in der Funktion nutzen oder ?
Wie kann ich denn den Wert von index global übergeben?
 
Es handelt dich um eine Funktion, Index wird als Ergebnis zurückgeliefert. Wie rufst Du die denn auf?
 
Ich rufe die Funktion für ein Character so auf

GetCharacterIndex("a");

Wenn ich einen String "umrechnen" möchte


StringtoCharacter("Hallo");

Die einzelnen Index Werte werden mir ins VRAM geschoben (Zeichen, Symbole)
 
GetCharsetIndex(char) ist 'ne FUNKTION des Typ's uint8_t.

Die liefert ihr Ergebnis (Return...) in Form eines uint8_t-Wertes zurück. Bei Deiner Form des Aufrufes landet dieses ergebnis im Nirvana, Du Du is nicht zuweist.
Normalerweise ruft man 'ne Funktion in Form einer Zuweisung auf, also etwa

lustige_Adresse=GetCharsetIndex(lächerlicher_char);

Hast Du das von Dirk empfohlene Tutorial wegen derlei Grundlagen schonmal eingesehen?
 
Ich habe mal schnell etwas geschrieben. Es ist nicht getestet oder compiliert.

Vielleicht kannst du ja einfach mal testen ob es funktioniert.

Leerspalten zwischen Zeichen sind nicht enthalten und ob es bei Stringende funktioniert, weiß ich nicht ... es ist schon ein bisschen Spät für mich :eek: ;)

Vielleicht bringt dich das ja auf neue Ideen.

Code:
[B]// Aufruf zum Beispiel:[/B]

    char s[30] = "Das ist ein Teststring";
    
    for (uint16_t x=0; x<(strlen(s)*8); x++)
    {
        DisplayString(x, s);
        _delay_ms(50);
    }


[B]// Der Lösungsansatz:[/B]

#include <string.h>

void DisplayString(uint16_t x, const char *s)
{
    uint16_t len;
    uint8_t i, d;
    
    len = strlen(s)*8;
    
    if (x < len)
    {
        
        i = x >> 3; // durch 8
        
        if (x & 7)
        {
            // zwei Zeichen passen in vram
            i = GetCharacterIndex(s[i++]); // erstes Zeichen
            for (d=0 ; d<8 ; d++)
               vram[d] = pgm_read_byte(&charset[i][d]) << (x & 7); // verschoben nach links
            
            i = GetCharacterIndex(s[i]);  // zweites Zeichen
            for (d=0 ; d<8 ; d++)
               vram[d] =| (pgm_read_byte(&charset[i][d]) >> (8-(x & 7)));  // verschoben nach rechts
            
            } else {
            // komplettes Zeichen passt in vram
            i = GetCharacterIndex(s[i]);
            for (d=0 ; d<8 ; d++)
               vram[d] = pgm_read_byte(&charset[i][d]);
            
        }
        
        } else {
        // x zu groß, alles aus
        for (d=0 ; d<8 ; d++)
           vram[d] = 0xFF;
        
    }
    
}

uint8_t GetCharacterIndex(char a)
{
    uint8_t index = 1;    // alles aus

    if ((a >= '0') && (a <= '9'))
      index = a+2-48;  
    else if ((a >= 'A') && (a <= 'Z'))
      index = a+12-65;
    else if ((a >= 'a') && (a <= 'z'))
      index = a+38-97;
    else if ((a == '.'))
      index = a+70-46;
        
    return index;

}
 
Danke Dirk,

Damit kann ich was anfangen!
Wenn man überhaupt nicht mal den Weg weiß wie man dahin kommt, ist alles ziemlich schwer. Ich werde den Code mal genaustens durchgehen.

Jetzt habe ich nur noch das Problem das meine Anzeige "low activ" ist... und einige Zeilen sind dann dauerhaft an.
 
Ich sehe schon die Frage kommen: "Ich habe jetzt 2 Matrizen am Controller, wie steuer ich die als 16*8 an?"
Bei meinem Vorschlag müßte man dann nur 'ne "numberOfMatrixColumns"-Konstante anpassen, und die Multiplexing-Frequenz eventuell erhöhen.

Ist bei fixed width fonts nicht der Zwischenraum "zwischen" 2 Zeichen Bestandteil des ersten Zeichens? Also die letzte Spalte der 8 Pixel bleibt "frei", und bei den meisten die unterste Zeile? (abgesehen von einigen erweiterten ASCII -> ASCII-Grafik)
 
Das ist doch alles kein Problem. Ich weiss nun auch nicht, ob die Anzeige so bleiben soll oder ob sie vergrößert wird oder ob der String noch in Y Richtung sinusfoermig hüpfen soll. Kann man alles machen. Da es kein Assembler ist und bisher auch ein simpler code, lässt sich alles leicht erweitern und modifizieren.

Es ist auch ueberhaupt kein Problem die Funktionen in die TimerISR zu setzen und anstelle in das vram zu schreiben (würde man sich bei größeren Display sparen) sofort die IO Pins zu multiplexen. Im Moment gefällt es mir anders besser ... Möglichst viel aus einer ISR raus, nur das nötigste rein.

Ob nun in den Fontdaten eine Leerspalte dabei ist, puhh. Ich würde das einfach mal versuchen zum Laufen zu kriegen und dann schauen.

Mein Beispiel würde ich jetzt erst mal als Anreiz für eigene Ideen nehmen es muss ja nicht die Lösung werden.

Dirk :ciao:
 
Das ist doch alles kein Problem...lässt sich alles leicht erweitern und modifizieren...
Genau das sehe ich Janiiix betreffend eben nicht so - aber das ist ein anderes Thema...
Es ist auch ueberhaupt kein Problem die Funktionen in die TimerISR zu setzen und anstelle in das vram zu schreiben (würde man sich bei größeren Display sparen) sofort die IO Pins zu multiplexen. Im Moment gefällt es mir anders besser ... Möglichst viel aus einer ISR raus, nur das nötigste rein...
Das hast Du falsch verstanden, es ging um das verschieben selbst, also das (verschobene) neubeschreiben des VRAM. Du hast das (erstmal und testweise, schon klar) in der Hauptschleife mit einem delay. Final gehört sowas an eine Zeitbasis gekoppelt, also an einen Timer. Diese Zeitbasis kann der Multiplex-Timer ohne nennenswerten mehraufwand generieren, und ein geeignetes Zeitbasis-Flag setzen. Die Reaktion darauf erfolgt weiterhin in der Hauptschleife, die dann aber nicht durch das Delay gestoppt wird.

Der Vorschlag aus #25 war generell der Rechenweg, um aus einem String, der Verschiebung (also die Argumente von Deinem DisplayString) und der Position wo das zu erscheinen (Spalte im VRAM/Matrix) halt die Adresse im charset, zu berechnen, also nicht nur die erste wo das Zeichen beginnt, sondern die absolute für diese Spalte. Das hatte ich in #25 in der MUX-ISR aufrufen wollen, man kann das aber ebenso in eine Routine setzen, die das ins VRAM schreibt.
Also eine Routine, die in einer Schleife für jede vorhandene VRAM Spalte eine weitere Routine/Funktion aufruft, welche ihrerseits aus den 3 Argumenten die Adresse des Zeilenbytes berechnet/zurückliefert. Für den Zugriff auf Janiiix Tabelle unter zuhilfenahme von GetCharacterIndex()..
 
Hallo Dirk,

Die Rückgabewerte deiner Funktion "GetCharackter"... Kann ich die zwischenspeichern ?
Für einen längeren String muss ich ja die ganzen Indexnummern irgendwo zwischenspeichern und später wieder auslesen damit ich sie der Reihe nach darstellen kann.
 

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