Forum: Mikrocontroller und Digitale Elektronik Proplem mit LED Matrix 20 x 7


Announcement: there is an English version of this forum on EmbDev.net. Posts you create there will be displayed on Mikrocontroller.net and EmbDev.net.
von Hendrik B. (hendrik_b456)


Bewertung
0 lesenswert
nicht lesenswert
Hallo,

ich habe in den letzten Wochen mir ein 20x7 LED Display aufgebaut und 
momentan propleme bei der Programmierung.
Den Schaltplan und Quelcode hab ich aus dem Buch "AVR Hardeware und 
C-Programmierung in der Praxis" von Florian Schäffer.
Feines Buch für Anfänger übrigens...

Verwendete Bauteile
CD74HCT164E Schieberegister für die Spalten
ULN2003A für die Zeilen
TA20-11CGKWA DOT MATRIX Anzeige 5x7 LED mit gemeinsame Anode

C /***************************************************
 *  Musteraufbau mit 4 LED Modulen am Atmega 8     *       
 *  5x7 Matrixmodule mit gemeinsamer Anode         *
 *  angesteuert über ULN2003A an PortB PB0 - PB6   *
 *  Multiplexing über 3 Schieberegister 74HCT164   *
 *  PC4 --> Bit setzen  ;  PC5 --> Tackt schieben  * 
 *                                                 *
 * Created: 17.01.2016 17:30:27                    *
 *  Author: Hendrik                                *
 ***************************************************/ 

#define F_CPU 8000000UL
#include <avr/io.h>
#include "lcd-routines.c"
#include <util/delay.h>

#define Spalten 20          // Anzahl der Spalten
volatile uint8_t memory[Spalten];  // Speicher für Display, Spaltenweise
                  // orientiert, Index 0=links

void set_row (uint8_t row)
{
  uint8_t i;    // Alle Spalten des Displays durchlaufen
  // Mit rechten Spalte beginnen
  for (i=Spalten-1; i>=0; i--)
  {
    if ((memory[i] >>(6-row)) & 1)  // Bit in der Spalte an der übergebenen Zeile gesetzt?
    {
      PORTC |= (1<<PC4);    // Data Bit setzen
    }
    else
    {
      PORTC &=~(1<<PC4);    // Data Bit löschen
    }
    PORTC |=(1<<PC5);      // Takt HIGH -> Flanke => schreiben
    PORTC &=~(1<<PC5);      // Takt LOW
  }
}

void write_rows ()
{
  uint8_t i;
  
  for (i=0; i<=6; i++)    // Alle Zeilen durchlaufen
  {
    PORTB = 0;        // alle Zeilen aus
    set_row (i);      // Daten für aktuelle Zeile in Schieberegister schieben
    PORTB = (1 << i);    // aktuelle Zeile an
    _delay_ms(2);      // Zeile Leuchten lassen
  }
}

int main(void)
{
  
//  ***  Ausgänge definieren und ausschalten ***
  DDRC |= (1<< PC4) | (1<<PC5);    // PC4 und PC5 als Ausgang
//  PORTC &=~((1<<PC4) | (1<<PC5));  // PC4 und PC5 aus 
  DDRB = 0xFF;            // PortB als Ausgang
//  PORTB = 0;              // PortB aus
  
  lcd_init();              // LCD aktivieren
  lcd_clear();
  
  lcd_setcursor(2,2);
  lcd_string("20x7 LED Matrix");
  lcd_setcursor(3,4);
  lcd_string("Muster ausgeben");
  
  // beliebeiges Muster Spaltenweise definieren
  //  Spalte =   -7654321  
  memory[0] =  0b01111110;
  memory[1] =  0b01010101;
  memory[2] =  0b00101010;
  memory[3] =  0b01010101;
  memory[4] =  0b01010101;
  memory[5] =  0b01100110;
  memory[6] =  0b00011001;
  memory[7] =  0b01001100;
  memory[8] =  0b01100110;
  memory[9] =  0b01111111;
  memory[10] = 0b01010101;
  memory[11] = 0b00101010;
  memory[12] = 0b01010101;
  memory[13] = 0b00101010;
  memory[14] = 0b00011100;
  memory[15] = 0b01111001;
  memory[16] = 0b01001001;
  memory[17] = 0b01001001;
  memory[18] = 0b01001001;
  memory[19] = 0b01001111;
    
    while(1)
    {
        write_rows(); 
    }
  return 0;
} 

