www.mikrocontroller.net

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


Autor: M.Hauser (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.
#include <avr/io.h>          
#include <util/delay.h> 


int main (void) 
{
  DDRA=0xff;
  DDRC=0xff;
  DDRB=0xff;
  
int i,z;          
  
  PORTB |= (1<<PB2) | (1<<PB4);  // Schieberegister SRCLR, RCLR auf High
  PORTB |= (1<<PB0);        // logische 1 wird in das Schieberegister gegeben
  PORTC |= (1<<PC5);         // D-Ausgang des Multiplexer auf 1
while(1)
{

  for (i=0; i<=40; i++)
  {
    PORTB |= (1<<PB1);   // Schieberegister SRCLK, RCLK im Wechsel High => Low (Takt)
    PORTB |= (1<<PB3);

    _delay_ms(1);
    
    PORTB &= ~(1<<PB1);
    PORTB &= ~(1<<PB3);

    _delay_ms(1);
  }

for (z=0; z<=7; z++)
{
      
  
    PORTA |= (1<<PA3);            //Zeile 1
      _delay_ms(100);
    PORTA &= ~(1<<PA3);
  

    
    
    PORTA |= (1<<PA2) | (1<<PA3);      //Zeile 2
      _delay_ms(100);
    PORTA &= ~(1<<PA2);
    PORTA &= ~(1<<PA3);

  


    PORTA |= (1<<PA1) | (1<<PA2);      //Zeile 3
      _delay_ms(100);
    PORTA &= ~(1<<PA1);
    PORTA &= ~(1<<PA2);    
      
  
    
    PORTA |= (1<<PA1) | (1<<PA3);      //Zeile 4
      _delay_ms(100);
    PORTA &= ~(1<<PA1);
    PORTA &= ~(1<<PA3);
    
  
    //Alle Ports des Multiplexers auf Low  
      _delay_ms(100);            //Zeile 5

    
    
    PORTA |= (1<<PA2);            //Zeile 6
      _delay_ms(100);
    PORTA &= ~(1<<PA2);
    
    
    
    PORTA |= (1<<PA1);            //Zeile 7
      _delay_ms(100);
    PORTA &= ~(1<<PA1);
      
  
  
    
    }
  }
}

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht 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!

Autor: M.Hauser (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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??

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht 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?

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Welchen Prozessor benutzt du und wie schnell wird er getaktet?

Autor: M.Hauser (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht 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 :-)

Autor: Matthias Lipinsky (lippy)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wie sieht deine Hardware aus?
Wie ist das Schieberegister angeschlossen?

Autor: M.Hauser (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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).

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht 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?

Autor: M.Hauser (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: M.Hauser (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht 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.
#include <avr/io.h>
#include <util/interrupt.h>
#include <util/delay.h>
#include "inttypes.h"

// Displayorganisation
//   Jedes Byte stellt eine Spalte dar. Das komplette Display ist
//   32*5 (=160) Spalten breit
//   Der Index ins Array ist also die x-Koordinate eines Punktes
//   Die Bits 0 bis 6 stellen die y-Koordinate des Punktes dar.
//   Bit 7 eines jeden Bytes bleibt unbenutzt.
//
//   Grund: Das Timing ist so schon verdammt eng. Es bleibt keine Zeit für
//          aufändige Optimierungsversuche so dass jedes Bit benutzt
//          werden kann
uint8_t Display[160];
uint8_t CurRow;
uint8_t RowCodes[] = { 0x08, 0x0C, 0x06, 0x0A, 0x00, 0x04, 0x02 };

ISR( TIMER0_OVF_vect )
{
  uint8_t Mask;
  uint8_t i;
  
  CurRow++;
  if( CurRow == 7 )
     CurRow = 0;
  
  // welches Bit in Display interessiert denn überhaupt für diese Zeile
  Mask = 1 << CurRow;
  
  // 40 Bits ausgeben
  for( i = 0; i < 40; ++i ) {
    if( Display[i] & Mask )
      PORTB |= ( 1 << PB0 );
    else
      PORTB &= ~( 1 << PB0 );
      
    PORTB |=  ( 1 << PB1 );    // SCLK Puls
    PORTB &= ~( 1 << PB1 );
  }
  
  // alle 40 sind im Schieberegister:
  //   bisherige Anzeige ausschalten,
  //   RCLK Puls auf Schieberegister
  //   3-8 Dekoder auf neue Zeile setzen,
  // -> damit leuchtet die nächste Zeile
  PORTA &= 0x0F;           // 3-8 Dekoder auf einen Wert, so dass nichts leuchtet

  PORTB |=  ( 1 << PB3 );  // Schieberegister zum durchschalten der Bits bringen
  PORTB &= ~( 1 << PB3 );

  PORTA |= RowCodes[CurRow];  // 3-8 Dekoder auf die aktuelle Zeile
}

void SetPixel( uint8_t x, uint8_t y )
{
  uint8_t Mask = ( 1 << y );
  Display[x] |= Mask;
}

void ClearPixel( uint8_t x, uint8_t y )
{
  uint8_t Mask = ( 1 << y );
  Display[x] &= ~Mask;
}

void ClearDisplay()
{
  uint8_t i;
  for( i = 0; i < 160; ++i )
    Display[i] = 0;
}

int main()
{
  uint8_t x, y;
  
  DDRA = 0xff;
  DDRB = 0xff;

  ClearDisplay();
  
  TCCRO = ( 1 << CS01 );  // Timer0: Vorteiler 8
  TIMSK = ( 1 << TOIE0 ); // Timer0: Overflow Interrupt
  
  sei();                  // und los geht der Displayrefresh
  
  while( 1 ) {

    // mal ein bischen was am Display malen
    for( y = 0; y < 7; ++y ) {
      for( x = 0; x < 40; ++x )
        SetPixel( x, y );
        
      _delay_ms( 100 );
    }
    
    ClearDisplay();
  }
}

Autor: M.Hauser (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: M.Hauser (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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)

Autor: M.Hauser (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Stopp

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

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

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht 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
>
#include <util/interrupt.h>
> rum.

Fehlermeldung?

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

Tutorial lesen. Abschnitt: Interrupts.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
M.Hauser wrote:

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

Datenblatt zum Prozessor lesen.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Karl heinz Buchegger wrote:

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

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

Autor: M.Hauser (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
error: util/interrupt.h: No such file or directory

Das ist der Fehler.

Autor: M.Hauser (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
So alle Fehler beseitigt und jetzt blinkt gar nichts mehr

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht 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?

Autor: M.Hauser (Gast)
Datum:

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

Autor: W. S. (wope)
Datum:

Bewertung
0 lesenswert
nicht 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. :-)

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht 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:
uint8_t ISRCnt = 0;    // :-)

ISR( ... )
{
  ISRCnt++;
  if( ISRCnt < 10 )
    return;
  ISRCnt = 0;

  ....  weiter wie gehabt

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

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: M.Hauser (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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 :(

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht 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?

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: M.Hauser (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Matthias Lipinsky (lippy)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: M.Hauser (Gast)
Datum:

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

Autor: M.Hauser (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: M.Hauser (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#include "inttypes.h"

//   Displayorganisation
//   Jedes Byte stellt eine Spalte dar. Das komplette Display ist
//   32*5 (=160) Spalten breit
//   Der Index ins Array ist also die x-Koordinate eines Punktes
//   Die Bits 0 bis 6 stellen die y-Koordinate des Punktes dar.
//   Bit 7 eines jeden Bytes bleibt unbenutzt.
//
//   Grund: Das Timing ist so schon verdammt eng. Es bleibt keine Zeit für
//          aufändige Optimierungsversuche so dass jedes Bit benutzt
//          werden kann
uint8_t Display[40];
uint8_t CurRow;
uint8_t RowCodes[] = { 0x08, 0x0C, 0x06, 0x0A, 0x00, 0x04, 0x02 };

ISR( TIMER0_OVF_vect )
{
  uint8_t Mask;
  uint8_t i;
  
  CurRow++;
  if( CurRow > 6 )
     CurRow = 0;
  
  // welches Bit in Display interessiert denn überhaupt für diese Zeile
  Mask = 1 << CurRow;
  
  // 40 Bits ausgeben
  for( i = 0; i < 40; ++i ) 
  {
    if( Display[i] & Mask )
      PORTB |= (1<<PB0);
    else
      PORTB &= ~(1<<PB0);
      
    PORTB |=  ( 1 << PB1 );    // SRCLK Puls
  PORTB &= ~( 1 << PB1 );
  }
  
  // alle 40 sind im Schieberegister:
  // bisherige Anzeige ausschalten,
  // 3-8 Dekoder auf neue Zeile setzen,
  // RCLK Puls auf Schieberegister
  // -> damit leuchtet die nächste Zeile
  PORTA |= 0x0E;           // 3-8 Dekoder auf einen Wert, so dass nichts leuchtet

  PORTB |=  ( 1 << PB3 );  // Schieberegister zum durchschalten der Bits bringen
  PORTB &= ~( 1 << PB3 );

  PORTA |= RowCodes[CurRow];  // 3-8 Dekoder auf die aktuelle Zeile
}


void SetPixel( uint8_t x, uint8_t y )
{
  uint8_t Mask = ( 1 << y );
  Display[x] |= Mask;
}


void ClearPixel( uint8_t x, uint8_t y )
{
  uint8_t Mask = ( 1 << y );
  Display[x] &= ~Mask;
}


void ClearDisplay()
{
  uint8_t i;
  for( i = 0; i < 40; ++i )
    Display[i] = 0;
}

int main()
{
  uint8_t x, y;
  
  DDRA = 0xff;
  DDRB = 0xff;
  DDRC = 0xff;
  
  PORTB |= (1<<PB2) | (1<<PB4);    // RCLR, SRCRL der Schieberegister auf 1 setzen 
  PORTC |= (1<<PC5);        // D-Eingang des Decoder auf 1 setzen
      
  ClearDisplay();
  
  TCCR0 = ( 1 << CS01 );  // Timer0: Vorteiler 8
  TIMSK = ( 1 << TOIE0 ); // Timer0: Overflow Interrupt
    
  CurRow = 0;    
  sei();                  // und los geht der Displayrefresh
  
  while( 1 ) {
    for( y = 0; y < 7; ++y ) 
  {
      for( x = 0; x < 40; ++x )
        SetPixel( x, y );
        
      _delay_ms( 100 );
    }
    
    ClearDisplay();
  }
}

Autor: P.B. (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.
 
uint8_t Display[160];
.
.
.

// 40 Bits ausgeben
  for( i = 0; i < 40; ++i ) {
    if( Display[i] & Mask )
      PORTB |= ( 1 << PB0 );
    else
      PORTB &= ~( 1 << PB0 );
      
    PORTB |=  ( 1 << PB1 );    // SCLK Puls
    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

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht 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
    PORTA = ( PORTA & ~0x0E ) | RowCodes[CurRow];

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: P.B. (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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??

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht 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.
uint8_t Codes[128][5] = {     // Led Codes für alle Buchstaben im ASCII Code
   .....
   .....
   { 0x7F, 0x11, 0x11, 0x11, 0x7F },   // Code für 'A', an der Arrayposition 0x41
   .....
};

void PutChar( uint8_t col, char Character )
{
  uint8_t i;

  for( i = 0; i < 5; ++i ) {    // weil ja immer 5 Bytes auszugeben sind
    Display[col++] = Codes[Character][i];
  }
}

void PutString( uint8_t col, const char* String )
{
  while( *String )
    PutChar( col++, *String++ );
}

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht 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.
    if( Display[i] & Mask )
      PORTB |= ( 1 << PB0 );
    else
      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

Autor: M.Hauser (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#include "inttypes.h"
#include <stdbool.h>

//   Displayorganisation
//   Jedes Byte stellt eine Spalte dar. Das komplette Display ist
//   40 Spalten breit
//   Der Index ins Array ist also die x-Koordinate eines Punktes
//   Die Bits 0 bis 6 stellen die y-Koordinate des Punktes dar.
//   Bit 7 eines jeden Bytes bleibt unbenutzt.
//
//   Grund: Das Timing ist so schon verdammt eng. Es bleibt keine Zeit für
//          aufändige Optimierungsversuche so dass jedes Bit benutzt
//          werden kann

uint8_t Display[40];
uint8_t CurRow=0;
uint8_t RowCodes0[] = { 0x08, 0x0C, 0x06, 0x0A, 0x00, 0x04, 0x02 }; //Matrixblock1
uint8_t RowCodes1[] = { 0x40, 0x60, 0x30, 0x50, 0x00, 0x20, 0x10 }; //Matrixblock2
uint8_t RowCodes2[] = { 0x02, 0x03, 0x21, 0x22, 0x00, 0x01, 0x02 }; //Matrixblock3
uint8_t RowCodes3[] = { 0x30, 0x38, 0x2C, 0x34, 0x20, 0x28, 0x24 }; //Matrixblock4

ISR( TIMER0_OVF_vect )
{
  uint8_t Mask;
  uint8_t i;
  
  CurRow++;
  if( CurRow > 6 )
     CurRow = 0;
  
  // welches Bit in Display interessiert denn überhaupt für diese Zeile
  Mask = 1 << CurRow;
  
  // 40 Bits ausgeben
  for( i = 0; i < 40; ++i ) 
  {
    if( Display[i] & Mask )
      PORTB |= (1<<PB0);
    else
      PORTB &= ~(1<<PB0);
      
    PORTB |=  ( 1 << PB1 );    // SRCLK Puls
  PORTB &= ~( 1 << PB1 );
  }
 
  // alle 40 sind im Schieberegister:
  // bisherige Anzeige ausschalten,
  // 3-8 Dekoder auf neue Zeile setzen,
  // RCLK Puls auf Schieberegister
  // -> damit leuchtet die nächste Zeile

PORTA = ( PORTA & ~0x8E ) | RowCodes0[CurRow];  //3-8 Dekoder auf Wert setzen das nichts leuchtet und dann Zeilen anschalten
PORTA = ( PORTA & ~0x70 ) | RowCodes1[CurRow];
PORTC = ( PORTC & ~0x23 ) | RowCodes2[CurRow];
PORTC = ( PORTC & ~0x3C ) | RowCodes3[CurRow];

PORTB |=  ( 1 << PB3 );  // Schieberegister zum durchschalten der Bits bringen
PORTB &= ~( 1 << PB3 );

}




void SetPixel( uint8_t x, uint8_t y )
{
  uint8_t Mask = ( 1 << y );
  Display[x] |= Mask;
}


void ClearPixel( uint8_t x, uint8_t y )
{
  uint8_t Mask = ( 1 << y );
  Display[x] &= ~Mask;
}


void ClearDisplay()
{
  uint8_t i;
  for( i = 0; i < 40; ++i )
    Display[i] = 0;
}

int main()
{
  uint8_t x, y, z;
  
  DDRA = 0xff;
  DDRB = 0xff;
  DDRC = 0xff;
  
  PORTB |= (1<<PB2) | (1<<PB4);    // RCLR, SRCRL der Schieberegister auf 1 setzen 
  PORTA |= (1<<PA7);        // D-Eingang des Decoder auf 1 setzen
      
  ClearDisplay();
  
  TCCR0 = (1 << CS01);    // Timer0: Vorteiler 8
  TIMSK = (1 << TOIE0);   // Timer0: Overflow Interrupt
    
  sei();                  // und los geht der Displayrefresh

while( 1 ) 
 
    for( y = 0; y < 27; ++y ) 
    {     
      for( x = 0; x < 40; ++x )
        SetPixel( x, y );
        
      _delay_ms( 500 );
    }
  
    //ClearDisplay(); 
}

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.