Forum: Mikrocontroller und Digitale Elektronik 7 Segment Anzeige


von Jan (Gast)


Lesenswert?

Hallo,


kleines Problem...
Bin gerade dabei meine Anzeigen zu testen.
Möchte gerne einen Counter darstellen.
Hochzählen klappt prima.

Aktuell zeigt er mir " 0 | 0 | 0 | Einer"
Also ich möchte die "0" en ausmaskieren solange der Wert noch nicht 
ereicht ist (aus lassen).

Tue mir da gerade etwas schwer mit...
Was muss ich noch Einfügen?
1
/*
2
 * _7_Segment_Counter.c
3
 *
4
 * Created: 30.09.2015 15:27:52
5
 *  Author:
6
 */ 
7
8
#define F_CPU 8000000
9
10
#include <avr/io.h>
11
#include <util/delay.h>
12
#include <avr/interrupt.h>
13
14
#define STATE_LED_RED_ON    PORTA |=  (1<<PA0)
15
#define STATE_LED_RED_TOGGLE  PORTA ^=  (1<<PA0)
16
#define STATE_LED_RED_OFF    PORTA &= ~(1<<PA0)
17
18
#define STATE_LED_GREEN_ON    PORTD |=  (1<<PD2)
19
#define STATE_LED_GREEN_TOGGLE  PORTD ^=  (1<<PD2)
20
#define STATE_LED_GREEN_OFF    PORTD &= ~(1<<PD2)
21
22
const char numbers[11] = {  
23
              0b00111111, // 0
24
              0b00000110, // 1
25
              0b01011011, // 2
26
              0b01001111, // 3
27
              0b01100110, // 4
28
              0b01101101, // 5
29
              0b01111101, // 6
30
              0b00000111, // 7
31
              0b01111111, // 8
32
              0b01101111, // 9 
33
               0b00000000  // all off
34
             };  
35
            
36
volatile uint16_t VRAM = 0x0000;
37
38
39
void count_up(void);
40
41
42
int main(void)
43
{
44
  
45
  /* data pins */
46
  DDRB |= 0xFF;
47
  DDRD |= ((1<<PD6) | (1<<PD5) | (1<<PD4) | (1<<PD3) | (1<<PD2)); // data direction register for 7- segment display & transistors
48
  DDRA |= (1<<PA0); // data direction register for state led red
49
  
50
  PORTD |= (1<<PD2); // state led green on
51
  PORTA |= (1<<PA0); // state led red on
52
  
53
  /* Legt den VRAM ZUM Überlaufes fest ( ca. jede 1 Sec. ) */
54
  OCR1A   = 1350;
55
56
  /* Compare Match Interrupt enable */
57
  TIMSK  |= (1<<OCIE1A);
58
59
  /* Prescaler auf 1024 setzen (F_CPU/1024) */
60
  TCCR1B |= ((1<<CS12) | (1<<CS10) | (1<<WGM12));
61
62
  /* Erlaubt globale Interrupts */
63
  sei();
64
  
65
  
66
    while(1)
67
    {
68
      
69
70
    PORTD |= (1<<PD5);
71
    PORTB = numbers[VRAM & 0x000F];
72
    _delay_ms(4);
73
    PORTD &= ~(1<<PD5);    
74
    
75
    PORTD |= (1<<PD4);
76
    PORTB = numbers[(VRAM & 0x00F0)>>4];
77
    _delay_ms(4);
78
    PORTD &= ~(1<<PD4);  
79
    
80
    PORTD |= (1<<PD3);
81
    PORTB = numbers[(VRAM & 0x0F00)>>8];
82
    _delay_ms(4);
83
    PORTD &= ~(1<<PD3);  
84
      
85
    PORTD |= (1<<PD6);
86
    PORTB = numbers[(VRAM & 0xF000)>>12];
87
    _delay_ms(4);
88
    PORTD &= ~(1<<PD6);      
89
    }
90
}
91
92
93
ISR (TIMER1_COMPA_vect)
94
{
95
  STATE_LED_GREEN_TOGGLE;
96
  count_up();
97
}
98
99
/* count up */
100
void count_up(void)
101
{
102
  
103
   VRAM++;  
104
      
105
  if ((VRAM & 0x000F) == (0x000A))
106
  {
107
    VRAM += 0x0006;
108
  }
109
110
  if ((VRAM & 0x00F0) == (0x00A0))
111
  {
112
    VRAM += 0x0060;
113
  }  
114
  
115
  if ((VRAM & 0x0F00) == (0x0A00))
116
  {
117
    VRAM += 0x0600;
118
  }  
119
}

von Karl H. (kbuchegg)


Lesenswert?

Jan schrieb:
> Hallo,
>
>
> kleines Problem...
> Bin gerade dabei meine Anzeigen zu testen.
> Möchte gerne einen Counter darstellen.
> Hochzählen klappt prima.
>
> Aktuell zeigt er mir " 0 | 0 | 0 | Einer"
> Also ich möchte die "0" en ausmaskieren solange der Wert noch nicht
> ereicht ist (aus lassen).
>
> Tue mir da gerade etwas schwer mit...
> Was muss ich noch Einfügen?

Wie wärs mit einem if, das abfragt ob die Zahl zum Beispiel kleiner als 
0x1000 ist. Denn in diesem Fall willst du ja nicht das Muster für die 
'Tausender'-Stelle anzeigen (welches ja offensichtlich 0 wäre), sondern 
das Muster für 'all off'.


Allerdings.
Ehe du dich da jetzt drann machst, wartet noch eine Menge andere Arbeit 
auf dich (so schlimm ist es jetzt auch wieder nicht). Denn so wie das 
jetzt abläuft ist das ganze Multiplexen praktisch nicht zu gebrauchen.

Ein vernünftiger Multiplex läuft genau anders herum ab. Mit dem Timer 
steuerst du die Anzeige an und nicht dadurch, dass du in der 
Hauptschleife da einen Haufen delays einbaust.
Und zum anderen gibt es auch keinen Grund, warum du da Hexadezimal 
hochzählen sollst und da enorme Klimmzüge für den Zehner-Übertrag machen 
musst. Du hast einen COmputer. Der kann rechnen! Für den ist es kein 
Problem aus der Zahl 5638 herauszurechnen, wieviele Tausender da drinn 
enthalten sind. Die DIvision mit Rest ist schon lange erfunden.

: Bearbeitet durch User
von Jan (Gast)


Lesenswert?

Ja das mit dem Multiplexen änder ich auch noch!

Ja das mit der if klappt nicht so wie ich mir das vorstelle.


if (VRAM < 0x0009)
{
 VRAM &= 0xAAAF;
}

oder sehe ich das falsch? Das ist jetzt nur für die 1 er

von Karl H. (kbuchegg)


Lesenswert?

Jan schrieb:
> Ja das mit dem Multiplexen änder ich auch noch!
>
> Ja das mit der if klappt nicht so wie ich mir das vorstelle.
>
>
> if (VRAM < 0x0009)
> {
>  VRAM &= 0xAAAF;
> }

