Forum: Mikrocontroller und Digitale Elektronik Überlauf klappt nicht wie vorgestellt


von J. T. (chaoskind)


Lesenswert?

MoinMoin

ich schreib grad ein kleines NightRider-Lauflicht auf nem Mega128. Das 
klappt soweit auch ganz gut, nur geht es nur einmal hin und her und 
bleibt dann stehen.

Dazu gehe ich wie folgt vor:

Mit Timer1A/B/C erzeuge per PWM drei feste Helligkeitsstufen. Diese gebe 
ich dann auf PortE aus und lasse nach einer Zeit, die ich per Timer0 
erzeuge, aufs nächste "Muster" umschalten.

Der Timer0 läuft im CTC und erhöht mit jedem Durchlauf eine Variable 
Zeit (uint8_t).

Speicher aktuelle Zeit in Zeitalt,
gib solange MusterX aus wie Zeitalt+y größer als Zeit ist

Speicher aktuelle Zeit in Zeitalt,
gib solange MusterX+1 aus .......

Wenn nun der Überlauf kommt, klappt das ganze nicht mehr. Also wenn mein 
Zeitversatz bspw 10(Timertakte) ist, und Zeit bei 252 gespeichert wurde, 
ist der nächste Vergleich: solange 252 + 10 größer als die aktuelle Zeit 
ist (also eigentlich ja 6 wegen der 8bit Variable) mache das Muster.

Aber da nach 252 die Zeit 253 kommt, klappt das ganze halt nicht, da 6 
kleiner als 252 ist.

Wie kann ich das ganze so lösen, das ich einfach immer mein Offset zu 
addieren kann, und das trotz Überlauf klappt?

Hier nochmal mein Code:
1
/*
2
 * STK500____C_Test.c
3
 *
4
 * Created: 15.06.2015 18:03:48
5
 *  Author: Ichich
6
 */ 
