- LiTime Speicher und Akkus         
Ergebnis 1 bis 10 von 15

Thema: LED Matrix 8 x 8 AVR C

Hybrid-Darstellung

Vorheriger Beitrag Vorheriger Beitrag   Nächster Beitrag Nächster Beitrag
  1. #1
    Benutzer Stammmitglied Avatar von Janiiix3
    Registriert seit
    29.11.2010
    Ort
    Hannover
    Alter
    32
    Beiträge
    48

    LED Matrix 8 x 8 AVR C

    Hallo liebe Gemeinde :-P

    Ich habe ein wirklich "klitze kleines" Problemchen... Am besten stelle ich auch mal direkt mein Anliegen (Projekt) vor!

    Undzwar...

    Bin ich dabei die Software für einen fertig entwickelten "Würfel" zu programmieren (Hardware steht schon).
    Dieser soll in erster Linie, Zahlen von 1-6 darstellen. Die "gewürfelten" soll jeder Spieler zu gunsten seines Sitzplatzes sehen können ( man stelle sich ein Tisch vor an jeder Seite sitzt ein Spieler, es gibt 4 Tasten... Aufgrund der gedrückten Taste, weiß der Würfel zu welcher Seite er die Zahl darstellen muss) Das klappt soweit auch alles.

    Sprich meine "CharMap" ( enthält die ganzen Zeichen ) steht auch schon. Diese kann ich auch schon wie gewünscht aufrufen und ausgeben.
    Nun möchte ich noch am Anfang oder mitten drinn eine Laufschrift über das Display jagen. Diese soll von : rechts nach links "scrollen".
    Imoment habe ich meine an zu zeigende Grafik in einem "VRAM" (Videospeicher) Dort steht mein Zeichen drinn was ich wie gesagt anzeigen will.
    Das Multiplexen funktioniert via. Interrupt ganz gut.

    Mein Problem ist jetzt, dass ich nicht weiß wie ich das mit der Laufschrift hin bekommen soll...
    Stand jemand von euch schon mal vor einem ähnlichen Problem und kann mir helfen ?

    Anbei der Code.

    Code:
    
    /* Definiert die Frequenz */
        #define F_CPU 16000000UL
    
    /* Umbennung der Eingabe ( Taster ) */
        #define TASTER_1    (!(PIND & (1<<PD5))
        #define TASTER_2    (!(PIND & (1<<PD6))
        #define TASTER_3    (!(PIND & (1<<PD3))
        #define TASTER_4    (!(PIND & (1<<PD4))
        
    /* USB Ladeerkennung */
        #define USB_CONNECTED PINB & (1<<PINB4)
    
    /* Akku muss geladen werden */    
        #define ACCU_MUST_LOADING (!(PIND & (1<<PIND7)))
    
    /* Summer */
        #define SUMMER_AUS      PORTC |=  (1<<PC2)
        #define SUMMER_AN     PORTC &= ~(1<<PC2)
        #define SUMMER_TOGGLE PORTC ^=  (1<<PC2)
        
    /* Richtung zum schieben der Anzeige */
        #define RIGHT 1
        #define LEFT  0
        
    /* Schwelle für AutoOFF ( 6000 = 1 min. ) */
        #define AUTO_OFF 6000
        
    /* Verhindert ein drücken während des Betriebes */
        #define INTERRUPT_INT0_DISABLE GICR &= ~(1<<INT0)
        #define INTERRUPT_INT0_ENABLE  GICR |=  (1<<INT0)
        
    /* Benötigte Bibliotheken */                                    
        #include <avr/io.h>
        #include <util/delay.h>
        #include <avr/interrupt.h>
        #include <avr/sleep.h>
        #include "avr/pgmspace.h"
        #include "avr/sleep.h"
        #include <string.h>
        
    
    /* Grafiken */
    
    const char charMap[71][8] PROGMEM ={
         {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // an
         {0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF}, // aus
         {0xC3,0x99,0x99,0x99,0x99,0x99,0xC3,0xFF}, // null
         {0xE7,0xC7,0xE7,0xE7,0xE7,0xE7,0xE7,0xFF}, // eins
         {0xC3,0x99,0xF9,0xF3,0xE7,0xCF,0x81,0xFF}, // zwei
         {0xC3,0x99,0xF9,0xE3,0xF9,0x99,0xC3,0xFF}, // drei
         {0xF3,0xE3,0xC3,0x93,0x81,0xF3,0xF3,0xFF}, // vier
         {0x81,0x9F,0x83,0xF9,0xF9,0x99,0xC3,0xFF}, // fünf
         {0xE3,0xCF,0x9F,0x83,0x99,0x99,0xC3,0xFF}, // sechs
         {0x81,0xF9,0xF9,0xF3,0xE7,0xE7,0xE7,0xFF}, // sieben
         {0xC3,0x99,0x99,0xC3,0x99,0x99,0xC3,0xFF}, // acht
         {0xC3,0x99,0x99,0xC1,0xF9,0xF3,0xC7,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
         {0xFF,0xE7,0xC3,0xDB,0xDB,0xDB,0xDB,0xC3}, // Battery (leer)
         {0xFF,0xE7,0xC3,0xDB,0xDB,0xDB,0xC3,0xC3}, // Battery ( mit einem Strich  )
         {0xFF,0xE7,0xC3,0xDB,0xDB,0xC3,0xC3,0xC3}, // Battery ( mit zwei Strichen )
         {0xFF,0xE7,0xC3,0xDB,0xC3,0xC3,0xC3,0xC3}, // Battery ( mit drei Strichen )
         {0xFF,0xE7,0xC3,0xC3,0xC3,0xC3,0xC3,0xC3}, // Battery ( mit vier Strichen )
         {0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFE,0xFF}  // Punkt für´s www(.)
         };
    
    const char Spieler_links[7][8] PROGMEM ={
    
        {0xFF,0xFF,0xFD,0x80,0x80,0xFF,0xFF,0xFF}, // eins
        {0xFF,0xBD,0x9C,0x8E,0xA6,0xB0,0xB9,0xFF}, // zwei
        {0xFF,0xDD,0x9C,0xB6,0xB6,0x80,0xC9,0xFF}, // drei
        {0xFF,0xE7,0xE3,0xE9,0x80,0x80,0xEF,0xFF}, // vier
        {0xFF,0xD8,0x98,0xBA,0xBA,0x82,0xC6,0xFF}, // füns
        {0xFF,0xC3,0x81,0xB4,0xB6,0x86,0xCF,0xFF} // sechs
        };
    
    const char Spieler_rechts[7][8] PROGMEM ={
    
        {0xFF,0xE7,0xE7,0xE7,0xE7,0xE7,0xE3,0xE7},
        {0xFF,0x81,0xF3,0xE7,0xCF,0x9F,0x99,0xC3},
        {0xFF,0xC3,0x99,0x9F,0xC7,0x9F,0x99,0xC3},
        {0xFF,0xCF,0xCF,0x81,0xC9,0xC3,0xC7,0xCF},
        {0xFF,0xC3,0x99,0x9F,0x9F,0xC1,0xF9,0x81},
        {0xFF,0xC3,0x99,0x99,0xC1,0xF9,0xF3,0xC7}
        };
    
    const char Spieler_gegenueber[7][8] PROGMEM ={
    
        {0xFF,0xFF,0xFF,0x01,0x01,0xBF,0xFF,0xFF},
        {0xFF,0x9D,0x0D,0x65,0x71,0x39,0xBD,0xFF},
        {0xFF,0x93,0x01,0x6D,0x6D,0x39,0xBB,0xFF},
        {0xFF,0xF7,0x01,0x01,0x97,0xC7,0xE7,0xFF},
        {0xFF,0x63,0x41,0x5D,0x5D,0x19,0x1B,0xFF},
        {0xFF,0xF3,0x61,0x6D,0x2D,0x81,0xC3,0xFF}
        };
    
    
    
    
        uint8_t VRAM[50] = { };
        uint8_t USB_STATE = 0;
        uint16_t AUTO_OFF_Counter = 0;
        uint16_t CharacterIndexValue = 0;
        
        void clear_screen();
        void fill_screen();
        void check_usb();
        void Display_all_Symbols();
        uint8_t GetCharacterIndex(char a);
        void ShiftVRAM(uint8_t direction, uint16_t ms);
        void StringtoCharacter(const char *s);
        void check_ACCU();
        void check_AUTO_OFF();
        void DisplayString(uint16_t x, const char *s);
    
    
    int main(void)
    {
        DDRA |= ((1<<PA0) | (1<<PA1) | (1<<PA2) | (1<<PA3) | (1<<PA4) | (1<<PA5) | (1<<PA6) | (1<<PA7));
        DDRB |= ((1<<PB0) | (1<<PB1) | (1<<PB2) | (1<<PB3) | (1<<PB5) | (1<<PB6) | (1<<PB7));
        DDRC |= ((1<<PC2) | (1<<PC3) | (1<<PC4) | (1<<PC5) | (1<<PC6) | (1<<PC7));
        
    
    /* TIMER0 CompareMatch (Multiplexen der Anzeige) */
        TCCR0 |= (1<<WGM01) | (1<<WGM00) | (1<<CS01) | (1<<CS00);
        TIMSK |= (1<<OCIE0);
        
        
    /* Timer 1 Initalisieren */
        TCCR1B |= ((1<<CS12) | (1<<CS10)); // Teiler auf 1028
        TCCR1B |= (1<<WGM12); // CTC = ClearTimerCompare
        OCR1A   = 77; // ca. jede 10 ms. ein Überlauf
        TIMSK  |= (1<<OCIE1A); 
        
    /* Interrupt "0" aktivieren */
        GICR |= (1<<INT0);
        
    /* Muss ausgeschaltet werden, weil der Summer sonst dauernd an ist */
        SUMMER_AUS;
        
    /* Interrupts global erlauben */
        sei(); 
    
    
    
        while(1)
        {    
            INTERRUPT_INT0_DISABLE;        
    
            check_usb();
            check_ACCU();
            check_AUTO_OFF();
        
        
            if (USB_STATE == 0)
            {        
                Display_all_Symbols();
            }
            
    
        
        }// Ende While 
    
    }// Ende Main
    
    
    
    /* Multiplexen der Anzeige */
    ISR(TIMER0_COMP_vect)
    {
        static volatile uint8_t spalte = 0;
    
        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        
    }
    
    
    
    /* Jede 10 ms wird hier die Variable "Save_Value_Counter" um + 1 erhöht */
    ISR (TIMER1_COMPA_vect)
    {
        AUTO_OFF_Counter = AUTO_OFF_Counter + 1;        
    }
    
    /* Aufwecken des Gerätes */
    ISR (INT0_vect)
    {
        SUMMER_AN;
        _delay_ms(1);
        SUMMER_AUS;
    }
    
    
    /* Löschen des aktuellen Displays */
    void clear_screen(void) 
    {
        for(uint8_t i = 0 ; i < 8 ; i++)
        {
            VRAM[i] = 0xFF;
        }    
    }
    
    /* Display komplett anschalten */
    void fill_screen(void)
    {
        for (uint8_t i = 0 ; i < 8 ; i++)
        {
            VRAM[i] = 0x00;
        }
    }
    
    /* Checkt ob Maxi Dice mit USB Verbunden ist */
    void check_usb(void)
    {
    
        if (USB_CONNECTED)
        {
            USB_STATE = 1;
            
            for (uint8_t i = 65 ; i < 70 ; i++)
            {
                for (uint8_t d= 0 ; d < 8 ; d++)
                {
                        VRAM[d] = pgm_read_byte(&charMap[i][d]);            
                }
                 _delay_ms(500);
            }
           
         }
            else
        {
            USB_STATE = 0;
        }
            
    
            
    }
    
    /* Routine um das gesamte Grafikaray da zu stellen */
    void Display_all_Symbols()
    {
        if (USB_STATE == 0)
        {
            for (uint8_t i = 0 ; i < 70 ; i++)
            {
    
                for (uint8_t d= 0 ; d < 8 ; d++)
                {
                    VRAM[d] = pgm_read_byte(&charMap[i][d]);
                }
                check_usb();
                _delay_ms(500);
    
            }// Ende for
        }
    }
    
    /* Errechnet 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;
                    
            return index;
    }
    
    /* Schiebt den gesamten Zwischenspeicher (VRAM) des Zeichens */
    void ShiftVRAM(uint8_t direction, uint16_t ms)
    {
        if (direction == 1)
        {
                    for (uint8_t d= 0 ; d < 8 ; d++)
                    {
                        VRAM[0] = VRAM[0] >> 1 | 0x80;
                        VRAM[1] = VRAM[1] >> 1 | 0x80;
                        VRAM[2] = VRAM[2] >> 1 | 0x80;
                        VRAM[3] = VRAM[3] >> 1 | 0x80;
                        VRAM[4] = VRAM[4] >> 1 | 0x80;
                        VRAM[5] = VRAM[5] >> 1 | 0x80;
                        VRAM[6] = VRAM[6] >> 1 | 0x80;
                        VRAM[7] = VRAM[7] >> 1 | 0x80;
                        
                        for (uint16_t i = 0; i < ms ; i++ )
                        {
                            _delay_ms(1);
                        }
                    }
        }
            else if (direction == 0)
            {
                        for (uint8_t d= 0 ; d < 8 ; d++)
                        {
                            VRAM[0] = VRAM[0] << 1 | 0x01;
                            VRAM[1] = VRAM[1] << 1 | 0x01;
                            VRAM[2] = VRAM[2] << 1 | 0x01;
                            VRAM[3] = VRAM[3] << 1 | 0x01;
                            VRAM[4] = VRAM[4] << 1 | 0x01;
                            VRAM[5] = VRAM[5] << 1 | 0x01;
                            VRAM[6] = VRAM[6] << 1 | 0x01;
                            VRAM[7] = VRAM[7] << 1 | 0x01;
                            
                            
                            for (uint16_t i = 0; i < ms ; i++ )
                            {
                                _delay_ms(1);
                            }
                        }
                        
                        
            }
    
        
    }
    
    /* Übergibt den String der Routine "GetCharacterIndex" */
    void StringtoCharacter(const char *s)
    {
            while (*s)
            
        CharacterIndexValue = GetCharacterIndex(*s++);
    
    }
    
    /* Überprüft ob Akku leer ist */
    void check_ACCU(void)
    {
        clear_screen();
        
        if ((ACCU_MUST_LOADING))
        {
            for (uint8_t i = 65 ; i < 66 ; i++)
            {
    
                for (uint8_t d= 0 ; d < 8 ; d++)
                {
                    VRAM[d] = pgm_read_byte(&charMap[i][d]);
                }
                check_usb();
                _delay_ms(500);
                        
            }// Ende for
            
            clear_screen();
            _delay_ms(500);
                    
        }
    }
    
    /* Funktion für AutoOff */
    void check_AUTO_OFF(void)
    {
                set_sleep_mode(SLEEP_MODE_PWR_DOWN);
                cli();
        
                if (AUTO_OFF_Counter >= AUTO_OFF)
                {
                    INTERRUPT_INT0_ENABLE;
                    
                    AUTO_OFF_Counter = 0;
                    
                    SUMMER_AN;
                    _delay_ms(4);
                    SUMMER_AUS;
                    
                    sleep_enable();
                    sei();
                    clear_screen();
                    sleep_cpu();
                    sleep_disable();
                    
                    INTERRUPT_INT0_DISABLE;
                    
                }
                    sei();
    }

    Klicke auf die Grafik für eine größere Ansicht

Name:	2014-08-02 11-46-46.026.jpg
Hits:	19
Größe:	73,1 KB
ID:	28890
    Geändert von Janiiix3 (12.08.2014 um 18:50 Uhr)

  2. #2
    Moderator Robotik Visionär Avatar von radbruch
    Registriert seit
    27.12.2006
    Ort
    Stuttgart
    Alter
    61
    Beiträge
    5.799
    Blog-Einträge
    8
    Hallo

    Ich glaube, der einfachste Ansatz wäre, wenn du fürs Scrollen deinen Bildspeicher von 8 auf 16 Bit erweitern würdest. Das wären je 8 Bit für das aktuell dargestellte Zeichen und 8 Bit für das Zeichen das reingeschoben werden soll. Nach 8 Shifts ist das neue Zeichen komplett ins dargestellte Byte gewandert und du kannst das nächste Zeichen in das reinzuschiebende Byte kopieren. Je nach Scrollrichtung mußt du natürlich das High- oder das Lowbyte an die Matrix senden und das jeweils andere Byte für das Reinscrollzeichen verwenden.

    Wenn's klappt wollen wir natürlich ein Filmchen sehen :)

    Gruß

    mic


    P.S.: Meine Matrixversuche mit dem 12X10-Pingpong verwendeten am Anfang das Scrollprogramm von ELO:
    https://www.roboternetz.de/community...l=1#post492046
    Geändert von radbruch (12.08.2014 um 18:57 Uhr)
    Bild hier  
    Atmel’s products are not intended, authorized, or warranted for use
    as components in applications intended to support or sustain life!

  3. #3
    Benutzer Stammmitglied Avatar von Janiiix3
    Registriert seit
    29.11.2010
    Ort
    Hannover
    Alter
    32
    Beiträge
    48
    Hallo Mic,

    Du meinst das was ich jetzt aktuell mit "VRAM[0] = VRAM[0] << 1" mache, auf 16 erweitern?
    Wie bekomme ich es denn hin das dass Bild auch von "rechts" rein geschoben kommt? Dann müsste ich es doch vorher auch 8 x im VRAM nach rechts (>>) schieben oder ?
    Das Problem ist noch, dass ich meine LED´ "low active" geschaltet habe... Dann müsste ich quasie noch mal alles invertieren?!

  4. #4
    Erfahrener Benutzer Roboter-Spezialist Avatar von Thegon
    Registriert seit
    21.01.2011
    Beiträge
    562
    Also ich habe bei unserer Matrix folgendes Prinzip angewandt: Ein großer langer Videospeicher enthält alle LED an/aus Informationen des gesamten anzuzeigenden Textes. Und dann gibt es zwei kleine Videospeicher, die genau so groß sind wie die Fläche, auf der angezeigt werden kann. Jetzt wird ein socher Videospeicher wie ein "Fenster" auf den großen gelegt und dann der Multiplex-Einheit zur anzeige übergeben. Währenddessen wird der zweite kleine Videospeicher beschrieben, nur dass das "Fenster" jetzt um eine Spalte weiter verschoben wurde (Sozusagen das nächste Frame, der Text ist eine Spalte weitergewandert). Nach einer gewissen Zeit (z.B. ein vielfaches der Multiplex-Frequenz, dann kann man den gleichen Timer benutzen) werden die beiden Arrays dann ausgetauscht.

    Um einen Teil des großen Videospeichers in den kleinen zu bekommen ist halt eine Schleife und die entsprechenden << und >> - Anweisungen nötig.
    Da hilft es ungemein wenn man sich eine Skizze des Speichers auf einem Blatt Papier macht und sich überlegt was wieviel wohin geshiftet werden muss

    Alternativ, falls du es dir vom Speicher her leisten kannst, könnte man auch für jede LED ein eigenes Byte spendieren, dadurch erspart man sich die ganze Bitshifterei und kann mit übersichtlicheren Schleifen arbeiten.

    Hoffentlich war das jetzt einigermaßen verständlich ausgedrückt.
    Ich kann auch ein bisschen Quellcode posten, nur glaube ich nicht dass er dir viel hilft.

    Grüße Thegon

  5. #5
    Benutzer Stammmitglied Avatar von Janiiix3
    Registriert seit
    29.11.2010
    Ort
    Hannover
    Alter
    32
    Beiträge
    48
    Hallo Thegon,

    Wie hast du es realisiert, dass die Zeichen direkt hintereinander kommen ? Sprich z.B "www.google.de" das man die "leerzeichen" frei wählen kann.
    Code würde mich sehr freuen, ich habe im moment echt noch keinen Ansatz wie ich das einigermaßen ordentlich umsetzen könnte.
    Geändert von Janiiix3 (12.08.2014 um 19:30 Uhr)

  6. #6
    Erfahrener Benutzer Roboter-Spezialist Avatar von Thegon
    Registriert seit
    21.01.2011
    Beiträge
    562
    Also der Zeichengenerator (der den großen Videospeicher vollschreibt) besteht aus einem großen PROGMEM-Array, das die ganzen Pixel-Informationen der einzelnen Buchstaben enthält (damit alles schön in ein Byte passt kann bei mir ein Buchstabe nicht länger sein als 8 Spalten, da ich 7 Zeilen LEDs habe sind es dann 7 Bytes pro Buchstabe). Jeder Buchstabe enthält bei mir eine Leerspalte (gehört also fix zu den Pixeldaten), dass die Buchstaben nicht so aufeinander kleben. Ein Leerzeichen besteht dann halt aus vier oder fünf Leerspalten, glaube ich. Die perfekte Umsetzung ist auch das nicht, aber so schlecht schaut es meiner Meinung nicht aus. Bleibt noch, dass manche Buchstaben mehr Spalten brauchen als andere (z.B. ist B länger als i), deswegen gibt es ein zweites PROGMEM-Array, in dem die Längen abgespeichert sind für die einzelnen Buchstaben. Die beiden Arrays generiere ich mit einem simplen kleinen VB.net Programm, das geht schneller ein solches zu schreiben als alles per Hand reinzuklopfen.

    Code:
    #define     used_length       5 // d.h. der große Videospeicher ist 5*8 Spalten lang, wenn wir darüber hinaus sind fängts von vorne an
    
    void bufcpy(char startpoint, char targetbuffer){
        /*
            So, was macht diese Funktion jetzt: 
            Sie kopiert ausgehend vom Startpoint (in Bits -> LED-Spalten im großen Videospeicher) ein Byte in den Ausgabebuffer, das in jeder Zeile
            
            d1[5][8] ist der große Videospeicher, 
                  wobei [5] bedeutet dass die Länge 8*5 = 40 Spalten beträgt. 
                  [8] bedeutet, dass die Matrix 8 Zeilen hat
    
           dm[2][8] sind die zwei Swap-Buffer 
                  [2] bedeutet dass es zwei gibt, in die geschrieben werden kann (als Funktionsparameter übergeben,
                  in welchen geschrieben werden soll)
                  [8] bedeutet, dass die Matrix 8 Zeilen hat
    
        */
        
        //Funktionsinterne Variablen:
            //So viele Bits ist unterschied zwischen den Byte-Reihen der beiden Buffer
                char startblock = startpoint/8; 
                char offset = startpoint%8; 
            
            //Zählervariablen der Schleifen
                char i, j; 
                
            //Hier werden die beiden Bytes, also das halbe drüber und das halbe drunter hineinkopiert und entsprechend geshiftet
                char low, high; 
        
        //Die Zeilen durchgehen
        for(i=0; i < 8; i++){   
                //Lowbyte laden und entsprechend verschieben, gleiches für Highbyte
                low = d1[(startblock )%used_length][i]; 
                low = low >> offset; 
                high = d1[(startblock + 1)%used_length][i]; 
                high = high << (8-offset); 
                
                //Nun zusammenfügen
                dm[targetbuffer][i] = high | low; 
        }
        
    
    }
    Das ist jetzt ein wenig angepasst, dass es zu deinen Abmessungen passt, deshalb auch nicht getestet und eher nur als "Pseudocode" zu verstehen.
    Aber ich hoffe, es ist ein wenig verständlich wie ich das meine

    Grüße
    Thegon

  7. #7
    Moderator Robotik Visionär Avatar von radbruch
    Registriert seit
    27.12.2006
    Ort
    Stuttgart
    Alter
    61
    Beiträge
    5.799
    Blog-Einträge
    8
    Hallo

    Nein, das bauchst du nicht auf 16 erweitern, denn nach 8 Shifts ist das alte Zeichen rausgeschoben und das neue Zeichen wird dargestellt. Jetzt kopierst du das nächste Zeichen in das freie Byte (je nach Scrollrichtung) des 16Bit-Bildspeichers und beginnst das Schieben von neuem.

    In ISR(TIMER0_COMP_vect):

    Beim nach rechts schieben: PORTA = VRAM[spalte] & 0xFF;
    Beim nach links schieben: PORTA = VRAM[spalte] >> 8;

    In check_usb(void) schreibst du nach 8 Shifts das neue Zeichen je nach Richtung in das High- oder Lowbyte:

    Beim nach rechts schieben: VRAM[d] = VRAM[d] + pgm_read_byte(&charMap[i][d]) * 0xFF; // ins Highbyte schreiben
    Beim nach links schieben: VRAM[d] = VRAM[d] + pgm_read_byte(&charMap[i][d]); // ins Lowbyte schreiben

    natürlich ungetestet ;)

    btw: Ich glaube, du verwechselst Zeile und Spalte bei "VRAM[spalte]". Diese Codeausschitte deuten darauf hin, dass die Zeichen im Zeichensatz von oben nach unten, also zeilenweise aufgebaut sind:

    Code:
         {0x99,0x99,0x99,0x99,0x99,0x99,0xC1,0xFF}, // U (6 mal 0x99 ist die Öffnung des Zeichens oben)
         {0x99,0x99,0x99,0x99,0x99,0xC3,0xE7,0xFF}, // V (dito)
         {0x83,0x99,0x99,0x83,0x9F,0x9F,0x9F,0xFF}, // P (0x9f ist der Strich links)
         {0xF3,0xFF,0xF3,0xF3,0xF3,0x33,0x33,0x87}, // j (0x33 der Strich rechts)
    Wenn du an Port B/C einen Ausgang auf High setzt, aktivierst du eine Zeile die in PortA codiert ist. Da das im Moment schon funktioniert brauchst du zum Scrollen auch nichts zusätzlich zu invertieren.

    Die Methode von Thegon ist auch clever, allerdings ein komplett anderer Aufbau. Viele Wege führen nach Rom...

    Gruß

    mic
    Bild hier  
    Atmel’s products are not intended, authorized, or warranted for use
    as components in applications intended to support or sustain life!

  8. #8
    Benutzer Stammmitglied Avatar von Janiiix3
    Registriert seit
    29.11.2010
    Ort
    Hannover
    Alter
    32
    Beiträge
    48
    Zitat Zitat von radbruch Beitrag anzeigen
    Hallo

    Nein, das bauchst du nicht auf 16 erweitern, denn nach 8 Shifts ist das alte Zeichen rausgeschoben und das neue Zeichen wird dargestellt. Jetzt kopierst du das nächste Zeichen in das freie Byte (je nach Scrollrichtung) des 16Bit-Bildspeichers und beginnst das Schieben von neuem.

    In ISR(TIMER0_COMP_vect):

    Beim nach rechts schieben: PORTA = VRAM[spalte] & 0xFF;
    Beim nach links schieben: PORTA = VRAM[spalte] >> 8;

    In check_usb(void) schreibst du nach 8 Shifts das neue Zeichen je nach Richtung in das High- oder Lowbyte:

    Beim nach rechts schieben: VRAM[d] = VRAM[d] + pgm_read_byte(&charMap[i][d]) * 0xFF; // ins Highbyte schreiben
    Beim nach links schieben: VRAM[d] = VRAM[d] + pgm_read_byte(&charMap[i][d]); // ins Lowbyte schreiben

    natürlich ungetestet

    btw: Ich glaube, du verwechselst Zeile und Spalte bei "VRAM[spalte]". Diese Codeausschitte deuten darauf hin, dass die Zeichen im Zeichensatz von oben nach unten, also zeilenweise aufgebaut sind:

    Code:
         {0x99,0x99,0x99,0x99,0x99,0x99,0xC1,0xFF}, // U (6 mal 0x99 ist die Öffnung des Zeichens oben)
         {0x99,0x99,0x99,0x99,0x99,0xC3,0xE7,0xFF}, // V (dito)
         {0x83,0x99,0x99,0x83,0x9F,0x9F,0x9F,0xFF}, // P (0x9f ist der Strich links)
         {0xF3,0xFF,0xF3,0xF3,0xF3,0x33,0x33,0x87}, // j (0x33 der Strich rechts)
    Wenn du an Port B/C einen Ausgang auf High setzt, aktivierst du eine Zeile die in PortA codiert ist. Da das im Moment schon funktioniert brauchst du zum Scrollen auch nichts zusätzlich zu invertieren.

    Die Methode von Thegon ist auch clever, allerdings ein komplett anderer Aufbau. Viele Wege führen nach Rom...

    Gruß

    mic

    Also muss ich in der Multiplex ISR noch mal eine If Abfrage einbauen, ob rechts | links geschoben wird & je-nach-dem "Maskieren".
    Hört sich echt logisch an, ich habe so lange dran rum gesessen ohne auch annähernd eine gute Lösung zu bekommen.

Ähnliche Themen

  1. LED Matrix
    Von Zwerwelfliescher im Forum Elektronik
    Antworten: 3
    Letzter Beitrag: 02.09.2011, 20:54
  2. LED Matrix
    Von Tanne123 im Forum Vorstellung+Bilder+Ideen zu geplanten eigenen Projekten/Bots
    Antworten: 3
    Letzter Beitrag: 13.10.2010, 23:20
  3. LED MATRIX
    Von Beta im Forum Elektronik
    Antworten: 7
    Letzter Beitrag: 01.06.2009, 22:47
  4. LED Matrix Baustein
    Von karlmonster im Forum Elektronik
    Antworten: 3
    Letzter Beitrag: 07.04.2008, 20:57
  5. LED Matrix
    Von .Johannes. im Forum Elektronik
    Antworten: 5
    Letzter Beitrag: 30.08.2006, 22:29

Berechtigungen

  • Neue Themen erstellen: Nein
  • Themen beantworten: Nein
  • Anhänge hochladen: Nein
  • Beiträge bearbeiten: Nein
  •  

LiTime Speicher und Akkus