Forum: Mikrocontroller und Digitale Elektronik multiplexen für dummies


von dude123 (Gast)


Lesenswert?

hey leute,

also ich bin ein ziemlicher anfänger, bitte nicht auslachen,
also ich habe da meinen atmel at89c5131a controller und eine led matrix
an P0 vom controller sind die zeilen angeschlossen und an P2 die 
splaten, ich versuche jetz lediglich das auf der matrix auszugeben was 
ich ins array eintrage. igendwie klappts aber überhaupt nicht, ich hab 
bestimmt fatale logikfehler drin
entschuldigung hierfür

1
#include<at89c5131.h>
2
unsigned int spielfeld[6][7];
3
int j;
4
int i;
5
isr_t0()interrupt 1
6
  {
7
  TR0=0;
8
  TH0=0xFC;
9
  TL0=0x18;
10
  TR0=1;
11
  for (j=0;j=5;j++)
12
    {
13
    for (i=0;i=6;i++)
14
      {
15
      if(spielfeld[i][j]=1)
16
        {P0 |=(1<<i);
17
        }
18
      else{}
19
      }
20
  P2 |=(1<<j);
21
  }
22
23
24
   }
25
26
main(void)
27
  {
28
   TMOD=0x01;
29
   EA=1;
30
   ET0=1;
31
   TH0=0xFC ;
32
   TL0=0x18 ;
33
   TR0=1;
34
  spielfeld[0][0]=1;
35
  spielfeld[1][1]=1;
36
  spielfeld[2][2]=1;
37
  spielfeld[3][3]=1;
38
  spielfeld[4][4]=1;
39
  spielfeld[5][5]=1;
40
  spielfeld[6][6]=1;
41
42
  }

danke im voraus

von holger (Gast)


Lesenswert?

for (j=0;j=5;j++)
  for (i=0;i=6;i++)
  if(spielfeld[i][j]=1)

Diese drei Zeilen enthalten Fehler, ich sag aber nicht welche.
Dann solltest du beim multiplexen Spalten- und Zeilenbits
auch mal wieder auf 0 setzen. So geht es jedenfalls nicht.

von layouter (Gast)


Lesenswert?

wie wäre es damit:


unsigned char j=0;

isr_t0()interrupt 1
{
    unsigned char row_data = 0;
    unsigned char i;

    for (i=0; i=<6; i++)
        if (spielfeld[i][j]==1) row_data |=(1<<i);

    P0 = 0; // avoid smear
    P2 = ~ (1<<j); // set active row cathode to low
    P0 = row_data; // set active column anodes to high

    // next interrupt call will process next row
    j++;
    (if j>5) j=0;
}


a) wenn du die LEDs direkt an die ports angehängt hast, fließt strom, 
wenn an dem Annotden-Pin eine 1 liegt, und am Anoden-Pin eine 0.
In meinem Beispiel würdest du die Anoden an P0 anschließen.

b) Die Schleifenbedingung ist bei dir falsch

c) Der "Verleich" "spielfeld[i][j]=1" setzt in deinem Code die Variable, 
anstatt sie zu vergleichen.

d) Du hast irgendwelche Portkonfigurationen in der Interrupt Funktion.
Der Code im Interrupt muss möglichst schnell sein. Daher alles da 
rausnehmen, was auch in main() gemacht werden kann.

e) in meinem Beispiel bleibt die "aktive" spalte solange an, bis der 
nächste Interrupt kommt (indem die Schleife "j" erst beim nächsten 
Interrupt weiterzählt). Ansonsten blinkt dein Display evtl. kurz auf, 
und dann bleibt die letzte Spalte an, bis der nächste Interrupt kommt...

von Peter D. (peda)


Lesenswert?

Ein Byte pro Bit ist Verschwendung und auch Blödsinn (kostet viel zuviel 
Code).

Mach ein Array "unsigned char pattern[6]", auch wenn es nur 7 Bit sind.
Und im Timerinterrupt wird immer ein komplettes Byte ausgegeben.

Daß P0 noch externe Pullups benötigt, weißt Du?
Du brauchst in jedem Fall Treibertransistoren für die Spalten und die 
Zeilen.


Peter

von Max (Gast)


Lesenswert?

Willst du dir wirklich nen 8051 antun?
Nimm lieber nen AVR oder gleich nen arm (mbed) (is auch nich mehr schwer 
zu benutzen) und geniess den hohen durchsatz

von Peter D. (peda)


Lesenswert?

Max schrieb:
> Willst du dir wirklich nen 8051 antun?

Das mußte ja kommen.

Der 8051 ist immer noch für viele Aufgaben mehr als ausreichend und 
bewährt.
Der einzige Nachteil ist, daß der Keil C51-Compiler sehr teuer ist.

Wie gut der SDCC im Vergleich zum WINAVR ist, weiß ich nicht. Ich hab ja 
ne Keil Lizenz, auch wenn die uralt ist (1995).

Im Unterschied zum AVR werden neue 8051 immer vom alten Compiler 
unterstützt (da 100% Code kompatibel), man muß sich nur das neue Include 
(die IO-Register Definition) kopieren oder einfach selber editieren.
Ich compiliere z.B. den AT89C51CC03 mit meinem 1995-er Keil.


Peter

von Dirk (Gast)


Lesenswert?

Max schrieb:
> Willst du dir wirklich nen 8051 antun?
> Nimm lieber nen AVR oder gleich nen arm (mbed) (is auch nich mehr schwer
> zu benutzen) und geniess den hohen durchsatz

Lieber nen Atom Prozessor und dann in Java oder html.
Einfacher gehts nicht :-)

Gruß an MAX Gast

von 80c51 (Gast)


Lesenswert?

Und als erstes sollte die main () nicht beendet werden.

von Achim M. (minifloat)


Lesenswert?

Dirk schrieb:
> Atom Prozessor
Sind wir hier ein _Mega_controllerforum oder was? Völlig 
überdimensioniert.
mfg mf

von dude123 (Gast)


Lesenswert?

also ich habe jetz die variante von layouter mal ausprobiert, 
funktioniert leider immer noch nicht, und bei dem controller hab ich 
keine wahl, ich habe ein controller aus der schule und eine matrix aus 
der schule, mein ziel ist es 4-gewinnt zu programmieren, mit einer 
mehrfarbigen led-matrix, jetzt wollt ich aber erst mal das 2d array auf 
der matrix ausgeben, es funktioniert aber nicht, ich sehe nichts. Welche 
zeit muss ich den für den Timer nehmen das man etwas sieht?
noch ne andere frage: warum kann ich kein array von bit oder boolean 
machen?

hier mein jetztiger code
1
#include<at89c5131.h>
2
unsigned char spielfeld[6][7];
3
unsigned char row_data = 0;
4
unsigned char i;
5
unsigned char j;
6
7
isr_t0()interrupt 1
8
  {
9
  TR0=0;
10
  TH0=0x00;
11
  TL0=0x00;
12
  TR0=1;
13
  
14
    for (i=0; i<=6; i++)
15
    {
16
        if (spielfeld[i][j]==1) row_data |=(1<<i);
17
     }
18
    P0 = 0; 
19
    P2 = ~ (1<<j);
20
    P0 = row_data; 
21
22
   
23
    j++;
24
    if (j>5)j=0;  
25
  
26
27
28
   }
29
30
void main()
31
  {
32
   
33
  spielfeld[0][0]=1;
34
  spielfeld[1][1]=1;
35
  spielfeld[2][2]=1;
36
  spielfeld[3][3]=1;
37
  spielfeld[4][4]=1;
38
  spielfeld[5][5]=1;
39
  spielfeld[6][6]=1;
40
   while(1){
41
   TMOD=0x01;
42
   EA=1;
43
   ET0=1;
44
   TH0=0x00 ;
45
   TL0=0x00 ;
46
   TR0=1;
47
   }
48
  }

