Forum: Compiler & IDEs LED Matrix Zeile für Zeile leuchten lassen


von M.Hauser (Gast)


Lesenswert?

Hallo Leute,

ich sitze hier gerade und steh total auf dem Schlauch.
Zum Problem:
Ich habe eine LED Matrix aus 32 7x5 LED Bausteinen. Jetzt möchte ich 
eigentlich nur das Zeile für Zeile angeschalten wird und die vorherige 
Zeile auch an bleibt. Wenn ihr unten meinen Code betrachtet werdet ihr 
sehen, das es momentan für 7 Zeilen einfach durchläuft. Jetzt hätte ich 
aber gerne, das wenn die Schleife durchlaufen ist alle 7 Zeilen 
leuchten. Es soll immer eine mehr dazukommen.

Für Tipps bin ich euch dankbar, wie gesagt bin gerade total verwirrt und 
hab auch momentan keinen Lösungsansatz mehr bereit. Alle versuche sind 
bis jetzt gescheitert oder führten nicht zu einem ferfolgreichen 
Ergebnis.
1
#include <avr/io.h>          
2
#include <util/delay.h> 
3
4
5
int main (void) 
6
{
7
  DDRA=0xff;
8
  DDRC=0xff;
9
  DDRB=0xff;
10
  
11
int i,z;          
12
  
13
  PORTB |= (1<<PB2) | (1<<PB4);  // Schieberegister SRCLR, RCLR auf High
14
  PORTB |= (1<<PB0);        // logische 1 wird in das Schieberegister gegeben
15
  PORTC |= (1<<PC5);         // D-Ausgang des Multiplexer auf 1
16
while(1)
17
{
18
19
  for (i=0; i<=40; i++)
20
  {
21
    PORTB |= (1<<PB1);   // Schieberegister SRCLK, RCLK im Wechsel High => Low (Takt)
22
    PORTB |= (1<<PB3);
23
24
    _delay_ms(1);
25
    
26
    PORTB &= ~(1<<PB1);
27
    PORTB &= ~(1<<PB3);
28
29
    _delay_ms(1);
30
  }
31
32
for (z=0; z<=7; z++)
33
{
34
      
35
  
36
    PORTA |= (1<<PA3);            //Zeile 1
37
      _delay_ms(100);
38
    PORTA &= ~(1<<PA3);
39
  
40
41
    
42
    
43
    PORTA |= (1<<PA2) | (1<<PA3);      //Zeile 2
44
      _delay_ms(100);
45
    PORTA &= ~(1<<PA2);
46
    PORTA &= ~(1<<PA3);
47
48
  
49
50
51
    PORTA |= (1<<PA1) | (1<<PA2);      //Zeile 3
52
      _delay_ms(100);
53
    PORTA &= ~(1<<PA1);
54
    PORTA &= ~(1<<PA2);    
55
      
56
  
57
    
58
    PORTA |= (1<<PA1) | (1<<PA3);      //Zeile 4
59
      _delay_ms(100);
60
    PORTA &= ~(1<<PA1);
61
    PORTA &= ~(1<<PA3);
62
    
63
  
64
    //Alle Ports des Multiplexers auf Low  
65
      _delay_ms(100);            //Zeile 5
66
67
    
68
    
69
    PORTA |= (1<<PA2);            //Zeile 6
70
      _delay_ms(100);
71
    PORTA &= ~(1<<PA2);
72
    
73
    
74
    
75
    PORTA |= (1<<PA1);            //Zeile 7
76
      _delay_ms(100);
77
    PORTA &= ~(1<<PA1);
78
      
79
  
80
  
81
    
82
    }
83
  }
84
}

von Karl H. (kbuchegg)


Lesenswert?

Kann es sein, dass die Zeilen über einen 8-aus-3 Dekoder angesteuert 
werden? Zumindest lässt dein Code das so vermuten.

Wenn ja, dann hast du so überhaupt keine Chance, weil per 
Hardware-Design immer nur eine Zeile leuchten kann.

Du musst die Zeilen multiplexen!

von M.Hauser (Gast)


Lesenswert?

Ja ist korrekt, ich benutze für die Zeilen Ansteuerung einen 8-aus-3 
Dekoder (74HC138). Für die Spalten nehme ich 5 Schieberegister.

Das heißt ich kann mit meiner Schaltung nicht mehrere Zeilen leuchten 
lassen, so ich es mir ursprünglich gedacht hatte??

von Karl H. (kbuchegg)


Lesenswert?

M.Hauser wrote:

> Das heißt ich kann mit meiner Schaltung nicht mehrere Zeilen leuchten
> lassen, so ich es mir ursprünglich gedacht hatte??

Exakt gleichzeitig nicht.
Aber du kannst die Zeilen so schnell hintereinander einschalten, dass 
ein Mensch nicht merkt, dass nur 1 Zeile leuchtet. Genau das nennt man 
Multiplexen.

Edit: Ist ja auch nicht schlimm, dass du nicht mehrere Zeilen exakt 
gleichzeitig leuchten lassen kannst. Den Fall, dass alle Zeilen genau 
dasselbe Muster anzeigen sollen, hast du ja in der Praxis nicht. Das ist 
ja jetzt nur aus deiner speziellen 'Ich-probier-mal-was'-Situation 
heraus entstanden.

Edit2:
Sag mal, was hast du denn da für einen Saustall bei der Adressierung der 
Zeilen veranstaltet? Da ist ja überhaupt kein System drinn. Warst du so 
in Routing-Nöten, dass du die Leitungen wild durcheinander würfeln 
musstest?

von Karl H. (kbuchegg)


Lesenswert?

Welchen Prozessor benutzt du und wie schnell wird er getaktet?

von M.Hauser (Gast)


Lesenswert?

>Aber du kannst die Zeilen so schnell hintereinander einschalten, dass
>ein Mensch nicht merkt, dass nur 1 Zeile leuchtet. Genau das nennt man
>Multiplexen.

Das habe ich versucht, ich bin folgendermaßen vorgegangen:
Zeile für Zeile schnell anschalten, nur wenn ich in der _delay-Funktion 
einen kleineren Wert eingebe, dann habe ich nur ein schwaches flackern 
in den jeweiligen Zeilen. Bekomme ich das irgendwie anders in den Griff?

>Den Fall, dass alle Zeilen genau
>dasselbe Muster anzeigen sollen, hast du ja in der Praxis nicht. Das ist
>ja jetzt nur aus deiner speziellen 'Ich-probier-mal-was'-Situation
>heraus entstanden.

Leider doch. Ich benötige den Fall, das Zeile für Zeile angeschalten 
wird(immer mit dem selben Spaltenmuster)und die vorher geschaltene 
wieder leuchtet. Am Ende sollen alle 28 Zeilen leuchten. Nicht 
gleichzeitig aber eben so das man nicht erkennt das diese nacheinander 
angeschaltet werden, wo wir wieder beim Multiplexen wären.