Den Code hab ich soweit vom Buch abgeschrieben und auf 20 Zeilen 
geändert(Buch waren nur 15Zeilen) doch nix tat sich hinterher, keine LED 
war an.
Ich hab momentan in einem Testprogramm die Zeilen einzeln ein und 
ausgeschalten, sprich
while(1)
{
PORTB |=(1<<PB0);
_delay_ms(500);
PORTB &=~ (1<<PB0);
_delay_ms(500);
}
und siehe da es leuchtet die erste Zeile, allerdings komplett alle 20. 
Auch die restlichen Zeilen (PB1 bis PB6) leuchten alle LEDs auf.

Nun ist meine Frage, kann der oben gezeigte Code so funktionieren, 
zumindest sollte das ja laut Buch, oder hab ich doch noch irgendwo einen 
Fehler übersehen ?
Würde mich freuen wenn ihr mir weiterhelfen könntet.

Liebe Grüße Hendrik

von Falk B. (falk)


Bewertung
0 lesenswert
nicht lesenswert
@ Hendrik Brade (hendrik_b456)

>Den Schaltplan und Quelcode hab ich aus dem Buch "AVR Hardeware und
>C-Programmierung in der Praxis" von Florian Schäffer.
>Feines Buch für Anfänger übrigens...

OK, aber wir haben das nicht, genausowenig wie einen Schaltplan. der ist 
aber wichtig. Siehe Netiquette.