von dude123 (Gast)


Lesenswert?

ich hab jetz noch and der ausgabe bisschen gedrecht, aber ich weiß 
einfach nicht mehr was ich jetz noch falsch sein könnte und warum es 
einfach nicht funtionieren will
1
P0 = 0; 
2
    P2 = (1<<j);
3
    P0 = ~ (row_data);

die zeilen sind ja low aktiv bei meiner matrix und die spalten high 
aktiv
hab an p0 die zeilen und an p2 die spalten

BITTE UM HILFE!!!

von dude123 (Gast)


Lesenswert?

hat keiner eine lösung?

von router (Gast)


Lesenswert?

also erstens musst du row_data in der interrupt funktion auf 0 setzen, 
bevor deine schleife läuft.

isr_t0()interrupt 1
{
    row_data=0;

(...)



Als nächstes solltest du mal prüfen, ob deine Interrupt funktion 
überhaupt ausgeführt wird, und wie oft.
Wenn du ein einigermaßen flimmerfreies Display haben willst, solltest du 
mit min. 25 Updates pro Sekunde arbeiten.
Multipliziert mit 6 Spalten ergibt das min. 300 Hz für deinen Interrupt.

Hast du ein Oszilloskop?
Dann könntest du in der Interruptfunktion die Zeile
P2 = ~ (1<<j);

mal durch

P2 = P2 ^ 0xff;

ersetzen. Dann solten an P2 alle Pins einen schönen Rechteckpuls zeigen, 
jede Flanke ist ein Interrupt.

von router (Gast)


Lesenswert?

Ausserdem ist es natürlich Unsinn, in main() in der while(1) schleife 
ständig auf den Timer Registern rumzumachen.

Besser so:

main()
{
   (...) // setze spielfeld
   (...) // setze timer interrupt
   while (1)
   {
   }
}

Ich kenne mich mit Atmel nicht aus, aber TH0 und TL0 sind wohl die 
Delay-Werte des Timers. 0 scheint mir hier kein vernünftiger Wert.

Ich denke, als ersten Schritt solltest du erstmal schaffen, deine 
Interruptfunktion zuverlässig und mit der gewünschten Spaltenfrequenz 
ausführen zu lassen, bevor du dir um den restlichen Code gedanken 
machst.

von holger (Gast)


Lesenswert?

>die zeilen sind ja low aktiv bei meiner matrix und die spalten high
>aktiv
>hab an p0 die zeilen und an p2 die spalten

Welche Treiber benutzt du für die Matrix?
Keine? Dann geht das so nicht. P2 kann bei
High nur ein paar uA liefern. Das reicht nicht
für eine LED und für Multiplex schon gar nicht.

von dude123 (Gast)


Lesenswert?

ich hab da so ne fertige matrix muss funktioniert auch jetz eigenlich 
fast alles, also wenn ich die zeit vom teimer auf 2^16 mikrosekunden 
einstelle sehe ich auch wie der interrupt zeile für zeile durchgeht.

jedoch kommmt auf row_data nicht das was im array steht sondern immer 
nur 0xff als die ganze spalte an, was stimmt da nicht?
row data soll ja eigentlich immer nur daß was im array steht übertragen
1
isr_t0()interrupt 1
2
  {
3
  row_data=0;
4
  TR0=0;
5
  TH0=0xFE;
6
  TL0=0x0C;
7
  TR0=1;
8
  
9
    for (i=0; i<=6; i++)
10
    {
11
        if (spielfeld[i][j]==1) row_data |=(1<<i);
12
     }
13
    P0 = 0; 
14
    P2 = (1<<j);
15
    P0 = ~(row_data); 
16
17
   
18
    j++;
19
    if (j>5)j=0;  
20
  
21
22
23
   }

ich habe ja werte in das array eingetragen, die sind aber nicht auf der 
anzeige zu sehen

das array
1
unsigned char spielfeld[6][7]=
2
{{0x01,0x00,0x00,0x00,0x00,0x00,0x00},
3
                 {0x00,0x01,0x00,0x00,0x00,0x00,0x00},
4
                 {0x00,0x00,0x01,0x00,0x00,0x00,0x00},
5
                 {0x00,0x00,0x00,0x01,0x00,0x00,0x00},
6
                 {0x00,0x00,0x00,0x00,0x01,0x00,0x00},
7
8
                 {0x00,0x00,0x00,0x00,0x00,0x01,0x01}};

von dude123 (Gast)


Lesenswert?

bitte um antwort!

von Karl H. (kbuchegg)


Lesenswert?

>     for (i=0; i<=6; i++)
>    {
>        if (spielfeld[i][j]==1) row_data |=(1<<i);
>    }

Du musst dich mal mit dir selber einig werden, welche Dimension des 
Arrays wie gross ist.

Dein i läuft in der Schleife durch:
  0, 1, 2, 3, 4, 5, 6

zähl nach, das sind 7 Werte

Dein Array hat aber in der ersten Dimension nur 6 Werte:
0, 1, 2, 3, 4, 5


Hinweis: Ein <= in einer for-Schleife, die noch dazu dient ein Array 
abzuarbeiten, ist meistens einfach nur falsch.

> nur 0xff als die ganze spalte an
wie genau hast du aufgepasst?
Die meisten deiner Werte sind 0. WEnn du hier
   P0 = ~(row_data);
das auszugebende Byte invertierst, dann darfst du dich nicht wundern, 
wenn die Portpins praktisch ständig 1 sind. Die 0, die da ab und zu 
auftritt, kann man ganz leicht übersehen.


Und da ein 2D-Array dafür zu benutzen, ist nach wie vor Unsinn. Du 
fürchtest dich da vor etwas, wovor du dich nicht fürchten musst: nämlich 
beim LED ein/ausschalten Bitoperationen anwenden zu müssen. Als 
Ausgleich dafür machst du jetzt dafür deine ISR maximal kompliziert, 
wenn du es eigentlich genau umgekehrt machen solltest: Die ISR so 
einfach wie möglich und dafür ein bischen Bit-"Magie" beim 
setzen/löschen von LED
(Und lass den Timer in der ISR in Ruhe!)

So sollte deine ISR eigentlich aussehen:
1
volatile unsigned char spielfeld[6];
2
3
isr_t0()interrupt 1
4
{
5
  P0 = 0; 
6
  P2 = (1<<j);
7
  P0 = spielfeld[j];   // oder P0 = ~spielfeld[j]; je nachdem wie die Matrix
8
                       // hardwaremässig aufgebaut ist
9
10
  j++;
11
  if (j>5)
12
    j=0;  
13
}

und dazu noch 2 Funktionen um LED gezielt in einem x/y Koordinatensystem 
ein/auszuschalten, die diese x/y Koordinaten in eine Bitposition in 
diesem Array umrechnen. X ist leicht, das kann man direkt übernehmen und 
y muss man eben in eine Bitmaske umrechnen mit der man dann gezielt 1 
Bit setzt/löscht.

von Peter D. (peda)


Lesenswert?

dude123 schrieb:
> jedoch kommmt auf row_data nicht das was im array steht sondern immer
> nur 0xff als die ganze spalte an, was stimmt da nicht?

Na dann lade es dochmal mit ner Konstante, z.B. 0xAA.


Peter

von dude123 (Gast)


Lesenswert?

zu dem post von karl heinz buchenegger,

das mit der isr so einfach wie möglich machen is ja schön und gut, aber 
mein ziel ist es später die spielstände von 4 gewinnt auf einem array zu 
speichern und das array ohne große umstände dann auszugeben in der isr 
des programms, in die main kommt dann das eigentliche programm, aber ich 
will jetz hald ersteinmal diese blöde multiplexanzeige zum laufen 
bekommen.

und den timer kann ich in der isr nicht in ruhe lassen weil er kein 
auto_reload hat, also muss ich immer wieder den startwert reinschreiben,

das ich row_data invertiert habe stimmt, aber das ist weil die leds auf 
port0 low aktiv sind, also kein grund warum die spalten immer nur an 
sind.

von jonas biensack (Gast)


Lesenswert?

>und den timer kann ich in der isr nicht in ruhe lassen weil er kein
>auto_reload hat, also muss ich immer wieder den startwert reinschreiben,

Ne, dann hast du ihn nicht nach deinen Anforderungen konfiguriert. Da 
musst du nochmal schauen - Thema "Timer". Was sonst noch an Tips 
geschrieben wurde, ist absolut richtig und das solltest du auch 
beherzigen.

Gruß Jonas

von Peter D. (peda)


Lesenswert?

dude123 schrieb:
> das mit der isr so einfach wie möglich machen is ja schön und gut, aber
> mein ziel ist es später die spielstände von 4 gewinnt auf einem array zu
> speichern und das array ohne große umstände dann auszugeben in der isr
> des programms, in die main kommt dann das eigentliche programm

Ein 2-dimensionales Array ist deutlich umständlicher als ein 6 Byte 
großes Array.
Sowohl vom Schreiben her und erst recht für den Compiler.
Und die CPU hat auch deutlich mehr zun ackern (Multiplikation).


jonas biensack schrieb:
> Ne, dann hast du ihn nicht nach deinen Anforderungen konfiguriert.

Das mit dem Timer laden ist schon richtig so. Man muß ihn aber nicht 
anhalten. Da er ja gerade übergelaufen ist, kann kein Low-Byte-Überlauf 
während des Ladens passieren.
Du könntest aber auch T2 nehmen.

Nur wenige 8051 können auch ein 16-Bit Autoreload für T0/T1, z.B. 
AT89LP4052.


Peter

von router (Gast)


Lesenswert?

kannst du mal einen schaltplan posten, wie du die matrix angeschlossen / 
getrieben hast? das macht es uns einfacher zu erkennen, was an den ports 
anliegen muss.

von dude123 (Gast)


Lesenswert?

Also Z= Die Steuerung der Zeilen
SG= Spalten Grün
SR= Spalten Rot
auf der Spalte muss eine 1 sein und auf der Zeile eine null
mein Primärziel ist es wie gesagt erst einmal ein 2D-array auszugeben,
später dann 3D-array also grün und rot in der dritten dimension, für 
vier gewinnt hald, das ich im main code alles auf ein array speicher 
kann, dies dann ausgebe und auch im array die gewinnabfrage machen soll, 
habe bisher keine andere idee wie ich 4-gewinnt programmieren soll


---------------------                  ----------------------
                     |                 |                    |
     2-Farbige       |                 | Atmel              |
  LED- Matrix  6x8   |                 | Mikrocontroller    |
                     |                 | AT89C5131A         |
  __   ___   __    |                 |  __   ___   __   |
 |Z  | |SG | |SR |   |                 | |P0 | |P1 | |P2 |  |
   |      |    |     |                 |   |     |     |    |
   |      |    |     |                 |   |     |     |    |
   |      |    |     |                 |   |     |     |    |
---|------|----|-----                  ----|-----|-----|----
   |      |    |                           |     |     |
   |      |     ---------------------------|-----      |
   |      |                                |           |
   |      |--------------------------------|-----------
   |                                       |
   |                                       |
   ----------------------------------------

von router (Gast)


Lesenswert?

Wie Holger am 26.06.2011 / 18:58 bereits schrieb, brauchst du Spalten- 
und Zeilen-Treiber.
Zum Beispiel so:
Beitrag "LED-Matrix Treiber"

Wenn du es tatsächlich so angeschlossen hast wie in deiner Zeichnung 
(ohne Vorwiderstände & direkt an die Mikrocontroller-Pins), hast du eine 
gute Chance deinen Controller und/oder die Matrix bereits "gebraten" zu 
haben - nimm einen neuen, um kaputte Ports als Fehlerquelle 
auszuschließen.

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.