7-Segment Anzeige ansteuern

#3144107
Lesenswert?

Hallo Community!

Mir geht es darum ein 7-Segment Display mit einem ATmega8 anzusteuern. 
Das alles möchte ich in C (GCC) machen. Einzelne Zahlen darzustellen ist 
ja nicht das Problem, jedoch scheitere ich daran Variablen auszugeben. 
Also dem Controller beizubringen, welche Ziffer zu welchem Binärwert für 
PortD (da hängt das Display dran) gehört. Macht man sowas über einen 
#define-Block, mit einem Array oder noch anders? Wenn möglich sollte es 
nicht den SRAM belasten.

Weiter habe ich Probleme beim Multiplexen (Segmentweise). Wie bekomme 
ich es hin, dass er bei z.B. einer 21 die 2 "isoliert" und an erster 
Stelle anzeigt und das gleiche mit der 1 an zweiter Stelle macht?

Ich danke schon mal!

Edgar
Gast #3144154
Lesenswert?

Michael L. schrieb:
> Das Array ist ja "const", kann also nicht mehr verändert werden. Wiso
> sollte es der GCC dann ins RAM stecken?

Weil das für den Compiler einfacher ist.

Wenn man wirklich haben will daß er das Array im Flash läßt braucht man 
entsprechende "progmem" attribute.
1
    GLOBAL const uint8 PROGMEM SegTab[16] = {/* Umwandlungstabelle Wert -> Segmente  */
2
  /*  + a +    */
3
  /*  f   b    */
4
  /*  + g +    */
5
  /*  e   c    */
6
  /*  + d + p  */
7

8
  /* 0 */ SEG_a | SEG_b | SEG_c | SEG_d | SEG_e | SEG_f         ,
9
  /* 1 */         SEG_b | SEG_c                                 ,
10
  /* 2 */ SEG_a | SEG_b |         SEG_d | SEG_e |         SEG_g ,
11
  /* 3 */ SEG_a | SEG_b | SEG_c | SEG_d |                 SEG_g ,
12
  /* 4 */         SEG_b | SEG_c |                 SEG_f | SEG_g ,
13
  /* 5 */ SEG_a |         SEG_c | SEG_d |         SEG_f | SEG_g ,
14
  /* 6 */ SEG_a |         SEG_c | SEG_d | SEG_e | SEG_f | SEG_g ,
15
  /* 7 */ SEG_a | SEG_b | SEG_c                                 ,
16
  /* 8 */ SEG_a | SEG_b | SEG_c | SEG_d | SEG_e | SEG_f | SEG_g ,
17
  /* 9 */ SEG_a | SEG_b | SEG_c | SEG_d |         SEG_f | SEG_g ,
18
  /* A */ SEG_a | SEG_b | SEG_c |         SEG_e | SEG_f | SEG_g , 
19
  /* b */                 SEG_c | SEG_d | SEG_e | SEG_f | SEG_g ,
20
  /* c */                 SEG_d | SEG_e |                 SEG_g ,
21
  /* d */         SEG_b | SEG_c | SEG_d | SEG_e |         SEG_g ,
22
  /* E */ SEG_a |                 SEG_d | SEG_e | SEG_f | SEG_g ,
23
  /* F */ SEG_a |                         SEG_e | SEG_f | SEG_g ,
24
  };
25

26
        /* Zugriff auf Tabelle dann mit */
27
  j = pgm_read_byte_near(SegTab + (Akku & 0xF));
Gast #3144158
Lesenswert?

So groß sind die Arrays nicht, dass man da unbedingt vermeiden muss die 
ins RAM zu packen. Das sind nur 10 Bytes  für die Umrechnung von 0-9 in 
die Segmente. Den Speicher für die aktuelle Anzeige muss man ja ohnehin 
ins RAM ablegen, und das sind auch nur 1 Byte je Stelle.

Wenn das Array im RAM steht, wird der Zugriff in der Regel schneller und 
einfacher. Damit die Daten nicht ins Flash kommen müsste man schon 
PGM_space nutzen und dann einen umständlicheren Zugriff, weil das Flash 
einen anderen Adressbereich nutzt. Entsprechend landen bei GCC-AVR auch 
konstante Arrays normalerweise im RAM.

p.s. für ungenutztes RAM gibt es kein Geld zurück.
#3144170
Lesenswert?