>void set_row (uint8_t row)
>{
>  uint8_t i;    // Alle Spalten des Displays durchlaufen
>  // Mit rechten Spalte beginnen
>  for (i=Spalten-1; i>=0; i--)

Das knallt. ein uint8_8 ist IMMER >=0. besser so, ohne u!

>  int8_t i;    // Alle Spalten des Displays durchlaufen

>  {
>    if ((memory[i] >>(6-row)) & 1)  // Bit in der Spalte an der übergebenen Zeile 
gesetzt?
>    {

Kann man so machen, ist aber lahm. Dein Problem liegt woanders.

>und siehe da es leuchtet die erste Zeile, allerdings komplett alle 20.

Zuerst solltest du mal zwischen Zeilen und Spalten unterscheiden, 
sprachlich wie auch gedanklich!

>Auch die restlichen Zeilen (PB1 bis PB6) leuchten alle LEDs auf.

Das warf nicht sein, es muss immer nur eine Zeile leuchten. Ansonsten 
hast du möglicherweise einen Hardwarefehler.

>Nun ist meine Frage, kann der oben gezeigte Code so funktionieren,
>zumindest sollte das ja laut Buch, oder hab ich doch noch irgendwo einen
>Fehler übersehen ?

Bis auf sie Sache mit dem uint sollte das passen.

von Hendrik B. (hendrik_b456)


Bewertung
0 lesenswert
nicht lesenswert
Danke für die schnelle Antwort und ich bitte um Verzeihung, hatte heute 
Morgen im der Eile den schaltplan ganz vergessen. Hab ihn jetz nur mit 
dem Handy fotografiert aus dem Buch heraus.

Die Zeilen werden über den Zeilentreiber ULN2003AN geschalten 
(wagerecht).
Die Spalten werden über die Schieberegister 74HCT164 geschalten 
(senkrecht).

Danke, das hab ich übersehen,bzw. falsch abgeschrieben vom Buch,
soll auch int8_t i lauten.


Wie gesagt ist ja nur ein Beispielprogramm was die Funktion der 
Schieberegister verdeutlichen soll, sicherlich gibt es bessere 
möglichkeiten das zu schreiben. Paar Seiten Weiter geht es ja dann 
weiter mit Textausgabe. Wie gesagt Anfängerbuch mit vielen Beispielen.

Auch die restlichen Zeilen (PB1 bis PB6) leuchten alle LEDs auf.

Ich meinte damit nur das ich testweise alle Pins an Port B nacheinander 
auf 1 gesetzt habe, um festzustellen ob ich irgendwas falsch gelötet 
habe. Ich war halt erstaund das wagerecht alle 20 LEDs leuchten.

Grüße Hendrik

von Hendrik B. (hendrik_b456)


Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Guten Morgen,

kann das obrige Bild allerdings nicht mehr löschen, bzw. bearbeiten.

Hier nun mein Schaltplan.


ATmega8 PB0 - PB6 ---> ULN2003AN
ATmega8 PC4       ---> 74HCT164 Pin DS1 und DS2 (DATA)
Atmega8 PC5       ---> 74HCT164 Pin CLK         (Takt)

Grüße Hendrik

: Bearbeitet durch User
von Falk B. (falk)


Bewertung
0 lesenswert
nicht lesenswert
@ Hendrik B. (hendrik_b456)

>    20x7_Matrix.png

>ATmega8 PB0 - PB6 ---> ULN2003AN
>ATmega8 PC4       ---> 74HCT164 Pin DS1 und DS2 (DATA)
>Atmega8 PC5       ---> 74HCT164 Pin CLK         (Takt)

OK, damit ist das nun klar. Aber das Problem bleibt das Gleiche.
Zuerst musst du prüfen, ob du die ZEILEN einzeln schalten kannst. 
Sprich, lade in das Schieberegister 3x0xFF und schalte danach die Zeilen 
einzeln durch. Die müssen dann einzeln leuchten. Zum Glück sind die 
Widerstände für die LEDs schwach dimensioniert, dort fließen maximal 
13mA/Spalte, in Summe 260mA pro Zeile. Das hälten die LEDs problemlos 
aus, auch ohne Multiplexing.
eigentlich reicht es, die Pause von _delay_ms(2) auf _delay_ms(500) zu 
ändern, dann sieht man das.

Also!
/***************************************************
 *  Musteraufbau mit 4 LED Modulen am Atmega 8     *       
 *  5x7 Matrixmodule mit gemeinsamer Anode         *
 *  angesteuert über ULN2003A an PortB PB0 - PB6   *
 *  Multiplexing über 3 Schieberegister 74HCT164   *
 *  PC4 --> Bit setzen  ;  PC5 --> Tackt schieben  * 
 *                                                 *
 * Created: 17.01.2016 17:30:27                    *
 *  Author: Hendrik                                *
 ***************************************************/ 

#define F_CPU 8000000UL
#include <avr/io.h>
#include "lcd-routines.c"
#include <util/delay.h>

#define Spalten 20          // Anzahl der Spalten
// Speicher für Display, Spaltenweise orientiert, Index 0=links

volatile uint8_t memory[Spalten] ={
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
0xFF, 0xFF, 0xFF, 0xFF
};  
                  
void set_row (uint8_t row)
{
  int8_t i;    // Alle Spalten des Displays durchlaufen

  // Mit rechten Spalte beginnen
  for (i=Spalten-1; i>=0; i--)
  {
    if ((memory[i] >>(6-row)) & 1)  // Bit in der Spalte an der übergebenen Zeile gesetzt?
    {
      PORTC |= (1<<PC4);    // Data Bit setzen
    }
    else
    {
      PORTC &=~(1<<PC4);    // Data Bit löschen
    }
    PORTC |=(1<<PC5);      // Takt HIGH -> Flanke => schreiben
    PORTC &=~(1<<PC5);      // Takt LOW
  }
}

void write_rows ()
{
  uint8_t i;
  
  for (i=0; i<=6; i++)    // Alle Zeilen durchlaufen
  {
    PORTB = 0;        // alle Zeilen aus
    set_row (i);      // Daten für aktuelle Zeile in Schieberegister schieben
    PORTB = (1 << i);    // aktuelle Zeile an
    _delay_ms(500);      // Zeile Leuchten lassen
  }
}

int main(void)
{
  
  //  ***  Ausgänge definieren und ausschalten ***
  DDRC |= (1<< PC4) | (1<<PC5);    // PC4 und PC5 als Ausgang
  //  PORTC &=~((1<<PC4) | (1<<PC5));  // PC4 und PC5 aus 
  DDRB = 0xFF;            // PortB als Ausgang
  //  PORTB = 0;              // PortB aus
  
  lcd_init();              // LCD aktivieren
  lcd_clear();
  
  lcd_setcursor(2,2);
  lcd_string("20x7 LED Matrix");
  lcd_setcursor(3,4);
  lcd_string("Muster ausgeben");
  
  // beliebeiges Muster Spaltenweise definieren
  //  Spalte =   -7654321  
/*
  memory[0] =  0b01111110;
  memory[1] =  0b01010101;
  memory[2] =  0b00101010;
  memory[3] =  0b01010101;
  memory[4] =  0b01010101;
  memory[5] =  0b01100110;
  memory[6] =  0b00011001;
  memory[7] =  0b01001100;
  memory[8] =  0b01100110;
  memory[9] =  0b01111111;
  memory[10] = 0b01010101;
  memory[11] = 0b00101010;
  memory[12] = 0b01010101;
  memory[13] = 0b00101010;
  memory[14] = 0b00011100;
  memory[15] = 0b01111001;
  memory[16] = 0b01001001;
  memory[17] = 0b01001001;
  memory[18] = 0b01001001;
  memory[19] = 0b01001111;
*/    
    while(1)
    {
        write_rows(); 
    }
  return 0;
} 

von Hendrik B. (hendrik_b456)


Bewertung
0 lesenswert
nicht lesenswert
Hallo Falk,

Die Wiederstände hab ich auf 150ohm hochgesetzt, da mir die 100ohm laut 
Buch etwas zu wenig waren. Der ULN2003 verträgt pro Ausgang 500mA.

Ich hatte bereits die Schieberegister so getestet

 while(1)
    {
    PORTC |= (1<<PC4);      // Bit 1 Setzen
    PORTC |=(1<<PC5);      // Takt HIGH -> Flanke => schreiben
    PORTC &=~(1<<PC5);      // Takt LOW

    PORTC |= (1<<PC4);      // Bit 1 Setzen
    PORTC |=(1<<PC5);      // Takt HIGH -> Flanke => schreiben
    PORTC &=~(1<<PC5);      // Takt LOW

    PORTC |= (1<<PC4);      // Bit 1 Setzen
    PORTC |=(1<<PC5);      // Takt HIGH -> Flanke => schreiben
    PORTC &=~(1<<PC5);      // Takt LOW

    PORTC &=~ (1<<PC4);      // Bit 0 Setzen
    PORTC |=(1<<PC5);      // Takt HIGH -> Flanke => schreiben
    PORTC &=~(1<<PC5);      // Takt LOW

    for (i=0; i<=6; i++)    // Alle Zeilen durchlaufen
    {
      PORTB = 0;        // alle Zeilen aus
      PORTB = (1 << i);    // aktuelle Zeile an
      _delay_ms(2);      // Zeile Leuchten lassen
    }
  }

Es leuchten so jeweil 3 Spalten und die 4. bleibt aus.

von Falk B. (falk)


Bewertung
0 lesenswert
nicht lesenswert
@ Hendrik B. (hendrik_b456)

>Die Wiederstände hab ich auf 150ohm hochgesetzt, da mir die 100ohm laut
>Buch etwas zu wenig waren.

100 Ohm gehen auch, erst recht beim aktiven Multiplexing.

> Der ULN2003 verträgt pro Ausgang 500mA.

Ja, aber nicht an allen Ausgängen gleichzeitig.

>Ich hatte bereits die Schieberegister so getestet

Auch als Hobbyprogrammierer wirst du nicht nach der Anzahl der Zeilen 
bezahlt oder bewertet. Also nutze sinnvollerweise Schleifen. Dein 
Programm oben ist nahezu korrekt. Jetzt heißt es, den Fehler zu finden.

>Es leuchten so jeweil 3 Spalten und die 4. bleibt aus.

Leuchten den die 7 Zeilen einzeln, wenn du die Pause auf 500ms 
verlängerst?

von Hendrik B. (hendrik_b456)


Bewertung
0 lesenswert
nicht lesenswert
Falk B. schrieb:
> Leuchten den die 7 Zeilen einzeln, wenn du die Pause auf 500ms
> verlängerst?

ja leuchten schön der Reihe nach einzeln

Falk B. schrieb:
> Hobbyprogrammierer

lach, glaub soweit bin ich noch lange nicht das ich mich so bezeichnen 
kann.
Ich erarbeite mir alles mit dem was ich bereits weiß und nehme neues 
dazu.
Bis jetzt hat ja auch alles aus dem Buch funktioniert, "7 Segmentanzeige 
Multiplexing" z.B.
Nur bei diesem Thema ist der Wurm irgendwo versteckt und bis auf das 
eine "u" hab ich ja alles mehr oder weniger abgeschrieben, Quellcode 
steht ja im Buch, bzw. auch online downloadbar.

von Falk B. (falk)


Bewertung
0 lesenswert
nicht lesenswert
@ Hendrik B. (hendrik_b456)

>> Leuchten den die 7 Zeilen einzeln, wenn du die Pause auf 500ms
>> verlängerst?

>ja leuchten schön der Reihe nach einzeln

Gut, dann kannst du ja dein Ursprungsprogramm in Betieb nehmen, aber 
immer noch mit 500ms Pause. Dann siehst du die Muster der einzelnen 
Zeilen aufleuchten. Wenn das passt, dann wieder 2ms und du siehtst alles 
auf einmal.

von Hendrik B. (hendrik_b456)


Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Danke , super es funktioniert einwandfrei jetzt. Vermute mal das vorher 
das Muster nicht richtig zugeordnet werden konnte... egal jetzt gehts 
und ich bin erstmal ein Stück weiter.

Nochmals vielen Dank

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.