7
8
9
10
#include <avr/io.h>
11
#include <avr/interrupt.h>
12
13
#define Hell PORTB & (1 << PB5)
14
#define Mittel PORTB & (1 << PB6)
15
#define Dunkel PORTB & (1 << PB7)
16
17
void Init(void);
18
void Step1(void);
19
void Step2(void);
20
void Step3(void);
21
void Step4(void);
22
void Step5(void);
23
void Step6(void);
24
void Step7(void);
25
void Step8(void);
26
27
uint8_t Zeit = 0;
28
uint8_t Zeit_alt = 0;
29
30
ISR (TIMER0_COMP_vect)
31
{
32
  Zeit++;
33
}
34
35
36
int main(void)
37
{
38
  Init();
39
  
40
    while(1)
41
    {
42
    Zeit_alt = Zeit;
43
    while(Zeit_alt + 12 >= Zeit)
44
    {
45
      Step1();
46
    }
47
    
48
    Zeit_alt = Zeit;
49
    while(Zeit_alt + 12 >= Zeit)
50
    {
51
      Step2();
52
    }
53
    
54
    Zeit_alt = Zeit;
55
    while(Zeit_alt + 12 >= Zeit)
56
    {
57
      Step3();
58
    }
59
    
60
    Zeit_alt = Zeit;
61
    while(Zeit_alt + 12 >= Zeit)
62
    {
63
      Step4();
64
    }
65
    
66
    Zeit_alt = Zeit;
67
    while(Zeit_alt + 12 >= Zeit)
68
    {
69
      Step5();
70
    }
71
    
72
    Zeit_alt = Zeit;
73
    while(Zeit_alt + 12 >= Zeit)
74
    {
75
      Step6();
76
    }
77
    
78
    Zeit_alt = Zeit;
79
    while(Zeit_alt + 12 >= Zeit)
80
    {
81
      Step7();
82
    }
83
    
84
    Zeit_alt = Zeit;
85
    while(Zeit_alt + 12 >= Zeit)
86
    {
87
      Step8();
88
    }
89
    
90
    Zeit_alt = Zeit;
91
    while(Zeit_alt + 12 >= Zeit)
92
    {
93
      Step7();
94
    }
95
    
96
    Zeit_alt = Zeit;
97
    while(Zeit_alt + 12 >= Zeit)
98
    {
99
      Step6();
100
    }
101
    
102
    Zeit_alt = Zeit;
103
    while(Zeit_alt + 12 >= Zeit)
104
    {
105
      Step5();
106
    }
107
    
108
    Zeit_alt = Zeit;
109
    while(Zeit_alt + 12 >= Zeit)
110
    {
111
      Step4();
112
    }
113
    
114
    Zeit_alt = Zeit;
115
    while(Zeit_alt + 12 >= Zeit)
116
    {
117
      Step3();
118
    }
119
    
120
    Zeit_alt = Zeit;
121
    while(Zeit_alt + 12 >= Zeit)
122
    {
123
      Step2();
124
    }
125
    }
126
}
127
128
void Step1(void)
129
{
130
  uint8_t S1;
131
  uint8_t S2;
132
  uint8_t S3;
133
  
134
  if ( (PINB & (1 << PB5)) >= 1 )
135
  {
136
    S1 = 1;
137
  }else
138
  {
139
    S1 = 0;
140
  }
141
  
142
  if ( (PINB & (1 << PB6)) >= 1 )
143
  {
144
    S2 = 1;
145
  }else
146
  {
147
    S2 = 0;
148
  }
149
  
150
  if ( (PINB & (1 << PB7)) >= 1 )
151
  {
152
    S3 = 1;
153
  }else
154
  {
155
    S3 = 0;
156
  }
157
  PORTE = ~( (S3 << 0) | (S2 << 1) | (S1 << 2) );
158
}
159
160
void Step2(void)
161
{
162
  uint8_t S1;
163
  uint8_t S2;
164
  uint8_t S3;
165
  
166
  if ( (PINB & (1 << PB5)) >= 1 )
167
  {
168
    S1 = 1;
169
  }else
170
  {
171
    S1 = 0;
172
  }
173
  
174
  if ( (PINB & (1 << PB6)) >= 1 )
175
  {
176
    S2 = 1;
177
  }else
178
  {
179
    S2 = 0;
180
  }
181
  
182
  if ( (PINB & (1 << PB7)) >= 1 )
183
  {
184
    S3 = 1;
185
  }else
186
  {
187
    S3 = 0;
188
  }
189
  PORTE = ~( (S2 << 0) | (S3 << 1) | (S2 << 2) | (S1 << 3) );
190
}
191
192
void Step3(void)
193
{
194
  uint8_t S1;
195
  uint8_t S2;
196
  uint8_t S3;
197
  
198
  if ( (PINB & (1 << PB5)) >= 1 )
199
  {
200
    S1 = 1;
201
  }else
202
  {
203
    S1 = 0;
204
  }
205
  
206
  if ( (PINB & (1 << PB6)) >= 1 )
207
  {
208
    S2 = 1;
209
  }else
210
  {
211
    S2 = 0;
212
  }
213
  
214
  if ( (PINB & (1 << PB7)) >= 1 )
215
  {
216
    S3 = 1;
217
  }else
218
  {
219
    S3 = 0;
220
  }
221
  PORTE = ~( (S1 << 0) | (S2 << 1) | (S3 << 2) | (S2 <<3) | (S1 << 4) );
222
}
223
224
void Step4(void)
225
{
226
  uint8_t S1;
227
  uint8_t S2;
228
  uint8_t S3;
229
  
230
  if ( (PINB & (1 << PB5)) >= 1 )
231
  {
232
    S1 = 1;
233
  }else
234
  {
235
    S1 = 0;
236
  }
237
  
238
  if ( (PINB & (1 << PB6)) >= 1 )
239
  {
240
    S2 = 1;
241
  }else
242
  {
243
    S2 = 0;
244
  }
245
  
246
  if ( (PINB & (1 << PB7)) >= 1 )
247
  {
248
    S3 = 1;
249
  }else
250
  {
251
    S3 = 0;
252
  }
253
  PORTE = ~( (S1 << 1) | (S2 << 2) | (S3 << 3) | (S2 << 4) | (S1 << 5) );
254
}
255
256
void Step5(void)
257
{
258
  uint8_t S1;
259
  uint8_t S2;
260
  uint8_t S3;
261
  
262
  if ( (PINB & (1 << PB5)) >= 1 )
263
  {
264
    S1 = 1;
265
  }else
266
  {
267
    S1 = 0;
268
  }
269
  
270
  if ( (PINB & (1 << PB6)) >= 1 )
271
  {
272
    S2 = 1;
273
  }else
274
  {
275
    S2 = 0;
276
  }
277
  
278
  if ( (PINB & (1 << PB7)) >= 1 )
279
  {
280
    S3 = 1;
281
  }else
282
  {
283
    S3 = 0;
284
  }
285
  PORTE = ~( (S1 << 2) | (S2 << 3) | (S3 << 4) | (S2 << 5) | (S1 << 6) );
286
}
287
288
void Step6(void)
289
{
290
  uint8_t S1;
291
  uint8_t S2;
292
  uint8_t S3;
293
  
294
  if ( (PINB & (1 << PB5)) >= 1 )
295
  {
296
    S1 = 1;
297
  }else
298
  {
299
    S1 = 0;
300
  }
301
  
302
  if ( (PINB & (1 << PB6)) >= 1 )
303
  {
304
    S2 = 1;
305
  }else
306
  {
307
    S2 = 0;
308
  }
309
  
310
  if ( (PINB & (1 << PB7)) >= 1 )
311
  {
312
    S3 = 1;
313
  }else
314
  {
315
    S3 = 0;
316
  }
317
  PORTE = ~( (S1 << 3) | (S2 << 4) | (S3 << 5) | (S2 << 6) | (S1 << 7) );
318
}
319
320
void Step7(void)
321
{
322
  uint8_t S1;
323
  uint8_t S2;
324
  uint8_t S3;
325
  
326
  if ( (PINB & (1 << PB5)) >= 1 )
327
  {
328
    S1 = 1;
329
  }else
330
  {
331
    S1 = 0;
332
  }
333
  
334
  if ( (PINB & (1 << PB6)) >= 1 )
335
  {
336
    S2 = 1;
337
  }else
338
  {
339
    S2 = 0;
340
  }
341
  
342
  if ( (PINB & (1 << PB7)) >= 1 )
343
  {
344
    S3 = 1;
345
  }else
346
  {
347
    S3 = 0;
348
  }
349
  PORTE = ~( (S1 << 4) | (S2 << 5) | (S3 << 6) | (S2 << 7) );
350
}
351
352
void Step8(void)
353
{
354
    uint8_t S1;
355
  uint8_t S2;
356
  uint8_t S3;
357
  
358
  if ( (PINB & (1 << PB5)) >= 1 )
359
  {
360
    S1 = 1;
361
  }else
362
  {
363
    S1 = 0;
364
  }
365
  
366
  if ( (PINB & (1 << PB6)) >= 1 )
367
  {
368
    S2 = 1;
369
  }else
370
  {
371
    S2 = 0;
372
  }
373
  
374
  if ( (PINB & (1 << PB7)) >= 1 )
375
  {
376
    S3 = 1;
377
  }else
378
  {
379
    S3 = 0;
380
  }
381
  PORTE = ~( (S1 << 5) | (S2 << 6) | (S3 << 7) );
382
}
383
384
void Init(void)
385
{  
386
  DDRB = 0xFF;
387
  DDRE = 0xFF;
388
  
389
  ICR1 = 0x00FF;
390
  OCR1A = 0x00FC;
391
  OCR1B = 0x00BF;
392
  OCR1C = 0x0001;
393
  TCCR1A = (1 << COM1A0) | (1 << COM1A1) | (1 << COM1B0) | (1 << COM1B1) | (1 << COM1C0) | (1 << COM1C1) | (1 <<WGM11);
394
  TCCR1B = (1 << WGM12) | (1 << WGM13) | (1 << CS10) | (1 << CS11);
395
  
396
  OCR0 = 255;
397
  TCCR0 = (1 << WGM01) | (1 << CS01) | (1 << CS02);
398
  TIMSK = (1 << OCIE0);
399
  
400
  sei();
401
}

von LostInMusic (Gast)


Lesenswert?

1
   Zeit_alt = Zeit;
2
   while(Zeit_alt + 12 >= Zeit)
3
   ...

Finde ich unnötig kompliziert. Warum nicht so:
1
   Zeit = 0;
2
   while (Zeit < 12)
3
   ...

von J. T. (chaoskind)


Lesenswert?

LostInMusic schrieb:
> Finde ich unnötig kompliziert. Warum nicht so:
>    Zeit = 0;
>    while (Zeit < 12)
>    ...

Vermutlich denke ich gern zu kompliziert, merk ich immer wieder :D

Guter Tipp, ich werds direkt mal versuchen =)

von Sebastian V. (sebi_s)


Lesenswert?

Deine Zeit Variable sollte auch volatile sein 
(https://www.mikrocontroller.net/articles/FAQ#Was_hat_es_mit_volatile_auf_sich). 
Außerdem überleg dir mal wie man deine Funktion verallgemeinern kann, 
sodass man nicht 8 Step Funktionen hat die fast das gleiche machen. Der 
Code wird dadurch deutlich übersichtlicher und kürzer.

von J. T. (chaoskind)


Lesenswert?

Müsste das nicht reichen, wenn die Zeit-Variable global definiert ist?

Sie zählt ja schließlich hoch wie sie soll, der "Fehler" lag ja im 
Überlauf zusammen mit dem Vergleich.

Wobei ich mich dunkel erinnere, das ich das auch mal irgendwie so 
hinbekommen hatte, das ich immer eine Differenz aufaddieren konnte, und 
das ganze auch über den Überlauf hinweg geklappt hat.

von Fpgakuechle K. (Gast)


Lesenswert?

statt
1
 if ( (PINB & (1 << PB5)) >= 1 )
2
  {
3
    S1 = 1;
4
  }else
5
  {
6
    S1 = 0;
7
  }

kürzer
1
S1 = (PINB & (1 << PB5)) ;
2
if (S1 != 0) S1 = 1;

MfG,

von J. T. (chaoskind)


Lesenswert?

Fpga Kuechle schrieb:
> kürzerS1 = (PINB & (1 << PB5)) ;
> if (S1 != 0) S1 = 1;

Das ist schön! Danke dafür.

Ich versuche das Ganze grad ein wenig einzukürzen, wie Sebastian schon 
vorschlug. Jetzt erzeuge ich wieder mein "Grundmuster" und verschiebe es 
dann um die Steps. Gibt es nicht auch eine Möglichkeit, das in einem 
Schritt zu machen?
1
#include <avr/io.h>
2
#include <avr/interrupt.h>
3
4
#define Offset 10
5
6
void Init(void);
7
void Step1(uint8_t Steps);
8
/*void Step2(void);
9
void Step3(void);
10
void Step4(void);
11
void Step5(void);
12
void Step6(void);
13
void Step7(void);
14
void Step8(void);*/
15
16
uint8_t Zeit = 0;
17
18
19
ISR (TIMER0_COMP_vect)
20
{
21
  Zeit++;
22
}
23
24
25
int main(void)
26
{
27
  Init();
28
  
29
  uint8_t Steps = 2;
30
  uint8_t UpDownFlag = 0;
31
  
32
    while(1)
33
    {
34
    Zeit = 0;
35
    while(Zeit < Offset)
36
    {
37
      Step1(Steps);
38
    }
39
    
40
    if (UpDownFlag == 0)
41
    {
42
      Steps++;
43
      if (Steps == 8)
44
      {
45
        UpDownFlag = 1;
46
      }
47
    }else
48
    {
49
      Steps--;
50
      if (Steps == 0)
51
      {
52
        UpDownFlag = 0;
53
      }
54
    }
55
    
56
57
    }
58
}
59
60
void Step1(uint8_t Steps)
61
{
62
  uint8_t S1;
63
  uint8_t S2;
64
  uint8_t S3;
65
  
66
  S1 = (PINB & (1 << PB5));
67
  if (S1 != 0) S1 = 1;
68
  
69
  S2 = (PINB & (1 << PB6));
70
  if (S2 != 0) S2 = 1;
71
  
72
  S3 = (PINB & (1 << PB7));
73
  if (S3 != 0) S3 = 1;
74
  
75
  
76
  PORTE = ~( (S1 << 0) | (S2 << 1) | (S3 << 2) | (S2 <<3) | (S1 << 4) );
77
  PORTE = (PORTE << Steps); //Mustererzeugung und Shit in 2Steps, einer möglich?
78
}
79
80
81
82
void Init(void)
83
{  
84
  DDRB = 0xFF;
85
  DDRE = 0xFF;
86
  
87
  ICR1 = 0x00FF;
88
  OCR1A = 0x00FC;
89
  OCR1B = 0x00BF;
90
  OCR1C = 0x0001;
91
  TCCR1A = (1 << COM1A0) | (1 << COM1A1) | (1 << COM1B0) | (1 << COM1B1) | (1 << COM1C0) | (1 << COM1C1) | (1 <<WGM11);
92
  TCCR1B = (1 << WGM12) | (1 << WGM13) | (1 << CS10) | (1 << CS11);
93
  
94
  OCR0 = 255;
95
  TCCR0 = (1 << WGM01) | (1 << CS01) | (1 << CS02);
96
  TIMSK = (1 << OCIE0);
97
  
98
  sei();
99
}

von Sebastian V. (sebi_s)


Lesenswert?

J. T. schrieb:
> Müsste das nicht reichen, wenn die Zeit-Variable global definiert ist?

Nein, denn die Zeit Variable wird im Interrupt verändert und davon weiß 
der Compiler in der main Funktion aber nichts. So wie es jetzt steht 
könnte der Compiler auch eine Endlosschleife einbauen weil er nicht 
sieht, dass sich Zeit oder Zeit_alt ändern können. Warum das nicht 
passiert liegt wohl daran, dass du Optimierungen ausgeschaltet hast.

J. T. schrieb:
> Wobei ich mich dunkel erinnere, das ich das auch mal irgendwie so
> hinbekommen hatte, das ich immer eine Differenz aufaddieren konnte, und
> das ganze auch über den Überlauf hinweg geklappt hat.

Versuch mal:
1
while(Zeit - Zeit_alt <= 12)

von J. T. (chaoskind)


Lesenswert?

Sebastian V. O. schrieb:
> Versuch mal:while(Zeit - Zeit_alt <= 12)

Werd ich gleich mal versuchen. Danke auch dafür.

Nun seh ich grad das nächste Problem. Wenn das Lauflicht auf dem 
"Rückweg" ist, bleiben die LED´s an.....

P.S.
Da fällt mirs wie Schuppen von den Augen. Die LEDs auf dem STK500 sind 
ja Lowactiv.

Aber wieso bleiben sie denn nur in einer Richtung an?


P.P.S.
Auch da bleibt er stehen. Wobei ich die Variable noch nicht volatile 
gemacht hab. Ich hab die Optimierungen ausgeschaltet, von daher sollte 
dass dann in dem Fall doch egal sein? Ich erlaube dem Compiler somit 
doch garnicht, irgendwelche Annahmen zu machen?

: Bearbeitet durch User
von J. T. (chaoskind)


Lesenswert?

Ach falschrum... Die LEDs bleiben auf dem "Hinweg" an(LED0 ist aber 
rechts und nicht links). Und noch ein Problem, das damit zu tun hat 
(glaub ich). Ich hab Steps mit 2 initialisiert, in der Hoffnung, das 
damit mein "Startmuster" auch in Richtung LED0 rausgeschoben wird. Dabei 
hab ich aber nicht bedacht, dass damit einfach das Muster nicht an LED0 
startet, sondern  halt mit LED2. Die ist dann "dunkelhell", 
LED3"mittelhell", 4"hell", 5"mittelhell", 6"dunkelhell". Ich müsste also 
eigentlich von Steps (der Wert, um den geshiftet wird) 2 abziehen, damit 
die hellste LED LED0 wird, und somit den Rand erreicht.

Macht der Compiler aus nem negativen leftshift automatisch nen 
entsprechenden rechtshift?

von J. T. (chaoskind)


Lesenswert?

Oder muss ich Steps als int8 machen, und dann bei negativen Werten "per 
Hand" zwischen links und rechtsshift wechseln?

von Sebastian V. (sebi_s)


Lesenswert?

J. T. schrieb:
> Oder muss ich Steps als int8 machen, und dann bei negativen Werten "per
> Hand" zwischen links und rechtsshift wechseln?

Ja. Aus einem Shift nach links um -1 wird kein Rechtsshift.

von J. T. (chaoskind)


Lesenswert?

Ok, das hilft schonmal weiter.

Hast du evtl noch einen Tip zum Anbleiben der LEDs?

ich habs schon mit
1
  PORTE = ~( (S1 << 0) | (S2 << 1) | (S3 << 2) | (S2 <<3) | (S1 << 4) );
2
  PORTE = (PORTE << Steps);
3
  PORTE ^= PORTE;
versucht, aber da bleibt komischerweise alles an, ohne irgendwelches 
Geblinke. "^" ist doch xor? Damit invertiert man doch ein Byte wenn man 
es mit sich selbst xort(schönes Wort, find ich :D)?

: Bearbeitet durch User
von GCC (Gast)


Lesenswert?

Fpga Kuechle schrieb:
> kürzer
> S1 = (PINB & (1 << PB5)) ;
> if (S1 != 0) S1 = 1;
Oder noch kürzer
1
  S1 = (PINB & (1 << PB5)) ? 1 : 0;
oder
1
  S1 = !!(PINB & (1 << PB5));

von Walter S. (avatar)


Lesenswert?

J. T. schrieb:
> PORTE ^= PORTE;
> versucht, aber da bleibt komischerweise alles aus. "^" ist doch xor?
> Damit invertiert man doch ein Byte wenn man es mit sich selbst
> xort(schönes Wort, find ich :D)?

nein, da kommt immer 0 raus

von Sebastian V. (sebi_s)


Lesenswert?

J. T. schrieb:
> "^" ist doch xor? Damit invertiert man doch ein Byte wenn man
> es mit sich selbst xort(schönes Wort, find ich :D)?

Ja ^ is XOR aber XOR mit sich selbst ergibt 0. Wenn du alle Bits 
invertieren willst musst du XOR mit 0xFF machen oder besser du nutzt den 
Operator zum invertieren:
1
PORTE = ~PORTE;

von Walter S. (avatar)


Lesenswert?

GCC schrieb:
> oder  S1 = !!(PINB & (1 << PB5));

oder

S1 = (PINB>>PB5) & 1;

von J. T. (chaoskind)


Lesenswert?

Ich habs. Es liegt daran, das die leeren Stellen vom shiften mit Nullen 
gefüllt werden... Kann man die auch mit 1 füllen lassen?

von Sebastian V. (sebi_s)


Lesenswert?

Walter S. schrieb:
> S1 = (PINB>>PB5) & 1;

Wollte ich auch erst vorschlagen, ist aber teuer auf dem AVR weil man 
immer nur um ein Bit Shiften kann.

von Sebastian V. (sebi_s)


Lesenswert?

J. T. schrieb:
> Ich habs. Es liegt daran, das die leeren Stellen vom shiften mit Nullen
> gefüllt werden... Kann man die auch mit 1 füllen lassen?

Statt:
1
PORTE = (PORTE << Steps);
sowas:
1
PORTE = (PORTE << Steps) | (0xFF >> (8-Steps));

von J. T. (chaoskind)


Lesenswert?

Sebastian V. O. schrieb:
> Ja ^ is XOR aber XOR mit sich selbst ergibt 0. Wenn du alle Bits
> invertieren willst musst du XOR mit 0xFF machen oder besser du nutzt den
> Operator zum invertieren:PORTE = ~PORTE;

Ach ja klar, ich bin auch n Idiot, das hab ich in der Ursprungsversion 
sogar genauso benutzt. Hilft aber hier nicht weiter, da nach dem shiften 
irgendwas wie 11xxxxx00. Die vorderen Einsen vom invertieren fürs 
Ausgeben, in der while, die hinteren Nullen vom Shiften. Wenn ich 
invertiere, hätte ich nur erreicht, dass die LEDs nach vorn statt nach 
hinten wegleuchten.

Also nochmal die Frage, kann man beim shiften auch mit Einsen auffüllen 
lassen?

: Bearbeitet durch User
von J. T. (chaoskind)


Lesenswert?

Sebastian V. O. schrieb:
> J. T. schrieb:
>> Ich habs. Es liegt daran, das die leeren Stellen vom shiften mit Nullen
>> gefüllt werden... Kann man die auch mit 1 füllen lassen?
>
> Statt:PORTE = (PORTE << Steps);sowas:PORTE = (PORTE << Steps) | (0xFF >>
> (8-Steps));

Mhhh eigentlich total offensichtlichh... wieso komm ich auf sowas nicht 
von selbst?

von J. T. (chaoskind)


Lesenswert?

Mhhh irgendwas hapert da aber noch. Sieht aber ganz lustig aus. Das 
"Grundmuster" steht im ersten Schritt an seiner Stelle, fängt an zu 
Wandern, aber gleichzeitig bleibt es die ganze Zeit im an der 
Startstelle stehen.
Also ich hab das stehende Grundmuster, da bewegt sich dann das selbe 
Muster raus, ich habs also einmal stehend und einmal in Bewegung.
Hier ist die aktuellste Version: (Eigentlich nur langsamer gemacht und 
die erwähnten Änderungen)
1
#include <avr/io.h>
2
#include <avr/interrupt.h>
3
4
#define Offset 60
5
6
void Init(void);
7
8
9
uint8_t Zeit = 0;
10
11
ISR (TIMER0_COMP_vect)
12
{
13
  Zeit++;
14
}
15
16
17
int main(void)
18
{  
19
  uint8_t S1;
20
  uint8_t S2;
21
  uint8_t S3;
22
  
23
  uint8_t Steps = 4;
24
  uint8_t UpDownFlag = 0;
25
  
26
  Init();
27
28
  
29
    while(1)
30
    {
31
    Zeit = 0;
32
    
33
    while(Zeit < Offset)
34
    {
35
      S1 = (PINB & (1 << PB5));
36
      if (S1 != 0) S1 = 1;
37
  
38
      S2 = (PINB & (1 << PB6));
39
      if (S2 != 0) S2 = 1;
40
  
41
      S3 = (PINB & (1 << PB7));
42
      if (S3 != 0) S3 = 1;
43
  
44
  
45
      PORTE = ~( (S1 << 0) | (S2 << 1) | (S3 << 2) | (S2 <<3) | (S1 << 4) );
46
      PORTE = (PORTE << Steps) | (0xFF >> (8-Steps));
47
    }
48
    
49
    if (UpDownFlag == 0)
50
    {
51
      Steps++;
52
      if (Steps == 8)
53
      {
54
        UpDownFlag = 1;
55
      }
56
    }else
57
    {
58
      Steps--;
59
      if (Steps == 0)
60
      {
61
        UpDownFlag = 0;
62
      }
63
    }
64
    
65
66
    }
67
}
68
69
70
void Init(void)
71
{  
72
  DDRB = 0xFF;
73
  DDRE = 0xFF;
74
  
75
  ICR1 = 0x00FF;
76
  OCR1A = 0x00FC;
77
  OCR1B = 0x00BF;
78
  OCR1C = 0x0001;
79
  TCCR1A = (1 << COM1A0) | (1 << COM1A1) | (1 << COM1B0) | (1 << COM1B1) | (1 << COM1C0) | (1 << COM1C1) | (1 <<WGM11);
80
  TCCR1B = (1 << WGM12) | (1 << WGM13) | (1 << CS10) | (1 << CS11);
81
  
82
  OCR0 = 255;
83
  TCCR0 = (1 << WGM01) | (1 << CS01) | (1 << CS02);
84
  TIMSK = (1 << OCIE0);
85
  
86
  sei();
87
}

von Karl H. (kbuchegg)


Lesenswert?

Ich versteh hier
1
      PORTE = ~( (S1 << 0) | (S2 << 1) | (S3 << 2) | (S2 <<3) | (S1 << 4) );
2
      PORTE = (PORTE << Steps) | (0xFF >> (8-Steps));
den Sinn nicht bzw. ist das meiner Meinung nach viel zu kompliziert.

Worin liegt der Sinn, ein Muster (das noch invertiert werden muss), erst 
mal im PORTE kompliziert zusammenzusetzen, nur um sich dann hinterher 
damit rumzuärgern, dass man an allen Nicht-Muster-Stellen ein 1 Bit rein 
pfriemeln muss, welche durch die Verschiebung frei geworden sind.

Setz dir doch das Muster zusammen
Schieb es an die richtige Position
dann invertierst du es, weil du das für die Low-activen LED so brauchst
und erst dann gibst du es am Port aus.

Wenn du die Bits umdrehen musst, weil deine LED low-activ sind, dann ist 
es eine gute Idee, wenn diese Invertierung der allerletze Schritt vor 
der Ausgabe ist.
Denn eines ist unbestritten: Wir Menschen tun uns in der Logik leichter, 
wenn wir 'Led leuchtet' mit einer 1 assoziieren. Mit negativer Logik 
verhauen wir uns leicht.

Und ja: Zwischenvariablen zu benutzen macht manchmal vieles leichter, 
weil man dann keine Monsterausdrücke hat. Meistens zieht der Compiler 
die einzelnen Ausdrücke dann ohnehin wieder zusammen und wird die 
Zwischenvariable los.

: Bearbeitet durch User
von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

J. T. schrieb:
> NightRider-Lauflicht
Nur zur Allgemeinbildung: der legendäre Reiter ist kein "Nacht-Reiter", 
sondern ein "Ritter-Reiter" und schreibt sich deshalb mit K am Anfang...
https://de.wikipedia.org/wiki/Knight_Rider

BTW:
1
Antwort schreiben
2
Wichtige Regeln - erst lesen, dann posten!
3
  * Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Karl Heinz schrieb:
> Setz dir doch das Muster zusammen
Ich würde einfach ein Muster im Flash ablegen, und das der Reihe nach 
abfahren. In VHDL (einer üblicherweise als sehr geschwätzig verschrienen 
Hardware-Beschreibungssprache) passt das dann locker auf einen 
Bildschirm. Und ich denke in C wird das nicht viel länger. Siehe dort 
ganz unten:
http://www.lothar-miller.de/s9y/archives/61-Lauflicht.html
Mit ein wenig Überlegen kommt amn locker auf die Idee: die aktuell 
hellste LED ist im ROM. Die wird dauerhaft angeschaltet, danach wird 
dieses Muster in das Register leddimmed übernommen und leuchtet mit 
einer PWM nur die Hälfte der Zeit. Danach wird dieser Wert in ein 
Register ledglow übernommen und leuchtet nur mit 1/4 der 
Tastverhältnis...

: Bearbeitet durch Moderator
von J. T. (chaoskind)


Lesenswert?

Karl Heinz schrieb:
> Ich versteh hier      PORTE = ~( (S1 << 0) | (S2 << 1) | (S3 << 2) | (S2
> <<3) | (S1 << 4) );
>       PORTE = (PORTE << Steps) | (0xFF >> (8-Steps));
> den Sinn nicht bzw. ist das meiner Meinung nach viel zu kompliziert.

Karl Heinz schrieb:
> Denn eines ist unbestritten: Wir Menschen tun uns in der Logik leichter,
> wenn wir 'Led leuchtet' mit einer 1 assoziieren. Mit negativer Logik
> verhauen wir uns leicht.

Genau deshalb. Ich hatte im Hinterkopf das die LEDs Lowavtive sind, also 
hab ich mir gedacht, die normal hellste wird die dunkelste sein, das 
muss ja aber andersrum sein. Also Muster erzeugen und umdrehen. Das 
kommt noch aus meiner ersten Version, wo ich einfach jedes nötige Muster 
als einzelne Funktion gemacht hatte. Das mit dem shiften kam dann erst 
beim Versuch dazu, das ganze in einer Funktion zusammenzufassen, die 
dann Zustandsabhängig das richtige Muster ausgibt.

Das ist also quasi gewachsene Komplexität :D

Hast du zufällig den Beitrag über deinem gelesen? (Manche Leute lesen ja 
nur das Eingangsposting, wobei ich bei dir aus dem Bauch heraus sagen 
würde, du gehörst eher zu denen, die den Threadverlauf wenigst einmal 
überfliegen).
Das Problem dass das Muster doppelt auftaucht (einmal bewegt, einmal 
unbewegt) konnte ich immer noch nicht lösen. Ich hab noch nichtmal einen 
Ansatz, wo das herkommen könnte. Magst du  nochmal in deine gut gefüllte 
Zaubertruhe gucken, ob du da nicht n Wundermittelchen für mich drin 
hast?

Ich hab schon versucht, das ganze mit dem Simulator nachzuvollziehen, 
aber der gibt mir irgendwie sehr verwirrende Sachen aus. Erwartet hatte 
ich, das er mir das Grundmuster ausgibt, nur nicht in unterschiedlichen 
Helligkeiten, sondern in unterschiedlichen Zeitanteilen(das läuft ja 
alles etwas langsamer im Simulator), die die jeweilige LED 0 oder 1 
sind. Die hellste halt dauernd 0(dem Lowactiv geschuldet), die mittlere 
ca 50/50 oder welchen Wert ich da nun genau für gewählt hatte, und die 
dunkelste die meiste Zeit 1und ab und an 0. Aber er irgendwie hat er so 
garnichts ausgeben, was auch nur entfernt an mein Muster erinnert hätte. 
Ich starte mal eben das Studio, ums nochmal kurz nachzuvollziehen.

von J. T. (chaoskind)


Lesenswert?

Also irgendwie stimmen Simulator und Realität nicht überein. Im 
Simulator ist nach der Invertierung LED5 0. Nach ner Weile nextStep 
klicken kommen dann die anderen dazu. Also das ist wie auf dem STK. Das 
bewegte Muster startet auch bei LED5 als hellste. Aber im Simulator 
bleiben LED0-4 auf 1 (also aus), auf dem STK dagegen leuchten sie in 
ganzer Pracht. Mal das Oszi ranhängen und gucken, ob sie wirklich 
leuchten, oder nicht doch Blinken (also die hellste zumindest, die 
dunkleren werden natürlich schon Blinken)......

Ich hätte nicht gedacht, das son einfaches nicht-nächtliches 
Ritter-Reiter-Lauflicht so viel ärger macht.

Lothar Miller schrieb:
> J. T. schrieb:
>> NightRider-Lauflicht
> Nur zur Allgemeinbildung: der legendäre Reiter ist kein "Nacht-Reiter",
> sondern ein "Ritter-Reiter" und schreibt sich deshalb mit K am Anfang...

Da hier gezeigt hast, das du da deutlich mehr als ich drüber weißt, hast 
du dich hiermit zum Experten qualifiziert und darfst mir gleich bei der 
nächsten Frage helfen *gg (alle anderen selbstverständlich auch)

Sieht das Lauflicht überhaupt so aus? also dunkelhell, mittelhell, hell, 
mittelhell, dunkelhell und das läuft dann hin und her? Oder ist das in 
aktueller Laufrichtung Vorderste das hellste, und zieht eine Spur 
dunklerwerdender hinter sich her? (würd mir jetzt grad eigentlich viel 
logischer vorkommen, aber in meiner dunklen Erinnerung wars so, wie ich 
es jetzt gemacht hab)

Lothar Miller schrieb:
> BTW:Antwort schreiben
> Wichtige Regeln - erst lesen, dann posten!
>   * Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Daran dachte ich nach dem posten beim ersten auch, ich sah das es dann 
deutlich länger geworden war, als ich dachte. Aber den 2ten fand ich von 
der Länge eigentlich noch okay, evtl Richtung grenzwertig aber noch ok.

: Bearbeitet durch User
von K.I.T. (Gast)


Lesenswert?

Lothar Miller schrieb:
> J. T. schrieb:
>> NightRider-Lauflicht
> Nur zur Allgemeinbildung: der legendäre Reiter ist kein "Nacht-Reiter",
> sondern ein "Ritter-Reiter" und schreibt sich deshalb mit K am Anfang...
> https://de.wikipedia.org/wiki/Knight_Rider

Hach. Ich mag Lothar, den lieben alten Erbsenzähler. :-)


Hach! Die Amerikaner und ihr Bild von Europo bzw. genauer: Ihr Bild von 
germanischen Sprachen (wobei Englisch ja auch eine ist.).

Denn ein "Ritter" ist per Definition vor allem erstmal ein Reiter, ein 
"Berittener". Die Sendung heisst dann irgendwie "Reiter-Reiter" Aber 
gut. Mir egal.

Denn ich möchte dann doch mal darauf hinweisen, dass nicht etwa der 
Reiter, Rider oder Ritter das Licht getragen oder an sich gehabt hat, 
sondern ich - sein Auto, sein Beschützer und Freund.

;-)

von J. T. (chaoskind)


Lesenswert?

P.S. mal schnell das Multimeter mit Frequenzmessung rangehalten. LED3 
blinkt mit 45kHz bei 52% Pulsweite, also doch kein Dauerleuchten. Wenn 
man genau hinsieht, sieht man auch, das sie heller wird, wenn sich die 
hellste vom bewegten auf die hellste stehende LED "legt"

K.I.T. schrieb:
> Denn ich möchte dann doch mal darauf hinweisen, dass nicht etwa der
> Reiter, Rider oder Ritter das Licht getragen oder an sich gehabt hat,
> sondern ich - sein Auto, sein Beschützer und Freund.

Dafür langt meine geringe nicht-Nacht-Ritter-Reiter-Kenntnis dann doch 
grad noch :D

K.I.T. schrieb:
> Denn ein "Ritter" ist per Definition vor allem erstmal ein Reiter, ein
> "Berittener". Die Sendung heisst dann irgendwie "Reiter-Reiter" Aber
> gut. Mir egal.

Evtl wollten sie nur darauf hinweisen, das er noch krasser als Ritter 
mit krasses Pfärd ist, und daher keine Pferde als Reittier benutzt, 
sondern halt Ritter :D
Ist ja auch irgendwie praktisch, wenn einem das Reittier in der Schlacht 
mit ner 2ten Schwerthand zur Seite stehen kann. Ob die auch Kokosnüsse 
benutzt haben, um guten Hufsound zu haben?

: Bearbeitet durch User
von J. T. (chaoskind)


Lesenswert?

Ich hab jetzt aus:
1
      PORTE = ~( (S1 << 0) | (S2 << 1) | (S3 << 2) | (S2 <<3) | (S1 << 4) );
2
      PORTE = (PORTE << Steps) | (0xFF >> (8-Steps));

das hier:
1
Sammler = ~( (S1 << 0) | (S2 << 1) | (S3 << 2) | (S2 <<3) | (S1 << 4) );
2
      PORTE = (Sammler << Steps) | (0xFF >> (8-Steps));

gemacht, und es geht.

Aber wie kann das sein, das sich das Grundmuster so stark durchgesetzt 
hat, obwohl es doch im nächsten Takt direkt umgeschaltet wurde?

von J. T. (chaoskind)


Lesenswert?

Ich hab  nun mal ein Blick ins Disassembly geworfen. Das erklärte 
einiges.
Da werden ja nur aus der Ausgabe auf PORTE soviele Schritte draus, das 
der gesamte Rest des Programms völlig erblasst. Somit war das nix mit 
meiner Überlegung, dass das die erste Ausgabe nach einem Takt durch 
wäre... Und somit ist das bewegte Lauflicht nahezu gleichlang im Wechsel 
mit dem Stehenden zu sehen, und nicht im von mir angenommen Verhältnis 
von ca "1Takt/Befehl / gesamter Rest des Programms",  das Verhältnis war 
quasi zu "riesiger Haufen Befehle/riesiger Haufen Befehle + winziger 
Rest des Programms" eingeschrumpft worden.

von J. T. (chaoskind)


Lesenswert?

Ich hab nun noch versucht, ein Rechtsshift mit einzubauen.

Karl Heinz schrieb:
> Wenn du die Bits umdrehen musst, weil deine LED low-activ sind, dann ist
> es eine gute Idee, wenn diese Invertierung der allerletze Schritt vor
> der Ausgabe ist.

Hab ich nun auch beachtet, und es liest sich nebenbei auch viel 
angenehmer, wenn man das viele Geshifte durchs frühe Invertieren 
spart.=)


Aber ganz klappt das noch nicht, wenn Steps negativ wird, bleibt das 
Lauflicht im "Grundmuster" stehen, statt über LED0 nach rechts "aus dem 
Bild zu laufen". Wenn Steps dann wieder positiv wird läufts wieder 
sauber. Läuft zurück, bleibt wieder stehen usw.

hier nochmal die Stelle
1
 while(1)
2
    {
3
    Zeit = 0;
4
    
5
    while(Zeit < Offset)
6
    {
7
      S1 = (PINB & (1 << PB5));
8
      if (S1 != 0) S1 = 1;
9
  
10
      S2 = (PINB & (1 << PB6));
11
      if (S2 != 0) S2 = 1;
12
  
13
      S3 = (PINB & (1 << PB7));
14
      if (S3 != 0) S3 = 1;
15
  
16
  
17
      Sammler = ( (S1 << 0) | (S2 << 1) | (S3 << 2) | (S2 <<3) | (S1 << 4) );
18
      
19
      if (Steps > 0)
20
      {
21
        PORTE = ~(Sammler << Steps);
22
      }
23
      else if (Steps < 0)
24
      {
25
        PORTE = ~(Sammler >> Steps);
26
      }
27
      else
28
      {
29
        PORTE = ~(Sammler);  
30
      }
31
    }
32
    
33
    if (UpDownFlag == 0)
34
    {
35
      Steps++;
36
      if (Steps == 8)
37
      {
38
        UpDownFlag = 1;
39
      }
40
    }else
41
    {
42
      Steps--;
43
      if (Steps == -3)
44
      {
45
        UpDownFlag = 0;
46
      }
47
    }
48
    
49
50
    }

von J. T. (chaoskind)


Angehängte Dateien:

Lesenswert?

else if (Steps < 0)
      {
        PORTE = ~(Sammler >> Steps);

Steps ist natürlich negativ, das hab ich nun durch :

[c]
else if (Steps < 0)
{
  Stephalter = 0 - Steps;
  PORTE = ~(Sammler >> Stephalter);
}
ersetzt(Stephalter als int8).

Im Anhang der nochmal der Code für Interessierte

: Bearbeitet durch User
von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

J. T. schrieb:
> Sieht das Lauflicht überhaupt so aus? also dunkelhell, mittelhell, hell,
> mittelhell, dunkelhell und das läuft dann hin und her?
Meines sieht aus wie deines aussehen soll: die erste LED ist hell, 
danach wirds dunkler. Ich werde das aber überarbeiten müssen, denn im 
Auto vom Herrn Knight sind die ersten 3 Lampen hell, die folgenden 
werden dann abnehmend dunkler... :-/

> Sieht das Lauflicht überhaupt so aus?
Siehe dort bei 0:20 oder 1:20
https://www.youtube.com/watch?v=iQwlrEdka6Q
Ein wenig historische Genauigkeit muss sein... ;-)

> Ich hätte nicht gedacht, das son einfaches nicht-nächtliches
> Ritter-Reiter-Lauflicht so viel ärger macht.
Jeder Code, der nicht auf 1 Bilschirmseite passt, macht Ärger. Immer... 
;-)

K.I.T. schrieb:
> Denn ich möchte dann doch mal darauf hinweisen, dass nicht etwa der
> Reiter, Rider oder Ritter das Licht getragen oder an sich gehabt hat,
> sondern ich - sein Auto, sein Beschützer und Freund.
Hallo K.I.T., das Ganze ist mehrschichtig. Dein Fahrer (= rider, naja, 
wenigstens wenn du ein Moped wärst) ist ein gewisser Herr "Michael 
Knight" ist. Damit ist der Knight-Rider eigentlich nur "Fahrer 
Knight"...

von Peter D. (peda)


Lesenswert?


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.