Gut, dann ins RAM, das bisschen interessiert nun auch nicht...
Ich als Anfäger bin nur etwas vorsichtiger, man liest ja auch überall, 
das man ressourcensparend programmieren soll.

Die Frage mit dem Multiplexen wäre da noch, oder habe ich dort einen 
vollkommen falschen Ansatz?
#3144206
Lesenswert?

Mein Wert kommt vom ADC und wird ein bisschen umgerechnet, am Ende 
bleibt eine zweistellige Zahl.

Meine Idee gerade: Bei einem Integer wird bei einer Division immer 
abgerundet(richtig?). Also einfach den Wert durch 10 und gut ist. Also 
21 / 10 = 2,1 -> 2 wird ausgegeben und dann angezeigt.

Für die 1 dann 21 % 10 müsste doch 1 ergeben

Könnte das funktionieren?
#3144340
Lesenswert?

c-hater schrieb:
> Klar kann er das, kostet (jedenfalls bis 64k Flash) nur genau einen Takt
> mehr pro Zugriff.
nein, kann er nicht.
direkte adressierung ist nicht möglich. und ein compiler wird den teufel 
tun und die adressierung einfach so einbauen.
das ist bei harvard-architekturen prinzipbedingt so.

aber wenn dus nicht glauben willst, kann mir das egal sein. ein drittes 
mal schreiben werd ichs nicht.
lies es nach oder stirb dumm - deine sache.
Gast #3144543
Lesenswert?

edgar 339 schrieb:
> Ich als Anfäger bin nur etwas vorsichtiger, man liest ja auch überall,
> das man ressourcensparend programmieren soll.

Höre nicht auf die Angstmacher! Das sind vielfach Ratschläge (heute sind 
es Vorurteile), die im letzten Jahrhundert entstanden sind und nicht 
mehr aus den Köpfen wollen.

Als Anfänger bietet Dir ein ATmega8 unendlich viel Platz. Kümmere Dich 
zunächst um die Lösung Deines Problems. Mit zunehmender Erfahrung 
programiert man automatisch effizienter.

Zur Orientierung noch ein Beispiel, wie man ADC-Werte auf ein Display 
bekommen kann. Beitrag "7-Segm. LCD-Ansteuerung, 4-stelliges Einbaumodul, Attiny45"
AVR-GCC erzeugt 2122 Byte Code und es werden 75 Byte Ram gebraucht - 
ohne irgendwelche platzsparenden Tricksereien.

Für eine 2-stellige Anzeige würde ich kein Multiplex veranstalten. Zwei 
Schieberegister CD4094 (die CMOS-Version) direkt an die Segmente 
angeschlossen reichen aus. Statischer Betrieb: keine Treiber, keine 
Widerstände und kein Ausfall der Anzeige, falls der µC hängen bleibt, 
keine 'Geistersegmente', kein Ripple in der Versorgungsspannung, keine 
Störstrahlung (um mal selber Angst zu schüren :-), ...
Aber mache, wie Du willst.
#3144656
Lesenswert?

Danke für deine Vorschläge!
Das mit dem Angst machen ist mir auch schon aufgefallen. Bisher aber nur 
in den ganzen Schaltungen. Mindestbeschaltung der Controller 
beispielsweise. Abblockkondensatoren kann ich ja noch verstehen, aber 
Start-Up-Kondensator, oder nen externen Brown-Out-Detektor?

Ich wollte das Multiplexen, damit ich erstens lerne, wie das geht, und 
da dort noch weitere Digits dazukommen(derzeit läuft es mit 4, sollen 6 
werden).
Ein Problem fällt jetzt schon auf: die Berechnungen für die Ziffern 
dauern unterschiedlich lange, deshalb sind auch die Digits 
unterschiedlich hell. Ich werde das jetzt mit Timerinterrups machen, 
dann sollte das ja gehen.

Edgar
Gast #3144688
Lesenswert?

edgar 339 schrieb:
> Ich wollte das Multiplexen, damit ich erstens lerne, wie das geht, und

Das ist gut, mach es!

Selber hatte ich im Laufe der Zeit einige Großanzeigen (25cm 
Ziffernhöhe) gebaut, wo Multiplexen nicht mehr sinnvoll war; aktuell 
habe ich eine Schaltung vor mir, die noch mit <3V arbeitet. Auch hier 
ist die statische Ansteuerung einfacher. Deshalb mein Rat zum statischen 
Betrieb.


