8x8 Matrix Laufschrift

OP #5457613
Lesenswert?

Halli Hallo,

habe irgendwie einen kompletten "Blackout" was das "scrollen" eines 
Textes betrifft.

Habe eine 8x8 Matrix aufgebaut. Nun möchte ich gerne von rechts nach 
links einen Text rein scrollen lassen und diesen links ausrollen lassen.

Meine Zeichen stelle ich wie folgt ( mittig ) auf die Anzeige dar..
1
for( uint8_t i = 0 ; i < 8 ; i++ )
2
{
3
 VRAM[i] &= pgm_read_byte(&charMap[ZEICHEN][i])
4
}

Nun habe ich irgendwie mega Probleme mich in den Ablauf des scrollens 
rein zu denken & wie ich das am besten nachbilden kann..

Kann mir jemand evtl. mit einem Kodebeispiel weiter helfen? Darf auch 
gerne Pseudokode sein.. Würde mich über Hilfe riesig freuen.

Angenehmen, siegreichen Sonntag noch ;)

P.S
Die Anzeige wird schon gemultiplext.
#5457632
Lesenswert?

Moin,

Hab's nicht getestet - und warum nimmst du "&=" bei der Zuweisung ans 
VRAM?
1
for( uint8_t j = 0 ; j < 8 ; j++ )
2
  for( uint8_t i = 0 ; i < 8 ; i++ )
3
  {
4
   z1 = pgm_read_byte(&charMap[ZEICHEN][i]);
5
   z2 = pgm_read_byte(&charMap[NAECHSTES_ZEICHEN][i]);
6
   VRAM[i] = (z1 << j) | (z2 >> (8-j));
7
  }

Gruss
WK
edit: z1 und z2 sollten unsigned sein, sonst stoert das Vorzeichen beim 
rechtsschieben.
#5457646
Lesenswert?

Hallo,
vorausgesetzt dass die Ausgabe ohne Scrollen so funktioniert (verstehe 
das &= auch nicht, aber egal) stellt sich mir die Frage:
Wie sind die Bytes angeordnet?

Horizontal oder vertikal?

Anders ausgedrückt: Die Laufvariable i, ist das die Zeile von oben nach 
unten oder die Spalte von links nach rechts? Danach richtet sich es, ob 
man die Spalten versetzt ausgeben muss, oder die einzelnen Zeilen 
bitweise nach links schieben.


Wenn das klar ist kann man sinnvolle Ansätze erarbeiten.
Gruß
Thomas
Gast #5457669
Lesenswert?

Hallo Georg,

das geht schon mit einer Matrix Lauftext anzusehen, Zielführend war bei 
mir die für mich passende Scrollgeschwindigkeit zu wählen.
Do kann ich einfach 5 Zeichen + 1 Leerzeichen anzeigen.

georg schrieb:
> Jan H. schrieb:
>> Habe eine 8x8 Matrix aufgebaut. Nun möchte ich gerne von rechts nach
>> links einen Text rein scrollen lassen
>
> Einen Text in 8 Spalten? Ist dir klar dass man da nur ein einziges
> Zeichen sieht oder 2 halbe? Wer soll das lesen können?
>
> Georg
Moderator (Firma: Titel) Persönliche Seite #5457713
Lesenswert?

Jan H. schrieb:
> Die Anzeige wird schon gemultiplext.
Bau dein Programm so um, dass du dein Zeichen aus dem RAM darstellen 
kannst.  Und dann speicherst du die gesamte Meldung mitsamt Abstand 
hintereinander in das RAM und fährst mit einem "Anfangszeiger" durch das 
RAM. Diesen Anfangszeiger inkremenierst du nach jeweils ca. 100ms und 
fängst somit immer eine Pixelreihe "weiter hinten" an.
Gast #5457731
Lesenswert?

Jan H. schrieb:
> Nun habe ich irgendwie mega Probleme mich in den Ablauf des scrollens
> rein zu denken

Tja, wenn man nicht weiss, ob deine Bytes eine senkrechte Spalte oder 
waagerechte Zeile darstellen, wird das auch nichts.

Man braucht jedenfalls das aktuelle Zeichen und das nächste Zeichen, du 
hast nur ZEICHEN, also 1.

Man muss dann entweder eine Anzahl von Spalten aus dem ersten und die 
Restanzahl aus dem nächsten Zeichen holen,

oder eben aus 2 byzes 1 16 bit Wort machen und so schirben dass die 
benötigten Bildpunkte z.B. im lower byte stehen, welches dann auf die 
Matrix kommt
#5457768
Lesenswert?

Jan H. schrieb:
> Dergute W. schrieb:
>> Hab's nicht getestet - und warum nimmst du "&=" bei der Zuweisung ans
>> VRAM?
> Das habe ich gemacht, damit alle anderen LED´s aus sind. Habe die LED´s
> "active low" angeschlossen.
> Ohne würden die anderen nicht ausgehen. Hängt auch mit dem Zeichensatz
> zusammen.

Das möchtest Du Dir nochmal an Hand von Beispiel Werten durchrechen. In 
meinen Augen funktioniert das nämlich nur genau ein Mal - es sei denn Du 
hast irgendwo ein
1
memset(VRAM, 0xFF, sizeof(VRAM));

versteckt.
OP #5457775
Lesenswert?

Dergute W. schrieb:
> Jan H. schrieb:
>> Das habe ich gemacht, damit alle anderen LED´s aus sind. Habe die LED´s
>> "active low" angeschlossen.
>> Ohne würden die anderen nicht ausgehen. Hängt auch mit dem Zeichensatz
>> zusammen.
>
> Da staunt der Fachmann und der Wunde leiert sich...
>
> Gruss
> WK

So ganz funktioniert das noch nicht. Die Schrift soll von rechts rein 
kommen und nach links raus rollen. Hier mal ein Video..

https://www.dropbox.com/s/m1xoapgqulvenrj/IMG_1795.MOV?dl=0
Gast #5457824
Lesenswert?

