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


von Hendrik B. (hendrik_b456)


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

1
C /***************************************************
2
 *  Musteraufbau mit 4 LED Modulen am Atmega 8     *       
3
 *  5x7 Matrixmodule mit gemeinsamer Anode         *
4
 *  angesteuert über ULN2003A an PortB PB0 - PB6   *
5
 *  Multiplexing über 3 Schieberegister 74HCT164   *
6
 *  PC4 --> Bit setzen  ;  PC5 --> Tackt schieben  * 
7
 *                                                 *
8
 * Created: 17.01.2016 17:30:27                    *
9
 *  Author: Hendrik                                *
10
 ***************************************************/ 
11
12
#define F_CPU 8000000UL
13
#include <avr/io.h>
14
#include "lcd-routines.c"
15
#include <util/delay.h>
16
17
#define Spalten 20          // Anzahl der Spalten
18
volatile uint8_t memory[Spalten];  // Speicher für Display, Spaltenweise
19
                  // orientiert, Index 0=links
20
21
void set_row (uint8_t row)
22
{
23
  uint8_t i;    // Alle Spalten des Displays durchlaufen
24
  // Mit rechten Spalte beginnen
25
  for (i=Spalten-1; i>=0; i--)
26
  {
27
    if ((memory[i] >>(6-row)) & 1)  // Bit in der Spalte an der übergebenen Zeile gesetzt?
28
    {
29
      PORTC |= (1<<PC4);    // Data Bit setzen
30
    }
31
    else
32
    {
33
      PORTC &=~(1<<PC4);    // Data Bit löschen
34
    }
35
    PORTC |=(1<<PC5);      // Takt HIGH -> Flanke => schreiben
36
    PORTC &=~(1<<PC5);      // Takt LOW
37
  }
38
}
39
40
void write_rows ()
41
{
42
  uint8_t i;
43
  
44
  for (i=0; i<=6; i++)    // Alle Zeilen durchlaufen
45
  {
46
    PORTB = 0;        // alle Zeilen aus
47
    set_row (i);      // Daten für aktuelle Zeile in Schieberegister schieben
48
    PORTB = (1 << i);    // aktuelle Zeile an
49
    _delay_ms(2);      // Zeile Leuchten lassen
50
  }
51
}
52
53
int main(void)
54
{
55
  
56
//  ***  Ausgänge definieren und ausschalten ***
57
  DDRC |= (1<< PC4) | (1<<PC5);    // PC4 und PC5 als Ausgang
58
//  PORTC &=~((1<<PC4) | (1<<PC5));  // PC4 und PC5 aus 
59
  DDRB = 0xFF;            // PortB als Ausgang
60
//  PORTB = 0;              // PortB aus
61
  
62
  lcd_init();              // LCD aktivieren
63
  lcd_clear();
64
  
65
  lcd_setcursor(2,2);
66
  lcd_string("20x7 LED Matrix");
67
  lcd_setcursor(3,4);
68
  lcd_string("Muster ausgeben");
69
  
70
  // beliebeiges Muster Spaltenweise definieren
71
  //  Spalte =   -7654321  
72
  memory[0] =  0b01111110;
73
  memory[1] =  0b01010101;
74
  memory[2] =  0b00101010;
75
  memory[3] =  0b01010101;
76
  memory[4] =  0b01010101;
77
  memory[5] =  0b01100110;
78
  memory[6] =  0b00011001;
79
  memory[7] =  0b01001100;
80
  memory[8] =  0b01100110;
81
  memory[9] =  0b01111111;
82
  memory[10] = 0b01010101;
83
  memory[11] = 0b00101010;
84
  memory[12] = 0b01010101;
85
  memory[13] = 0b00101010;
86
  memory[14] = 0b00011100;
87
  memory[15] = 0b01111001;
88
  memory[16] = 0b01001001;
89
  memory[17] = 0b01001001;
90
  memory[18] = 0b01001001;
91
  memory[19] = 0b01001111;
92
    
93
    while(1)
94
    {
95
        write_rows(); 
96
    }
97
  return 0;
98
}

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)


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)


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:

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)


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!
1
/***************************************************
2
 *  Musteraufbau mit 4 LED Modulen am Atmega 8     *       
3
 *  5x7 Matrixmodule mit gemeinsamer Anode         *
4
 *  angesteuert über ULN2003A an PortB PB0 - PB6   *
5
 *  Multiplexing über 3 Schieberegister 74HCT164   *
6
 *  PC4 --> Bit setzen  ;  PC5 --> Tackt schieben  * 
7
 *                                                 *
8
 * Created: 17.01.2016 17:30:27                    *
9
 *  Author: Hendrik                                *
10
 ***************************************************/ 