Wieso kleiner 0x0009.

Deine Tasuenderstelle ist 0x1000

Und du willst da auch nicht VRAM ändern. in VRAM zählst du ja. Du willst 
etwas anderes anzeigen, wenn da eigentlich eine 0 stehen sollte.

> oder sehe ich das falsch? Das ist jetzt nur für die 1 er

Bei den Einern wird aber eine 0 nicht unterdrückt.

: Bearbeitet durch User
von Jan (Gast)


Lesenswert?

Es geht nicht nur um die Tausender.
Wenn ich im einer Bereich bin soll nur die eine Stelle angezeigt werden, 
die anderen Segmente sollen dann aus sein.

von Karl H. (kbuchegg)


Lesenswert?

Karl H. schrieb:

> Wieso kleiner 0x0009.
>
> Deine Tasuenderstelle ist 0x1000
>
> Und du willst da auch nicht VRAM ändern. in VRAM zählst du ja. Du willst
> etwas anderes anzeigen, wenn da eigentlich rein rechnerisch eine 0
> stehen sollte.
1
....
2
3
    PORTD |= (1<<PD6);
4
    if( VRAM < 0x1000 )
5
      PORTB = numbers[10];
6
    else
7
      PORTB = numbers[(VRAM & 0xF000)>>12];
8
    _delay_ms(4);
9
    PORTD &= ~(1<<PD6);     
10
11
....

: Bearbeitet durch User
von Karl H. (kbuchegg)


Lesenswert?

Jan schrieb:
> Es geht nicht nur um die Tausender.

Was jetzt.
Willst du führende 0-en unterdrücken oder nicht?

: Bearbeitet durch User
von Jan (Gast)


Lesenswert?

Ja will ich!

von Karl H. (kbuchegg)


Lesenswert?

Jan schrieb:
> Ja will ich!

Na dann

Führende 0-en fangen nun mal in der Tausender Stelle an.
Natürlich gibt es sie auch in der Hunderter Stelle und in der Zehner 
Stelle. Diese Erweiterung für diese Stellen ist als Übung für den 
Lernenden gelassen. Ist genau das gleiche Prinzip

Wenn dein VRAM kleiner als 0x0100 ist, dann wird in der Hunderter STelle 
nichts ausgegeben, andernfalls das Muster welches zu dieser Ziffer 
gehört.

Wenn VRAM kleiner als 0x0010 ist, dann wird in der Zehner Stelle nichts 
ausgegeb, andernfalls das Muster welches zu dieser Ziffer gehört.

Beachte. Wenn die Zahl kleiner als 0x0100 ist, dann ist sie damit auch 
automatisch kleiner als 0x1000. Wenn also die Hunderter unterdrückt 
werden, dann werden damit auch bei der Bewertung der Tausender diese 
ebenfalls unterdrückt.

: Bearbeitet durch User
von Jan (Gast)


Lesenswert?

Perfekt. Funktioniert!
Besten dank.

von 6a66 (Gast)


Lesenswert?

Jan schrieb:
> Es geht nicht nur um die Tausender.
> Wenn ich im einer Bereich bin soll nur die eine Stelle angezeigt werden,
> die anderen Segmente sollen dann aus sein.

Vorschlag:
Wenn Du führende Nullen unterdrücke willst dann fange doch von oben an:

if (VRAM >= 1000)
   "display digit"
else
   "display nothing"
delay 4ms;

// next digit
if (VRAM > 100)
...

rgds

von Karl H. (kbuchegg)


Lesenswert?

Jan schrieb:
> Perfekt. Funktioniert!
> Besten dank.

Gut.
Dann den Multiplex entsprechend umbauen.

Zusätzlich führst du dir noch ein Array mit 4 Elementen ein, in welchem 
das Muster gespeichert wird, das an der jeweiligen Stelle auszugeben 
ist.

dein main soll am Ende so aussehen
1
const uint8_t numbers[11] = {  
2
              0b00111111, // 0
3
              0b00000110, // 1
4
              0b01011011, // 2
5
              0b01001111, // 3
6
              0b01100110, // 4
7
              0b01101101, // 5
8
              0b01111101, // 6
9
              0b00000111, // 7
10
              0b01111111, // 8
11
              0b01101111, // 9 
12
               0b00000000  // all off
13
             };  
14
15
volatile uint8_t muster[4];
16
....
17
18
void output( uint16_t zahl )
19
{
20
.... zahl zerlegen, muster[] entsprechend befüllen
21
}
22
23
int main()
24
{
25
  uint16_t cnt;
26
   ....
27
28
29
   while( 1 )
30
   {
31
     cnt++;
32
     output( cnt );
33
34
     _delay_ms( 500 );
35
   }
36
}

die Funktion output (die du schreiben musst), zerlegt die Zahl in die 
Tausender, Hunderter, Zehner und Einer und schreibt die jeweils 
auszugebenden Muster in das globale Muster Array. Die Timergetrieben 
Interrupt Funktion gibt reihum die so hinterlegten Muster aus. D.h. 
während des eigentlichen Bedienens der Anzeige, interessiert sich die 
Interrupt Funktion nicht mehr dafür, was die Muster bedeuten, die sie an 
die LED anlegt. Die schaufelt einfach nur die Muster genau so auf die 
Anzeige, wie sie im Muster Array stehen. (und macht das ganze natürlich 
ohne delays)

: Bearbeitet durch User
von Jan (Gast)


Lesenswert?

Das mit dem neuen Muster Array...
Spart das an Leistung ein?

von Karl H. (kbuchegg)


Lesenswert?

Jan schrieb:
> Das mit dem neuen Muster Array...
> Spart das an Leistung ein?


erstens das.
Zweitens soll deine Anzeige ja ständig laufen, ohne dass du dir im 
Hauptprogramm (also dort wo dann die eigentliche Arbeit gemacht wird) 
dauernd den Kopf darüber zerbrechen willst, wie du eine Zahl auf die 
Anzeige kriegst.
Du kriegst einen Zahlenwert von irgendwo her, zum Bleistift vom ADC, 
rufst damit die Funktion output auf und dann steht sie auch schon auf 
der Anzeige.
1
....
2
3
  while( 1 )
4
  {
5
    wert = ADC_read( 0 );
6
    output( wert );
7
  }

Du willst dich ja auf deine eigentliche Berechnung bzw. Aufgabe 
konzentrieren und nicht um so Nebensächlichkeiten wie eine 7-Segment 
Anzeige.

und drittens.
Wer sagt denn, dass immer Zahlen auf der Ausgabe sein müssen. Man kann 
ja auch zum Bleistift einen Fehler damit anzeigen, dass die Anzeige 
lauter '-' anzeigt. Einfach das Muster für '-' in die 4 Stellen des 
Muster Arrays schreiben und die Interrupt Routine zeigt auch das brav 
an.

: Bearbeitet durch User
von Jan (Gast)


Lesenswert?

[c]
void display(uint16_t value)
{
  uint16_t result_tmp;

  result_tmp = value / 1000;
  sample[0] = result_tmp;

  result_tmp = value / 100;
  sample[1] = result_tmp;

  result_tmp = value / 10;
  sample[2] = result_tmp;

}
[\c]

so in etwa das zerlegen?

von Karl H. (kbuchegg)


Lesenswert?

Jan schrieb:
> [c]
> void display(uint16_t value)
> {
>   uint16_t result_tmp;
>
>   result_tmp = value / 1000;
>   sample[0] = result_tmp;
>
>   result_tmp = value / 100;
>   sample[1] = result_tmp;
>
>   result_tmp = value / 10;
>   sample[2] = result_tmp;
>
> }
> [\c]
>
> so in etwa das zerlegen?

fast. probiers halt mal mit konkreten Zahlen durch.

value sei zum Bleistift 5634. Die einzelnen Stellen müssen also 5, 6, 3, 
und 4 sein.
1
result_tmp = value / 1000;

5634 / 1000 ergibt  5
1
result_tmp = value / 100;
5634 / 100 ergibt 56. Da sollte aber 6 rauskommen.
1
result_tmp = value / 10;
5634 / 10 ergibt 563. Da sollte aber 3 rauskommen.


Was dir fehlt, das ist der % Operator. Das ergibt den Rest bei einer 
Division. So wie du das in der Grundschule gelernt hast. Eine Mutter hat 
5 Kinder und 13 Äpfel. Wenn jedes Kind gleich viele Äpfel bekommt, 
wieviele Äpfel kriegt es dann und wieviele bleiben der Mutter übrig?

13 / 5 ergibt 2. Jedes Kind kriegt 2 Äpfel
13 % 5 ergibt 3. Und der Mutter bleiben 3 Äpfel übrig.

Probe. 5*2 + 3 ergibt wieder die 13

was also ergibt
32 / 10
32 % 10

und was hat das mit den Stellen der Dezimalzahl 32 zu tun?

von Jan (Gast)


Lesenswert?

Karl H. schrieb:
> was also ergibt
> 32 / 10
> 32 % 10

32/ 10 = 3

3,2 % 10 = 2

von Karl H. (kbuchegg)


Lesenswert?

Jan schrieb:
> Karl H. schrieb:
>> was also ergibt
>> 32 / 10
>> 32 % 10
>
> 32/ 10 = 3
>
> 32 % 10 = 2

genau. Das hat also die Zahl 32 in 3 und 2 zerlegt.

Jetzt hast du aber nicht eine 2 stellige Zahl sondern zb 846.
Wie stellst du es jetzt an, die in die Ziffern 8 4 und 6 zu zerlegen?

846 / 100   ergibt 8
846 % 100  ergibt 46  (denn 8*100 + 46 ergibt wieder die 846)

46 / 10   ergibt  4
46 % 10   ergibt  6

da sind sie. 8, 4 und 6

Jetzt das ganze mit 4 stelligen Zahlen. Zu zerlegen ist 9625

??

: Bearbeitet durch User
von Paul B. (paul_baumann)


Lesenswert?

Karl H. schrieb:
> Willst du führende 0-en unterdrücken oder nicht?

Jan schrieb:
> Ja will ich!

Wir sind in Deutschland -da werden führende Nullen nicht 
unterdrückt...!

MfG Paul

von Jan (Gast)


Lesenswert?

3291

3291 / 1000 = 3,291
3291 % 1000 = 291

291 / 100 = 2,91
291 % 100 = 91

91 / 10 = 9,1
91 % 10 = 1

so richtig ?

von Jan (Gast)


Lesenswert?

so?

  uint16_t result_tmp[6];

  result_tmp[0] = value / 1000;
  result_tmp[1] = value % 1000;

  result_tmp[2] = result_tmp[1] / 100;
  result_tmp[3] = result_tmp[2] % 100;

  result_tmp[4] = result_tmp[3] / 10;
  result_tmp[5] = result_tmp[4] % 10;

von Karl H. (kbuchegg)


Lesenswert?

Jan schrieb:
> 3291
>
> 3291 / 1000 = 3,291

vergiss bitte hier die Nachkommastellen. IN deinem Programm werden sie 
nie erzeugt. Wenn du einen int durch einen anderen int dividierst, dann 
ist das Ergebnis wieder ein int. Also eine ganze Zahl

> so richtig ?

Jep.
Jetzt das ganze in Codeform.

von Karl H. (kbuchegg)


Lesenswert?

Jan schrieb:
> so?
>
>   uint16_t result_tmp[6];
>
>   result_tmp[0] = value / 1000;
>   result_tmp[1] = value % 1000;
>
>   result_tmp[2] = result_tmp[1] / 100;
>   result_tmp[3] = result_tmp[2] % 100;
>
>   result_tmp[4] = result_tmp[3] / 10;
>   result_tmp[5] = result_tmp[4] % 10;

IM Prinzip: ja.
Aber da braucht es kein 6-er Array.
Du brauchst genau einen uint16_t um das 'zwischenergebnis' nach der 
Modulo-Division (=Rest) zwischenzuspeichern und um damit weiter zu 
rechnen. Es ist nicht verboten Variablen auch mehrmals zu beschreiben, 
wenn man ihren Wert nicht mehr weiter benötigt.
1
uint16_t tmp;
2
3
  stelle[0] = value / 1000;
4
  tmp = value % 1000;
5
6
  stelle[1] = tmp / 100;
7
  tmp = tmp % 100;
8
9
  stelle[2] = tmp / 10;
10
  stelle[3] = tmp % 10;

: Bearbeitet durch User
von Jan (Gast)


Lesenswert?

1
/*
2
 * _7_Segment_Counter.c
3
 *
4
 * Created: 30.09.2015 15:27:52
5
 *  Author: Hm
6
 */ 
7
8
#define F_CPU 8000000
9
10
#include <avr/io.h>
11
#include <util/delay.h>
12
#include <avr/interrupt.h>
13
14
#define STATE_LED_RED_ON    PORTA |=  (1<<PA0)
15
#define STATE_LED_RED_TOGGLE  PORTA ^=  (1<<PA0)
16
#define STATE_LED_RED_OFF    PORTA &= ~(1<<PA0)
17
18
#define STATE_LED_GREEN_ON    PORTD |=  (1<<PD2)
19
#define STATE_LED_GREEN_TOGGLE  PORTD ^=  (1<<PD2)
20
#define STATE_LED_GREEN_OFF    PORTD &= ~(1<<PD2)
21
22
const char numbers[11] = {  
23
              0b00111111, // 0
24
              0b00000110, // 1
25
              0b01011011, // 2
26
              0b01001111, // 3
27
              0b01100110, // 4
28
              0b01101101, // 5
29
              0b01111101, // 6
30
              0b00000111, // 7
31
              0b01111111, // 8
32
              0b01101111, // 9 
33
               0b00000000  // all off
34
             };  
35
             
36
volatile uint8_t sample[4];
37
            
38
volatile uint16_t VRAM = 0x0000;
39
volatile uint8_t state = 0x00;
40
41
void count_up(void);
42
void display(uint16_t value);
43
44
45
int main(void)
46
{
47
  
48
  /* data pins */
49
  DDRB |= 0xFF;
50
  DDRD |= ((1<<PD6) | (1<<PD5) | (1<<PD4) | (1<<PD3) | (1<<PD2)); // data direction register for 7- segment display & transistors
51
  DDRA |= (1<<PA0); // data direction register for state led red
52
  
53
  PORTD |= (1<<PD2); // state led green on
54
  PORTA |= (1<<PA0); // state led red on
55
  
56
  /* Legt den VRAM ZUM Überlaufes fest ( ca. jede 1 Sec. ) */
57
  OCR1A   = 350;
58
59
  /* Compare Match Interrupt enable */
60
  TIMSK  |= (1<<OCIE1A);
61
62
  /* Prescaler auf 1024 setzen (F_CPU/1024) */
63
  TCCR1B |= ((1<<CS12) | (1<<CS10) | (1<<WGM12));
64
65
  /* Erlaubt globale Interrupts */
66
  sei();
67
  
68
    while(1)
69
    {
70
    display(1234);
71
      
72
73
    PORTD |= (1<<PD5);
74
    PORTB = numbers[sample[0] & 0x000F];
75
    _delay_ms(4);
76
    PORTD &= ~(1<<PD5);    
77
    
78
    PORTD |= (1<<PD4);
79
    if( VRAM < 0x0010 )
80
    PORTB = numbers[10];
81
    else
82
    PORTB = numbers[(sample[1] & 0x00F0)>>4];
83
    _delay_ms(4);
84
    PORTD &= ~(1<<PD4);  
85
    
86
    PORTD |= (1<<PD3);
87
    if( VRAM < 0x0100 )
88
    PORTB = numbers[10];
89
    else
90
    PORTB = numbers[(sample[2] & 0x0F00)>>8];
91
    _delay_ms(4);
92
    PORTD &= ~(1<<PD3);  
93
      
94
    PORTD |= (1<<PD6);
95
    if( VRAM < 0x1000 )
96
    PORTB = numbers[10];
97
    else
98
    PORTB = numbers[(sample[3] & 0xF000)>>12];
99
    _delay_ms(4);
100
    PORTD &= ~(1<<PD6);    
101
    }
102
}
103
104
105
ISR (TIMER1_COMPA_vect)
106
{
107
  STATE_LED_GREEN_TOGGLE;
108
  count_up();
109
}
110
111
/* count up */
112
void count_up(void)
113
{
114
115
//   VRAM++;
116
//     
117
//   if ((VRAM & 0x000F) == (0x000A))
118
//   {
119
//     VRAM += 0x0006;
120
//   }
121
// 
122
//   if ((VRAM & 0x00F0) == (0x00A0))
123
//   {
124
//     VRAM += 0x0060;
125
//   }
126
//     
127
//   if ((VRAM & 0x0F00) == (0x0A00))
128
//   {
129
//     VRAM += 0x0600;
130
//   }
131
//   
132
//   if (VRAM == 0x9999)
133
//   {
134
//     VRAM = 0x0000;
135
//   }
136
137
}
138
139
void display(uint16_t value)
140
{
141
  uint16_t tmp;
142
143
  sample[0] = value / 1000;
144
  tmp = value % 1000;
145
146
  sample[1] = tmp / 100;
147
  tmp = tmp % 100;
148
149
  sample[2] = tmp / 10;
150
  sample[3] = tmp % 10;
151
  
152
}


sieht das so richtig aus?

von Karl H. (kbuchegg)


Lesenswert?

Jan schrieb:

> sieht das so richtig aus?

Nein.
1
    PORTB = numbers[(sample[2] & 0x0F00)>>8];

In stelle[2] steht ja schon der korrekte INdex in das numbers Array. Das 
steht ja bei 8763 schon die 6 drinnen!
1
    PORTB = numbers[sample[2]];

für die anderen sinngemäss gleich.

: Bearbeitet durch User
von Karl H. (kbuchegg)


Lesenswert?

PS: wir sind mit dem Umbau noch lange nicht fertig.
Aber mir gefällt, wie dau das Stück für Stück machst. Am Ende werden wir 
trotzdem beim Ziel angekommen sein. Und gerade deswegen wirst du auch 
jeden Zwischenschritt und auch das Endergebnis verstehen

von Karl H. (kbuchegg)


Lesenswert?

Und ach ja.
Das hab ich vergessen. Deine führende 0-Unterdrückung arbeitet momentan 
noch nicht richtig. Also wieder raus damit. Die kommt im übernächsten 
Schritt wieder rein (aber an einer anderen Stelle)

: Bearbeitet durch User
von Peter D. (peda)


Lesenswert?

Jan schrieb:
> Das mit dem neuen Muster Array...
> Spart das an Leistung ein?

Aber hallo, ganz gewaltig.
Damit es nicht flackert muß man mit 100Hz oder mehr multiplexen. Kein 
Mensch kann aber 100 Werte/s ablesen und da wäre es vergeudete CPU-Zeit, 
den Wert immer ständig neu zu wandeln. 2..5/s reicht völlig aus oder 
einfach nur, wenn er sich auch ändert.

von Jan (Gast)


Lesenswert?

Karl H. schrieb:
> Und ach ja.
> Das hab ich vergessen. Deine führende 0-Unterdrückung arbeitet momentan
> noch nicht richtig. Also wieder raus damit. Die kommt im übernächsten
> Schritt wieder rein (aber an einer anderen Stelle)

Das wollte ich gerade bemerken das dass noch nicht funzt.
Wo kommt die denn rein? Ich wollte das mit dem Multiplexen (Timer) 
morgen machen.
Kann ich das mit der Unterdrückung schon einbauen?

von Karl H. (kbuchegg)


Lesenswert?

Jan schrieb:
> Karl H. schrieb:
>> Und ach ja.
>> Das hab ich vergessen. Deine führende 0-Unterdrückung arbeitet momentan
>> noch nicht richtig. Also wieder raus damit. Die kommt im übernächsten
>> Schritt wieder rein (aber an einer anderen Stelle)
>
> Das wollte ich gerade bemerken das dass noch nicht funzt.
> Wo kommt die denn rein? Ich wollte das mit dem Multiplexen (Timer)
> morgen machen.
> Kann ich das mit der Unterdrückung schon einbauen?


Nein.
Die nächste Beobachtung ist nämlich, dass wir hier
1
    PORTB = numbers[sample[2]];

eigentlich viel zu viel Aufwand treiben.
wozu da jedesmal indirekt über samples[2] ins numbers Array gehen?

Im Grunde interessiert uns doch gar nicht, welchen Zahlenwert die Stelle 
hatte. Alles was wir an dieser Stelle brauchen, das ist doch nur das 
Muster, das auszugeben ist.
Dieses Muster, das kann aber auch die Funktion display gleich selbst ins 
sample-Array schreiben.
1
void display(uint16_t value)
2
{
3
  uint16_t tmp;
4
5
  sample[0] = numbers[ value / 1000 ];
6
  tmp = value % 1000;
7
8
  sample[1] = numbers[ tmp / 100 ];
9
  tmp = tmp % 100;
10
11
  sample[2] = numbers[ tmp / 10 ];
12
  sample[3] = numbers[ tmp % 10 ]; 
13
}


das ermöglicht dir an dieser Stelle
1
    PORTD |= (1<<PD5);
2
    PORTB = numbers[sample[0] & 0x000F];
3
    _delay_ms(4);
4
    PORTD &= ~(1<<PD5);

einfacher zu schreiben
1
    PORTD |= (1<<PD5);
2
    PORTB = sample[0];
3
    _delay_ms(4);
4
    PORTD &= ~(1<<PD5);

denn in sample[0] steht ja schon das LED Muster für diese Stelle 
fix&fertig aufbereitet drinnen.

: Bearbeitet durch User
von Karl H. (kbuchegg)


Lesenswert?

Karl H. schrieb:

> denn in sample[0] steht ja schon das LED Muster fix&fertig aufbereitet
> drinnen.

Und jetzt hast du auch die Code-Position, in die die Unterdrückung der 
führenden 0-en hin kommt.
Es ist die Funktion display, die entweder das jeweils korrekte Muster 
für eine Stelle ins Array schreibt, oder eben das Muster für 'keine 
LED'. Die Unterdrückung geschieht code-technisch dem Prinzip nach genau 
gleich wie vorher (nur dass du natürlich Dezimalzahlen nimmst)
1
void display(uint16_t value)
2
{
3
  uint16_t tmp;
4
5
  if( value < 1000 )
6
    sample[0] = numbers[10];   // es gibt keine Tausender, diese Position leer lassen
7
  else
8
    sample[0] = numbers[ value / 1000 ];
9
10
  tmp = value % 1000;
11
12
....

: Bearbeitet durch User
von Karl H. (kbuchegg)


Lesenswert?

Muss mich entschuldigen.
Ich war kurzzeitig in einem anderen Thread.

von Jan (Gast)


Lesenswert?

Karl H. schrieb:
> Muss mich entschuldigen.
> Ich war kurzzeitig in einem anderen Thread.

Macht nichts.
Klappt sehr gut, besten dank für das kleine Tutorial;)

von Karl H. (kbuchegg)


Lesenswert?

Jan schrieb:
> Karl H. schrieb:
>> Muss mich entschuldigen.
>> Ich war kurzzeitig in einem anderen Thread.
>
> Macht nichts.
> Klappt sehr gut, besten dank für das kleine Tutorial;)

Irgendwie musst du es ja lernen :-)
Bis jetzt soweit alles nachvollziehbar und die Gedankengänge klar?

Den Umbau auf Timer machen wir dann morgen.
Es ist jetzt nur noch ein kleiner SChritt, bis du die ANzeige insofern 
vergessen kannst, dass du einfach nur noch display aufrufen musst und 
deine Anzeige zeigt dir die Zahl. Egal was deine Hauptschleife in main 
sonst noch so treibt :-)

: Bearbeitet durch User
von Jan (Gast)


Lesenswert?

Ja, soweit alles klar. Man muss nur erstmal drauf kommen.
Welche Zeitbasis währe denn perfekt für das Multiplexen?

von Karl H. (kbuchegg)


Lesenswert?

Jan schrieb:
> Ja, soweit alles klar. Man muss nur erstmal drauf kommen.
> Welche Zeitbasis währe denn perfekt für das Multiplexen?

Peter hat es schon angesprochen.
Irgendwas so um die 100Hz. Der Wert ist nicht wirklich kritisch, solange 
er nur hoch genug ist.
(Obwohl es auch ganz reizvoll ist, erst mal mit einer kleineren Frequenz 
anzufangen. Wenn man das erste mal sieht, wie eine STelle nach der 
anderen aufleuchtet und verlöscht und dann sukzessive die 
Geschwindigkeit steigert, bis die Anzeige rock solid steht, dann erkennt 
man erst, welcher Trick da dahinter steckt und wie leicht wir Menschen 
uns doch täuschen lassen)

Hast du einen Timer 0?
Wenn ja, dann nehmen wir den dafür her. Der Timer 1 mit seinen 
vielfältigen Möglichkeiten ist dazu zu wertvoll. Welchen µC hast du 
eigentlich?

: Bearbeitet durch User
von Jan (Gast)


Lesenswert?

Habe einen TINY2313.

von Karl H. (kbuchegg)


Lesenswert?

Jan schrieb:
> Habe einen TINY2313.

Passt.
Der hat einen Timer 0.
da suchen wir uns einen Vorteiler, dass er pro Sekunde so zirka 100 mal 
seinen Wertebereich 0..255 durchläuft. Wenns 200 mal sind, ist es auch 
kein Beinbruch. Da ist genug Spielraum.

von Peter D. (peda)


Lesenswert?

Man kann das ganze aber auch C-like machen, C hat ja schon fertige 
Bibliotheken für die formatierte Zahlenausgabe.
Man muß das Fahrrad nicht nochmal erfinden.
Die Umwandlung in 7-Segment bleibt und zu beachten ist die Ausgabe 
erfolgt in ASCII, d.h. man muß noch die '0' abziehen.
1
#include <stdio.h>
2
#include <string.h>
3
4
const char numbers[] = {  
5
              0b00111111, // 0
6
              0b00000110, // 1
7
              0b01011011, // 2
8
              0b01001111, // 3
9
              0b01100110, // 4
10
              0b01101101, // 5
11
              0b01111101, // 6
12
              0b00000111, // 7
13
              0b01111111, // 8
14
              0b01101111, // 9 
15
             };
16
#define CHAR_BLANK 0
17
18
volatile uint8_t sample[4];
19
20
void valout_4digit( uint16_t val )
21
{
22
  char temp[5];                       // 4 Digits + '/0'
23
  if( val >= 10000 ){
24
    memset( sample, CHAR_BLANK, 4 );  // blank on overrange
25
    return;
26
  }
27
  sprintf( temp, "%4u", val );        // 4 digits without leading zeros
28
  for( uint8_t i = 0; i < 4; i++ ){
29
    sample[i] = (temp[i] == ' ') ? CHAR_BLANK : numbers[temp[i] - '0'];
30
                                      // convert ' ' -> CHAR_BLANK 
31
                                      // or '0' .. '9' to 7 segment
32
  }
33
}

von Karl H. (kbuchegg)


Lesenswert?

Peter D. schrieb:
> Man kann das ganze aber auch C-like machen, C hat ja schon fertige
> Bibliotheken für die formatierte Zahlenausgabe.
> Man muß das Fahrrad nicht nochmal erfinden.

Korrekt.
Ich finde es schadet aber auch nichts, wenn man sich einmal überlegt, 
wie eigentlich unser Zahlensystem funktioniert. Die Leute haben sowieso 
alle schon viel zu viel Angst vor ein bisschen rechnen.

von Jan (Gast)


Lesenswert?

Karl H. schrieb:
> Peter D. schrieb:
>> Man kann das ganze aber auch C-like machen, C hat ja schon fertige
>> Bibliotheken für die formatierte Zahlenausgabe.
>> Man muß das Fahrrad nicht nochmal erfinden.
>
> Korrekt.
> Ich finde es schadet aber auch nichts, wenn man sich einmal überlegt,
> wie eigentlich unser Zahlensystem funktioniert. Die Leute haben sowieso
> alle schon viel zu viel Angst vor ein bisschen rechnen.
1
/* Legt den TIMER0 zum Überlauf fest ( ca. jede 10 ms. ) */
2
    OCR0A   = 0x4D;            
3
 
4
/* Compare Match Interrupt enable */ 
5
    TIMSK  |= (1<<OCIE0A);                
6
     
7
/* Prescaler auf 1024 setzen (F_CPU/1024) */
8
    TCCR0B |= ((1<<CS02) | (1<<CS00));   
9
10
/* CTC */
11
    TCCR0A |= (1<<WGM01);
12
         
13
/* Erlaubt globale Interrupts */
14
    sei();

Jetzt sollte TIMER0 ca. jede 10 ms. überlaufen.
Ich finde den Weg von Karz Heinz, für den Anfang besser um alles zu 
verstehen.

von Peter D. (peda)


Lesenswert?

Jan schrieb:
> Habe einen TINY2313.

Der stammt ja noch aus der Zeit, wo Atmel-AVR mit Flash gegeizt hatte 
(AT90S2313).
Da könnte es mit printf etwas knapp werden (86% full).

Jan schrieb:
> Ich finde den Weg von Karz Heinz, für den Anfang besser um alles zu
> verstehen.

Ist es auf jeden Fall.

Meine Variante sollte nur zeigen, wie es ein langjähriger 
C-Programmierer machen würde. Die haben printf/scanf quasi schon mit der 
Muttermilch aufgesogen.

von Karl H. (kbuchegg)


Lesenswert?

Jan schrieb:

>
1
> /* Legt den TIMER0 zum Überlauf fest ( ca. jede 10 ms. ) */
2
>     OCR0A   = 0x4D;
3
> 
4
> /* Compare Match Interrupt enable */
5
>     TIMSK  |= (1<<OCIE0A);
6
> 
7
> /* Prescaler auf 1024 setzen (F_CPU/1024) */
8
>     TCCR0B |= ((1<<CS02) | (1<<CS00));
9
> 
10
> /* CTC */
11
>     TCCR0A |= (1<<WGM01);
12
> 
13
> /* Erlaubt globale Interrupts */
14
>     sei();
15
>
>
> Jetzt sollte TIMER0 ca. jede 10 ms. überlaufen.

GuMo

Da hast du dir ja eine Menge Arbeit gemacht :-)
Ich hätt einfach den nächst kleineren Vorteiler genommen, Timer im ganz 
normalen Modus, Interrupt auf Overflow.

Passt schon.
Die Interrupt Service Routine hast du schon erstellt?

von Jan (Gast)


Lesenswert?

Ja, die ist soweit vorhanden.
Jetzt brauche ich nur noch einen Intiligenten Lösungsvorschlag.

von Karl H. (kbuchegg)


Lesenswert?

Karl H. schrieb:

> Die Interrupt Service Routine hast du schon erstellt?

Ich geh mal davon aus, dass es sie schon gibt, dass die aber noch leer 
ist. Also so
1
ISR (TIMER0_COMPA_vect)
2
{
3
}

Gleich ein Wort der Warnung: Wenn du einen Interrupt frei gibst, dann 
musst du immer eine ISR dafür schreiben. Auch wenn sie leer ist.
Denn sonst kommt eine Standard-ISR ins Spiel, die den Prozessor neu 
startet.


OK. Genug des Vorgeplänkels. Welche Aufgabe hat die ISR?
Einfach. Sie soll die 7-Segment Anzeigen ansteuern.
Wie macht sie das?

Das macht sie nicht so, wie du das bisher gemacht hast, dass sie eine 
Stelle einschaltet, wartet, nächste Stelle einschaltet etc.
Sondern eine Stelle der Anzeige leuchtet, während das Programm nicht 
in der ISR ist. Die ISR hat die Aufgabe von einer gerade leuchtenden 
Stelle auf die nächste Stelle umzuschalten, die leuchten soll. Danach 
hat sie ihre Arbeit getan und ist fertig. Diese Stelle leuchtet dann, 
während das Programm irgend etwas anderes macht. Bis dann ein paar 
Millisekunden der nächste Interrupt auftritt und die ISR reihum auf die 
nächste Stelle weiterschaltet.

Der Vorteil liegt auf der Hand. Rechenzeit für die Ansteuerung der 
7-Segment Anzeige wird nur dazu benötigt um dieses Umschalten 
durchzuführen. Das aber geht schnell und vor allen Dingen: aus Sicht des 
µC mit seinen 8 Mhz ist ein Ereignis, dass nur alle 10ms eintritt 
seltener als für uns Weihnachten. In Summ braucht die Ansteuerung der 
Anzeige dadurch praktisch keine Rechenzeit mehr. Es sind weit weniger 
als ein paar Promille, die dafür draufgehen.

Zur Sache.
Die ISR muss offensichtlich wissen, welche Stelle gerade leuchtet, denn 
beim nächsten Aufruf soll ja dann 'die nächste' leuchten. 'Die nächste' 
kann ich aber nur dann feststellen, wenn ich weiss was jetzt gerade 
Sache ist und das muss ich mir irgendwo merken.
Wir brauchen also eine Variable, in der wir uns das merken, welche 
Stelle gerade drann ist.
Was hat die ISR noch zu tun?
Am Anfang schaltet sie die gerade aktive Stelle ab. Der Einfachheit 
halber schalten wir einfach ALLE Stellen ab, dann ist die jetzt gerade 
leuchtende mit Sicherheit auch dabei und wir brauchen da keine 
Fallunterscheidungen bezüglich der Portpins mit denen abgeschaltet wird.
Dann wird das Muster für die nächste Stelle auf den Port ausgegeben.
Und diese Stelle wird eingeschaltet.

Und das wars auch schon. Klingt doch gar nicht so übel.
In Code
1
volatile uint8_t sample[4];
2
uint8_t nextSample;
3
4
ISR (TIMER0_COMPA_vect)
5
{
6
  // erst mal alles aus!
7
  PORTD &= ~( (1<<PD6) | (1<<PD5) | (1<<PD4) | (1<<PD3); 
8
9
  // welches ist die nächste Stelle, die angezeigt werden soll?
10
  nextSample++;
11
  if( nextSample == 4 )
12
    nextSample = 0;
13
14
  // das zugehörige Muster auf die Ausgänge
15
  PORTB = sample[nextSample];
16
17
  // und die betreffende Stelle einschalten
18
  if( nextSample == 0 )
19
    PORTD |= (1<<PD5);
20
  else if( nextSample == 1 )
21
    PORTD |= (1<<PD4);
22
  else if( nextSample == 2 )
23
    PORTD |= (1<<PD3);
24
  else if( nextSample == 3 )     
25
    PORTD |= (1<<PD6);
26
27
  // das wars.
28
  // die Stelle leuchtet jetzt, bis die ISR vom Timer das nächste mal
29
  // aufgerufen wird. Dann wird die Stelle wieder abgeschaltet
30
  // und die nächste Stelle kommt drann und darf leuchten
31
}

Der letzte Teil, der mit dem aktivieren der nächsten Stelle, den könnte 
man noch etwas eleganter formulieren, aber so schlimm ist die Version 
auch wieder nicht.

Jetzt kannst du dein main noch aufräumen. Innerhalb der Hauptschleife 
bleibt im Grunde nichts übrig, als ein Aufruf der display Funktion und 
ev. ein _delay_ms
1
int main()
2
{
3
...
4
  Ports freischalten
5
  Timer 0 aufsetzen
6
...
7
  VRAM = 0;
8
9
  sei();
10
11
  while( 1 ) {
12
    display( VRAM );
13
    _delay_ms( 500 );
14
    VRAM++;
15
  }
16
}

Beim ersten Test wird man vielleicht nicht gleich einen Zähler machen, 
sondern erst mal eine statische Anzeige
1
int main()
2
{
3
...
4
  Ports freischalten
5
  Timer 0 aufsetzen
6
...
7
8
  display( 5678 );
9
10
  sei();
11
12
  while( 1 ) {
13
  }
14
}

aber im Grunde ist das 7-Segment Subsystem damit fertig.
Wenn es in Zukunft etwas auszugeben gibt, dann rufst du einfach display 
mit dem Zahlenwert auf und der Mechanismus dahinter kümmert sich 
eigenständig darum, dass die Zahl auf die Anzeige kommt.

Jetzt bleibt nur noch: Programm aufräumen. Alles was nicht mehr 
gebraucht wird, rauswerfen. Noch mal über die Form drüber schauen, ob 
alle Einrückungen konsistent sind und das ganze so organisieren, dass 
man auch nach 2 Monaten noch nachvollziehen kann, was da abgeht. Denn 
das nächste Projekt kommt bestimmt und es gibt keinen Grund, warum man 
da diese Anzeige Routinen nicht weiterverwenden können sollte.

von Peter D. (peda)


Lesenswert?

Karl H. schrieb:
> if( nextSample == 4 )
>     nextSample = 0;
>
>   // das zugehörige Muster auf die Ausgänge
>   PORTB = sample[nextSample];
>
>   // und die betreffende Stelle einschalten
>   if( nextSample == 0 )
>     PORTD |= (1<<PD5);
>   else if( nextSample == 1 )
>     PORTD |= (1<<PD4);
>   else if( nextSample == 2 )
>     PORTD |= (1<<PD3);
>   else if( nextSample == 3 )
>     PORTD |= (1<<PD6);

Solche if-Kaskaden macht man besser lesbar mit switch/case.

von Karl H. (kbuchegg)


Lesenswert?

Peter D. schrieb:
> Karl H. schrieb:
>> if( nextSample == 4 )
>>     nextSample = 0;
>>
>>   // das zugehörige Muster auf die Ausgänge
>>   PORTB = sample[nextSample];
>>
>>   // und die betreffende Stelle einschalten
>>   if( nextSample == 0 )
>>     PORTD |= (1<<PD5);
>>   else if( nextSample == 1 )
>>     PORTD |= (1<<PD4);
>>   else if( nextSample == 2 )
>>     PORTD |= (1<<PD3);
>>   else if( nextSample == 3 )
>>     PORTD |= (1<<PD6);
>
> Solche if-Kaskaden macht man besser lesbar mit switch/case.

Kann man machen.
Ich bevorzuge bei so wenigen Fällen die Kaskade (wenn ich kein Array 
benutzen kann). Ein switch/case zieht den Code so in die Länge oder ich 
müsste die Formatierung aufgeben (was ich normalerweise nicht will)

: Bearbeitet durch User
von Karl H. (kbuchegg)


Lesenswert?

Karl H. schrieb:

> Ich bevorzuge bei so wenigen Fällen die Kaskade (wenn ich kein Array
> benutzen kann).

Aber: Warum eigentlich nicht?
Jan ist ein wiffes Kerlchen. Ich denke, das kann ich ihm zutrauen.
Überhaupt wenn er die Herleitung kennt, was an dieser Stelle passieren 
soll.
1
volatile uint8_t sample[4];
2
uint8_t nextSample;
3
const uint8_t digitPin[4] = { (1<<PD5), (1<<PD4),(1<<PD3), (1<<PD6) };
4
5
ISR (TIMER0_COMPA_vect)
6
{
7
  // erst mal alles aus!
8
  PORTD &= ~( (1<<PD6) | (1<<PD5) | (1<<PD4) | (1<<PD3); 
9
10
  // welches ist die nächste Stelle, die angezeigt werden soll?
11
  nextSample++;
12
  if( nextSample == 4 )
13
    nextSample = 0;
14
15
  // das zugehörige Muster auf die Ausgänge
16
  PORTB = sample[nextSample];
17
18
  // und die betreffende Stelle einschalten
19
  PORTD |= digitPin[nextSample];
20
21
  // das wars.
22
  // die Stelle leuchtet jetzt, bis die ISR vom Timer das nächste mal
23
  // aufgerufen wird. Dann wird die Stelle wieder abgeschaltet
24
  // und die nächste Stelle kommt drann und darf leuchten
25
}

Es gibt also (mindestens) 3 Möglichkeiten, diesen Teil zu formulieren.
* entweder Array wie hier
* oder switch/case
1
....
2
  switch( nextSample )
3
  {
4
    case 0:
5
      PORTD |= (1<<PD5);
6
      break;
7
8
    case 1:
9
      PORTD |= (1<<PD4);
10
      break;
11
12
    case 2:
13
      PORTD |= (1<<PD3);
14
      break;
15
16
    case 3:
17
      PORTD |= (1<<PD6);
18
      break;
19
  }
20
}

* oder if Kaskade
1
  if( nextSample == 0 )
2
    PORTD |= (1<<PD5);
3
  else if( nextSample == 1 )
4
    PORTD |= (1<<PD4);
5
  else if( nextSample == 2 )
6
    PORTD |= (1<<PD3);
7
  else if( nextSample == 3 )     
8
    PORTD |= (1<<PD6);
9
}

* oder Schemata, die aus dem Zahlenwert den Portpin berechnen
* ....

Wie immer: viele Wege führen nach Rom.

: Bearbeitet durch User
von Jan (Gast)


Lesenswert?

Karl H. schrieb:
> uint8_t nextSample;

sollte dort nicht auch "volatile" stehen?

von Karl H. (kbuchegg)


Lesenswert?

Jan schrieb:
> Karl H. schrieb:
>> uint8_t nextSample;
>
> sollte dort nicht auch "volatile" stehen?

Braucht es nicht.
Die Variable wird aussliesslich in der ISR benutzt


FAQ: Was hat es mit volatile auf sich

Das Problem kann also per Definition nicht auftreten.

Was man machen sollte, ist die Variable in die ISR hineinziehen. Aber 
ich weiss nicht, wie gut dein C ist :-)
1
const uint8_t digitPin[4] = { (1<<PD5), (1<<PD4),(1<<PD3), (1<<PD6) };
2
3
ISR (TIMER0_COMPA_vect)
4
{
5
  static uint8_t nextSample;
6
7
  // erst mal alles aus
8
  ...

von Jan (Gast)


Lesenswert?

1
int main(void)
2
{
3
  
4
  /* data pins */
5
  DDRB |= 0xFF;
6
  DDRD |= ((1<<PD6) | (1<<PD5) | (1<<PD4) | (1<<PD3) | (1<<PD2)); // data direction register for 7- segment display & transistors
7
  DDRA |= (1<<PA0); // data direction register for state led red
8
  
9
  PORTD |= (1<<PD2); // state led green on
10
  PORTA |= (1<<PA0); // state led red on
11
  
12
13
  OCR0A   = 0x20;
14
15
  TIMSK  |= (1<<OCIE0A);
16
  TCCR0B |= ((1<<CS02) | (1<<CS00));
17
  TCCR0A |= (1<<WGM01);
18
19
  STATE_LED_GREEN_OFF;
20
  STATE_LED_RED_OFF;
21
22
  /* Erlaubt globale Interrupts */
23
  sei();
24
  
25
  uint16_t cnt = 0;
26
  
27
    while(1)
28
    {
29
    while(1)
30
    {
31
      if (cnt > 9999)
32
      {
33
        break;
34
      }
35
      
36
      display_7_segment(cnt++);
37
      
38
      _delay_ms(10);
39
    }
40
  }
41
}

Also mit nem delay die ganze Geschichte hoch zu zählen ist wohl nicht so 
klug, gel?

von Jan (Gast)


Lesenswert?

Doch klappt. Die "0" unterdrückung ist jetzt nur noch ein Problem.

von Jan (Gast)


Lesenswert?

Jan schrieb:
> Doch klappt. Die "0" unterdrückung ist jetzt nur noch ein Problem.

Geisterbilder sind auch vorhanden.

von Karl H. (kbuchegg)


Lesenswert?

Jan schrieb:

> Also mit nem delay die ganze Geschichte hoch zu zählen ist wohl nicht so
> klug, gel?

Ist ja nur ein Testprogramm

von Karl H. (kbuchegg)


Lesenswert?

Jan schrieb:

> Geisterbilder sind auch vorhanden.

welche Version?
Wie genau werden die einzelnen Stellen ein bzw. aus geschaltet.
Ich bin davon ausgegangen, dass eine 0 am Pin aussschaltet und eine 1 
einschaltet

von Uwe (de0508)


Lesenswert?

Hi Jan,

was versprichst Du Dir mit
1
if (cnt > 9999)
2
 {
3
  break;
4
 }
und den beiden while(true) - Schleifen ?

von Jan (Gast)


Lesenswert?

Karl H. schrieb:
> Jan schrieb:
>
>> Geisterbilder sind auch vorhanden.
>
> welche Version?
> Wie genau werden die einzelnen Stellen ein bzw. aus geschaltet.
> Ich bin davon ausgegangen, dass eine 0 am Pin aussschaltet und eine 1
> einschaltet
1
  if( nextdigit > 4 )
2
  {
3
    nextdigit = 0;
4
  }

das war das Problem.

Wie löse ich das jetzt am besten mit der "0" Unterdrückung?

von Karl H. (kbuchegg)


Lesenswert?

Jan schrieb:

>
> Wie löse ich das jetzt am besten mit der "0" Unterdrückung?

Ist doch weiter oben schon angesprochen

Das macht die Funktion display

: Bearbeitet durch User
von Karl H. (kbuchegg)


Lesenswert?

Jan schrieb:
> Karl H. schrieb:
>> Jan schrieb:
>>
>>> Geisterbilder sind auch vorhanden.
>>
>> welche Version?
>> Wie genau werden die einzelnen Stellen ein bzw. aus geschaltet.
>> Ich bin davon ausgegangen, dass eine 0 am Pin aussschaltet und eine 1
>> einschaltet
>
>
1
>   if( nextdigit > 4 )
2
>   {
3
>     nextdigit = 0;
4
>   }
5
>
>
> das war das Problem.

wenn schon, dann
1
  if( nextdigit >= 4 )
2
  {
3
    nextdigit = 0;
4
  }

denn ein Wert von 4 in nextdigit ist ja nicht zulässig.
Das Array hat nur 4 Stellen.
1
sample[0]
2
sample[1]
3
sample[2]
4
sample[3]
zähl nach. Sind  genau 4 Stück. Der höchste zulässige Index ist aber 3 
und nicht 4

von beric (Gast)


Lesenswert?

Karl H. schrieb:
> wenn schon, dann
>   if( nextdigit >= 4 )
>   {
>     nextdigit = 0;
>   }

Warum nicht einfach
1
nextdigit &= 0x3; // nimm nextdigit modulo 4

von Karl H. (kbuchegg)


Lesenswert?

beric schrieb:
> Karl H. schrieb:
>> wenn schon, dann
>>   if( nextdigit >= 4 )
>>   {
>>     nextdigit = 0;
>>   }
>
> Warum nicht einfach
>
1
> nextdigit &= 0x3; // nimm nextdigit modulo 4
2
>

Weil ich nicht Moby bin :-)

Ne, im Ernst. Wenn du dir sicher bist, dass du immer genau 4 Stellen 
hast, dann mach das. Ich schreib mir die Dinge für mich persönlich so 
um, dass ich die Anzahl der Stellen nur an einer einzigen Stelle hab und 
der Compiler den Code für eine geänderte Stallenzahl anpasst. D.h. der 
Code würde bei mir sowieso nicht so bleiben, die Konstante 4 taucht da 
mit Sicherheit in Produktionscode nicht auf. 3 Taktzyklen mehr kratzen 
mich dabei nicht wirklich.

PS: Wenn schon,dann schreib ich das so
1
  nextdigit %= 4;

Compiler sind gut darin, bei bekannten Zahlenwerten die wortwörtliche 
Operation durch etwas, was schneller geht auszutauschen.

: Bearbeitet durch User
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.