von Karl H. (kbuchegg)


Lesenswert?

M.Hauser wrote:
>>Aber du kannst die Zeilen so schnell hintereinander einschalten, dass
>>ein Mensch nicht merkt, dass nur 1 Zeile leuchtet. Genau das nennt man
>>Multiplexen.
>
> Das habe ich versucht, ich bin folgendermaßen vorgegangen:
> Zeile für Zeile schnell anschalten, nur wenn ich in der _delay-Funktion
> einen kleineren Wert eingebe, dann habe ich nur ein schwaches flackern
> in den jeweiligen Zeilen. Bekomme ich das irgendwie anders in den Griff?

Mit delay wird das sowieso nichts.
Was du brauchst ist ein Timer, der einen regelmässigen Interrupt 
generiert. In der ISR wird dann reihum immer die nächste Zeile mit 
Werten versorgt und eingeschaltet.

> Leider doch. Ich benötige den Fall, das Zeile für Zeile angeschalten
> wird(immer mit dem selben Spaltenmuster)und die vorher geschaltene
> wieder leuchtet. Am Ende sollen alle 28 Zeilen leuchten. Nicht
> gleichzeitig aber eben so das man nicht erkennt das diese nacheinander
> angeschaltet werden, wo wir wieder beim Multiplexen wären.

Willst du nicht Buchstaben oder Grafiken ausgeben?
Oder ist die einzige Anwendung deiner Matrix darin, so einen Vorhang 
Effekt zu erreichen? Den hättest du auch einfacher haben können :-)

von Matthias L. (Gast)


Lesenswert?

Du solltest Dich mal mit den Grundlagen der Matrixansteuerung vertraut 
machen. Und wie das Softwareseitig angesteuert wird. Mit Timern, ohne 
delay.

Sieh dazu hier im Tutorial

von Karl H. (kbuchegg)


Lesenswert?

Wie sieht deine Hardware aus?
Wie ist das Schieberegister angeschlossen?

von M.Hauser (Gast)


Lesenswert?

>Willst du nicht Buchstaben oder Grafiken ausgeben?
>Oder ist die einzige Anwendung deiner Matrix darin, so einen Vorhang
>Effekt zu erreichen?

Ich muss auch Buchstaben ausgeben aber in erster Linie sollte der 
"Vorhand Effekt" funktionieren.

>Wie sieht deine Hardware aus?
>Wie ist das Schieberegister angeschlossen?

Als Controller verwende ich einen Atmega16. 5 Schieberegister (74HC594) 
sind an PortB angeschlossen und kaskadiert. Für die Zeilen benutze ich, 
wie oben schon erwähnt vier 3 zu 8 Decoder an Port A und C angeschlossen 
(74HC138).

von Karl H. (kbuchegg)


Lesenswert?

M.Hauser wrote:
> Als Controller verwende ich einen Atmega16. 5 Schieberegister (74HC594)
> sind an PortB angeschlossen und kaskadiert.

Welcher Pin ist SCLK und welcher RCLK?
Kann das aus deinem Code nicht entnehmen.

von Karl H. (kbuchegg)


Lesenswert?

M.Hauser wrote:

> sind an PortB angeschlossen und kaskadiert. Für die Zeilen benutze ich,
> wie oben schon erwähnt vier 3 zu 8 Decoder an Port A und C angeschlossen
> (74HC138).

Das war keine so gute Idee eine Zeile in 4 Teile zu zerteilen.
Das bedeutet, dass du einen 28:1 Multiplex brauchst. Das könnte
a) vom Timing her schon mächtig eng werden
b) die Leds werden fast bis zur Unkenntlichkeit dunkel sein.


Welche Prozessorfrequenz benutzt du?

von M.Hauser (Gast)


Lesenswert?

>Welche Prozessorfrequenz benutzt du?

Interner Oszillator 1Mhz

>Welcher Pin ist SCLK und welcher RCLK?
>Kann das aus deinem Code nicht entnehmen.

SCLK ist PB1
RCLK ist PB3

von Karl H. (kbuchegg)


Lesenswert?

M.Hauser wrote:
>>Welche Prozessorfrequenz benutzt du?
>
> Interner Oszillator 1Mhz

Mal etwas rechnen.
Mit dem Timer0 kannst du im besten Fall alle 256 Taktzyklen einen
Interrupt auslösen lassen.

1000000/256 = 3906.25  Interrupts pro Sekunde
3906.25/28 = 139.5 Hz

Das wäre an und für sich noch akzeptabel. 139Hz Refreshfrequenz pro 
Matrixteil.
Aber: Du hast für jeweils ein Ausgabepaket nur 256 Takte Zeit zur 
Verfügung. 40 Bit aus dem Speicher schaufeln und auf die Schieberegister 
ausgeben, Schleifenverwaltung und alles drum herum ... dazu reicht die 
zur Verfügung stehende Zyklenzahl nicht. Wenn ich mich nicht verzählt 
habe, dann brauchst du dafür mindestens 320 Zyklen (und das hab ich 
jetzt nur grob im Kopf überschlagen, genaueres kann man erst sagen, wenn 
die ISR steht).

Also gehts nur mit einem Vorteiler im Timer. Der nächst mögliche 
Vorteiler im Timer 0 ist 8. Damit kriegst du von einer ISR zur nächsten 
immerhin ein Polster von 256 * 8 = 2048 Taktzyklen. Das sollte 
überschlagsmässig reichen.

Aber die Refreshfrequenz
1000000/256/8/28 = 17

17Hz ist zuwenig. Das flackert wie Sau.

-> Du musst was mit den 1Mhz machen. Damit wirst du nicht glücklich 
werden.

Und ob die Led bei einem 28:1 Multiplex noch einigermassen lesbar 
leuchten? Meine Hand würd ich nicht dafür ins Feuer legen. Mit welchem 
Strom gehst du denn an eine Led ran? Rein rechnerisch müsstest du mit so 
um die 280 bis 300mA in eine LED reinbuttern (pro LED hab ich mal 10mA 
Konstantstrom angenommen). Wehe wenn da mal der Multiplex ausfällt. Dann 
sterben die LED wie die Fliegen. Und ob die LED diesen Spitzenstrom 
überhaupt mitmachen ... Datenblatt gibt Auskunft.

Aber seis drum:
Ich versuch mal hier im Trockendock, ob ich dir was zusammenstellen 
kann.

von M.Hauser (Gast)


Lesenswert?

>Mit welchem Strom gehst du denn an eine Led ran?

gut 400mA

Die einzelnen Zeilen leuchten schön erkennbar auf, wenn ich mit dem 
oberen Code das ganze ansteuer.

Soll ich vielleicht noch einen externen Quarz an den Controller hängen? 
12Mhz hätte ich da grad auf Lager.

von Karl H. (kbuchegg)


Lesenswert?

M.Hauser wrote:
>>Mit welchem Strom gehst du denn an eine Led ran?
>
> gut 400mA
>
> Die einzelnen Zeilen leuchten schön erkennbar auf, wenn ich mit dem
> oberen Code das ganze ansteuer.

Da ist ja auch noch kein Multiplex drauf!
Im Endeffekt sind deine einzelnen Zeilenfragmente nur 1/28 der 
kompletten Zeit eingeschaltet!
In einer Sekunde ist jede LED nur 30 Millisekunden an und 970 
Millisekunden auf jeden Fall aus. Vielleicht kannst du dir jetzt 
vorstellen, was das für die Helligkeit heissen wird.

> Soll ich vielleicht noch einen externen Quarz an den Controller hängen?
> 12Mhz hätte ich da grad auf Lager.

Auf jeden Fall. Das befreit dich ein wenig aus der Zeitnot die entstehen 
wird.

von Karl H. (kbuchegg)


Lesenswert?

Jag das mal durch den Compiler. Ich hab hier kein AVR-Studio und kein 
WinAvr installiert. Der Code wurde daher nicht compiliert und auch nicht 
getestet. Gut möglich dass kleine Flüchtigkeitsfehler drinnen sind.

Von den 160 möglichen Spalten kümmert sich der Code nur um die ersten 
40.
1
#include <avr/io.h>
2
#include <util/interrupt.h>
3
#include <util/delay.h>
4
#include "inttypes.h"
5
6
// Displayorganisation
7
//   Jedes Byte stellt eine Spalte dar. Das komplette Display ist
8
//   32*5 (=160) Spalten breit
9
//   Der Index ins Array ist also die x-Koordinate eines Punktes
10
//   Die Bits 0 bis 6 stellen die y-Koordinate des Punktes dar.
11
//   Bit 7 eines jeden Bytes bleibt unbenutzt.
12
//
13
//   Grund: Das Timing ist so schon verdammt eng. Es bleibt keine Zeit für
14
//          aufändige Optimierungsversuche so dass jedes Bit benutzt
15
//          werden kann
16
uint8_t Display[160];
17
uint8_t CurRow;
18
uint8_t RowCodes[] = { 0x08, 0x0C, 0x06, 0x0A, 0x00, 0x04, 0x02 };
19
20
ISR( TIMER0_OVF_vect )
21
{
22
  uint8_t Mask;
23
  uint8_t i;
24
  
25
  CurRow++;
26
  if( CurRow == 7 )
27
     CurRow = 0;
28
  
29
  // welches Bit in Display interessiert denn überhaupt für diese Zeile
30
  Mask = 1 << CurRow;
31
  
32
  // 40 Bits ausgeben
33
  for( i = 0; i < 40; ++i ) {
34
    if( Display[i] & Mask )
35
      PORTB |= ( 1 << PB0 );
36
    else
37
      PORTB &= ~( 1 << PB0 );
38
      
39
    PORTB |=  ( 1 << PB1 );    // SCLK Puls
40
    PORTB &= ~( 1 << PB1 );
41
  }
42
  
43
  // alle 40 sind im Schieberegister:
44
  //   bisherige Anzeige ausschalten,
45
  //   RCLK Puls auf Schieberegister
46
  //   3-8 Dekoder auf neue Zeile setzen,
47
  // -> damit leuchtet die nächste Zeile
48
  PORTA &= 0x0F;           // 3-8 Dekoder auf einen Wert, so dass nichts leuchtet
49
50
  PORTB |=  ( 1 << PB3 );  // Schieberegister zum durchschalten der Bits bringen
51
  PORTB &= ~( 1 << PB3 );
52
53
  PORTA |= RowCodes[CurRow];  // 3-8 Dekoder auf die aktuelle Zeile
54
}
55
56
void SetPixel( uint8_t x, uint8_t y )
57
{
58
  uint8_t Mask = ( 1 << y );
59
  Display[x] |= Mask;
60
}
61
62
void ClearPixel( uint8_t x, uint8_t y )
63
{
64
  uint8_t Mask = ( 1 << y );
65
  Display[x] &= ~Mask;
66
}
67
68
void ClearDisplay()
69
{
70
  uint8_t i;
71
  for( i = 0; i < 160; ++i )
72
    Display[i] = 0;
73
}
74
75
int main()
76
{
77
  uint8_t x, y;
78
  
79
  DDRA = 0xff;
80
  DDRB = 0xff;
81
82
  ClearDisplay();
83
  
84
  TCCRO = ( 1 << CS01 );  // Timer0: Vorteiler 8
85
  TIMSK = ( 1 << TOIE0 ); // Timer0: Overflow Interrupt
86
  
87
  sei();                  // und los geht der Displayrefresh
88
  
89
  while( 1 ) {
90
91
    // mal ein bischen was am Display malen
92
    for( y = 0; y < 7; ++y ) {
93
      for( x = 0; x < 40; ++x )
94
        SetPixel( x, y );
95
        
96
      _delay_ms( 100 );
97
    }
98
    
99
    ClearDisplay();
100
  }
101
}

von M.Hauser (Gast)


Lesenswert?

Hm....hab den Code mal so übernommen. Die ersten 7 Zeilen sind jetzt an, 
nur eben fast nicht sichtbar und mit einem höllischen flackern.

von Karl H. (kbuchegg)


Lesenswert?

M.Hauser wrote:
> Hm....hab den Code mal so übernommen. Die ersten 7 Zeilen sind jetzt an,
> nur eben fast nicht sichtbar und mit einem höllischen flackern.

Geh mal mit den 100 MilliSekunden in der Hauptschleife höher. Da war ich 
etwas zu knausrig. Damit kann man das Flackern vom Multiplexen nicht 
mehr vom Flackern der Malroutine unterscheiden. Mit 1000 sollte sich 
eigentlich ein ruhigeres Bild ergeben. Die 7 Zeilen müssen sich eine 
nach der anderen dazuschalten mit jeweils einer 1 Sekunden Pause 
dazwischen. Sind alle 7 Zeilen da, wird die komplette Anzeige gelöscht 
und das Spielchen geht von vorne los.

von M.Hauser (Gast)


Lesenswert?

>Die 7 Zeilen müssten sich eine nach der anderen dazugeschaltet haben,
>wenn du das nicht siehst, dreh mal die 100 Millisekunden in der
>Hauptschleife hoch

Habe ich gemacht, doch die LEDs fangen alle gleichzeitig an zu flackern 
:(


Kann ich in den Fuses Einstellungen im AVR-Studio den Internen 8Mhz 
Oszillator auswählen?

(Int RC Osc. 8 MHz; Start-up time: 6CK + 64 ms)

von M.Hauser (Gast)


Lesenswert?

Stopp

War doch noch nicht Perfekt der Code. Der Compiler meckert gerade an dem
1
#include <util/interrupt.h>
rum.

Und noch etwas was ich nicht ganz versteh. Was ist das?
1
sei();

von Karl H. (kbuchegg)


Lesenswert?

M.Hauser wrote:
> Stopp
>
> War doch noch nicht Perfekt der Code.

:-)
Wundert mich nicht wirklich. Mangels Compiler konnte ich ihn nie 
compilieren.

> Der Compiler meckert gerade an dem
>
1
#include <util/interrupt.h>
> rum.

Fehlermeldung?

>
> Und noch etwas was ich nicht ganz versteh. Was ist das?
>
1
sei();

Tutorial lesen. Abschnitt: Interrupts.

von Karl H. (kbuchegg)


Lesenswert?

M.Hauser wrote:

> Kann ich in den Fuses Einstellungen im AVR-Studio den Internen 8Mhz
> Oszillator auswählen?

Datenblatt zum Prozessor lesen.

von Karl H. (kbuchegg)


Lesenswert?

Karl heinz Buchegger wrote:

>> Der Compiler meckert gerade an dem
>>
1
#include <util/interrupt.h>
>> rum.
>
> Fehlermeldung?

OK. Muss offensichtlich
1
#include <avr/interrupt.h>
heissen

von M.Hauser (Gast)


Lesenswert?

error: util/interrupt.h: No such file or directory

Das ist der Fehler.

von M.Hauser (Gast)


Lesenswert?

So alle Fehler beseitigt und jetzt blinkt gar nichts mehr

von Karl H. (kbuchegg)


Lesenswert?

Sorry.
Hab mir gerade AVR-Studio und WinAvr gezogen.
Aber auf dieser Vista-Maschine funktioniert das Zeugs nicht (warum auch 
immer) und ich hab jetzt nicht die Zeit diesem Problem nachzugehen.

Werds in der Nacht mal auf meiner Entwicklungsmaschine zu Hause 
probieren. Dort funktioniert AVR-Studio/WinAvr

Kann aber nicht viel sein. Immerhin hattest du ja schon mal ein paar 
Leds am Leuchten. Alternativ kannst du ja mal selbst im Simulator 
nachsehen, ob die richtigen Pins zum richtigen Zeitpunkt wie erwartet 
ihren Zustand wechseln. Breakpoint in die ISR setzen und mit F10 
durchsteppen und im I/O View die Portpins beobachten.

Fährst du eigentlich schon auf 8Mhz?

von M.Hauser (Gast)


Lesenswert?

Ich werde das ganze auch noch bisschen versuchen zu optimieren. Hab bis 
jetzt noch nicht auf die 8 MHz umgestellt.

von W. S. (wope)


Lesenswert?

Habe das Beispiel (dankbarerweise) gleich benutzt, um mein neues 
Linuxenvironment zu testen :-)

Ein paar Kleinigkeiten sind schon angesprochen worden 
("avr/interrupt.h").  Für "trockenes" Coding wirklich bemerkenswert, Hut 
ab! :-)

Wenn dennoch nichts passiert könnte es auch noch daran liegen:

* Statt TCCR0 ("Null" hinten) stand TCCRO ("Oh" hinten) im Code von Karl 
Heinz (zumindest ergab sich das bei mir beim herauskopieren). Das SFR 
ist wichtig, sonst läuft der Timer nicht los und es gibt keine 
Interrupts. Unbedingt richtig setzen.

* CurRow wird IMHO nicht initialisiert. Wenn der Wert beim Start im 
Speicher zufällig größer 7 ist, geht das setzen der Zeile danach schief 
und der Arrayzugriff geht "ins Leere" (ev. crash). Zumindest dauert es 
einige increments, bis er sich fängt.
Entweder vor "sei()" (unbedingt davor) noch ein "CurRow=0;" im Code 
einfügen. Zusätzlich würde ich die Abfrage in der ISR von "if( CurRow == 
7 )" auf "if( CurRow > 6 )" ändern, dann "fängt" sich die ISR auch 
selbst.

Ist aber auch nur mal kompiliert + grob überprüft. Bei Bedarf kann ich 
den Code auch gerne anhängen, aber ich denke dass hast Du ja im Griff.

Hope it helps. :-)

von Karl H. (kbuchegg)


Lesenswert?

Hmm. Hab gestern in der Nacht noch ein paar Runden im Simulator gedreht 
und hab die Portpins beobachtet.
Da ist mir nichts aufgefallen. Eigentlich sollte das klappen.

Angenommene Pins an PortB
  PB0         Datenleitung zu den Schieberegistern
  PB1         SCLK Leitung der Schieberegister
  PB3         RCLK Leitung der Schieberegister

Angenommene Pins an PortA
  PA0 - PA3  sind die Leitungen die zum 8-aus-3 Dekoder gehen

  Der Dekoder ist so verschaltet, dass ein Datenwort von

     PA3 PA2 PA1 PA0
      1   0   0   0          Zeile 1
      1   1   0   0          Zeile 2
      0   1   1   0          Zeile 3
      1   0   1   0          Zeile 4
      0   0   0   0          Zeile 5
      0   1   0   0          Zeile 6
      0   0   1   0          Zeile 7

anspricht. Diese Zuordnung hab ich mir aus dem ursprünglichen Programm 
zusammengesucht und ich geh davon aus, dass das auch so stimmt.

Die ISR wird aufgerufen, ich kann in der Simulation sehen, dass die Bits 
entsprechend rausgetaktet werden und ein abschliessender RCLK Puls 
kommt. Was jetzt sein könnte: Das die Puls etwas zu kurz ausfallen. Da 
könnte man mal ein zusätzliches NOP einfügen. Glauben tu ich aber 
ehrlich gesagt nicht daran. Hab schon Schieberegister mit 12Mhz full 
speed angefahren und hat tadellos geklappt.

Auch die Leitungen am Port A werden nacheinander auf die oben 
angegebenen Werte gebracht.

Was man jetzt mal machen könnte: Den Timer Vorteiler auf einen sehr 
grossen Wert setzen (1024, ergibt knapp 4 ISR Aufrufe in der Sekunde) 
und mit einem Messgerät (kann auch eine einzelne Led+Vorwiderstand 
sein), mal die A-Leitungen beobachten. Da müsste man deutlich Blinken 
sehen. Auch an den Ausgängen des 3-zu-8 Dekoders müsste man mit einer 
Led sehen können, wie nacheinander ein Ausgang nach dem anderen aktiv 
wird. Damit könnte man mal sicher gehen, dass dieser Teil funktioniert.

Durch den grossen Vorteiler gewinnt man dann etwas Zeit in der ISR und 
könnte mal testweise(!) bei der Pulsgenerierung (SCLK bzw. RCLK) 
zwischen dem Setzen und dem Rücksetzen einen delay einbauen. Sinn der 
Sache ist es wieder direkt am Pin mit einem Messgerät (Led) die Pulse zu 
sehen und auch nachzusehen, was am Datenausgang rauskommt.

Du siehst schon. Testen bedeutet hier sich die Dinge soweit zu 
verlangsamen, dass man extern mit irgendwelchen geeigneten Messmitteln 
was sehen kann. Vielleicht hast du ja auch ein Oszi zur Verfügung, das 
wär natürlich optimal. Aber das hättest du wahrscheinlich auch ohne mich 
schon mal an die Ausgänge angehängt um zu sehen was da abgeht.

Wie gesagt: Im Simulator sieht alles gut aus. Wenn ich die Hardware aus 
deinem Originalprogramm richtig rekonstruiert habe, sollte es eigentlich 
klappen.

Noch was: Wenn die Verlangsamung dann immer noch nicht reicht, dann kann 
man die ISR noch weiter verlangsamen:
1
uint8_t ISRCnt = 0;    // :-)
2
3
ISR( ... )
4
{
5
  ISRCnt++;
6
  if( ISRCnt < 10 )
7
    return;
8
  ISRCnt = 0;
9
10
  ....  weiter wie gehabt

Damit wird dann nur noch alle 2.5 Sekunden (Vorteiler 1024) eine neue 
Zeile ausgegeben (und entsprechend die A-Leitungen umgeschaltet)

von Karl H. (kbuchegg)


Lesenswert?

Wolfgang Scherr wrote:

> * Statt TCCR0 ("Null" hinten) stand TCCRO ("Oh" hinten) im Code von Karl
> Heinz (zumindest ergab sich das bei mir beim herauskopieren). Das SFR
> ist wichtig, sonst läuft der Timer nicht los und es gibt keine
> Interrupts. Unbedingt richtig setzen.

Yep. Hab ich im Editor nicht gesehen. Ist immer wieder ein leidiges 
Problem 0 und O, l und 1
Da stolpert aber der Compiler drüber, sollte also kein Problem gewesen 
sein.

> * CurRow wird IMHO nicht initialisiert.

Doch wird es.
Globale Variablen werden in C immer auf 0 initialisiert, wenn nichts 
anderes angegeben.

> Entweder vor "sei()" (unbedingt davor) noch ein "CurRow=0;" im Code
> einfügen.

Schaden kanns nicht.

> Zusätzlich würde ich die Abfrage in der ISR von "if( CurRow ==
> 7 )" auf "if( CurRow > 6 )" ändern, dann "fängt" sich die ISR auch
> selbst.

Das ist sowieso immer eine gute Idee (=defensiv programmieren).
Danke für den Fix.

von M.Hauser (Gast)


Lesenswert?

>Sag mal, was hast du denn da für einen Saustall bei der Adressierung der
>Zeilen veranstaltet? Da ist ja überhaupt kein System drinn. Warst du so
>in Routing-Nöten, dass du die Leitungen wild durcheinander würfeln
>musstest?

Da ist schon ein System drin etwas verwirrend geb ich zu aber man kommt 
damit zurecht. PA0 ist ein analloger Eingang, somit hab ich den nicht 
nochmal verwendet.

Decoder 1 hängt an PA1, PA2 ,PA3
Decoder 2 hängt an PA4, PA5 ,PA6
Decoder 3 hängt an PA7, PC0, PC1
Decoder 4 hängt an PC2, PC3, PC4

Data an PC5
LE   an PC6
ME   an PC7

______________________________________________________________________

hab den Code nochmals nach euren Empfehlungen geändert, doch leider 
leuchtet immernoch nichts auf meinem Display auf :(

von Karl H. (kbuchegg)


Lesenswert?

Hast du schon kontrolliert, ob die ISR überhaupt aufgerufen wird 
(innerhalb der ISR einfach irgendeine andere LED einschalten oder einen 
Pin auf High oder Low setzen. Irgendwas tun, so dass du von aussen mit 
einem Messgerät sicher sagen kannst: Ja die ISR wird aufgerufen)


Hast du dich vielleicht vertan und SCLK und RCLK vertauscht?

von Karl H. (kbuchegg)


Lesenswert?

Warte mal.
Was hat es damit

  PORTB |= (1<<PB2) | (1<<PB4);  // Schieberegister SRCLR, RCLR auf High
  PORTC |= (1<<PC5);         // D-Ausgang des Multiplexer auf 1

auf sich.
PORTC wird in meinem Programm nicht benutzt und um PB2 und PB4 hab ich 
mich nicht gekümmert.

von M.Hauser (Gast)


Lesenswert?

PB2 und PB4 müssen auf 1 sein, sonst wird das Schieberegister auf dauer 
Reset gehalten.

PC 5 muss konstant auf 1 sein um den Decoder zu schalten.


Wahrheitstabelle für den Decoder:

PC5  PA1  PA2 PA3     Q0   Q1   Q2   Q3   Q4   Q5   Q6    Q7

1    0    0   0       1    0    0    0    0    0    0     0
1    0    0   1       0    1    0    0    0    0    0     0
1    0    1   0       0    0    1    0    0    0    0     0
1    0    1   1       0    0    0    1    0    0    0     0
1    1    0   0       0    0    0    0    1    0    0     0
1    1    0   1       0    0    0    0    0    1    0     0
1    1    1   0       0    0    0    0    0    0    1     0
1    1    1   1       0    0    0    0    0    0    0     1

von Matthias L. (Gast)


Lesenswert?

>(74HC138)

>Wahrheitstabelle für den Decoder:


Die Wahrheitstabelle ist falsch. Der 138er hat invertierende Ausgänge!

Also wenn dann so:

G    C    B   A       Q0   Q1   Q2   Q3   Q4   Q5   Q6    Q7


1    0    0   0       0    1    1    1    1    1    1     1
1    0    0   1       1    0    1    1    1    1    1     1
1    0    1   0       1    1    0    1    1    1    1     1
1    0    1   1       1    1    1    0    1    1    1     1
1    1    0   0       1    1    1    1    0    1    1     1
1    1    0   1       1    1    1    1    1    0    1     1
1    1    1   0       1    1    1    1    1    1    0     1
1    1    1   1       1    1    1    1    1    1    1     0

von M.Hauser (Gast)


Lesenswert?

Ja Stimmt ist richtig. Der 138 schaltet invertiert. Ändert allerdings 
nichts an der Ansteuerung. Trotzdem Vielen Dank für die Korrektur.

von M.Hauser (Gast)


Lesenswert?

** In der Wahrheitstabelle von mir müssen die Eingang Pins gedreht 
werden.

>PC5  PA1  PA2 PA3     Q0   Q1   Q2   Q3   Q4   Q5   Q6    Q7

Es muss lauten:

PA3 PA2 PA1.

von M.Hauser (Gast)


Lesenswert?

Hallo Laute,

so hat ein wenig länger gedauert aber jetzt bin ich mal wieder am 
rumwerkeln.
Habe mit ein Oszi besorgt und mal die Eingänge des Decoders sowie die 
Schieberegister angeschaut.

Die Schieberegister sehen super aus vom Timing. Sprich 40 Bits laden und 
dann RCLR auf 1. So wie es sein soll.

Beim Decoder allerdings komm ich nicht aus dem Zustand 111 (0x0E) raus. 
Hab schon fast alles Probiert irgendwie wollen die Zeilen aber nicht 
blinken.

Anbei nochmal mein Code, so wie er momentan aussieht. Hat jemand von 
euch noch einen Tipp? Wäre euch sehr dankbar.
1
#include <avr/io.h>
2
#include <avr/interrupt.h>
3
#include <util/delay.h>
4
#include "inttypes.h"
5
6
//   Displayorganisation
7
//   Jedes Byte stellt eine Spalte dar. Das komplette Display ist
8
//   32*5 (=160) Spalten breit
9
//   Der Index ins Array ist also die x-Koordinate eines Punktes
10
//   Die Bits 0 bis 6 stellen die y-Koordinate des Punktes dar.
11
//   Bit 7 eines jeden Bytes bleibt unbenutzt.
12
//
13
//   Grund: Das Timing ist so schon verdammt eng. Es bleibt keine Zeit für
14
//          aufändige Optimierungsversuche so dass jedes Bit benutzt
15
//          werden kann
16
uint8_t Display[40];
17
uint8_t CurRow;
18
uint8_t RowCodes[] = { 0x08, 0x0C, 0x06, 0x0A, 0x00, 0x04, 0x02 };
19
20
ISR( TIMER0_OVF_vect )
21
{
22
  uint8_t Mask;
23
  uint8_t i;
24
  
25
  CurRow++;
26
  if( CurRow > 6 )
27
     CurRow = 0;
28
  
29
  // welches Bit in Display interessiert denn überhaupt für diese Zeile
30
  Mask = 1 << CurRow;
31
  
32
  // 40 Bits ausgeben
33
  for( i = 0; i < 40; ++i ) 
34
  {
35
    if( Display[i] & Mask )
36
      PORTB |= (1<<PB0);
37
    else
38
      PORTB &= ~(1<<PB0);
39
      
40
    PORTB |=  ( 1 << PB1 );    // SRCLK Puls
41
  PORTB &= ~( 1 << PB1 );
42
  }
43
  
44
  // alle 40 sind im Schieberegister:
45
  // bisherige Anzeige ausschalten,
46
  // 3-8 Dekoder auf neue Zeile setzen,
47
  // RCLK Puls auf Schieberegister
48
  // -> damit leuchtet die nächste Zeile
49
  PORTA |= 0x0E;           // 3-8 Dekoder auf einen Wert, so dass nichts leuchtet
50
51
  PORTB |=  ( 1 << PB3 );  // Schieberegister zum durchschalten der Bits bringen
52
  PORTB &= ~( 1 << PB3 );
53
54
  PORTA |= RowCodes[CurRow];  // 3-8 Dekoder auf die aktuelle Zeile
55
}
56
57
58
void SetPixel( uint8_t x, uint8_t y )
59
{
60
  uint8_t Mask = ( 1 << y );
61
  Display[x] |= Mask;
62
}
63
64
65
void ClearPixel( uint8_t x, uint8_t y )
66
{
67
  uint8_t Mask = ( 1 << y );
68
  Display[x] &= ~Mask;
69
}
70
71
72
void ClearDisplay()
73
{
74
  uint8_t i;
75
  for( i = 0; i < 40; ++i )
76
    Display[i] = 0;
77
}
78
79
int main()
80
{
81
  uint8_t x, y;
82
  
83
  DDRA = 0xff;
84
  DDRB = 0xff;
85
  DDRC = 0xff;
86
  
87
  PORTB |= (1<<PB2) | (1<<PB4);    // RCLR, SRCRL der Schieberegister auf 1 setzen 
88
  PORTC |= (1<<PC5);        // D-Eingang des Decoder auf 1 setzen
89
      
90
  ClearDisplay();
91
  
92
  TCCR0 = ( 1 << CS01 );  // Timer0: Vorteiler 8
93
  TIMSK = ( 1 << TOIE0 ); // Timer0: Overflow Interrupt
94
    
95
  CurRow = 0;    
96
  sei();                  // und los geht der Displayrefresh
97
  
98
  while( 1 ) {
99
    for( y = 0; y < 7; ++y ) 
100
  {
101
      for( x = 0; x < 40; ++x )
102
        SetPixel( x, y );
103
        
104
      _delay_ms( 100 );
105
    }
106
    
107
    ClearDisplay();
108
  }
109
}

von P.B. (Gast)


Lesenswert?

Hallo,

ich bin hier gerade auf den Thread gestoßen.Ich möchte so etwas 
ähnliches mache. Wenn ich mir den Code von Karl heinz Buchegger 
anschaue. Frage ich mich, wie bekomme ich es hin ein Spaltenmuster für 
Buchstaben zu bekommen.
1
 
2
uint8_t Display[160];
3
.
4
.
5
.
6
7
// 40 Bits ausgeben
8
  for( i = 0; i < 40; ++i ) {
9
    if( Display[i] & Mask )
10
      PORTB |= ( 1 << PB0 );
11
    else
12
      PORTB &= ~( 1 << PB0 );
13
      
14
    PORTB |=  ( 1 << PB1 );    // SCLK Puls
15
    PORTB &= ~( 1 << PB1 );

So wie ich das sehe werden hier ja 40 mal eine "1" ausgegeben. Wenn ich 
jetzt zum Beispiel mehrere Buchstaben ausgeben will benötige ich ja "0" 
und "1" im Spaltenmuster. Wie kann ich so etwas realisieren? Über tipps 
wäre ich euch sehr dankbar.

mfg

P.B

von Karl H. (kbuchegg)


Lesenswert?

M.Hauser wrote:

> Beim Decoder allerdings komm ich nicht aus dem Zustand 111 (0x0E) raus.

Das ist der Ansatzpunkt.
Wusste doch, dass ich was übersehen habe beim blinden programmieren.


>   // -> damit leuchtet die nächste Zeile
>   PORTA |= 0x0E;           // 3-8 Dekoder auf einen Wert, so dass nichts
> leuchtet

Klar, hier werden die 0x0E gesetzt. Also Pins auf 1

>   PORTB |=  ( 1 << PB3 );  // Schieberegister zum durchschalten der Bits
> bringen
>   PORTB &= ~( 1 << PB3 );
>
>   PORTA |= RowCodes[CurRow];  // 3-8 Dekoder auf die aktuelle Zeile

Tja. Das wird wohl nichts. Wenn die Pins erst mal auf 1 sind, kann man 
1-en rausschreiben soviel man will. Die werden dadurch nicht zu 0, wenn 
man sie vorher nicht resettet.

    PORTA &= ~0x0E;
    PORTA |= RowCodes[CurRow];  // 3-8 Dekoder auf die aktuelle Zeile

Das hat jetzt natürlich den Nachteil, dass am Dekoder kurzzeitig alle 
Pins 0 sind und wenn ich mich richtig erinnere, ist mit 0 eine Auswahl 
verbunden.

Besser ist es daher das so zu machen
1
    PORTA = ( PORTA & ~0x0E ) | RowCodes[CurRow];

von Karl H. (kbuchegg)


Lesenswert?

P.B. wrote:

> So wie ich das sehe werden hier ja 40 mal eine "1" ausgegeben.

Äh nein.
Woraus liest du das?
Das jeweils als nächstes auszugebende Pixel kommt aus dem Display Array.

> Wenn ich
> jetzt zum Beispiel mehrere Buchstaben ausgeben will benötige ich ja "0"
> und "1" im Spaltenmuster. Wie kann ich so etwas realisieren? Über tipps
> wäre ich euch sehr dankbar.

Indem du die 0-en und 1-en so ins Display Array schreibst, wie du das 
brauchst, damit sich ein Buchstabe formt.

Hint: Für Buchstaben mag das leichter Overkill sein, aber um einzelne 
'Pixel' zu setzen bzw. zu löschen hab ich die Funktionen SetPixel bzw. 
ClearPixel angegeben.

von P.B. (Gast)


Lesenswert?

>Äh nein.
>Woraus liest du das?
>Das jeweils als nächstes auszugebende Pixel kommt aus dem Display Array.

Die Schleife läuft von 0 bis 40 und für jedes i wird PB0 auf 1 gesetzt 
=> somit 40x 1-en oder sehe ich das Falsch??

Btw. Ich seh das wohl falsch was macht den dieses & Mask in der 
If-Bedingung??

von Karl H. (kbuchegg)


Lesenswert?

Die Display-Organisation ist so, dass jeder einzelne der unsigned chars 
in Display für eine Spalte zuständig ist. Jedes Bit in jedem Display[i] 
steht für eine Led.

 Display
        [0] [1] [2] [3] [4] [5] [6] [7] [8] [9]
       +---+---+---+---+---+---+---+---+---+--- ...
 Bit 0 |   |   |   |   |   |   |   |   |   |
       +---+---+---+---+---+---+---+---+---+--- ...
 Bit 1 |   |   |   |   |   |   |   |   |   |
       +---+---+---+---+---+---+---+---+---+--- ...
 Bit 2 |   |   |   |   |   |   |   |   |   |
       +---+---+---+---+---+---+---+---+---+--- ...
 Bit 3 |   |   |   |   |   |   |   |   |   |
       +---+---+---+---+---+---+---+---+---+--- ...
 Bit 4 |   |   |   |   |   |   |   |   |   |
       +---+---+---+---+---+---+---+---+---+--- ...
 Bit 5 |   |   |   |   |   |   |   |   |   |
       +---+---+---+---+---+---+---+---+---+--- ...
 Bit 6 |   |   |   |   |   |   |   |   |   |
       +---+---+---+---+---+---+---+---+---+--- ...
 Bit 7 |   |   |   |   |   |   |   |   |   |
       +---+---+---+---+---+---+---+---+---+--- ...


so sieht das aus.

Wenn du also da ein 'A' drauf haben willst, müssen welche LED aktiv 
sein?

        [0] [1] [2] [3] [4] [5] [6] [7] [8] [9]
       +---+---+---+---+---+---+---+---+---+--- ...
 Bit 0 |   | * | * | * |   |   |   |   |   |
       +---+---+---+---+---+---+---+---+---+--- ...
 Bit 1 | * |   |   |   | * |   |   |   |   |
       +---+---+---+---+---+---+---+---+---+--- ...
 Bit 2 | * |   |   |   | * |   |   |   |   |
       +---+---+---+---+---+---+---+---+---+--- ...
 Bit 3 | * |   |   |   | * |   |   |   |   |
       +---+---+---+---+---+---+---+---+---+--- ...
 Bit 4 | * | * | * | * | * |   |   |   |   |
       +---+---+---+---+---+---+---+---+---+--- ...
 Bit 5 | * |   |   |   | * |   |   |   |   |
       +---+---+---+---+---+---+---+---+---+--- ...
 Bit 6 | * |   |   |   | * |   |   |   |   |
       +---+---+---+---+---+---+---+---+---+--- ...
 Bit 7 |   |   |   |   |   |   |   |   |   |
       +---+---+---+---+---+---+---+---+---+--- ...

Wenn ich jetzt mal über alle Spalten die Binärrepräsentierung ( 0/1 
enstrechend LED leuchtet/leuchtet nicht) zusammennehme und als Hex-Zahl
angebe:

        [0] [1] [2] [3] [4] [5] [6] [7] [8] [9]
       +---+---+---+---+---+---+---+---+---+--- ...
 Bit 0 |   | * | * | * |   |   |   |   |   |
       +---+---+---+---+---+---+---+---+---+--- ...
 Bit 1 | * |   |   |   | * |   |   |   |   |
       +---+---+---+---+---+---+---+---+---+--- ...
 Bit 2 | * |   |   |   | * |   |   |   |   |
       +---+---+---+---+---+---+---+---+---+--- ...
 Bit 3 | * |   |   |   | * |   |   |   |   |
       +---+---+---+---+---+---+---+---+---+--- ...
 Bit 4 | * | * | * | * | * |   |   |   |   |
       +---+---+---+---+---+---+---+---+---+--- ...
 Bit 5 | * |   |   |   | * |   |   |   |   |
       +---+---+---+---+---+---+---+---+---+--- ...
 Bit 6 | * |   |   |   | * |   |   |   |   |
       +---+---+---+---+---+---+---+---+---+--- ...
 Bit 7 |   |   |   |   |   |   |   |   |   |
       +---+---+---+---+---+---+---+---+---+--- ...

        7E  11  11  11  7E

Um also ein 'A' im Display ab der Spaltenposition 23 anzeigen zu lassen, 
genügt es

    Display[23] = 0x7E;
    Display[24] = 0x11;
    Display[25] = 0x11;
    Display[26] = 0x11;
    Display[27] = 0x7F;

zu machen, und dann sollte dort ein A auftauchen.
Natürlich wird man das nicht im Code so direkt machen, sondern man legt 
sich eine Tabelle an, die die Umsetzung vom ASCII Code zu den 
Spaltenwerten macht und gibt dann in einer Schleife aus dieser Tabelle 
heraus aus. Sinnvollerweise legt man die Tabelle so an, dass man mit dem 
ASCII Codes des Eingabezeichens auch gleich den ersten Tabellenindex 
bestimmt hat.
1
uint8_t Codes[128][5] = {     // Led Codes für alle Buchstaben im ASCII Code
2
   .....
3
   .....
4
   { 0x7F, 0x11, 0x11, 0x11, 0x7F },   // Code für 'A', an der Arrayposition 0x41
5
   .....
6
};
7
8
void PutChar( uint8_t col, char Character )
9
{
10
  uint8_t i;
11
12
  for( i = 0; i < 5; ++i ) {    // weil ja immer 5 Bytes auszugeben sind
13
    Display[col++] = Codes[Character][i];
14
  }
15
}
16
17
void PutString( uint8_t col, const char* String )
18
{
19
  while( *String )
20
    PutChar( col++, *String++ );
21
}

von Karl H. (kbuchegg)


Lesenswert?

P.B. wrote:
>>Äh nein.
>>Woraus liest du das?
>>Das jeweils als nächstes auszugebende Pixel kommt aus dem Display Array.
>
> Die Schleife läuft von 0 bis 40 und für jedes i wird PB0 auf 1 gesetzt
> => somit 40x 1-en oder sehe ich das Falsch??

Das siehst du falsch.
1
    if( Display[i] & Mask )
2
      PORTB |= ( 1 << PB0 );
3
    else
4
      PORTB &= ~( 1 << PB0 );

Abhängig vom Zustand des i-ten Bits in Display[i] wird entweder eine 1 
oder eine 0 an den Ausgabeport gelegt.

> Btw. Ich seh das wohl falsch was macht den dieses & Mask in der
> If-Bedingung??

Dann solltest du mal Grundlagen in Bitmaskierungen lernen, ehe du dich 
an Led-Matrizen wagst. Auf einem µC ist der Umgang mit & | und ^ 
tägliches Brot.

http://www.mikrocontroller.net/articles/Bitmanipulation

von M.Hauser (Gast)


Lesenswert?

Hallo,

wie ich sehe wurde hier schon wieder fleißig gepostet. Ich habe das Ding 
mittlerweile am laufen. Das ganze läuft nur noch nicht so wie ich es 
gerne hätte. Kurze Beschreibung des momantanen Szenario:

Wie schon oben Beschrieben besteht die Matrix aus 40 Spalten und 28 
Zeilen. Es laufen nun immer die 4 Blöcke parallel los. Wir haben nun 
schon mehrere Varianten getestet, um die Blöcke nacheinander 
anzuschalten. Mit klaren Worten: Zeile 1-7 danach 8-14 usw. Das ist uns 
aber nicht gelungen. Frage wie bekomme ich es hin das ich jeden 
Matrixblock mit den 7 Zeilen nacheinander aufrufen kann? Hatten schon 
versucht mit Zähler und If-Abfragen (usw.) Hier ist der momentane Code, 
der dafür sorgt das die 4 Blöcke (a 7 Zeilen) parallel starten.
1
#include <avr/io.h>
2
#include <avr/interrupt.h>
3
#include <util/delay.h>
4
#include "inttypes.h"
5
#include <stdbool.h>
6
7
//   Displayorganisation
8
//   Jedes Byte stellt eine Spalte dar. Das komplette Display ist
9
//   40 Spalten breit
10
//   Der Index ins Array ist also die x-Koordinate eines Punktes
11
//   Die Bits 0 bis 6 stellen die y-Koordinate des Punktes dar.
12
//   Bit 7 eines jeden Bytes bleibt unbenutzt.
13
//
14
//   Grund: Das Timing ist so schon verdammt eng. Es bleibt keine Zeit für
15
//          aufändige Optimierungsversuche so dass jedes Bit benutzt
16
//          werden kann
17
18
uint8_t Display[40];
19
uint8_t CurRow=0;
20
uint8_t RowCodes0[] = { 0x08, 0x0C, 0x06, 0x0A, 0x00, 0x04, 0x02 }; //Matrixblock1
21
uint8_t RowCodes1[] = { 0x40, 0x60, 0x30, 0x50, 0x00, 0x20, 0x10 }; //Matrixblock2
22
uint8_t RowCodes2[] = { 0x02, 0x03, 0x21, 0x22, 0x00, 0x01, 0x02 }; //Matrixblock3
23
uint8_t RowCodes3[] = { 0x30, 0x38, 0x2C, 0x34, 0x20, 0x28, 0x24 }; //Matrixblock4
24
25
ISR( TIMER0_OVF_vect )
26
{
27
  uint8_t Mask;
28
  uint8_t i;
29
  
30
  CurRow++;
31
  if( CurRow > 6 )
32
     CurRow = 0;
33
  
34
  // welches Bit in Display interessiert denn überhaupt für diese Zeile
35
  Mask = 1 << CurRow;
36
  
37
  // 40 Bits ausgeben
38
  for( i = 0; i < 40; ++i ) 
39
  {
40
    if( Display[i] & Mask )
41
      PORTB |= (1<<PB0);
42
    else
43
      PORTB &= ~(1<<PB0);
44
      
45
    PORTB |=  ( 1 << PB1 );    // SRCLK Puls
46
  PORTB &= ~( 1 << PB1 );
47
  }
48
 
49
  // alle 40 sind im Schieberegister:
50
  // bisherige Anzeige ausschalten,
51
  // 3-8 Dekoder auf neue Zeile setzen,
52
  // RCLK Puls auf Schieberegister
53
  // -> damit leuchtet die nächste Zeile
54
55
PORTA = ( PORTA & ~0x8E ) | RowCodes0[CurRow];  //3-8 Dekoder auf Wert setzen das nichts leuchtet und dann Zeilen anschalten
56
PORTA = ( PORTA & ~0x70 ) | RowCodes1[CurRow];
57
PORTC = ( PORTC & ~0x23 ) | RowCodes2[CurRow];
58
PORTC = ( PORTC & ~0x3C ) | RowCodes3[CurRow];
59
60
PORTB |=  ( 1 << PB3 );  // Schieberegister zum durchschalten der Bits bringen
61
PORTB &= ~( 1 << PB3 );
62
63
}
64
65
66
67
68
void SetPixel( uint8_t x, uint8_t y )
69
{
70
  uint8_t Mask = ( 1 << y );
71
  Display[x] |= Mask;
72
}
73
74
75
void ClearPixel( uint8_t x, uint8_t y )
76
{
77
  uint8_t Mask = ( 1 << y );
78
  Display[x] &= ~Mask;
79
}
80
81
82
void ClearDisplay()
83
{
84
  uint8_t i;
85
  for( i = 0; i < 40; ++i )
86
    Display[i] = 0;
87
}
88
89
int main()
90
{
91
  uint8_t x, y, z;
92
  
93
  DDRA = 0xff;
94
  DDRB = 0xff;
95
  DDRC = 0xff;
96
  
97
  PORTB |= (1<<PB2) | (1<<PB4);    // RCLR, SRCRL der Schieberegister auf 1 setzen 
98
  PORTA |= (1<<PA7);        // D-Eingang des Decoder auf 1 setzen
99
      
100
  ClearDisplay();
101
  
102
  TCCR0 = (1 << CS01);    // Timer0: Vorteiler 8
103
  TIMSK = (1 << TOIE0);   // Timer0: Overflow Interrupt
104
    
105
  sei();                  // und los geht der Displayrefresh
106
107
while( 1 ) 
108
 
109
    for( y = 0; y < 27; ++y ) 
110
    {     
111
      for( x = 0; x < 40; ++x )
112
        SetPixel( x, y );
113
        
114
      _delay_ms( 500 );
115
    }
116
  
117
    //ClearDisplay(); 
118
}

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.