11
12
#define F_CPU 8000000UL
13
#include <avr/io.h>
14
#include "lcd-routines.c"
15
#include <util/delay.h>
16
17
#define Spalten 20          // Anzahl der Spalten
18
// Speicher für Display, Spaltenweise orientiert, Index 0=links
19
20
volatile uint8_t memory[Spalten] ={
21
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
22
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
23
0xFF, 0xFF, 0xFF, 0xFF
24
};  
25
                  
26
void set_row (uint8_t row)
27
{
28
  int8_t i;    // Alle Spalten des Displays durchlaufen
29
30
  // Mit rechten Spalte beginnen
31
  for (i=Spalten-1; i>=0; i--)
32
  {
33
    if ((memory[i] >>(6-row)) & 1)  // Bit in der Spalte an der übergebenen Zeile gesetzt?
34
    {
35
      PORTC |= (1<<PC4);    // Data Bit setzen
36
    }
37
    else
38
    {
39
      PORTC &=~(1<<PC4);    // Data Bit löschen
40
    }
41
    PORTC |=(1<<PC5);      // Takt HIGH -> Flanke => schreiben
42
    PORTC &=~(1<<PC5);      // Takt LOW
43
  }
44
}
45
46
void write_rows ()
47
{
48
  uint8_t i;
49
  
50
  for (i=0; i<=6; i++)    // Alle Zeilen durchlaufen
51
  {
52
    PORTB = 0;        // alle Zeilen aus
53
    set_row (i);      // Daten für aktuelle Zeile in Schieberegister schieben
54
    PORTB = (1 << i);    // aktuelle Zeile an
55
    _delay_ms(500);      // Zeile Leuchten lassen
56
  }
57
}
58
59
int main(void)
60
{
61
  
62
  //  ***  Ausgänge definieren und ausschalten ***
63
  DDRC |= (1<< PC4) | (1<<PC5);    // PC4 und PC5 als Ausgang
64
  //  PORTC &=~((1<<PC4) | (1<<PC5));  // PC4 und PC5 aus 
65
  DDRB = 0xFF;            // PortB als Ausgang
66
  //  PORTB = 0;              // PortB aus
67
  
68
  lcd_init();              // LCD aktivieren
69
  lcd_clear();
70
  
71
  lcd_setcursor(2,2);
72
  lcd_string("20x7 LED Matrix");
73
  lcd_setcursor(3,4);
74
  lcd_string("Muster ausgeben");
75
  
76
  // beliebeiges Muster Spaltenweise definieren
77
  //  Spalte =   -7654321  
78
/*
79
  memory[0] =  0b01111110;
80
  memory[1] =  0b01010101;
81
  memory[2] =  0b00101010;
82
  memory[3] =  0b01010101;
83
  memory[4] =  0b01010101;
84
  memory[5] =  0b01100110;
85
  memory[6] =  0b00011001;
86
  memory[7] =  0b01001100;
87
  memory[8] =  0b01100110;
88
  memory[9] =  0b01111111;
89
  memory[10] = 0b01010101;
90
  memory[11] = 0b00101010;
91
  memory[12] = 0b01010101;
92
  memory[13] = 0b00101010;
93
  memory[14] = 0b00011100;
94
  memory[15] = 0b01111001;
95
  memory[16] = 0b01001001;
96
  memory[17] = 0b01001001;
97
  memory[18] = 0b01001001;
98
  memory[19] = 0b01001111;
99
*/    
100
    while(1)
101
    {
102
        write_rows(); 
103
    }
104
  return 0;
105
}

von Hendrik B. (hendrik_b456)


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)


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)


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)


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:

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

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.