> unterschiedlich hell. Ich werde das jetzt mit Timerinterrups machen,
> dann sollte das ja gehen.

Muliplexen sollte man grundsätzlich per Timerinterrupt machen. Achte auf 
ein bißchen Totzeit zwischen dem Abschalten des letzten Digits und dem 
Einschalten des nächsten. Die Zeit dazwischen kann man für weitere 
Befehle nutzen, die auch im Interrupt ausgeführt werden müssen. 
Andernfalls kommt es zu den 'Geistersegmenten'. Aber das wirst Du selber 
sehen.
#3144972
Lesenswert?

So, fertig. Das Programm zählt mit Timer1 hoch und zeigt mit Timer0 an.
1
#define F_CPU 1000000UL
2
#include <avr/io.h>
3
#include <avr/interrupt.h>
4
#include <util/delay.h>
5

6
const unsigned char Ziffer[10] = {0b01000000, 0b01111001 , 0b00100100,
7
0b00110000, 0b00011001, 0b00010010, 0b00000010, 0b01111000, 0b00000000, 0b00010000};
8
int y,i;
9
short int n;
10

11
int main(void)
12
{            
13
  sei();
14
  
15
  DDRD = 0b11111111;
16
  DDRB = 0b11111111;
17
  DDRC = 0b11111111;
18
  
19
  PORTD = 0b00000000;
20
  PORTB = 0b11111111;
21
  _delay_ms(1000);
22
  PORTB = 0b00000000;
23
                  
24
  TIMSK0 |= 1<<TOIE0;          
25
  TCCR0B |= (1<<CS01);  
26
  
27
  TIMSK1 |= 1<<TOIE1;  
28
  TCCR1B = (1<<CS10);
29
    
30
    while(1)
31
    {
32
                    //Trödeln
33
    }
34
}
35

36
ISR (TIMER0_OVF_vect)
37
{
38
  PORTC=0b00100000;
39
  i++;
40
  if (i>3)
41
  {
42
    i=0;
43
  }
44
  
45
  switch (i) 
46
  {
47
    case 0:    PORTB = 0b00000000;
48
          y = n / 1000;
49
          PORTB = 0b10000000;
50
          PORTD = Ziffer[y];
51
      break;
52
    case 1:    PORTB = 0b0000000;
53
          y = n % 1000;
54
          y = y / 100;
55
          PORTB = 0b01000000;
56
          PORTD = Ziffer[y];
57
      break;
58
    case 2:    PORTB = 0b00000000;
59
          y = n % 100;
60
          y = y / 10;
61
          PORTB = 0b00000001;
62
          PORTD = Ziffer[y];
63
      break;
64
    case 3:    PORTB = 0b00000000;
65
          y = n % 10;
66
          PORTB = 0b00000010;
67
          PORTD = Ziffer[y];
68
      break;
69
  }
70
    PORTC=0b00000000;          
71
}  
72

73
ISR (TIMER1_OVF_vect)
74
{
75
  n++;
76
}

Edgar
Gast #3145041
Lesenswert?

Da hast Du ja schon mal ein Erfolgserlebnis. Das braucht man unbedingt.

Wenn Du kurze Kommentare in den Code einfügst, kann man ihn später 
einmal besser verstehen, insbesondere wenn es nicht mehr 50 sondern 5000 
Zeilen sind.
Eine Sache ist aber ganz wichtig: deklariere die Variablen i und y, die 
nur in der ISR von T0 gebraucht werden auch dort.

ISR (TIMER0_OVF_vect)
{
static uint8_t i;     // Schleifenzähler
uint16_t y;           // Hilfsvariable und Index
....

Ferner sollte erst PORTD geschrieben werden und dann PORTB, auch wenn es 
aktuell nichts auszumachen scheint.
Mit den Berechnungen in der T0-ISR hast Du ja allen Optimierungsgurus 
zunächst die kalte Schulter gezeigt :-)
Irgendwann wirst Du ein 'ausgabe_register[MAX_DIGITS]' verwenden und im 
Interrupt nur noch die betreffeden Digits indiziert ausgeben. Spätestens 
dann, wenn noch ein '-' Vorzeichen angezeigt oder die Vornullen 
unterdrückt werden sollen.
#3145271
Lesenswert?