Ja dann sage doch endlich mal, wie die Matrix aufgebaut und ausgerichtet 
ist! Und wie sind die Zeichensätze im Speicher aufgebaut? Ein kleiner 
Schaltplan + die relevanten Codeschnipsel wären angemessen.
Gast #5457850
Lesenswert?

Das sind doch immer noch halbe Informationen. Ich dichte mal dazu, dass 
jedes Byte im VRAM eine vertikale Reihe von LED's ansteuert, und zwar 
Low=An. Ich dichte auch dazu, dass diese Darstellung der physischen 
Zuordnung entspricht, also keine Pins vertauscht werden müssen und keine 
Drehung um 90° nötig ist.

Stimmt das soweit?

Wie sind denn deine Daten im Zeichensatz angeordnet. Genau so? Könnte 
man also 8 Byte direkt vom Zeichensatz 1:1 ins VRAM Kopieren, um ein 
einzelnes stehendes Zeichen darzustellen?
OP #5457866
Lesenswert?

Stefanus F. schrieb:
> Das sind doch immer noch halbe Informationen. Ich dichte mal dazu, dass
> jedes Byte im VRAM eine vertikale Reihe von LED's ansteuert, und zwar
> Low=An. Ich dichte auch dazu, dass diese Darstellung der physischen
> Zuordnung entspricht, also keine Pins vertauscht werden müssen und keine
> Drehung um 90° nötig ist.
>
> Stimmt das soweit?
>
> Wie sind denn deine Daten im Zeichensatz angeordnet. Genau so? Könnte
> man also 8 Byte direkt vom Zeichensatz 1:1 ins VRAM Kopieren, um ein
> einzelnes stehendes Zeichen darzustellen?

Genau das kann man.
Mit..
1
for( uint8_t x = 0 ; x < 8 ; x++ )
2
{
3
 VRAM[x] = ~(pgm_read_byte(&charMap[u1][x]));
4
}
Kopier ich das Zeichen "u1" in den VRAM und es wird auf dem Display 
angezeigt.
Gast #5457877
Lesenswert?

Um ein neues Zeichen schrittweise von rechts herein zu schieben, musst 
du eine Schleife mit 8 Schritten programmieren. Bei jedem Schritt 
verschiebt sie den Inhalt des ganzen VRAM um eine Position nach links, 
um danach rechts eine Spalte des nächsten Zeichens einzufügen.

Angenommen, das VRAM Enthält zunächst die acht Spalten von dem 
Buchstaben "A" und dann soll der Buchstabe "B" von rechts herein 
geschoben werden, dann sieht das im VRAM so aus:

A0 A1 A2 A3 A4 A5 A6 A7
A1 A2 A3 A4 A5 A6 A7 B0
A2 A3 A4 A5 A6 A7 B0 B1
A3 A4 A5 A6 A7 B0 B1 B2
A4 A5 A6 A7 B0 B1 B2 B3
A5 A6 A7 B0 B1 B2 B3 B4
A6 A7 B0 B1 B2 B3 B4 B5
A7 B0 B1 B2 B3 B4 B5 B6
B0 B1 B2 B3 B4 B5 B6 B7
1
for( uint8_t step = 0 ; step < 8 ; step++ )
2
{
3
    // Schieben
4
    for( uint8_t spalte = 0 ; spalte < 7 ; spalte++ )
5
    {
6
       VRAM[spalte] = VRAM[spalte+1];
7
    }
8

9
    // neues Byte rechts einfügen
10
    VRAM[7] = ~(pgm_read_byte(&charMap[u1][step]));
11

12
   delay_ms(100);
13
}

Verständlich?
Gast #5457930
Lesenswert?

Jan H. schrieb:
> Habe ich soweit verstanden. Das Zeichen fängt aber auch hier wieder im
> Display an.


Meinst Du konkret das erste Zeichen Deines Textes? Dann stell ihm ein 
Leerzeichen voran, dann fällt das nicht auf.


Jan H. schrieb:
> Es wird nicht komplett von unten nach oben rein geschoben.

Jan H. schrieb:
> Nun möchte ich gerne von rechts nach links einen Text rein scrollen lassen


Magst Du Dich vielleicht mal entscheiden? Von wo nach wohin soll der 
Text scrollen?
OP #5457979
Lesenswert?

> Magst Du Dich vielleicht mal entscheiden? Von wo nach wohin soll der
> Text scrollen?

Der Text sollte von links nach rechts rein scrollen. Die Funktion 
@Stefanus F. geschrieben hat, funktioniert auch wunderbar aber da 
scrollt der Text von unten rein und nach oben raus..
OP #5458042
Lesenswert?

Dergute W. schrieb:
> Moin,
>
> Lass' mal die for schleife mit dem j weg, und setze j einfach mal auf
> einen festen Wert z.b. 3,4, oder 5.
> Vielleicht faellt ja dann der Groschen?
>
> Gruss
> WK
1
void scrollMessage( char *msg )
2
{
3
  char z1 = 0 , z2 = 0;
4
  while ( *msg )
5
  {
6

7
      for( uint8_t i = 0 ; i < 8 ; i++ )
8
      {
9
        z1 = ~pgm_read_byte(&charMap[ GetCharacterIndex( *msg )  ] [ i ] );
10
        z2 = ~pgm_read_byte(&charMap[ GetCharacterIndex( *msg++ )] [ i ] );
11
        VRAM[i] = ( z1 << 6 ) | (z2 >> ( 8 - 6 ) );
12
      }  
13
      _delay_ms(250);    
14

15

16
    
17
//     for( uint8_t step = 0 ; step < 8 ; step++ )
18
//     {
19
//       // Schieben
20
//       for( uint8_t spalte = 0 ; spalte < 8 ; spalte++ )
21
//       {
22
//         VRAM[spalte] = VRAM[spalte+1];
23
//       }
24
// 
25
//       // neues Byte rechts einfügen
26
//       VRAM[7] = ~(pgm_read_byte(&charMap[ GetCharacterIndex( *msg )][step]));
27
// 
28
//       _delay_ms(150);
29
//     }  
30
//     msg++;  
31
  }
32
}

Wenn ich die Funktion so einsetze, passiert folgendes..
https://www.dropbox.com/s/ln6vh99z0joixu3/IMG_1799.MOV?dl=0
Gast #5458061
Lesenswert?

Jan H. schrieb:
> Der Text sollte von links nach rechts rein scrollen. Die Funktion
> @Stefanus F. geschrieben hat, funktioniert auch wunderbar aber da
> scrollt der Text von unten rein und nach oben raus

Tja, dann ist deine Matrix falsch verdrahtet.
Dreh sie und die font definition um 90 Grad.
Gast #5458065
Lesenswert?

Offensichtlich ist die Schaltung und die Ausrichtung der Daten im 
Speicher immer noch völlig unklar. Meine Zusammenfassung wurde erst 
bestätigt und dann ein Problem (von unten nach oben) geschildert, dass 
nur bei einer völlig anderen Struktur möglich sein kann.
Ich werde much erst weiter beteiligen, wenn der TO Schaltplan, 
Speicherstruktur und Quelltext offen legt.
Gast #5458136
Lesenswert?

Der Test von Code fehlt, der die eigentliche Ausgabe macht. Auf jeden 
Fall ist der Zeichensatz schnmal ganz anders aufgebaut als hier 
abgestimmt wurde. Ich sehe 8 Bytes pro Zeichen. Jedes Byte repräsentiert 
eine Zeile.

Das macht den Scrill Effekt aufwändigwr denn du musst in jeder Zeile 
alle Bits um eins nach links schieben und dann rechts in jeder Zeile ein 
Bit aus dem Zeichensatz rein schieben.

Bitmanipulation ist dein Thema.
#5458141
Lesenswert?

Hi, ehrlich gesagt, ich hab nicht alles gelesen, aber ich würde das so 
machen:
Einen Bildspeicher anlegen, vertikal ein byte, horizontal Anzahl der 
Spalten deiner Matrix.
Eine Routine schreiben, die den Bildspeicher auf der Matrix anzeigt.
Einen font verwenden, der spaltenorinetiert ist.
Eine Routine schreiben, die jetzt nacheinander Buchstabe für Buchstabe 
aus dem Text nimmt und eine Spalte von Buchstaben in die rechteste 
Spalte vom Bildspeicher schreibt, den Bildspeicher anzeigen lässt, nach 
kurzer Zeit den Bildspeicher spaltenweise nach links umkopiert(linkeste 
Spalte fällt weg, 2. Spalte wird 1....rechteste Spalte wird die 2. von 
rechts). Jetzt nächste Spalte vom Buchstaben in die rechteste Stelle vom 
Bildspeicher schreiben, anzeigen lassen, warten, Bildspeicher nach links 
shiften, nächste Spalte vom Buchstaben in die rechteste Spalte des 
Bildspeichers...
OP #5458152
Lesenswert?

Stefanus F. schrieb:
> Ich meinte dass der TEXT von deinem Quelltext fehlt, der die Ausgabe vom
> VRAM zum Display macht.
1
 
2
/* Multiplexen der Anzeige */
3
ISR(TIMER0_COMP_vect)
4
{
5
  
6
    static volatile uint8_t spalte = 0;
7

8
    PORTC &= ~((1<<PC7) | (1<<PC6) | (1<<PC5) | (1<<PC4) | (1<<PC3));
9
    PORTB &= ~((1<<PB2) | (1<<PB1) | (1<<PB0));
10
    
11
    // neue Zeilendaten ausgeben
12
    
13
  PORTA = ~(VRAM)[spalte];
14
    
15
    // Spalte aktivieren  
16
    switch (spalte) {
17
      case 0: PORTC |= (1<<PC3);
18
      break;
19
      case 1: PORTC |= (1<<PC4);
20
      break;
21
      case 2: PORTC |= (1<<PC5);
22
      break;
23
      case 3: PORTC |= (1<<PC6);
24
      break;
25
      case 4: PORTC |= (1<<PC7);
26
      break;
27
      case 5: PORTB |= (1<<PB2);
28
      break;
29
      case 6: PORTB |= (1<<PB1);
30
      break;
31
      case 7: PORTB |= (1<<PB0);
32
      break;
33
      default: break;
34
    }
35

36
    spalte++; // nächste Spalte
37
    if (spalte >= 8) spalte = 0; // Spalten 0.
#5458168
Lesenswert?

Stefanus F. schrieb:
> Michael, so weit waren wir schon. Nun ist sein Zeichensatz aber
> Zeilenorientiert, wie sich herausgestellt hat.

Dann macht man den Bildspeicher einfach nach rechts breiter und zeigt 
halt nur den linken Teil an. Der Buchstabe wird rechts in den 
Bildspeicher geschrieben, man shiftet und zeigt den Bildspeicher an, 
nachdem man das 8x gemacht hat, wird wieder ein kompletter Buchstabe in 
den Speicher geladen...
#5458266
Lesenswert?

Moin,

Oioioi, ich glaub', da laeuft's noch an so vielen verschiedenen Stellen 
schief...
In dem Filmchen siehts so aus, als wuerde da wer weiss wer an den LEDs 
rumfummeln. Die muessten doch zumindest regelmaessig ihr Muster aendern; 
tun sie aber nicht. Da sind manchmal kurze und manchmal laengere Pausen 
dabei.

Die Bedeutung von Tilde (~) und die Gesetze von De Morgan sitzen auch 
noch lange nicht so, wie man das braucht, um Bitpopeleien vernuenftig 
auszufuehren:

Jan H. schrieb:
> z1 = ~pgm_read_byte(&charMap[ GetCharacterIndex( *msg )  ] [ i ] );
>         z2 = ~pgm_read_byte(&charMap[ GetCharacterIndex( *msg++ )] [ i ]
> );
>         VRAM[i] = ( z1 << 6 ) | (z2 >> ( 8 - 6 ) );


Gruss
WK
OP #5458336
Lesenswert?

Dergute W. schrieb:
> Die Bedeutung von Tilde (~) und die Gesetze von De Morgan sitzen auch
> noch lange nicht so, wie man das braucht, um Bitpopeleien vernuenftig
> auszufuehren:

Da es sich um "invertierte Logik" handelt, musste ich das so machen, 
sonst hätte ich den ganzen Font umschreiben müssen.

Wenn ich wüsste wie ich jetzt weiter machen sollte, würde ich mich wohl 
kaum hier zu Wort melden..
#5458342
Lesenswert?

Hier mal eine Funktion, so ähnlich habe ich das in meiner Uhr gelöst.
scroll ist hier die Verschiebung nach links (0 ist nicht verschoben)
.
Das Zeichen wird in die 8x8 hineingeschrieben, bei jedem Aufruf mit 
scroll einen größer wird es nach links herausgeschoben.
Will man es von rechts hereinschieben lassen muss man V8bit[1] ausgeben.

void ScrollPrint (unsigned char ZEICHEN, unsigned char scroll)
{
  union
  {
    unsigned int V16Bit;
    unsigned char V8Bit[2];
  } tmp;

  for( uint8_t i = 0 ; i < 8 ; i++ )
  {
    tmp.V16Bit = pgm_read_byte(&charMap[ZEICHEN][i]);
    tmp.V16Bit = V16Bit << scroll;//nach lins schieben
    VRAM[i] &= tmp.V8Bit[0];//die rechte Seite ausgeben
  }
}
Hilft das weiter?
OP #5458355
Lesenswert?

Thomas S. schrieb:
> Hier mal eine Funktion, so ähnlich habe ich das in meiner Uhr gelöst.
> scroll ist hier die Verschiebung nach links (0 ist nicht verschoben)
> .
> Das Zeichen wird in die 8x8 hineingeschrieben, bei jedem Aufruf mit
> scroll einen größer wird es nach links herausgeschoben.
> Will man es von rechts hereinschieben lassen muss man V8bit[1] ausgeben.
>
> void ScrollPrint (unsigned char ZEICHEN, unsigned char scroll)
> {
>   union
>   {
>     unsigned int V16Bit;
>     unsigned char V8Bit[2];
>   } tmp;
>
>   for( uint8_t i = 0 ; i < 8 ; i++ )
>   {
>     tmp.V16Bit = pgm_read_byte(&charMap[ZEICHEN][i]);
>     tmp.V16Bit = V16Bit << scroll;//nach lins schieben
>     VRAM[i] &= tmp.V8Bit[0];//die rechte Seite ausgeben
>   }
> }
> Hilft das weiter?

Hallo,

ich danke dir erstmal für deine Antwort. Kann es gerade leider nicht 
testen. Werde mich später dazu noch mal melden.
OP #5458366
Lesenswert?

Thomas S. schrieb:
> void ScrollPrint (unsigned char ZEICHEN, unsigned char scroll)
> {
>   union
>   {
>     unsigned int V16Bit;
>     unsigned char V8Bit[2];
>   } tmp;
>
>   for( uint8_t i = 0 ; i < 8 ; i++ )
>   {
>     tmp.V16Bit = pgm_read_byte(&charMap[ZEICHEN][i]);
>     tmp.V16Bit = V16Bit << scroll;//nach lins schieben
>     VRAM[i] &= tmp.V8Bit[0];//die rechte Seite ausgeben
>   }
> }
> Hilft das weiter?

Wenn ich es von rechts reinrollen lassen möchte, meinst du muss es so 
aussehen? Ist das richtig?
1
void ScrollPrint (unsigned char ZEICHEN, unsigned char scroll)
2
{
3
  union
4
  {
5
    unsigned int V16Bit;
6
    unsigned char V8Bit[2];
7
  } tmp;
8

9
  for( uint8_t i = 0 ; i < 8 ; i++ )
10
  {
11
    tmp.V16Bit = pgm_read_byte(&charMap[ZEICHEN][i]);
12
    tmp.V16Bit = V16Bit << scroll;//nach lins schieben
13
    VRAM[i] &= tmp.V8Bit[1];//die rechte Seite ausgeben
14
  }
15
}
#5458386
Lesenswert?

Genau so.
Mit jeder Vergrößerung des Parameters scroll rutscht die Ausgabe einen 
Pixel nach links.
tmp.V8Bit[0] ist dabei die rechte Hälfte, tmp.V8Bit[1] die linke.
Wenn man einen schiebt so sind wir einen Pixel in er linken Hälfte, wenn 
man die ausgibt sieht es so aus als käme das Zeichen von rechts.
Beim Schieben von 8 ist man genau drin, schiebt man weiter verschwindet 
es wieder links raus.
Gast #5458506
Lesenswert?

ich hatte auch ein 8x8 Gitter mit kleinen Glühlampen+Dioden gebastelt 
und dieses dann jahre später auf 16x10, mit LEDs, erweitert / 
modernisiert.
ab jenem Zeitpunkt musste die Anzeige dann Quer aufgehangen werden 
(16:10 Format quasi) und ich stand genau vor dem gleichen Problem. 
Konnte ich anfangs die Bytes aus dem Flash einfach so auf die Anzeige 
tröpfeln lassen und mitm Zeiger den Flash durchfahren, musste ich nun 
das anfangs geladene Byte(paar)[16bit] per Bitshift und hirnschmalz auf 
die Anzeige bringen, weil das Display ja nun 90° gedreht war. Ich such 
das gern mal raus - hab ich zu Hause.
(Hing damals am Balkon: "Merry Xmas ,Happy new Year" usw.)
#5458615
Lesenswert?

Wenn du eine 'inverse' Ansteuerung der Led hast, dann invertiere halt 
beim Lesen des fonts gleich alle bits der bytes und fülle damit den 
Bildspeicher. Wenn du den Bildspeicher aus 8 words aufbaust, ein word 
ist eine Zeile, dann kannst du doch 8 bits von dem word auf den Leds 
ausgeben und in den anderen 8bits eine Zeile des Buchstabens 
reinkopieren. Wenn du jetzt alle words shiftest, dann wandern die bits 
des Buchstabens in den dargestellten Bereich der words. Jetzt musst du 
halt das word entsprechend dem font anlegen. Wenn bit7 aus einem byte 
des fonts die linke Kante des Buchstabens ist, dann wäre bit15 des words 
die linke Kante deiner Ledmatrix, die dann bis bit8 den Inhalt des words 
darstellt. Bit7 bis bit0 wäre eine Zeile des Buchstabens.
Ein word ist bei mir eine 16bit-Variable.
Gast #5458716
Lesenswert?

Habe ich einen Knick in der Optik oder sehe ich doppelte Invertierung?

> Mit..
1
for( uint8_t x = 0 ; x < 8 ; x++ )
2
{
3
 VRAM[x] = ~(pgm_read_byte(&charMap[u1][x]));
4
}
> Kopier ich das Zeichen "u1" in den VRAM und es wird auf
> dem Display angezeigt.

Und:
1
ISR(TIMER0_COMP_vect)
2
{
3
    ...    
4
    // neue Zeilendaten ausgeben
5
    PORTA = ~(VRAM)[spalte];
6
    ...
7
}
OP #5458937
Lesenswert?

Vielen Dank! Das klappt echt super. Was mir jetzt noch nicht so ganz 
gefällt ist der Font. Ich habe zwischen den einzelnen Zeichen immer 
mindestens 6 x "Leerzeichen".. Das sieht echt kacka aus bei dem 
scrollen.
Wie löse ich das am besten? Font anpassen und mit jeweils der Breite 
eines Zeichens versehen?
#5458970
Lesenswert?

Ist nicht ein 8x8 font so aufgebaut, dass das Zeichen und eine leere 
Spalte in eine 8x8 Matrix passt? Wenn du 6 Spalten dazwischen hast, dann 
kommen 5 Spalten von deinem Programm. Das gilt jetzt für ein 'H', wenn 
du ein (schmales) 'I' hast, dann sind mehr Spalten zwischen den 
Buchstaben, ist halt kein proportional font.
OP #5458973
Lesenswert?

Michael K. schrieb:
> Ist nicht ein 8x8 font so aufgebaut, dass das Zeichen und eine leere
> Spalte in eine 8x8 Matrix passt? Wenn du 6 Spalten dazwischen hast, dann
> kommen 5 Spalten von deinem Programm. Das gilt jetzt für ein 'H', wenn
> du ein (schmales) 'I' hast, dann sind mehr Spalten zwischen den
> Buchstaben, ist halt kein proportional font.
Es sieht eben beim scrollen sehr doof aus. Es ist halt eine Menge Platz 
dazwischen.. Den muss ich irgendwie eliminieren..
#5459009
Lesenswert?

Tja, dann wird es das einfachste sein, im font bei jedem Zeichen ein 
'Breite'-byte einzufügen. Wenn der font zeilenorientiert ist, ist es 
schon aufwändig die Breite zu errechnen, könnte aber gehen.

Aber wenn du schreibs 'mindestens' 6 Leerspalten, dann ist was anderes 
faul. Was passiert, wenn du 'HHHH' als Text ausgibst? Da sollte nur 1 
Spalte als Platzhalter zwischen den Buchstaben sein.
OP #5459014
Lesenswert?

Michael K. schrieb:
> Aber wenn du schreibs 'mindestens' 6 Leerspalten, dann ist was anderes
> faul. Was passiert, wenn du 'HHHH' als Text ausgibst? Da sollte nur 1
> Spalte als Platzhalter zwischen den Buchstaben sein.

Da ist immer ein ganzer "Bildschirm" (8 Bytes) zwischen jedem 'H'...
1
uint8_t ScrollPrint ( char *msg )
2
{
3
  union
4
  {
5
    unsigned int V16Bit;
6
    unsigned char V8Bit[2];
7
  } tmp;
8

9
  uint8_t scrollPos;
10
  uint8_t leng;
11
  for ( leng = 0 ; *msg != '\0' ; leng++ )
12
  {
13
    for ( scrollPos = 0 ; scrollPos < 8 ; scrollPos++ )
14
    {
15
      for( uint8_t i = 0 ; i < 8 ; i++ )
16
      {
17
        tmp.V16Bit  =  0xFF & ~pgm_read_byte(&charMap[ GetCharacterIndex( *msg ) ][i]);
18
        tmp.V16Bit  = tmp.V16Bit << scrollPos; // nach links verschieben
19
        VRAM[i]    = tmp.V8Bit[1]; // rechte Seite ausgeben
20
      }
21
      _delay_ms(250);    
22
    }
23
    msg++;    
24
  }
25
  
26
  return leng;
27
}
#5459016
Lesenswert?

Breite berechnet diese Funktion:
//###########returns the length of a char in pixels####################
unsigned char SignLength (unsigned char A)      //returns length of A in 
pixels
{
  unsigned char max=1,tmp;
  register unsigned char i, j;

  if (A == ' ')  return 3;  //SPACE
  if (!A)  return 4;    //NULL
  if (A == ',')  return 2;  //comma

  for (i = 0; i < 8; i++)              //8 lines with 6 dots max each
  {
  tmp = (pgm_read_byte (&font6x8[A][i]));  //maximum char is 0x1F, 5 
bits right adjusted
  for (j = 32; j > 1; j/=2)
    {
    if ((tmp&j)&&(j > max))
      {
    max = j;              //max value in this line, next line...
        break;
    }
   }
  }
  j = 1;
  while (max)
  {
    max/=2;
    j++;
  }
  return j;
}

So geht es in meiner Uhr. Die Zeichen müssen dafür rechtsbündig 
definiert sein, also immer in Bit0 der rechteste Pixel.
#5459196
Lesenswert?

Ich verwende nicht C, aber wenn ich mich nicht irre (was dadurch leicht 
sein kann), shiftest du deine 16bit Variable und liest gleichzeitig die 
bytes des nächsten Buchstabens ein?. Wenn du den Buchstaben komplett in 
die eine Hälfte der 16bitVariablen einliest, dann diese 8x um 1bit 
shiftest und dann wieder komplett den nächsten Buchstaben lädst, dann 
muss alles passen.
OP #5459404
Lesenswert?

Michael K. schrieb:
> Ich verwende nicht C, aber wenn ich mich nicht irre (was dadurch leicht
> sein kann), shiftest du deine 16bit Variable und liest gleichzeitig die
> bytes des nächsten Buchstabens ein?. Wenn du den Buchstaben komplett in
> die eine Hälfte der 16bitVariablen einliest, dann diese 8x um 1bit
> shiftest und dann wieder komplett den nächsten Buchstaben lädst, dann
> muss alles passen.

Das "scrollen" ist nicht das Problem. Es geht jetzt nur noch darum das 
immer ein Zeichen ( 8 Byte ) durch geschoben wird und dahinter erstmal 
weiter nichts kommt, bis eben das nächste Zeichen anfängt. Das sieht aus 
als würde er erst nach jedem Zeichen noch ein ' ' durch schieben.

Wie stelle ich das jetzt am besten an, die Zeichen aneinander zu reihen 
mit max. 2 Leerstellen dazwischen?
#5459442
Lesenswert?

Hallo,
mit einer einzelnen 8x8 habe ich da auch noch nie gemacht, aber ich 
würde so ansetzen:

1. String definieren mit den Zeichen die ausgegeben werden müssen. z.B. 
"Das ist mein Scrolltext"

2. einen Zeiger drauf definieren der das erste Zeichen adressiert.
3. Breite B des Zeichens berechnen, siehe Funktion oben
4. PrintFunktion mit scroll = 8-B fürs Zeichen beim Zeiger
5. scroll++
6. wenn scroll == 8 ist, dann ist das erste Zeichen voll zu sehen
7. dann das zweite Zeichen dazu drucken (8-B), Zeiger incrementieren
8. wenn scroll des ersten Zeichens gleich 16 ist, dann ist das erste 
draußen
9. drittes Zeichen dazu drucken, usw...

Eventuell muss man mit zwei Zeigern und zwei scrolls arbeiten, einer für 
das erste, dritte, fünfte Zeichen, einer fürs zweite, vierte und so 
weiter. Zeiger dann immer um 2 erhöhen.

Es gibt da bestimmt verschiedene Ansätze, testen und überlegen. Soll ja 
nur eine Hilfe sein hier, keine Komplettlösung.

Zur Frage
>Wo baust du die Länge bei deinem "ScrollPrint" ein? Du musst ja
>irgendwie um 'x' schieben ?!

Wenn ich ein schmales Zeichen (z.B. 'i" drucken will (Breite x), so 
drucke ich es nicht an scroll = 0, sodern an scroll = 8-x, je schmaler 
desto linkser sozusagen. Ein breites Zeichen (8 breit sogar) wird dann 
an scroll=0 gedruckt. Simple Mathematik, keine "Rocket science" wie man 
im Englischen sagt.

Gruß
Thomas
#5459474
Lesenswert?

Jan H. schrieb:
> VRAM[i]    = tmp.V8Bit[1]; // rechte Seite ausgeben

Wäre es nicht richtig, die linke Seite auszugeben?

Jan H. schrieb:
> tmp.V16Bit  = tmp.V16Bit << scrollPos; // nach links verschieben

Hier schiebst du die Daten des Buchstabens nach links. Er wird so 
spaltenweise in's Sichtfeld geschoben. Wenn der voll zu sehen ist, muss 
der nächste Buchstabe in die 16bit Variablen kopiert werden. Dazu darf 
aber der alte Wert der 16bitVariablen nicht gelöscht werden, die müssen 
also global sein.
#5459507
Lesenswert?

Sehe ich etwas anders.
Es ist sicherlich richtig die linke Seite auszugeben. Dann kann man 
schön von rechts reinscrollen und links wieder raus. Passt.

Global sollten nur die Speicherzellen sein, die am Ende das zu sichtbare 
Zeichen enthalten. Die temporäre Variable wird ja achtmal wieder 
verwendet. Interessant ist nur das Endergebnis. Das wird global 
gespeichert (8 Bytes).
#5459869
Lesenswert?

Thomas S. schrieb:
> Global sollten nur die Speicherzellen sein, die am Ende das zu sichtbare
> Zeichen enthalten. Die temporäre Variable wird ja achtmal wieder
> verwendet. Interessant ist nur das Endergebnis. Das wird global
> gespeichert (8 Bytes).

Global sollten die 8 16bitVariablen ein. Die enthalten doch im Prinzip 2 
Buchstaben, wovon der linke Teil, der linke Buchstabe, angezeigt wird. 
Zum scrollen werden diese Variablen geshiftet, der linke Buchstabe 
verschwindet spaltenweise aus der Bildfläche, der rechte rück nach. Nach 
8x shiften sieht man nur den rechten Buchstaben. Jetzt wäre die Prozedur 
fertig. Ist der Text aber noch nicht komplett angezeigt, muss man in den 
rechten Teil der Variablen den nächsten Buchstaben kopieren, wobei der 
linke Teil der Variablen erhalten bleiben muss. Wenn in der Prozedur 
eben nur der nächste Buchstabe auf den rechten Platz kopiert wird und 
dann 8x geshiftet wird, dann lässt man doch geschickterweise die 
16bitVariablen global.
#5460198
Lesenswert?

Nee, stimmt nicht.
Die 16bit Variable gibt es nur einmal in der Funktion (und nicht 
statisch oder global), und NICHT achtmal.
Sie wird achtmal genutzt und am Ende verworfen. Zwischendurch wird 
achtmal ein Teil ausgelesen, der ist interessant und wird in ein 
globales Array geschrieben (sollte es zumindest).
So wird ein Schuh draus.

So kann man die Funktion mehrfach nutzen und die Ergebnisse in einem 
globalen Array miteinander "verodern" so dass die geschobenen Zeichen 
gemischt werden.
OP #5460227
Lesenswert?

Thomas S. schrieb:
> 1. String definieren mit den Zeichen die ausgegeben werden müssen. z.B.
> "Das ist mein Scrolltext"
>
> 2. einen Zeiger drauf definieren der das erste Zeichen adressiert.
Das müsste dann ja in der Funktion passieren? Die Zeichenkette übergebe 
ich ja schon der Funktion. Da bekommt die Funktion ja schon die Adresse 
vom ersten Buchstaben

> 3. Breite B des Zeichens berechnen, siehe Funktion oben
Das würde ich jetzt in der Font Datei hinterlegen so das ich da nichts 
mehr berechnen muss.

> 4. PrintFunktion mit scroll = 8-B fürs Zeichen beim Zeiger
Meinst du die Anzahl der Schleifendurchläufe damit?
for( scroll = ZEICHEN_BREITE - B ; scroll > 0 ; scroll--)?
> 5. scroll++
#5460406
Lesenswert?

Meine Ausführungen bezogen sich auf die von mir oben gepostete Funktion

void ScrollPrint (unsigned char ZEICHEN, unsigned char scroll)

Die druckt ein Zeichen in den Bildschirmspeicher der dann anderswo 
ausgegeben wird.
Erstes Zeichen Z1 mehrfach drucken mit scroll1 laufend von 0 bis 15. Das 
läuft dann von rechts nach links durch.
Wenn scroll1 8 erreicht das zweite Zeichen Z2, wieder mit scroll2=0 bis 
15 dazu drucken. Wenn scroll1 16 wird wieder auf 0 setzen und Zeichen3 
ausgeben.


scroll = 8-B ist der Anfangswert um Lücken zu vermeiden wobei B die 
Zeichenbreite in Pixeln ist. Kann man für jedes Zeichen hinterlegen, ist 
aber aufwändig, hab ich nicht so realisiert.

Im Code den du oben gepostet hast wird immer nur ein Zeichen von rechts 
hereingeschoben, wenn es voll drin steht wird das nächste in gleicher 
Weise behandelt.
Denke nicht dass das schön läuft. Um den Srolleffekt zu haben muss man 
zwei Zeichen hintereinander drucken die beide durchschieben.
#5460421
Lesenswert?

Hab deine Funktion mal angesehen, versuch mal das. String sollt emit 
einem Leerzeichen anfangen, das erste Zeichen wird erstmal voll 
gedruckt:

uint8_t ScrollPrint ( char *msg )
{
  union
  {
    unsigned int V16Bit;
    unsigned char V8Bit[2];
  } tmp;

  uint8_t scrollPos;
  uint8_t leng;
  for ( leng = 0 ; *msg != '\0' ; leng++ )
  {
    for ( scrollPos = 8 ; scrollPos < 16 ; scrollPos++ )
    {
      for( uint8_t i = 0 ; i < 8 ; i++ )
      {
        //Zeichen n
        tmp.V16Bit  =  0xFF & ~pgm_read_byte(&charMap[ 
GetCharacterIndex( *msg ) ][i]);
        tmp.V16Bit  = tmp.V16Bit << scrollPos; // nach links verschieben
        VRAM[i]    = tmp.V8Bit[1]; // linke Seite ausgeben

        //Zeichen n+1
        tmp.V16Bit  =  0xFF & ~pgm_read_byte(&charMap[ 
GetCharacterIndex( *(msg +1)) ][i]);
        tmp.V16Bit  = tmp.V16Bit << scrollPos-8; // nach links 
verschieben
        VRAM[i]    &= tmp.V8Bit[1]; // linke Seite ausgeben

      }
      _delay_ms(250);
    }
    msg++;
  }

  return leng;
}
OP #5460702
Lesenswert?

Also wenn ich das letzte Zeichen "verODER" klappt nichts. Wird also 
nichts angezeigt.
Ohne das "ODER" klappt es.

Das Zeichen wird direkt in der Mitte vom Display gedruckt und nach links 
herraus geschoben.
Es kommt nichts von rechts rein. Am besten muss ich noch mal ein Video 
davon machen.
1
  
2
uint8_t ScrollPrint ( char *msg )
3
{
4
  union
5
  {
6
    unsigned int V16Bit;
7
    unsigned char V8Bit[2];
8
  } tmp;
9

10
  uint8_t scrollPos;
11
  uint8_t leng;
12
  for ( leng = 0 ; *msg != '\0' ; leng++ )
13
  {
14
    for ( scrollPos = 8 ; scrollPos < 16 ; scrollPos++ )
15
    {
16
      for( uint8_t i = 0 ; i < 8 ; i++ )
17
      {
18
        //Zeichen n
19
        tmp.V16Bit =  0xFF & ~pgm_read_byte(&charMap[GetCharacterIndex( *msg ) ][i]);
20
        tmp.V16Bit = tmp.V16Bit << scrollPos; // nach links verschieben
21
        VRAM[i]    = tmp.V8Bit[0]; // linke Seite ausgeben
22

23
         //Zeichen n+1
24
         tmp.V16Bit =  0xFF & ~pgm_read_byte(&charMap[GetCharacterIndex( *(msg +1)) ][i]);
25
         tmp.V16Bit = tmp.V16Bit << (scrollPos-8); // nach links verschieben
26
         VRAM[i]    = tmp.V8Bit[0]; // linke Seite ausgeben
27
      }
28
      _delay_ms(150);
29
    }
30
    msg++;
31
  }
32

33
  return leng;
34
}
#5460725
Lesenswert?

Ich verstehe eure ganzen Aktionen nicht. Nehmt halt für die Ausgabe beim 
Multiplexen einfach 8 16bit Variablen (global) und gebt die linken bits 
an die Leds aus. Jetzt muss man zum scrollen doch nur die 8 Variablen 
nach link shiften. Und wenn ein Buchstabe in das Sichtbare rein scrollen 
soll, dann wird der vor dem scrollen in den rechten Teil der 8 Variablen 
reinkopiert. Nach 8x shiften ist jetzt der sichtbar und das Vorherige 
ist links aus dem Sichtbaren heraus getickert. Jetzt wird in den rechten 
Teil der nächste Buchstabe rein kopier und so weiter. Ist doch simpel.
Gast #5461117
Lesenswert?

Jan H. schrieb:
> In Sachen Kreativität bist du definitiv nicht zurückgeblieben!

Doch, für mich gilt immer noch KISS. Kreativ im Sinne von möglichst 
komplizierten Lösungen für einfache Probleme will ich garnicht sein, ich 
finde gute Ingenieurskunst besteht gerade aus dem Gegenteil. Aber jeder 
nach seinem Geschmack.

Georg
#5461381
Lesenswert?

War mein Vorschlag so unverständlich? Erweitere deine Ledmatrix virtuell 
um 8 Spalten nach rechts. Ein byte ist doch bei dir 8 Leds in einer 
Zeile. Jetzt häng rechts an das byte noch eins drann, dann wäre die 
Zeile 16 Leds breit. Diese 2 bytes fasst du zu einer 16bitVariable 
zusammen. Deine Multiplexroutine verwendet aber nur die linken bits, um 
8 Led in einer Zeile anzusteuern. Jetzt kopierst du in die rechten 8bit 
das byte einer Zeile des Buchstabens. Und das für alle 8 Zeilen. Als 
nächster Schritt werden die 16bitVariablen nach links und schon wird 
Spalte für Spalte des Buchstabens sichtbar. Sieht man den komplett, wird 
der nächste Buchstabe rechts hin kopiert und weiter nach links 
geshiftet...
#5461501
Lesenswert?

Ich kann halt kein C und basic wird nicht groß weiter helfen. Im basic 
gibt's halt mit overlay eine einfache Möglichkeit, 16bit auf 
2x8bit-Variablen zu verteilen (eine Speicherzelle im ram hat 2 Namen), 
dann könnte man ein byte zum Multiplexen verwenden und ins ander kommt 
eine Zeile vom Buchstaben. Zum shiften nimmt man dann die 16bit, weil's 
einfacher ist. Aber sowas muss es doch bei C auch geben.
Gast #5461513
Lesenswert?

> und basic wird nicht groß weiter helfen

Wieso? Es gibt doch Bascom.

> Aber sowas muss es doch bei C auch geben.

Sicher, auch in C kannst du hin und her schieben. Und auch in C kann man 
zwei Bytes wahlweise als 2x8bit oder 1x16bit ansprechen. DU musst halt 
mal die Grundlagen der Programmiersprache lernen. Am Besten auf dem PC, 
nicht auf einem Mikrocontroller.

Aber wenn du besser Basic kannst, dann bleibe doch dabei!
OP #5461543
Lesenswert?

Inzwischen klappt es schon einigermaßen.
1
void DisplayString( const char *s)
2
{
3
  uint16_t len;
4
  uint8_t i, d, u1, u2;
5
  
6
  len = strlen(s)*8;
7
  
8
  for (uint16_t x = 0 ; x < len ; x++ )
9
  {
10
    i = x >> 3; // Index vom ersten Zeichen
11
    u1 = GetCharacterIndex(s[i++]); // erstes Zeichen
12
    u2 = GetCharacterIndex(s[i]);  // zweites Zeichen
13
    for (d=0 ; d<16 ; d++)
14
    {
15
      VRAM[d] = 0xFFFF;
16
      VRAM[d] &= ~(pgm_read_byte(&charMap[u1][d]) << (( x & 7 )) ); // erstes Zeichen verschoben nach links
17
      VRAM[d] &= ~(pgm_read_byte(&charMap[u2][d]) >> ( 8 - ( x & 7 )) );  // zweites Zeichen verschoben nach rechts
18
    }  
19
    _delay_ms(80);  
20
  }
21
}

Was jetzt noch fehlt ist der Abstand zwischen den einzelnen Zeichen. 
Weiß absolut nicht wie ich das mit berechnen soll.
#5461561
Lesenswert?

Jan H. schrieb:
> Mir fehlt lediglich die genaue Vorgehensweise wie ich das bewältigen
> muss. Die Logik erschließt sich mir noch nicht so 100% ig.

Neuer Versuch:
8 16bitVariablen, denke sie dir binär und untereinander angeordnet. 
Jetzt hast du einen bit-Raster, 8bit hoch und 16 bit breit. Jetzt 
gestaltest du dein Multiplexing so, dass du die linke Hälfte von dem 
Raster an deine Leds ausgibst. Jetzt kopierst du in die rechte Hälfte 
die Daten des Buchstabens rein. Wenn du jetzt diese 8 16bitVariablen 
nach links shiftest, dann werden nach und nach die rechten bits in den 
Bereich wandern, die auf den Leds sichtbar sind. Wenn du 8x shiftest 
sind alle bits der rechten Hälfte nach links gewandert, der Buchstabe 
jetzt voll sichtbar. Jetzt ist der Zeitpunkt da, in die nunmehr leere 
rechte Hälfte die Daten des nächsten Buchstabens zu kopieren und das 
shiften geht weiter.
Was ich so von deinem Programm verstanden hab', du packst zuviel in eine 
Schleife. Das rein kopieren des Buchstabens ist eine Schleife und da 
passiert nix weiter. Das 8malige shiften ist eine weitere Schleife und 
da passiert außer dem Multiplexen auch nix weiter.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren