Forum: Mikrocontroller und Digitale Elektronik BCD auf C: was mache ich falsch?


von Maxim B. (max182)


Lesenswert?

Guten Tag,
ich bitte um Hilfe:
um besser C zu verstehen, habe ich eine Testschaltung gemacht: ATmega88 
kommuniziert mit MAX7219. Problem ist folgendes:
wenn die Ziffer 3 von 0 bis 7 ist, ist alles OK. Wenn aber 8 oder 9, 
bekomme ich in Ziffer 4-7 statt zu erwartenden Ziffer nur "FFFF".
Hier ist C-Text von BCD-Funktion (ich denke, das Problem liegt hier):
1
unsigned long preobras_bin10bcd3(unsigned long a) 
2
 {
3
  unsigned char ziff1 = 0;
4
  unsigned char ziff2 = 0;
5
  unsigned char ziff3 = 0;
6
  unsigned char ziff4 = 0;
7
  unsigned char ziff5 = 0;
8
  unsigned char ziff6 = 0;
9
  unsigned char ziff7 = 0;
10
  unsigned char ziff8 = 0;
11
  unsigned long c = 0;
12
  unsigned long b = 0;
13
14
  while(a>=10000000)
15
    {
16
      ziff1++;
17
      a-=10000000;
18
    }
19
  while(a>=1000000)
20
    {
21
      ziff2++;
22
      a-=1000000;
23
    }
24
  while(a>=100000)
25
    {
26
      ziff3++;
27
      a-=100000;
28
    }
29
  while(a>=10000)
30
    {
31
      ziff4++;
32
      a-=10000;
33
    }
34
  while(a>=1000)
35
    {
36
      ziff5++;
37
      a-=1000;
38
    }
39
  while(a>=100)
40
    {
41
      ziff6++;
42
      a-=100;
43
    }
44
  while(a>=10)
45
    {
46
      ziff7++;
47
      a-=10;
48
    }
49
  ziff8 = (a & 0x0000000f);
50
  ziff7 = (ziff7 & 0x0f);
51
  ziff6 = (ziff6 & 0x0f);
52
  ziff5 = (ziff5 & 0x0f);
53
  ziff4 = (ziff4 & 0x0f);
54
  ziff3 = (ziff3 & 0x0f);
55
  ziff2 = (ziff2 & 0x0f);
56
  ziff1 = (ziff1 & 0x0f);
57
58
59
  b = (ziff5<<12)|(ziff6<<8)|(ziff7<<4)|(ziff8);
60
  c = (ziff1<<12)|(ziff2<<8)|(ziff3<<4)|(ziff4);
61
  b |= (c<<16);
62
63
  return b;
64
}
Zuerst habe ich am Ende statt
1
  b = (ziff5<<12)|(ziff6<<8)|(ziff7<<4)|(ziff8);
2
  c = (ziff1<<12)|(ziff2<<8)|(ziff3<<4)|(ziff4);
3
  b |= (c<<16);

so geschrieben:
1
 b = (ziff1<<28)|(ziff2<<24)|(ziff3<<20)|(ziff4<<16)|(ziff5<<12)|(ziff6<<8)|(ziff7<<4)|(ziff8);

Aber Compiler sagte, ich bin aus dem zulässigen Bereich.
Ich habe vieles ausprobiert, kapiere aber noch nicht...

Diese Variante gibt allerdings richtige Ergebnis:
1
unsigned long preobras_bin10bcd3(unsigned long a) 
2
 {
3
  unsigned long b = 0;
4
  while(a>=10000000)
5
    {
6
      b = b + 0x10000000;
7
      a-=10000000;
8
    }
9
  while(a>=1000000)
10
    {
11
      b = b + 0x01000000;
12
      a-=1000000;
13
    }
14
  while(a>=100000)
15
    {
16
      b = b + 0x00100000;
17
      a-=100000;
18
    }
19
  while(a>=10000)
20
    {
21
      b = b + 0x00010000;
22
      a-=10000;
23
    }
24
  while(a>=1000)
25
    {
26
      b = b + 0x00001000;
27
      a-=1000;
28
    }
29
  while(a>=100)
30
    {
31
      b = b + 0x00000100;
32
      a-=100;
33
    }
34
  while(a>=10)
35
    {
36
      b = b + 0x00000010;
37
      a-=10;
38
    }
39
  while(a>=1)
40
    {
41
      b = b + 0x00000001;
42
      a-=1;
43
    }
44
  return b;
45
}

Wo liegt das Problem?
Vielen Dank im voraus!

: Bearbeitet durch User
von Peter D. (peda)


Lesenswert?

Wozu soll das ganze Rumgeschiebe gut sein?
Du hast 8 Ziffern und der MAX7219 braucht 8 Ziffern.
Mit packed BCD kann der nix anfangen.

von Stefan E. (sternst)


Lesenswert?

Maxim B. schrieb:
> wenn die Ziffer 3 von 0 bis 7 ist, ist alles OK. Wenn aber 8 oder 9,
> bekomme ich in Ziffer 4-7 statt zu erwartenden Ziffer nur "FFFF".

Glaube ich dir nicht so recht. Das Problem sollte bei Ziffer 5 (wenn 8 
oder 9) auftauchen, nicht bei Ziffer 3.

Grund:
1
  b = (ziff5<<12)|(ziff6<<8)|(ziff7<<4)|(ziff8);
hier wird die rechte Seite in signed int gerechnet und dementsprechend 
findet eine Sign-Extension statt beim Zuweisen an b.

von Falk B. (falk)


Lesenswert?

@ Maxim Burtsev (Firma: BBO-Potsdam) (max182)

>Hier ist C-Text von BCD-Funktion (ich denke, das Problem liegt hier):

Das Problem liegt vor deiner Tastatur. 8-0

Schon mal was von Schleifen und Arrays gehört?

Mach lieber erstmal einen Test mit konstanten Daten, um zu prüfen ob 
deine SPI-Ansteuerung OK ist. DANN kannst du dein bin2bcd Routine 
testen.

von Falk B. (falk)


Lesenswert?

@ Stefan Ernst (sternst)

>  b = (ziff5<<12)|(ziff6<<8)|(ziff7<<4)|(ziff8);

>hier wird die rechte Seite in signed int gerechnet

INT ist aber nicht long! Zumindest nicht auf deinem Compiler (avr gcc?)

>und dementsprechend findet eine Sign-Extension statt beim Zuweisen an b.

Nö. Eher so.

>  b = ((long)ziff5<<12)|((long)ziff6<<8)|((long)ziff7<<4)|((long)ziff8);

von Stefan E. (sternst)


Lesenswert?

Falk B. schrieb:
> INT ist aber nicht long! Zumindest nicht auf deinem Compiler (avr gcc?)
>
>>und dementsprechend findet eine Sign-Extension statt beim Zuweisen an b.
>
> Nö. Eher so.
>
>>  b = ((long)ziff5<<12)|((long)ziff6<<8)|((long)ziff7<<4)|((long)ziff8);

Wie kommst du darauf, dass die rechte Seite in long gerechnet würde?
Bei seinem Code wird sie in int gerechnet.

von Falk B. (falk)


Lesenswert?

Man beachte Table 4, Decode Mode Register.

von Maxim B. (max182)


Lesenswert?

Danke an alle!
Mit SPI und mit MAX7219 gibt es kein Problem, das habe ich mit anderen 
Tests festgestellt.
Auf die in MAX7219 eingebaute Möglichkeit, 7-segm- Decoder zu nutzen, 
verzichte ich aus zwei Gründen: dort sind die Zeichen ab 10 bis 15 
anders, keine "abcdef". Und ich wollte auch die Funktion fürs 7-segm. 
testen.

Untere Programmbeispiel arbeitet korrekt, mir geht es hier vor allem um 
die Erklärung, warum die Zeilen wie
1
b = (ziff1<<28)|(ziff2<<24)|(ziff3<<20)|(ziff4<<16)|(ziff5<<12)|(ziff6<<8)|(ziff7<<4)|(ziff8);
 und
1
b = (ziff5<<12)|(ziff6<<8)|(ziff7<<4)|(ziff8);
2
  c = (ziff1<<12)|(ziff2<<8)|(ziff3<<4)|(ziff4);
3
  b |= (c<<16);
  falsche Ergebnis bringen (d.h. nicht was ich erwartete). Ich brauche 
das zu klären, um ähnliche Probleme in anderen Programmen zu vermeiden.

Ich habe mit unsigned und mit signed ausprobiert, das war immer 
gleiches; wenn in Ziffer 3 (Ziffer 0 auf MAX7219 ist die kleinste) 8 
oder 9, dann vier höhere Ziffer zeigen "FFFF".

Vielen Dank!

P.S. Schleifen kenne ich. Aber daß das Pflicht ist, Schleifen zu 
verwenden - das habe ich bisher nicht gewußt. Ich glaube, Compiler ist 
selbst genug klug, um alles passend zu optimieren. Oder? Wenigstens, wie 
ich versucht habe, eine Aufgabe mit Assembler und dann mit C zu machen - 
kam überraschend vor, daß C-Variante schneller und mit weniger Hex-Code 
war, als Assemblers :) Das hat mich für C noch mal überzeugt.

Übrigens, volle Code von Test-Programm: ich werde für Kritik sehr 
dankbar.
1
#define F_CPU 1000000UL
2
#include <avr/io.h>      
3
#include <util/delay.h>    
4
#include <avr/interrupt.h>   
5
#include <stdint.h> 
6
7
#define KALFREQ 0xa5 
8
/* 
9
0xab
10
120c  8 MHz 3,3V: 1:57,16 5V: 1:56,17 = +0,497 %/V
11
1 MHz 5V  1:56,14
12
0xa5 598,85/600 +0,192%
13
0xa4 603,23/600  -0,538%
14
*/
15
16
volatile unsigned char FLAG_TIK = 0; 
17
#define KSCH1 ((F_CPU/64)-1)  
18
19
20
21
#define setSS (PORTB |= (1<<PB2))
22
#define resSS (PORTB &= ~(1<<PB2))
23
#define spi_einschalten  SPSR = 1<<SPI2X; SPCR = (1<<SPE)|(1<<MSTR); 
24
25
#define spi_ausschalten SPCR &= ~(1<<SPE); 
26
27
ISR(TIMER1_COMPA_vect) 
28
{
29
  
30
  FLAG_TIK = 1;    
31
}
32
33
34
35
36
37
unsigned char semisegment(unsigned char e) 
38
{
39
  switch(e) {  case 0: e=0x7e; break;
40
        case 1: e=0x30; break;
41
        case 2: e=0x6d; break;
42
        case 3: e=0x79; break;
43
        case 4: e=0x33; break;
44
        case 5: e=0x5b; break;
45
        case 6: e=0x5f; break;
46
        case 7: e=0x70; break;
47
        case 8: e=0x7f; break;
48
        case 9: e=0x7b; break;
49
        case 10: e=0x77; break;
50
        case 11: e=0x1f; break;
51
        case 12: e=0x4e; break;
52
        case 13: e=0x3d; break;
53
        case 14: e=0x4f; break;
54
        case 15: e=0x47; break;
55
        default: e=0; break;
56
      } 
57
      return e; 
58
}
59
60
void outword(unsigned char a,unsigned char b) 
61
  {
62
  resSS;
63
  /* Start transmission */
64
    SPDR = a;
65
    /* Wait for transmission complete */
66
    while(!(SPSR & (1<<SPIF)));
67
    SPDR = b;
68
    /* Wait for transmission complete */
69
    while(!(SPSR & (1<<SPIF)));
70
  setSS;
71
  }
72
73
unsigned long preobras_bin10bcd3(unsigned long a) 
74
 {
75
  unsigned long b = 0;
76
  while(a>=10000000)
77
    {
78
      b = b + 0x10000000;
79
      a-=10000000;
80
    }
81
  while(a>=1000000)
82
    {
83
      b = b + 0x01000000;
84
      a-=1000000;
85
    }
86
  while(a>=100000)
87
    {
88
      b = b + 0x00100000;
89
      a-=100000;
90
    }
91
  while(a>=10000)
92
    {
93
      b = b + 0x00010000;
94
      a-=10000;
95
    }
96
  while(a>=1000)
97
    {
98
      b = b + 0x00001000;
99
      a-=1000;
100
    }
101
  while(a>=100)
102
    {
103
      b = b + 0x00000100;
104
      a-=100;
105
    }
106
  while(a>=10)
107
    {
108
      b = b + 0x00000010;
109
      a-=10;
110
    }
111
  while(a>=1)
112
    {
113
      b = b + 0x00000001;
114
      a-=1;
115
    }
116
  return b;
117
} 
118
119
120
121
void display(unsigned long a, char adrs)
122
{
123
unsigned long b;
124
b=preobras_bin10bcd3(a);
125
unsigned char c;
126
c=b&0x0000000f;
127
c=semisegment(c);
128
spi_einschalten;
129
outword(adrs,c);
130
b=(b>>4);
131
c=b&0x0000000f;
132
c=semisegment(c);
133
outword((adrs+1),c);
134
b=(b>>4);
135
c=b&0x0000000f;
136
c=semisegment(c);
137
outword((adrs+2),c);
138
b=(b>>4);
139
c=b&0x0000000f;
140
c=semisegment(c);
141
outword((adrs+3),c);
142
b=(b>>4);
143
c=b&0x0000000f;
144
c=semisegment(c);
145
outword((adrs+4),c);
146
b=(b>>4);
147
c=b&0x0000000f;
148
c=semisegment(c);
149
outword((adrs+5),c);
150
b=(b>>4);
151
c=b&0x0000000f;
152
c=semisegment(c);
153
outword((adrs+6),c);
154
b=(b>>4);
155
c=b&0x0000000f;
156
c=semisegment(c);
157
outword((adrs+7),c);
158
spi_ausschalten;
159
}
160
161
void max7219init(void) 
162
{
163
  spi_einschalten;
164
     unsigned char i;
165
    for (i=1;i<10;i++) 
166
      {
167
        outword(i,0); 
168
      }
169
170
   outword(0x0a,0x0f); 
171
   outword(0x0b,0x07); 
172
   outword(0x0c,0x01); 
173
   outword(0x0f,0x01); 
174
  _delay_ms(1000);    
175
   outword(0x0f,0); 
176
   spi_ausschalten;
177
   }
178
/**********************************************************/
179
180
int main(void)
181
{
182
OSCCAL=KALFREQ;
183
184
PORTB = 0;
185
DDRB = 0xff;
186
PORTC = 0;
187
DDRC = 0x0f;
188
PORTD = 0;
189
DDRD = 0xff;
190
setSS; 
191
ACSR = (1<<ACD);
192
193
194
max7219init(); 
195
196
197
TCNT1=0;  
198
OCR1A=KSCH1; 
199
TCCR1C = 0;
200
201
TCCR1A = (1<<COM1A0);
202
TIMSK1 = (1<<OCIE1A);
203
204
// TCCR1B = (1<<WGM12)|(1<<CS12);
205
TCCR1B = (1<<WGM12)|(1<<CS11)|(1<<CS10);
206
207
sei();        
208
209
  long a=0; 
210
  display(a,1);
211
212
213
while(1)
214
{
215
  PORTB |= (1<<PB0);
216
  _delay_ms(5);
217
  PORTB &= ~(1<<PB0);
218
  while(!(FLAG_TIK));
219
  FLAG_TIK = 0;
220
  a++;
221
  display(a,1);
222
  if(a==100000000)
223
    {
224
    a=0;
225
    display(a,1);
226
    }  
227
}
228
return 0;
229
230
}

: Bearbeitet durch User
von Falk B. (falk)


Lesenswert?

@ Maxim Burtsev (Firma: BBO-Potsdam) (max182)

>anders, keine "abcdef". Und ich wollte auch die Funktion fürs 7-segm.
>testen.

>Untere Programmbeispiel arbeitet korrekt, mir geht es hier vor allem um
>die Erklärung, warum die Zeilen wie

>b = (ziff1<<28)|(ziff2<<24)|(ziff3<<20)|(ziff4<<16)|(ziff5<<12)|
>(ziff6<<8)|(ziff7<<4)|(ziff8);

eben WEIL hier die Cast auf long fehlen!

Deshalt HIER so!
1
b = ((long)ziff1<<28)|((long)ziff2<<24)|((long)ziff3<<20)|((long)ziff4<<16)|((long)ziff5<<12)|
2
>((long)ziff6<<8)|((long)ziff7<<4)|((long)ziff8);

>  falsche Ergebnis bringen (d.h. nicht was ich erwartete). Ich brauche
>das zu klären, um ähnliche Probleme in anderen Programmen zu vermeiden.

Du musst ganz andere Dinge klären, u.a. ein paar Programmiergrundlagen.

>P.S. Schleifen kenne ich. Aber daß das Pflicht ist, Schleifen zu
>verwenden - das habe ich bisher nicht gewußt.

Mensch bist du cooool!

> Ich glaube, Compiler ist
>selbst genug klug, um alles passend zu optimieren. Oder?

Wirst du nach Programmzeilen bezahlt?
1
unsigned long preobras_bin10bcd3(unsigned long a) {
2
  long b=0;
3
  int i;
4
5
  for(i=0; i<8, i++) {
6
    b >>=4;
7
    b |= (a % 10)<<28;
8
    a /= 10;
9
  }
10
  
11
  return b;
12
}

>Wenigstens, wie
>ich versucht habe, eine Aufgabe mit Assembler und dann mit C zu machen -
>kam überraschend vor, daß C-Variante schneller und mit weniger Hex-Code
>war, als Assemblers :) Das hat mich für C noch mal überzeugt.

Wenn das unser Moby hört!

: Bearbeitet durch User
von Maxim B. (max182)


Lesenswert?

Falk B. schrieb:

> eben WEIL hier die Cast auf long fehlen!
Danke für die Erklärung!
> Deshalt HIER so!

> Du musst ganz andere Dinge klären, u.a. ein paar Programmiergrundlagen.
Ich weiß das. Mit der Zeit erlerne ich auch das.
Viele Grüße!

von Maxim B. (max182)


Lesenswert?

Falk B. schrieb:

>
1
> unsigned long preobras_bin10bcd3(unsigned long a) {
2
>   long b=0;
3
>   int i;
4
> 
5
>   for(i=0; i<8, i++) {
6
>     b >>=4;
7
>     b |= (a % 10)<<28;
8
>     a /= 10;
9
>   }
10
> 
11
>   return b;
12
> }
13
>
8 mal % und 8 mal Dividieren... Eigentlich wollte ich gerade Dividieren 
ohne akute Notwendigkeit vermeiden: zu langsam.

von Falk B. (falk)


Lesenswert?

@ Maxim Burtsev (Firma: BBO-Potsdam) (max182)

>8 mal % und 8 mal Dividieren...

Darauf ist der Code nicht optimiert, sondern auf minimale Schreibarbeit.

>Eigentlich wollte ich gerade Dividieren
>ohne akute Notwendigkeit vermeiden: zu langsam.

Ach so? Wieviele Millionen Umwandlungen dieser Art willst du denn 
machen, daß die Geschwindigkeit sooo wichtig ist?

https://www.mikrocontroller.net/articles/AVR-GCC-Codeoptimierung#Prinzipien_der_Optimierung

Und wie schnell ist dein Code bei der Umwandlung der Zahl 99999999?

: Bearbeitet durch User
von Maxim B. (max182)


Lesenswert?

Falk B. schrieb:

> Ach so? Wieviele Millionen Umwandlungen dieser Art willst du denn
> machen, daß die Geschwindigkeit sooo wichtig ist?
>
In Test wohl nicht wichtig. Wenn aber Text woanders stehen wird, dann 
wird schon wichtig.

Wenn ich schon etwas lerne, dann praxisorientiert. Für die Zukunft.

Schleifen sind natürlich eine schöne Sache.
Allerdings habe ich noch Problem damit.

Z.B. es gibt Massiv von Zähler. Mit jedem Zähler ist LED verbunden, wenn 
Zähler bis 0 zählt, dann wird LED abgeschaltet. Es ist mir bisher nicht 
gelungen, Befragung und Verändern von Zähler und Löschen von LED mit 
einer Schleife zu machen.

Meine Lösung ist leider nur so:
1
void ledgasch(void)    
2
{
3
  if (tai_V[0] > 0)  
4
    {
5
      tai_V[0]--;
6
      if (tai_V[0]==0)
7
        {
8
        resVL0;
9
        }
10
    }
11
  if (tai_V[1] > 0)
12
    {
13
      tai_V[1]--;
14
      if (tai_V[1]==0)
15
        {
16
        resVL1;
17
        }
18
    }
19
  if (tai_V[2] > 0)
20
    {
21
      tai_V[2]--;
22
      if (tai_V[2]==0)
23
        {
24
        resVL2;
25
        }
26
    }
27
  if (tai_V[3] > 0)
28
    {
29
      tai_V[3]--;
30
      if (tai_V[3]==0)
31
        {
32
        resVL3;
33
        }
34
    }
35
  if (tai_V[4] > 0)
36
    {
37
      tai_V[4]--;
38
      if (tai_V[4]==0)
39
        {
40
        resVL4;
41
        }
42
    }
43
  if (tai_V[5] > 0)
44
    {
45
      tai_V[5]--;
46
      if (tai_V[5]==0)
47
        {
48
        resVL5;
49
        }
50
    }
51
  if (tai_V[6] > 0)
52
    {
53
      tai_V[6]--;
54
      if (tai_V[6]==0)
55
        {
56
        resVL6;
57
        }
58
    }
59
  if (tai_V[7] > 0)
60
    {
61
      tai_V[7]--;
62
      if (tai_V[7]==0)
63
        {
64
        resVL7;
65
        }
66
    }
67
68
  if (tai_V[8] > 0)  
69
    {
70
      tai_V[8]--;
71
      if (tai_V[8]==0)
72
        {
73
        resVR0;
74
        }
75
    }
76
  if (tai_V[9] > 0)
77
    {
78
      tai_V[9]--;
79
      if (tai_V[9]==0)
80
        {
81
        resVR1;
82
        }
83
    }
84
  if (tai_V[10] > 0)
85
    {
86
      tai_V[10]--;
87
      if (tai_V[10]==0)
88
        {
89
        resVR2;
90
        }
91
    }
92
  if (tai_V[11] > 0)
93
    {
94
      tai_V[11]--;
95
      if (tai_V[11]==0)
96
        {
97
        resVR3;
98
        }
99
    }
100
  if (tai_V[12] > 0)
101
    {
102
      tai_V[12]--;
103
      if (tai_V[12]==0)
104
        {
105
        resVR4;
106
        }
107
    }
108
  if (tai_V[13] > 0)
109
    {
110
      tai_V[13]--;
111
      if (tai_V[13]==0)
112
        {
113
        resVR5;
114
        }
115
    }
116
  if (tai_V[14] > 0)
117
    {
118
      tai_V[14]--;
119
      if (tai_V[14]==0)
120
        {
121
        resVR6;
122
        }
123
    }
124
  if (tai_V[15] > 0)
125
    {
126
      tai_V[15]--;
127
      if (tai_V[15]==0)
128
        {
129
        resVR7;
130
        }
131
    }
132
}

: Bearbeitet durch User
von Wolfgang (Gast)


Lesenswert?

Maxim B. schrieb:
> unsigned char semisegment(unsigned char e)
> {
>   switch(e) {  case 0: e=0x7e; break;
>         case 1: e=0x30; break;
>          ...
>         case 15: e=0x47; break;
>         default: e=0; break;
>       }
>       return e;
> }

Guck dir mal an, was man mit const Array machen kann. Das macht aus der 
Funktion einen Einzeiler.

von Maxim B. (max182)


Lesenswert?

Irgendwie mit progmem. Aber ich kapiere das noch nicht ganz...

Ich habe zuerst das so gemacht, wie ich verstehe. Damit nicht alles 
wegen einem klemmt. Das ist nicht optimal, klar - aber arbeitet.

Gleich habe ich noch ADC ausprobiert. Komisch - aber das arbeitet! :)

So mit kleinen Schritten möchte ich die Elementen eineignen, die für 
größere Projekte notwendig sind. Und wenn das etwas nicht optimal wird - 
dann werde ich weiter lernen. Oder auch so lassen - wenn MCU auch so 
macht, was ich davon erwarte. :)

: Bearbeitet durch User
von OldMan (Gast)


Lesenswert?

Mal als Anregung eine andere Möglichkeit in BCD zu wandeln:
1
uint16_t convtab[3]={10,100,1000};
2
3
uint_fast16_t tobcd(uint_fast16_t val){
4
  
5
  uint_fast8_t i,res;
6
  uint_fast16_t valret=0;
7
  
8
  
9
  i=3;    // Number of digits minus 1
10
  
11
  do {
12
  i--;
13
  
14
  for(res=0; val >= convtab[i]; val -= convtab[i]){
15
    res++;
16
  }
17
  valret |= res;
18
  valret <<= 4;
19
  
20
  } while(i);
21
  valret |= val;
22
  
23
  return(valret);
24
}

von Maxim B. (max182)


Lesenswert?

Sehr interessant, danke!

von Falk B. (falk)


Lesenswert?

@ Maxim Burtsev (Firma: BBO-Potsdam) (max182)

>Wenn ich schon etwas lerne, dann praxisorientiert. Für die Zukunft.

Dann solltest du lernen, dass man die Daten der 8 Digits, die man 
sowieso byteweise an den MAX7219 schickt, nicht vorher "aufwändig" in 
einen 32 Bit Wert presst. Eher so. Damit spart man sich tonnenweise 
Schieberei, was besonders auf kleinen Controllern CPU-Zeit kostet. 
Ausserdem kann man die Daten deutlich einfacher weiterverarbeiten, ohne 
sie über Schieberei und Maskierung wieder auseinandernehmen zu müssen.
1
void preobras_bin10bcd3(unsigned long a, char* digits) {
2
  int i;
3
4
  for(i=7; i>=0, i--) {
5
    digits[i] = (a % 10);
6
    a /= 10;
7
  }
8
}

>Schleifen sind natürlich eine schöne Sache.
>Allerdings habe ich noch Problem damit.

Das musst du schnellstens ändern, die sind elementar.

>Z.B. es gibt Massiv von Zähler. Mit jedem Zähler ist LED verbunden, wenn
>Zähler bis 0 zählt, dann wird LED abgeschaltet. Es ist mir bisher nicht
>gelungen, Befragung und Verändern von Zähler und Löschen von LED mit
>einer Schleife zu machen.

Das Zauberwort heißt Index.
1
void ledgasch(void) {
2
  int i;
3
4
  for(i=0; i<16; i++) {
5
    if (tai_V[i] > 0) {
6
      tai_V[i]--;
7
      if (tai_V[i]==0) {
8
        resVL0;  // hier muss auch was mit Index her, ANPASSEN
9
      }
10
    }
11
  }
12
}

von OldMan (Gast)


Lesenswert?

Falk B. schrieb:
> was besonders auf kleinen Controllern CPU-Zeit kostet.
Modulo ist wesentlich langsamer als eine Subtraktion und ein Shift.
Das ist meine Erfahrung. Denn ich hatte vorher auch Modulo genutzt und 
das hatte den 2313 ziemlich lahm gemacht. Auch der Code hatte sich 
erheblich aufgebläht.
Der von mir gepostet Code läuft aktuell auf einem Attiny 2313, mit 3,7 
MHz.
Entwicklungsumgebung Atmel Studio 6.2.

von Maxim B. (max182)


Lesenswert?

Falk B. schrieb:
1
 resVL0;  // hier muss auch was mit Index her, ANPASSEN

Hier ist gerade das Problem. Weil:
1
/* VL0 PORTC PC3 */
2
#define setVL0 (PORTC |= (1<<PC3))
3
#define resVL0 (PORTC &= ~(1<<PC3))
4
5
/* VL1 PORTC PC2 */
6
#define setVL1 (PORTC |= (1<<PC2))
7
#define resVL1 (PORTC &= ~(1<<PC2))
8
9
/* VL2 PORTC PC1 */
10
#define setVL2 (PORTC |= (1<<PC1))
11
#define resVL2 (PORTC &= ~(1<<PC1))
12
13
/* VL3 PORTC PC0 */
14
#define setVL3 (PORTC |= (1<<PC0))
15
#define resVL3 (PORTC &= ~(1<<PC0))
16
17
/* VL4 PORTB PB2 */
18
#define setVL4 (PORTB |= (1<<PB4))
19
#define resVL4 (PORTB &= ~(1<<PB4))
20
21
/* VL5 PORTB PB1 */
22
#define setVL5 (PORTB |= (1<<PB1))
23
#define resVL5 (PORTB &= ~(1<<PB1))
24
25
/* VL6 PORTD PD7 */
26
#define setVL6 (PORTD |= (1<<PD7))
27
#define resVL6 (PORTD &= ~(1<<PD7))
28
29
/* VL7 PORTB PB0 */
30
#define setVL7 (PORTB |= (1<<PB0))
31
#define resVL7 (PORTB &= ~(1<<PB0))
32
33
/* VR0 PORTD PD1 */
34
#define setVR0 (PORTD |= (1<<PD1))
35
#define resVR0 (PORTD &= ~(1<<PD1))
36
37
/* VR1 PORTD PD0 */
38
#define setVR1 (PORTD |= (1<<PD0))
39
#define resVR1 (PORTD &= ~(1<<PD0))
40
41
/* VR2 PORTD PD2 */
42
#define setVR2 (PORTD |= (1<<PD2))
43
#define resVR2 (PORTD &= ~(1<<PD2))
44
45
/* VR3 PORTD PD4 */
46
#define setVR3 (PORTD |= (1<<PD4))
47
#define resVR3 (PORTD &= ~(1<<PD4))
48
49
/* VR4 PORTB PB6 */
50
#define setVR4 (PORTB |= (1<<PB6))
51
#define resVR4 (PORTB &= ~(1<<PB6))
52
53
/* VR5 PORTB PB7 */
54
#define setVR5 (PORTB |= (1<<PB7))
55
#define resVR5 (PORTB &= ~(1<<PB7))
56
57
/* VR6 PORTD PD5 */
58
#define setVR6 (PORTD |= (1<<PD5))
59
#define resVR6 (PORTD &= ~(1<<PD5))
60
61
/* VR7 PORTD PD6 */
62
#define setVR7 (PORTD |= (1<<PD6))
63
#define resVR7 (PORTD &= ~(1<<PD6))
Die Macros beschreiben Verhältnis Ports:LED.
Ich weiß noch nicht, wie ich aus diesen Macros auf "C" etwas mit Index 
machen kann.

von Falk B. (falk)


Lesenswert?

@ Maxim Burtsev (Firma: BBO-Potsdam) (max182)

> resVL0;  // hier muss auch was mit Index her, ANPASSEN
>Hier ist gerade das Problem. Weil:

Da kann man einfach eine Funktion draus machen.
1
void VLx(int port, int value) {
2
3
  if (value !=0) {
4
    switch (port) {
5
      case 0: PORTC |= (1<<PC3); break;
6
      case 1: PORTC |= (1<<PC2); break;
7
      case 2: PORTC |= (1<<PC1); break;
8
      case 3: PORTC |= (1<<PC0); break;
9
      case 4: PORTB |= (1<<PB4); break;
10
      case 5: PORTB |= (1<<PB1); break;
11
      case 6: PORTD |= (1<<PD7); break;
12
      case 7: PORTB |= (1<<PB0); break;
13
    }
14
  } else {
15
    switch (port) {
16
      case 0: PORTC &= ~(1<<PC3); break;
17
      case 1: PORTC &= ~(1<<PC2); break;
18
      case 2: PORTC &= ~(1<<PC1); break;
19
      case 3: PORTC &= ~(1<<PC0); break;
20
      case 4: PORTB &= ~(1<<PB4); break;
21
      case 5: PORTB &= ~(1<<PB1); break;
22
      case 6: PORTD &= ~(1<<PD7); break;
23
      case 7: PORTB &= ~(1<<PB0); break;
24
    }
25
  } 
26
}

von Karl H. (kbuchegg)


Lesenswert?

Falk B. schrieb:
> @ Maxim Burtsev (Firma: BBO-Potsdam) (max182)
>
>> resVL0;  // hier muss auch was mit Index her, ANPASSEN
>>Hier ist gerade das Problem. Weil:
>
> Da kann man einfach eine Funktion draus machen.

Ist eine Möglichkeit.

Man könnte das ganze auch in eine andere Richtung weitertreiben.
Mit dieser Vorgabe
> Z.B. es gibt Massiv von Zähler. Mit jedem Zähler ist LED verbunden,
> wenn Zähler bis 0 zählt, dann wird LED abgeschaltet.
könnte man auch in diese Richtung weiterarbeiten, dass man einen Zähler 
nicht einfach nur als eine unsigned int Variable auffasst, sondern als 
ein Objekt welches aus
* Zählvariable
* Portdefinition
* Bit an diesem Port
besteht. Also ein
1
struct backCounter
2
{
3
  unsigned int            value;
4
  volatile unsigned char* port;
5
  unsigned char           bitmask;
6
};

dann definiert man sich die benötigten Zähler
1
struct backCounter counter[] =
2
{
3
  { 0, &PORTC, 1<<PC3 },
4
  { 0, &PORTC, 1<<PC2 },
5
  { 0, &PORTC, 1<<PC1 }
6
};

und hat damit dann in so einem backCounter Objekt alles beisammen, so 
dass eine einzige Decrement Funktion es bearbeiten kann
1
void decCounter( struct backCounter* cnt )
2
{
3
  if( cnt->value > 0 )
4
    cnt->value--;
5
  if( cnt->value == 0 )
6
    *(cnt->port) |= cnt->bitMask;
7
}
bzw. dann eben für alle Counter
1
...
2
  for( i = 0; i < sizeof(counter) / sizeof(*counter); ++ i ) {
3
    if( counter[i].value > 0 )
4
      counter[i].value--;
5
    if( counter[i].value == 0 )
6
      *(counter[i].port) |= counter[i].bitMask;
7
  }
8
...

bzw. dann eben eine entsprechende Setzfunktion, die einen Counter auf 
einen bestmmten Wert setzt und gleich auch noch die zugehörige LED 
einschaltet
1
void setCounter( int cntIndex, unsigned int value )
2
{
3
  counter[cntIndex] = value;
4
  if( value > 0 )
5
    *(counter[cntIndex].port) &= ~counter[cntIndex].bitMask;
6
}

zugegeben, die Portzugriffe optimieren dann nicht mehr so gut. Aber so 
schlimm ist das meistens dann auch wieder nicht.

Möglichkeiten gibt es viele und fast immer ist die Copy&Paste 
Programmierung mit weiterkopieren eines Codes und ersetzen von ein paar 
Konstanten die schlechteste davon.

: Bearbeitet durch User
von Maxim B. (max182)


Lesenswert?

Vielen Dank!
Mit Struct muß ich noch für mich klären. Variante mit Funktion verstehe 
ich schon genug gut.Wird zwar etwas langsamer, als so. Aber ich denke, 
für meine Aufgabe ist das nicht so kritisch. Es geht um Pegelmesser: 
jeder LED leuchtet bei Überschreitung von Pegel, wird aber mit 
Verzögerung gelöscht (für bessere Sichtbarkeit). Ich denke, so eine 
Schema läßt sich stromsparender mit ATmega zu machen, als mit LM3915. 
Ich habe LED gekauft, die schon bei 0,25 - 0,3 mA ziemlich hell sind. So 
wird 2-Kanal-8 Pos.-Indikator bei mittlerem Pegel (die Hälfte LEDs 
leuchtet) alles zusammen nicht über 3 mA bei 3,3 Volt fressen. So rechne 
ich mindestens.

von Karl H. (kbuchegg)


Lesenswert?

Maxim B. schrieb:
> Vielen Dank!
> Mit Struct muß ich noch für mich klären. Variante mit Funktion verstehe
> ich schon genug gut.Wird zwar etwas langsamer, als so. Aber ich denke,
> für meine Aufgabe ist das nicht so kritisch.

Für die meisten Aufgaben ist so etwas komplett unkritisch, wenn man 
ein paar Taktzyklen herschenkt.

: Bearbeitet durch User
von Falk B. (falk)


Lesenswert?

@Karl Heinz (kbuchegg) (Moderator)

>> Da kann man einfach eine Funktion draus machen.

>Ist eine Möglichkeit.

Das ist die, welche dem OP im Moment am meisten hilft.

>könnte man auch in diese Richtung weiterarbeiten, dass man einen Zähler
>nicht einfach nur als eine unsigned int Variable auffasst, sondern als
>ein Objekt welches aus

DAS ist was für die höheren Semester. Der OP muss erst einmal die 
Grundlagen lernen. Dann reden wir weiter.

von Karl H. (kbuchegg)


Lesenswert?

Falk B. schrieb:

> DAS ist was für die höheren Semester. Der OP muss erst einmal die
> Grundlagen lernen. Dann reden wir weiter.

Da gebe ich dir recht.
Er könnte es allerdings auch als Ansporn sehen, sein C drastisch zu 
verbessern, ehe er dann auch ein reales Projekt geht.
Und so schwer sind Strukturen dann auch wieder nicht zu verstehen.

von Falk B. (falk)


Lesenswert?

@ Karl Heinz (kbuchegg) (Moderator)

>> DAS ist was für die höheren Semester. Der OP muss erst einmal die
>> Grundlagen lernen. Dann reden wir weiter.

>Da gebe ich dir recht.
>Er könnte es allerdings auch als Ansporn sehen, sein C drastisch zu
>verbessern, ehe er dann auch ein reales Projekt geht.

Sehe ich nicht so.

>Und so schwer sind Strukturen dann auch wieder nicht zu verstehen.

Ich würde nicht den 3. Schritt vor dem 1. machen wollen. Du bist da 
schon ein gutes Stück betriebsblind, denn es geht nicht nur um structs 
sondern auch Pointer und Adressen und die dazugehörigen 
Dereferenzierungen und Schreibweisen. Das ist für den Anfänger schon 
reichlich kryptisch!

von Maxim B. (max182)


Lesenswert?

>>DAS ist was für die höheren Semester.

Ja, so denke ich auch. Man kann nicht gleich nach 10 Stunden 
Orgelunterricht schon Bachsche Fantasie und Fuge g-moll spielen. Manche 
können das auch nach 5 Jahren kaum.
Ich denke, mit Programmieren ist das nicht viel anders. Das ist kein 
Handwerk sondern Kunst.

: Bearbeitet durch User
von Karl H. (kbuchegg)


Lesenswert?

Ich seh schon.
Ich fahr wieder nach China. Die wollen noch was lernen.

von Falk B. (falk)


Lesenswert?

@ Maxim Burtsev (Firma: BBO-Potsdam) (max182)

>Ja, so denke ich auch. Man kann nicht gleich nach 10 Stunden
>Orgelunterricht schon Bachsche Fantasie und Fuge g-moll spielen. Manche
>können das auch nach 5 Jahren kaum.

Wohll wahr.

>Ich denke, mit Programmieren ist das nicht viel anders. Das ist kein
>Handwerk sondern Kunst.

Naja, wenn man mal GANZ oben Softwareentwicklung (aka Software Design) 
macht, dann vielleicht. Aber in den Normalgegenden ist es "nur" 
Handwerk.

von Falk B. (falk)


Lesenswert?

@ Karl Heinz (kbuchegg) (Moderator)

>Ich seh schon.
>Ich fahr wieder nach China. Die wollen noch was lernen.

Karl Heinz, dein Ansatz ist schlicht nicht soderlich pädagogisch. Du 
bringst einem Erstklässler auch keinen Satz des Phytagoras bei . . ., 
auch wenn der keine hohe Mathematik darstellt!

Merksatz:

Abraham sacht zu Bebraham: "Kann ich mal dein Cebra ham?". ;-)

von Maxim B. (max182)


Lesenswert?

Falk B. schrieb:

> Naja, wenn man mal GANZ oben Softwareentwicklung (aka Software Design)
> macht, dann vielleicht. Aber in den Normalgegenden ist es "nur"
> Handwerk.

Musizieren ist auch oft so. Das ist Realität. Trotzdem - die Leute haben 
von unseren Konzerten Spaß, sonst kämen sie nicht.

Auch MCU - wenn das Gerät macht, was davon erwartet wird - welcher 
Musiker wird drin kucken, ob auf C alles nach besten Regeln stimmt? Das 
ist eher das Problem von Künstler selbst, für eigene Selbstgefühl. 
Stimmt, daß die Wahrscheinlichkeit von Fehler von Weise abhängig ist. 
Wenn es aber um ganz einfache Dinge geht und sowieso viel Flash und Ram 
frei bleibt...

von Maxim B. (max182)


Lesenswert?

Falk B. schrieb:
> resVL0;  // hier muss auch was mit Index her, ANPASSEN
Lieber Herr Brunner,
ich habe diese Hausarbeit gemacht.
Ergebnis: Ihre Variante ist 350 bytes kleiner. Aber um 3-5 mal 
langsamer. D.h. alles hat Preis.
1
#define KPOR0 1100000 // Konst fuer Schwellen, ist gleich Referenz in uV
2
const unsigned int POR[] PROGMEM = {KPOR0/1283,KPOR0/1615,KPOR0/2282,
3
KPOR0/3225,KPOR0/6432,KPOR0/12790,KPOR0/25581,KPOR0/50000};
4
5
// Laenge fuer LED (x10 mS)
6
const unsigned char PeakLaenge[] PROGMEM = {30,29,28,27,26,25,24,23};
1
void vyvod_led(void)   // Alte Funktion LED ein
2
3
{
4
if (adclinks>POR[0])  // Links
5
  {
6
  tai_V[0] = pgm_read_byte(&PeakLaenge[0]);
7
  setVL0;;
8
  }
9
if (adclinks>POR[1])
10
  {
11
  tai_V[1] = pgm_read_byte(&PeakLaenge[1]);
12
  setVL1;
13
  }
14
if (adclinks>POR[2])
15
  {
16
  tai_V[2] = pgm_read_byte(&PeakLaenge[2]);
17
  setVL2;
18
  }
19
if (adclinks>POR[3])
20
.
21
.
22
.
23
if (adcrechts>POR[7])
24
  {
25
  tai_V[15] = pgm_read_byte(&PeakLaenge[7]);
26
  setVR7;
27
      }
28
}
29
30
void ledgasch(void)    // Alte Funktion LED aus 
31
{
32
if (tai_V[0] > 0)  // Links 
33
  {
34
  tai_V[0]--;
35
  if (tai_V[0]==0)
36
  {
37
  resVL0;
38
  }
39
  }
40
if (tai_V[1] > 0)
41
  {
42
  tai_V[1]--;
43
  if (tai_V[1]==0)
44
  {
45
  resVL1;
46
  }
47
  }
48
if (tai_V[2] > 0)
49
.
50
.
51
.
52
  resVR7;
53
}
54
}
55
}
1
void VLx(int port, int value) // Neue Funktion fuer LED mod
2
{
3
4
  if (value !=0) {
5
    switch (port) {
6
      case 0: setVL0; break;
7
      case 1: setVL1; break;
8
      case 2: setVL2; break;
9
      case 3: setVL3; break;
10
      case 4: setVL4; break;
11
      case 5: setVL5; break;
12
      case 6: setVL6; break;
13
      case 7: setVL7; break;
14
    case 8: setVR0; break;
15
    case 9: setVR1; break;
16
    case 10: setVR2; break;
17
    case 11: setVR3; break;
18
    case 12: setVR4; break;
19
    case 13: setVR5; break;
20
    case 14: setVR6; break;
21
    case 15: setVR7; break;
22
    }
23
  } else {
24
    switch (port) {
25
      case 0: resVL0; break;
26
      case 1: resVL1; break;
27
      case 2: resVL2; break;
28
      case 3: resVL3; break;
29
      case 4: resVL4; break;
30
      case 5: resVL5; break;
31
      case 6: resVL6; break;
32
      case 7: resVL7; break;
33
    case 8: resVR0; break;
34
    case 9: resVR1; break;
35
    case 10: resVR2; break;
36
    case 11: resVR3; break;
37
    case 12: resVR4; break;
38
    case 13: resVR5; break;
39
    case 14: resVR6; break;
40
    case 15: resVR7; break;
41
    }
42
  } 
43
} 
44
45
void v_led(int a, int b)   // Neue Funktion LED ein, POR und index
46
{
47
  int i;
48
  for(i=0; i<8; i++) 
49
  { 
50
  if (a > POR[i])
51
  {
52
    tai_V[i+b] = pgm_read_byte(&PeakLaenge[i]);
53
      VLx(i+b, 1);  
54
    }
55
  }
56
} 
57
58
void vyvod_led(void)   // Neue Funktion LED ein
59
{
60
  v_led(adclinks,0);
61
  v_led(adcrechts,8);
62
} 
63
64
void ledgasch(void) // Neue Funktion LED aus 
65
{
66
  int i;
67
68
  for(i=0; i<16; i++) 
69
  {
70
    if (tai_V[i] > 0) 
71
  {
72
      tai_V[i]--;
73
      if (tai_V[i]==0) 
74
    {
75
        VLx(i, 0);  
76
      }
77
    }
78
  }
79
} 
80
/* Alte Variante:1724 bytes LED aus: 247 Cycles max, LED ein: 215 Cycles max
81
   Neue Variante 1374 bytes LED aus: 848 Cycles max, LED ein: 1051 Cycles max */

Noch mal Vielen Dank!
Ich glaube, ich habe noch ein bißchen etwas erlernt!

: Bearbeitet durch User
von Falk B. (falk)


Lesenswert?

@ Maxim Burtsev (Firma: BBO-Potsdam) (max182)

>ich habe diese Hausarbeit gemacht.
>Ergebnis: Ihre Variante ist 350 bytes kleiner. Aber um 3-5 mal
>langsamer. D.h. alles hat Preis.

So ist es meistens. Nur in sehr wenigen Fällen ist ein Algorithmus 
kürzer UND schneller.

https://www.mikrocontroller.net/articles/AVR-GCC-Codeoptimierung#Prinzipien_der_Optimierung

https://www.mikrocontroller.net/articles/AVR-GCC-Codeoptimierung#Wie

von Maxim B. (max182)


Angehängte Dateien:

Lesenswert?

Falk B. schrieb:

> 
https://www.mikrocontroller.net/articles/AVR-GCC-Codeoptimierung#Prinzipien_der_Optimierung
>
> https://www.mikrocontroller.net/articles/AVR-GCC-Codeoptimierung#Wie

Ich habe das gelesen...

Also, die Variante ohne Schleifen hat auch Recht fürs Leben?

Warum?

Alle Pins sind schon so besetzt, daß etwas darüber zu machen kaum 
möglich erscheint (das ist Grund, warum SPI immer ein- und ausgeschaltet 
wird: wenn SPI eingeschaltet, wird MISO als Eingang von Hardware 
eingestellt, sonst ist das VL4-Ausgang. Variante mit TQFP auch - nur 
zwei LED mehr, sonst alles gleich).

Es gibt keine ATmega x8 mit 1,5 kB Flash, mindestens 4, oder was ich 
verwende (ATmega88) hat 8 kB. Ist Programm 1724 Bytes lang oder nur 
1374, bleibt sowieso viel Flash unbenutzt. Aber die Variante mit 1724 
Bytes ist spürbar schneller, und das ist absolut gratis! Hier ist 
Geschwindigkeit nicht absolut erforderlich, wirkt aber positiv auf 
Genauigkeit.
1
while(1)
2
  {            // Einmal in 400 mS mit Ind. MAX7219
3
  adclinks = leselinks();    
4
  adcrechts = leserechts();  
5
  vyvod_led();        // LED Einschalten nach Signal
6
    if (FLAG_TIK == 1) // Wenn Tik=1
7
    {
8
    ledgasch();  // LED-Zaehler aktualisieren und die mit "0" loeschen
9
    FLAG_TIK = 0;  
10
    }
11
#if (max7219_spi) // Wenn Indikator eingeschlossen, dann einmal in 400 mS
12
13
    if (FLAG_IND == 1)  // Wenn IND=1
14
    {
15
    CLKPR = 0x80; // F_CPU=Max
16
    CLKPR = K_CLKPR_MAX;
17
    ind_max7219(adclinks,0); // ADC-links > indikator ab 0
18
    ind_max7219(adcrechts,4);  // ADC-rechts > indikator ab 4
19
    FLAG_IND = 0;
20
    
21
    CLKPR = 0x80; 
22
    CLKPR = K_CLKPR; // F_CPU=Norm
23
    }
24
#endif
25
  }
Programm macht nichts anderes als mit ADC 2 Eingänge ablesen und 
bewerten. Einstimmung geht mit Programm, deshalb gibt es Funktionen für 
MAX7219, aber die sind mit #if - #endif nach der Einstimmung aus dem 
endgültigen Programm ausgeschlossen (Funktionen für MAX7219 brauchen 
relativ viel Zeit). Danach wird das Programm noch um 510 Bytes kürzer, 
was übrigens nichts ändert: Flash bleibt um mehrfaches über Bedarf.

In einem anderen Fall wird Schleife vielleicht praktischer, in diesem 
Beispiel aber eher nicht (lieber noch mehr F_CPU absenken, um 
Stromverbrauch zu reduzieren. Aber ich glaube, bei 500 kHz kann man 
schon nicht mehr viel optimieren). Interessant, daß Compiler eigentlich 
gleicher Meinung ist! :) Funktion
1
int lesenadc(void)    // ADC lesen
2
{
3
  ADCSRA |= (1<<ADSC);
4
  while (ADCSRA & (1<<ADSC)) {}
5
  return ADCW;
6
}
 macht er inline.

P.S. das ist immer noch nicht realisiert. Ich überlege noch, ob es nicht 
besser wird, auf einer Leitplatte gleich 4 Spuren zu machen, und zwar 
zusammen mit Vorverstärker und auch Stromversorgung. Es gibt Argumente 
dafür und dagegen.

: Bearbeitet durch User
von Falk B. (falk)


Lesenswert?

@ Maxim Burtsev (Firma: BBO-Potsdam) (max182)

>Also, die Variante ohne Schleifen hat auch Recht fürs Leben?

Hier nicht, allgemein schon, wenn man die maximale Geschwindigkeit 
braucht.

>Es gibt keine ATmega x8 mit 1,5 kB Flash, mindestens 4, oder was ich
>verwende (ATmega88) hat 8 kB. Ist Programm 1724 Bytes lang oder nur
>1374, bleibt sowieso viel Flash unbenutzt. Aber die Variante mit 1724
>Bytes ist spürbar schneller, und das ist absolut gratis!

Sürbar? Wer spürt denn das? Du? Wo? Im Simulator?
Deine CPU langeweilt sich bei der Aufgabe so oder so zu tode!

>Hier ist
>Geschwindigkeit nicht absolut erforderlich, wirkt aber positiv auf
>Genauigkeit.

Blödsinn.


>    CLKPR = 0x80; // F_CPU=Max
>    CLKPR = K_CLKPR_MAX;
>    ind_max7219(adclinks,0); // ADC-links > indikator ab 0
>    ind_max7219(adcrechts,4);  // ADC-rechts > indikator ab 4
>    FLAG_IND = 0;

>    CLKPR = 0x80;
>    CLKPR = K_CLKPR; // F_CPU=Norm

Warum stellst du hier den Prescaler für die CPU um? Das ist nicht 
sonderlich sinnvoll, zumal die SPI selber einen Prescaler hat. Nutze den 
Sleep Mode.

>relativ viel Zeit). Danach wird das Programm noch um 510 Bytes kürzer,
>was übrigens nichts ändert: Flash bleibt um mehrfaches über Bedarf.

Du wirst es überleben. Oder nimm einen kleinen Attiny2313 und ein paar 
Schieberegister als Porterweiterung, wenn es dich glücklich machen, den 
Flash nahzu zu 100% auszunutzen.

>In einem anderen Fall wird Schleife vielleicht praktischer,

Meistens. Denn damit hat man weniger Schreibarbeit und es ist deutlich 
übersichtlicher.

> in diesem
>Beispiel aber eher nicht (lieber noch mehr F_CPU absenken, um
>Stromverbrauch zu reduzieren.

Das macht man anders, siehe oben.

von Andreas H. (ahz)


Lesenswert?

Maxim B. schrieb:
> P.S. das ist immer noch nicht realisiert. Ich überlege noch, ob es nicht
> besser wird, auf einer Leitplatte gleich 4 Spuren zu machen, und zwar
> zusammen mit Vorverstärker und auch Stromversorgung.

Hallo Maxim

Mir ist ehrlich gesagt nicht ganz klar WAS Du eigentlich machen willst.

Willst Du nur einmal ausprobieren, ob Du so ein VU Meter zum laufen 
bekommst ?
Oder willst Du eher ein bisschen programmieren ?
Oder einfach nur ein bisschen spielen ?
Oder willst Du eigentlich ein VU-Meter irgendwo einsetzen ?

Dann könnte Dir das Forum vielleicht auch etwas zielgerichteter helfen.
Und Du müsstest nicht viel Geld für eine Platine ausgeben, die nachher 
nicht das macht, was Du eigentlich wolltest.

Viele Grüße
Andreas

von Maxim B. (max182)


Lesenswert?

Falk B. schrieb:

>>    CLKPR = 0x80; // F_CPU=Max
>>    CLKPR = K_CLKPR_MAX;
>>    ind_max7219(adclinks,0); // ADC-links > indikator ab 0
>>    ind_max7219(adcrechts,4);  // ADC-rechts > indikator ab 4
>>    FLAG_IND = 0;
>
>>    CLKPR = 0x80;
>>    CLKPR = K_CLKPR; // F_CPU=Norm
>
> Warum stellst du hier den Prescaler für die CPU um? Das ist nicht
> sonderlich sinnvoll, zumal die SPI selber einen Prescaler hat. Nutze den
> Sleep Mode.
Weil dadurch nicht nur SPI beschleunigt wird, sondern auch alle 
Funktionen, die für BCD u.ä. verantwortlich sind.
Was spricht dagegen? Das brauche ich nur für Abstimmung (weil Vref große 
Toleranz hat). Nach Abstimmung wird alles für Indikator raus.

>Oder nimm einen kleinen Attiny2313
Der hat doch kein ADC?

von Falk B. (falk)


Lesenswert?

@ Maxim Burtsev (Firma: BBO-Potsdam) (max182)

>>Oder nimm einen kleinen Attiny2313
>Der hat doch kein ADC?

Stimmt, hab ich übersehen. Es gibt aber andere Tinys mit ADC.
Solches krampfhafte Sparen von Flash, RAM oder sonstigen Resourcen lohnt 
sich nur bei (Groß)serienproduktion. Bei Einzelstücken oder Kleinserien 
sind die Kosten für die Hardware meist nebensächlich.

von Maxim B. (max182)


Lesenswert?

Andreas H. schrieb:

> Oder willst Du eigentlich ein VU-Meter irgendwo einsetzen ?
das möchte ich, klar. Ich brauche Schema fünfmal.

Alles, was ich mache, hat immer mehrere Ziele gleichzeitig in Visier.

Natürlich möchte ich auch etwas damit erlernen (schon etwas in dieser 
Richtung gegangen, vielen Dank an alle für eure geduldige Erklärungen!).

Wozu ich so etwas brauche? Ich habe einmal bei dem Mitschnitt etwas 
erlebt: jemand hat Mikrofonkabel zertreten. Ich habe das leider zu spät 
erkannt. So ein Indikator könnte mir damals helfen. Da das eine 
Nebenaufgabe ist, wäre es natürlich blöd, dafür zu viel Strom ausgeben - 
solange alles von Akku laufen soll.

Entschuldigung - ich möchte hier keinen provozieren. Aber wirklich: ich 
verstehe nicht, warum ich Schleife machen muß, solange das nur alles 
verlangsamt und Flash auch ohne Schleifen genug bleibt?

Wissen, wie man eine Schleife macht - das möchte ich (und hier hat man 
mir erklärt, was ich selber nicht finden konnte: wie man das mit Pins 
macht, innerhalb einer Schleife). Verwenden - hier ist zu überlegen.

Gerade in dem Artikel, den mir Herr Brunner gegeben hat, steht: 
optimieren kann man für Größe oder für Geschwindigkeit, je nachdem was 
man braucht.

Viele Grüße,

: Bearbeitet durch User
von Falk B. (falk)


Lesenswert?

@ Maxim Burtsev (Firma: BBO-Potsdam) (max182)

>verstehe nicht, warum ich Schleife machen muß,

Muss nicht, aber es ist meistens günstiger. Sagte ich bereits.

>solange das nur alles
>verlangsamt und Flash auch ohne Schleifen genug bleibt?

Denn damit hat man weniger Schreibarbeit und es ist deutlich
übersichtlicher.

von Maxim B. (max182)


Lesenswert?

Tinys haben bis 20 Pin. ich wollte eine Einheit, die gleich zwei Spuren 
bedient. Für jede Spur eigene Schema - das wäre zu viel bei 10 oder 12 
Spuren. Alles muß noch in eine Gehäuse vernünftiger Größe passen. So 
etwa 300 x 180, damit alle Buchsen bequem liegen und alle LED zu sehen 
sind, aber noch zu tragen wäre.

von Maxim B. (max182)


Lesenswert?

Falk B. schrieb:

> Denn damit hat man weniger Schreibarbeit und es ist deutlich
> übersichtlicher.

Ja, das stimmt. Viel übersichtlicher. Schließlich kann ich F_CPU bis auf 
1 MHz einstellen und Differenz ausgleichen (ADC braucht ungefähr gleiche 
Zeit unabhängig von CPU-Freq.), Preis dafür wäre 0,5 mA, das wäre noch 
zu verdauen.

Schön, wenn man viele Varianten hat, daß man wählen kann!

Was Sleep betrift: ich habe schon über ADC Noise Reduction Mode gedacht. 
Das wird wohl die Richtung für weitere Programmentwicklung. Noch ein 
paar hundert uA sparen :) Ob das dem Wandler für negative Spannung nicht 
merkbar stört? Was ich in keinem Fall möchte: Subfrequenzen in 
Speiseleitungen, die in Klang durchsickern können.

Für Spannungwandler plane ich ATtiny261A - und das mache ich eher mit 
Assembler. Oder doch C? :) Das wird ein einfacher Ersatz für 74HC-Serie, 
ein IC-Körper statt 6 oder 7.

: Bearbeitet durch User
von Maxim B. (max182)


Lesenswert?

Andreas H. schrieb:

> Und Du müsstest nicht viel Geld für eine Platine ausgeben, die nachher
> nicht das macht, was Du eigentlich wolltest.
So viel Geld ist das nicht. Eine Fotoplatine 160x100 für 2,2€, 1 oder 2 
Folien, ein bißchen Tinten, ein Löffel NaOH, etwas FeCl3... Etwas 
Meckern von meiner Frau vielleicht noch :)

: Bearbeitet durch User
von Andreas H. (ahz)


Lesenswert?

Maxim B. schrieb:
>> Und Du müsstest nicht viel Geld für eine Platine ausgeben, die nachher
>> nicht das macht, was Du eigentlich wolltest.
> So viel Geld ist das nicht. Eine Fotoplatine 160x100 für 2,2€, 1 oder 2
> Folien, ein bißchen Tinten, ein Löffel NaOH, etwas FeCl3... Etwas
> Meckern von meiner Frau vielleicht noch :)

Maxim B. schrieb:
>> Oder willst Du eigentlich ein VU-Meter irgendwo einsetzen ?
> das möchte ich, klar. Ich brauche Schema fünfmal.

Dann wäre das evtl. eher etwas für Dich. Und macht auch weniger Ärger 
mit Deiner Frau ;-)

https://www.itead.cc/open-pcb/pcb-prototyping/2layer-green-pcb-5cm-x-10cm-max.html?___SID=U

Die angegebene Größe ist die Maximalgröße. Die Platine darf also auch 
kleiner sein. Andere Maximalgrößen gibt es natürlich auch (z.B. 10cm x 
10 cm)

Maxim B. schrieb:
> Wozu ich so etwas brauche? Ich habe einmal bei dem Mitschnitt etwas
> erlebt: jemand hat Mikrofonkabel zertreten. Ich habe das leider zu spät
> erkannt. So ein Indikator könnte mir damals helfen.

Ich verstehe Dein Problem. Aber ist das, was Du vorhast dann eine Lösung 
?
Wenn Du gerade am spielen bist, dann kannst Du vermutlich nicht laufend 
auf die Anzeige schauen.

Wenn gerade nicht gespielt wird, dann zeigt das VU-Meter nichts an. Auch 
kein kaputtes Kabel.

Was für Mikrofone benutzt Du denn? Bei Mikros mit Phantomsspeisung 
könntest Du probieren den Abschlusswiderstand zu messen und ggf. EINE 
Led einschalten, wenn der Widerstand weg (also Kabel ab) ist.
Das lenkt beim spielen nicht ab (ausser das Mikro ist ab) und geht auch, 
wenn gerade nicht gespielt wird.

> Da das eine
> Nebenaufgabe ist, wäre es natürlich blöd, dafür zu viel Strom ausgeben -
> solange alles von Akku laufen soll.

Aber der Stromverbrauch Deiner Schaltung (die Du gepostet hattest) ist 
doch nicht das was der Prozessor verbraucht. Am meisten Strom 
verbrauchen Deine LEDs oder? Und die müssen On-Stage schon etwas heller 
sein. Sonst siehst Du sie nicht mehr richtig.

Meinst Du nicht, dass Du da an der falschen Stelle Strom sparen willst?

Maxim B. schrieb:
> Entschuldigung - ich möchte hier keinen provozieren. Aber wirklich: ich
> verstehe nicht, warum ich Schleife machen muß, solange das nur alles
> verlangsamt und Flash auch ohne Schleifen genug bleibt?
>

Du provozierst keinen (denke ich). Wenn Du nicht fagst bekommst Du auch 
keine Antworten. Also frag ;-)

Du musst keine Schleifen nehmen. Es ist das Deine Entscheidung.

Allerdings bieten Schleifen sooo viel Vorteile, dass man sie sehr gerne 
benutzt.
Der Code ist viel einfacher lesbar. Vergleiche doch z.B. Deinen Code mit 
dem Code den Falk oder Karl-Heinz gepostet haben. Ihr Code ist kürzer 
(was nicht notwendigerweise besser sein muss) und es wird auch sehr 
schnell klar, wie sich die Variablen von Schritt zu Schritt (also pro 
Schleifendurchlauf) verändern.

DU (und nur Du) siehst das bei Deinem Code vieleicht noch auf Anhieb. 
Aber andere Leute müssen da Zeile für Zeile genau hinsehen.
Auch deswegen, weil sie vermuten werden "Es gibt bestimmt einen 
speziellen Grund, warum er keine Schleife genommen hat".
Und wenn Du in 5 Jahren noch einmal in Dein Programm reinschaust, dann 
freust Du Dich auch, wenn Du ihn noch verstehst ;-)

Wenn Du Dich erst mal an Schleifen gewöhnt hast (und das geht sehr 
schnell), dann "denkst" Du auch beim Programmentwurf in diese Richtung.
Es ist nur ein Konstrukt der Dir (und anderen) das Verstehen des 
Programms vereinfacht. Mehr nicht ;-)

> Wissen, wie man eine Schleife macht - das möchte ich (und hier hat man
> mir erklärt, was ich selber nicht finden konnte: wie man das mit Pins
> macht, innerhalb einer Schleife). Verwenden - hier ist zu überlegen.
>
Probiere es einfach aus.

> Gerade in dem Artikel, den mir Herr Brunner gegeben hat, steht:
> optimieren kann man für Größe oder für Geschwindigkeit, je nachdem was
> man braucht.

Ist das nicht erst dann interessant, wenn Du entweder Platz oder 
Geschwindigkeitsprobleme hast?
Dein Prozessor (AT8 ?) macht typ. 8 Millionen Anweisungen pro Sekunde 
(!!!). Nutzt Du da wirklich schon alles aus? Ich vermute nicht.

Und Platz im Flash ist doch auch noch reichlich, oder?

Es ist ein sehr beliebter Fehler, die Leistungsfähigkeit von Prozessoren 
zu unterschätzen. So ein kleiner AT8 schafft schon gut was weg.
Vieleicht solltest Du das Programm erst einmal "im Groben" fertig machen 
und dann (!) schauen, ob es irgendwo zu eng wird? (Klappt oft :-D )

Viele Grüße
Andreas

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.