Die Kommentare habe ich nur weg gelassen, damit es schnell geht :D
Das die immer dazu gehören habe ich schon am eigenen Leibe erfahren 
müssen...

Globale Variablen sind böse, ich weiß...
i muss aber global sein, es soll ja von Interrupt zu Interrupt erhöht 
werden, ansonsten wird es jedes mal auf 0 gesetzt, oder?

Zur Leistungsoptimierung hatte ich mir gedacht: Für jede Ziffer eigene 
Variable, und die Berechnung nur durchführen, wenn sich die anzuzeigende 
Zahl auch wirklich geändert hat.
Außerdem wollte ich noch die Berechnung außerhalb der ISR durchführen.

Danke noch für das mit den Ports, da muss man nicht lange nachdenken, um 
zu sehen das das sinnvoller ist ...aber man muss selbst erstmal drauf 
kommen...

>ausgabe_register[MAX_DIGITS]
Ich verstehe zwar noch nicht, was das wird oder soll, aber wenn ich 
soweit bin, kann ich ja wieder hier vorbeischauen :)


Ich danke dir(und natürlich auch den anderen hier) das ihr mir helfen 
wollt und hoffe, das ich das irgendwann wieder gut machen kann(wie war 
das mit Maus und Löwe?...)

Edgar
Gast #3145306
Lesenswert?

edgar 339 schrieb:
> Globale Variablen sind böse, ich weiß...

Naja, ganz sooo ist es dann auch wieder nicht - es ist nur einfach 
sinnvoll, die Variablen in der kleinstmöglichen Sichtbarkeitsebene zu 
deklarieren - d. h. in einer Funktion, wenn sie nur ein der Funktion 
gebraucht werden, oder in der Datei, wenn sie nur in der Datei gebraucht 
werden.

> i muss aber global sein, es soll ja von Interrupt zu Interrupt erhöht
> werden, ansonsten wird es jedes mal auf 0 gesetzt, oder?

Nicht, wenn Du es mit dem Schlüsselwort "static" versiehst.

>>ausgabe_register[MAX_DIGITS]
> Ich verstehe zwar noch nicht, was das wird oder soll, aber wenn ich
> soweit bin, kann ich ja wieder hier vorbeischauen :)

Der Hintergedanke ist, dass die Berechnung in der main()-Loop oder wo 
auch immer vorgenommen und in der Timer-ISR nur das Ergebnis ausgegeben 
wird. Als Variable zur Übergabe dient dann sinnvollerweise ein 
(globales) Array, das den anzuzeigenden Wert jedes Digits enthält.
#3145310
Lesenswert?

>Berechnung in der main()-Loop oder wo
>auch immer vorgenommen und in der Timer-ISR nur das Ergebnis ausgegeben
>wird

Dann habe ich ja schon aus Versehen richtig gedacht :D
Ah, jetzt ist es klar, mich hatte "Register" nur verwirrt. Hatte 
überhaupt nicht an ein Array gedacht... Danke!
Gast #3145834
Lesenswert?

Peter Dannegger schrieb:
> Die Kollektorschaltung ist schnell genug und spart obendrein den
> Bassiswiderstand.

Das ist ja nicht verkehrt, aber wer macht es denn so? :-)
Allerdings ist der Anwendungsbereich eingeschränkt, da der sinnvolle 
Versorgungsspannungsbereich bei rund 4-5V liegt. Ein 3V-Design geht 
nicht mehr, da der Spannungsabfall (Segment ca. 1,8-2,2V + 2 x Vbe ca. 
1,4V) zu groß wird. Die obere Grenze wird durch VCC des Prozessors 
begrenzt. Größere Anzeigen mit mehreren LEDs in Reihenschaltung (>=2) 
funktionieren somit auch nicht.

Auf der anderen Seite sind ca. 5µs Totzeit bei einer Multiplexfrequenz 
von 0,4 - 1kHz (>= 1ms) doch kein Thema. Die Helligkeit wird um max. 
0,5% rduziert, was überhaupt nicht negativ auffällt.

Wenn wir schon bei der Helligkeit sind: bei statischer Ansteuerung kann 
man diese bequem über ein PWM-Signal an output-enable steuern.
Ein Pluspunkt, den ich oben noch vergessen hatte :-)
#3146351
Lesenswert?

edgar 339 schrieb:
> Noch was verbesserbar? :D

zb
1
    case 0:    PORTB = 0b00000000;                  //Ziffer4 anzeigen
2
          PORTD = Ziffer[Ausgabe_Ziffern[0]];
3
          PORTB = 0b10000000;
dir ist klar, dass du dir damit den Rest vom Port B unbenutzbar machst?
1
ISR (TIMER1_OVF_vect)
2
{
3
  n++;                                //Auszugebene Zahl erhöhen
4
  Ausgabe_Ziffern[0] = n / 1000;                    //Berechnungen
5
  Ausgabe_Ziffern[1] = (n % 1000) / 100;  
6
  Ausgabe_Ziffern[2] = (n % 100) / 10;
7
  Ausgabe_Ziffern[3] = n % 10;
8
}

Die Aufsplittung eines uint16_t in die einzelnen Ziffern (und das 
bestimmen des dafür anzuzeigenden Musters) hätte sich aber wirklich eine 
eigene Funktion verdient. Sowas wird man ja schliesslich öfter brauchen.


> Werte vom ADC sein, die sich willkürlich ändern.

Eben. Du willst Werte vom ADC ausgeben. Und dafür hättest du gerne eine 
Funktion

void disp_number( uint16_t value )
{
  ...
}

welche sich um das 'schmutzige' Geschäft kümmert, alles für die 
Multiplexroutine herzurichten, so dass diese dann auch tatsächlich diese 
Zahl anzeigt.

Lass diese Umkodierung von der numerischen Ziffer in das von der Anzeige 
anzuzeigende Muster
1
    PORTD = Ziffer[Ausgabe_Ziffern[0]];
auch gleich die Funktion disp_number machen.

Zum einen muss das nicht ständig in jedem Interrupt gemacht werden, zum 
anderen soll sich die Multiplex-Funktion gar nicht darum kümmern, was 
das was du anzeigst, eigentlich darstellen soll. Wenn du in deinem 
Programm entscheidest, dass die 7-Seg Anzeige in allen 4 Stellen lauter 
'-' anzeigen soll, dann sollte das der Multiplex-Funktion aber sowas von 
egal sein. Dein Programm schreibt die entsprechenden Musterbytes in das 
Array und der Multiplex-Code in der ISR zeigt sie an.
#3146387
Lesenswert?

edgar 339 schrieb:
> Ok, Danke!
>
> PortB brauche ich nicht,

:-)
kennst du die Kategorie: Berühmte letzte Worte?

> PortB |= 1 << [0/1/was auch immer] wäre
> natürlich besser.

Nicht nur "wäre". Es ist in Summe auch einfacher und universeller. 
Solche Basis-Sachen richtet man sich einmalig ordentlich her, so dass 
man sie die nächsten 10 Jahre in x Projekten benutzen kann, ohne dauernd 
das Rad neu erfinden zu müssen.
1
#define SEGMENT_PORT PORTD
2
#define DIGIT_PORT   PORTB
3

4
#define DIGIT_0     (1<<PB7)
5
#define DIGIT_1     (1<<PB6) 
6
#define DIGIT_2     (1<<PB0) 
7
#define DIGIT_1     (1<<PB1) 
8

9
#define ALL_DIGITS  DIGIT_0 | DIGIT_1 | DIGIT_2 | DIGIT_3
10

11

12
const uint8_t Ziffer[] = {
13
    0b01000000, 0b01111001,    // 0  1
14
    0b00100100, 0b00110000,    // 2  3
15
    0b00011001, 0b00010010,    // 4  5
16
    0b00000010, 0b01111000,    // 6  7
17
    0b00000000, 0b00010000     // 8  9
18
};
19

20

21
uint8_t digits[4]       = {DIGIT_0, DIGIT_1, DIGIT_2, DIGIT_3 };
22
volatile uint8_t digitPattern[4];
23

24

25
ISR( ... )
26
{
27
  static uint8_t digitNr = 0;
28

29
  DIGIT_PORT &= ~(ALL_DIGITS);        // alles aus
30

31
  digitNr++;                     // welches ist die nächste Anzeige die
32
  if( digitNr == 4 )             // leichten soll?
33
    digitNr = 0;
34

35
  SEGMENT_PORT = digitPattern[digitNr]; // Muster raus
36
  DIGIT_PORT |= digits[digitNr];      // ... und einschalten
37
}
38

39

40
void disp_number( uint16_t value )
41
{
42
  uint8_t i;
43

44
  for( i = 0; i < 4; ++i ) {
45
    digitPattern[3-i] = Ziffer[ value % 10 ];
46
    value /= 10;
47
  }
48
}
Gast #3146423
Lesenswert?

Zu Deiner T0-ISR:
Lösche bitte ganz zu Anfang alle Segmente und den zuletzt aktiven 
Digit-Treiber (hatte Karl-Heinz ja schon gezeigt). Danach mach mit
i++; .... weiter.
Dadurch erhälst Du automatisch eine Totzeit zwischen den Digits.
Als nächstes könntest Du probieren, die Vornullen zu unterdrücken, dass 
anstatt "0000" nun "   0", oder statt "0123" dann " 123" angezeigt wird.

Wenn Du ein bißchen mutiger bist, setze den CPU-Takt ruhig auf 8MHz :-)
#3147588
Lesenswert?

So, langes Wochenende :3

So, ich habe die Zeit sinnvoll genutzt und den Code umgeschrieben. Die 
Vornullen werden unterdrückt, indem erst abgefragt wird, ob ganz links 
eine 0 steht. Falls ja wird dieses Digit mit Ziffer[10] belegt, was 
nichts anzeigt. Nun wird abgefragt ob die zweite Stelle eine 0 ist. Wenn 
ja, dann wird nachgesehen, ob die vorherige Stelle unterdrückt wurde, um 
nicht Nullen in der Zahl zu unterdrücken(soll ja vorkommen). Das geht 
dann immer so weiter.
Ich habe auch schon überlegt, das in einer for-schleife zu machen, 
jedoch gab es da große Komplikationen und ich wollte, bevor ich weiter 
überlege erst einmal wissen, ob der Ansatz richtig ist.

Des weiteren wird "EEEE" ausgegeben, wenn die Zahl höher ist als 9999. 
Das wird am Anfang der Berechnungen durchgeführt.

Fragen die ich noch direkt habe:
1. Ist die Schleife notwendig, oder gibt es einen Weg, gleich mehreren 
Stellen eines Arrays den gleichen Wert zuzuweisen(Ziffer[0,1,2,3] mag 
der Compiler nicht)?

2. Wie ist die Null-Unterdrückung zu verbessern(Schleife?)?

Ich danke nochmals!

Edgar
Angehängte Dateien:
#3147594
Lesenswert?

Ähm, ich habe gerade bemerkt, dass nicht EEEE ausgegeben wird, sondern 
er wieder neu anfängt zu zählen. Zumindest beim erstem mal, bei den 
nächsten flackert er wieder, weil er über das Array hinausschießt.
Das kann ich mir irgendwie nicht erklären... Naja, ich werde noch mal 
nachsehen.

Edgar
#3147627
Lesenswert?

> uint8_t Ausgabe_Ziffern[4]  ;

>     for (i=0; i<5; i++)
                ***
>    {
>      Ausgabe_Ziffern[i] = Ziffer[11];
>    }


Ein Array der Länge 4 hat die Indizes
 0, 1, 2, 3
das sind 4 Stück ... zähl nach. Und der höchste gültige Index ist 3. 
Also 1 weniger als die Arraylänge.

eine Schleife
>     for (i=0; i<5; i++)
durchläuft den Schleifenkörper mit Werten in i von

   0, 1, 2, 3, 4

nach der nächsten Erhöhung von i wäre i dann 5 und für 5 gilt dann i < 5 
nicht mehr und die Schleife bricht ab.
Aber:
Innerhalb der Schleife greifst du daher auf
    Ausgabe_Ziffern[0], Ausgabe_Ziffern[1], Ausgabe_Ziffern[2],
    Ausgabe_Ziffern[3] und Ausgabe_Ziffern[4]
zu.
Nur: Ein Ausgabe_Ziffern[4] existiert nicht! Der höchste zulässige Index 
war 3!
#3150551
Lesenswert?

Ich sollte auch zurück schreiben, wenn ich das Problem gelöst habe und 
nich erst Tage warten...

Das Problem liegt auf der Hand: er stellt es schön auf "EEEE" ein ... um 
danach wie üblich alles für die Ziffern zu berechnen und Mist 
auszugeben...
Deshalb habe den Rest nach der for-Schleife in Klammern eines else 
gesteckt.

Edgar

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren