Forum: Mikrocontroller und Digitale Elektronik led toogle mit mega88


von Gast (Gast)


Lesenswert?

Hallo,

folgendes Programm mit einem ATmega88 läuft bei mir nicht:
1
#include <avr/io.h>
2
#include <avr/interrupt.h>
3
4
#define F_CPU 8000000
5
6
volatile int counter = 0;
7
8
9
int main( void ) {
10
11
  DDRC = 0xFF;                    // PORTC als Ausgang, LEDS aus
12
13
  TCCR0B |= (1<<CS00) | (1<<CS02);          // Prescaler = 1024, Timer aktivieren
14
  TIMSK0 |= (1<<TOIE0);                // Interrupt für TimerOverflow aktivieren
15
  sei();                        // Interrupts global aktivieren
16
17
  PORTC = 0x00;                    // Alle LEDS an
18
19
  return(0);    
20
}
21
22
23
ISR( TIMER0_OVF_vect ) {                // Timer InterruptHandler, Ausführung 30.5 mal pro Sekunden
24
  
25
  counter++;  
26
    
27
  if( counter >= 5 ) {
28
29
    switch( PORTC ) {
30
31
    case 0x00:
32
      
33
      PORTC = 0xFF;
34
35
    case 0xFF:
36
37
      PORTC = 0x00;
38
39
    }
40
  
41
  counter = 0;
42
43
  }  
44
}


Ich habs jetzt schon so oft kontrolliert aber ich find den Fehler nicht. 
Die Leds bleiben einfach an, da tut sich nichts. Sollten eigentlich so 
ca. 6 mal pro Sekunde wechseln. Das CKDIV8 Fuse ist nicht gesetzt.

Thx

von Fred S. (Gast)


Lesenswert?

Hi,

Dein main() läuft 1x bis zum "return" und dann? Also

int main(void){

// Initialisierung etc.
   sei;

   while (1) {};

   return 1; // nur um den Compiler glücklich zu machen....
}

Gruß

Fred

von Karlheinz (Gast)


Lesenswert?

PORTC = 0x00;                    // Alle LEDS an

 while ( 1 )
  ;

 return(0);
}

von Philipp R. (relaxxo)


Lesenswert?

setz ne endlosschleife nach "PORTC = 0x00;"  in die main-routine. dann 
sollte es funktionieren.

von Εrnst B. (ernst)


Angehängte Dateien:

Lesenswert?

Im Anhang ein Schnipsel aus dem Datenbatt:
PORTC hat nur 7 Bits, dass höchstwertige (8te) Bit ist immer 0.

d.H. dein Vergleich PORTC==0xFF kann nie wahr werden.

von Gast (Gast)


Lesenswert?

Da tut sich immer noch nichts. LEDs bleiben einfach an :-/

von Gast (Gast)


Lesenswert?

Aha, soll ichs dann so schreiben? 0b1111111 ? Oder per Bitmanipulation 
nur die Bits ansprechen, die ich wirklich brauche?

von Εrnst B. (ernst)


Lesenswert?

An die Drei "while(1)"-Poster:

Das brauchts nicht wirklich, diese Enlosschleife ist in der avr-libc 
(Startupcode) mit drinnen, falls man wirklich aus der main returned:
1
00000054 <main>:
2
......
3
  60:   00 c0           rjmp    .+0             ; 0x62 <_exit>
4
5
00000062 <_exit>:
6
  62:   ff cf           rjmp    .-2             ; 0x62 <_exit>

von Johannes M. (johnny-m)


Lesenswert?

1
switch( PORTC ) {
2
3
    case 0x00:
4
      
5
      PORTC = 0xFF;
6
7
    case 0xFF:
8
9
      PORTC = 0x00;
10
11
    }
Das ganze ist ziemlich umständlich. Schreib lieber
1
PORTC ~= PORTC;
oder
1
PORTC ^= 0xFF;
Das ist ein bisschen kürzer und macht im Prinzip dasselbe...

von Gast (Gast)


Lesenswert?

Mich würd erstmal freuen wenn überhaupt was blinken würde ;) Aber 
trotzdem Danke

von Fred S. (Gast)


Lesenswert?

Hallo Ernst,

> Das brauchts nicht wirklich, diese Enlosschleife ist in der avr-libc
> (Startupcode) mit drinnen, falls man wirklich aus der main returned:
...danke, das hatte ich nicht gewusst!

Gruß

Fred

von Gast (Gast)


Lesenswert?

da tut sich aber auch nichts wenn ich den counter zb auf 100 erhöhe, 
habs jetzt mal mit PortD versucht:
1
#include <avr/io.h>
2
#include <avr/interrupt.h>
3
4
#define F_CPU 8000000
5
6
volatile int counter = 0;
7
8
9
int main( void ) {
10
11
  DDRD = 0xFF;                    // PORTC als Ausgang, LEDS aus
12
13
  TCCR0B |= (1<<CS00) | (1<<CS02);          // Prescaler = 1024, Timer aktivieren
14
  TIMSK0 |= (1<<TOIE0);                // Interrupt für TimerOverflow aktivieren
15
  sei();                        // Interrupts global aktivieren
16
17
  PORTD = 0x00;                    // Alle LEDS an
18
19
  while( 1 )
20
21
  return(0);    
22
}
23
24
25
ISR( TIMER0_OVF_vect ) {                // Timer InterruptHandler, Ausführung 30.5 mal pro Sekunden
26
  
27
  counter++;  
28
    
29
  if( counter >= 100 ) {
30
31
    switch( PORTD ) {
32
33
    case 0x00:
34
      
35
      PORTD = 0xFF;
36
37
    case 0xFF:
38
39
      PORTD = 0x00;
40
41
    }
42
  
43
  counter = 0;
44
45
  }  
46
}

von Johannes M. (johnny-m)


Lesenswert?

Es ist auch nicht sinnvoll, für eine Zählvariable einen 16-Bit-Integer 
zu nehmen, der dazu noch vorzeichenbehaftet ist. Mach aus der Variable 
mal
1
volatile unsigned char counter;
Die Initialisierung mit 0 kann man sich bei globalen Variablen sparen.

von Johannes M. (johnny-m)


Lesenswert?

1
 while( 1 )
2
3
  return(0);
Das ist auch Unsinn. Hinter dem while(1) fehlt ein Semikolon. Das return 
kann man sich dann komplett schenken. Abgesehen davon gehören keine 
Klammern um das "Argument" von return. Wenn schon, dann
1
while(1);
2
3
return 0;

von Karsten B. (k-duke)


Lesenswert?

Hallo Gast!
Du hast die Initialiesierungen alle man in der Main-Funktion drinne.
Die gehören davor, da diese eigentlich nur einmal aufgerufen werden 
sollen.
1
  DDRC = 0xFF;                    // PORTC als Ausgang, LEDS aus
2
  TCCR0B |= (1<<CS00) | (1<<CS02);      // Prescaler = 1024, Timer aktivieren
3
  TIMSK0 |= (1<<TOIE0);             // Interrupt für TimerOverflow aktivieren
4
  sei();                        // Interrupts global aktivieren
5
  PORTC = 0x00;                    // Alle LEDS an

Der ganze Kram muss VOR die Main-Funktion stehen.
Dann sollte es klappen ;-)
MFG K-Duke

von Gast (Gast)


Lesenswert?

Ok abgeändert, weiterhin leuchten die LEDs nur:
1
#include <avr/io.h>
2
#include <avr/interrupt.h>
3
4
#define F_CPU 8000000
5
6
volatile unsigned char counter;
7
8
9
int main( void ) {
10
11
  DDRD = 0xFF;                    // PORTC als Ausgang, LEDS aus
12
13
  TCCR0B |= (1<<CS00) | (1<<CS02);          // Prescaler = 1024, Timer aktivieren
14
  TIMSK0 |= (1<<TOIE0);                // Interrupt für TimerOverflow aktivieren
15
  sei();                        // Interrupts global aktivieren
16
17
  PORTD = 0x00;                    // Alle LEDS an
18
19
  while( 1 );
20
21
}
22
23
24
ISR( TIMER0_OVF_vect ) {                // Timer InterruptHandler, Ausführung 30.5 mal pro Sekunden
25
  
26
  counter++;  
27
    
28
  if( counter >= 100 ) {
29
30
    switch( PORTD ) {
31
32
    case 0x00:
33
      
34
      PORTD = 0xFF;
35
36
    case 0xFF:
37
38
      PORTD = 0x00;
39
40
    }
41
  
42
  counter = 0;
43
44
  }  
45
}

von Karheinz (Gast)


Lesenswert?

@Ernst: Danke auch von mir.

@Gast (Gast): Die switch Anweisung funktioniert nicht ( siehe Ernst 
Bachmann (ernst) und Johannes M. (johnny-m) )!

von Johannes M. (johnny-m)


Lesenswert?

Karsten B. wrote:
> Hallo Gast!
> Du hast die Initialiesierungen alle man in der Main-Funktion drinne.
> Die gehören davor, da diese eigentlich nur einmal aufgerufen werden
> sollen.
>
1
  DDRC = 0xFF;                    // PORTC als Ausgang, LEDS aus
2
>   TCCR0B |= (1<<CS00) | (1<<CS02);      // Prescaler = 1024, Timer
3
> aktivieren
4
>   TIMSK0 |= (1<<TOIE0);             // Interrupt für TimerOverflow
5
> aktivieren
6
>   sei();                        // Interrupts global aktivieren
7
>   PORTC = 0x00;                    // Alle LEDS an
>
> Der ganze Kram muss VOR die Main-Funktion stehen.
> Dann sollte es klappen ;-)
> MFG K-Duke
Vor der main()-Funktion dürfen überhaupt keine Initialisierungen 
stehen! Lies Dir mal ein C-Buch durch, bevor Du hier so einen Unfug 
erzählst! In C darf Code nur innerhalb von Funktionen stehen.

Der ganze Kram steht da schon richtig.

von Johannes M. (johnny-m)


Lesenswert?

@ Gast:
Karlheinz hat natürlich völlig recht: solange immer noch das unsinnige 
und so wie es da steht nicht funktionierende switch-case da steht, 
kann es nicht funktionieren! Nimm eine der beiden von mir weiter oben 
geposteten Versionen. Die funktionieren sicher!

EDIT: Sehe grad, dass Du auf PORTD gewechselt hast. Sollte dann zwar 
eigentlich funktionieren, aber ist trotzdem unsinnig.

von Philipp R. (relaxxo)


Lesenswert?

switch( PORTD ) {

    case 0x00:
      PORTD = 0xFF;
    break;
    case 0xFF:
      PORTD = 0x00;
    break;
    }

muss die switch-anweisung nicht so aussehen?

von Gast (Gast)


Lesenswert?

Wie du Recht hast :)

Mit:

PORTD ^= 0xFF;

funktionierts.

Mit:

PORTD ~= PORTD;

bekomm ich nen: ../LED_Strobo.c:34: error: expected ';' before '~' token


Warum funktioniert die Switch Anweisung so nicht?

Danke

von Gast (Gast)


Lesenswert?

Stimmt ein break; hat gefehlt. So nimmt er das als eine 
Anweisung....verdammt

von Johannes M. (johnny-m)


Lesenswert?

Gast wrote:
> Warum funktioniert die Switch Anweisung so nicht?
Unter anderem, weil wir alle bis auf einen gewissen Relaxxo übersehen 
haben, dass Du die breaks vergessen hast! Zumindest nach dem ersten 
case muss ein break stehen!

von Johannes M. (johnny-m)


Lesenswert?

Gast wrote:
> Mit:
>
> PORTD ~= PORTD;
>
> bekomm ich nen: ../LED_Strobo.c:34: error: expected ';' before '~' token
Das kann eigentlich nicht sein, wenn vorher alles stimmt. Ich vermute 
mal, Du hast in der Zeile davor einen Bock drin (eben z.B. ein 
vergessenes ";").

von Philipp R. (relaxxo)


Lesenswert?

ohne Break-anweisung werden die nachstehenden cases auch abgearbeitet. 
bis zum nächstem break bzw. zum Switch-Anweisungs-Ende

von Johannes M. (johnny-m)


Lesenswert?

Siehst Du jetzt, warum switch an so einer Stelle völliger Unsinn ist? 
Erstens ist es fehleranfällig, zweitens macht switch nur dann Sinn, 
wenn man deutlich mehr als zwei Fälle unterscheiden muss und drittens 
gibt es grad in diesem Fall mehrere Varianten, das ganze einzeilig zu 
schreiben.

Wenn man schon eine Verzweigung mit zwei Möglichkeiten machen will, dann 
in so einem Fall ein if-else
1
if(!PORTD)
2
    PORTD = 0xFF;
3
else
4
    PORTD = 0;

von Gast (Gast)


Lesenswert?

Alles klar! Dank an alle. Schönen Abend noch.

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.