Forum: Mikrocontroller und Digitale Elektronik Soft-PWM, GCC, ATMEGA16


von AVR-Einsteiger (Gast)


Lesenswert?

Guten Abend,

ich versuche schon den ganzen Tage ein kleines Programm zu schreiben, 
welches im Endeffekt eine LED dimmen soll.
Leider klappt es einfach nicht :-(.

Da ich schon in vielen Tutorials gesucht habe (auch im GCC-Tutorial von 
mikrocontroller.net), jedoch meinen Fehler nicht finden kann, wende ich 
mich nun an euch.

Die verbaute Hardware:
- der Atmega 16
- eine rote LED an PA2 und
- ein Taster an PB2

Mein Code:
1
#ifndef F_CPU
2
#define F_CPU 1000000UL 
3
#endif
4
5
#include <avr/io.h>
6
#include <util/delay.h>
7
#include <avr/interrupt.h>
8
9
#define Rot_an    PORTA |= (1 << PA2)
10
#define Rot_aus    PORTA &= ~(1 << PA2)
11
12
// Variablen definieren
13
uint8_t timer;
14
uint8_t rot;
15
16
// Interrupt vom Taster 
17
ISR(INT2_vect)
18
{ 
19
rot = rot + 10;
20
// warte und lösche Interruptflag von Int2 um Tastenprellen zu entgehen
21
_delay_ms(50);
22
GIFR = (1<<INTF2); 
23
}
24
25
// Timer-Overflow-Interrupt
26
ISR (TIMER0_OVF_vect)
27
{ 
28
// zähle die Variable Timer von 0-255
29
timer++;
30
if (timer > 255) {timer = 0;}
31
}
32
33
int main(void){
34
35
// Variablen definieren
36
timer=0;
37
rot=0;
38
39
// PortA zu Ausgängen
40
DDRA= 0xff; 
41
PORTA= 0b00000000; 
42
43
// PB0 als Eingang, Pull-Up aktivieren
44
DDRB  &= ~(1<<PB2);  
45
PORTB |= (1<<PB2);     
46
47
// Int2 aktivieren
48
GICR|=(1<<INT2);     
49
//Low Level erzeugt  Interrupt            
50
MCUCR &= ~(1<<ISC01)|(1<<ISC00);   
51
                  
52
// Timer 0 konfigurieren: Prescaler aus, FastPWM-Modus an
53
  TCCR0 = (1<<CS00);
54
55
// Overflow Interrupt aktivieren
56
    TIMSK |= (1<<TOIE0);
57
58
// Global Interrupts aktivieren
59
   sei();
60
61
62
while(1){
63
64
if (timer < rot) {Rot_an;}
65
else {Rot_aus;}
66
67
} //eof while
68
69
} //eof main

Die Interrupt vom Taster funktioniert einwandfrei(auch wenn ich in 
dieser 50ms Zeit verschwende, was ja nicht elegant ist, aber zu 
Testzwecken ausreicht denke ich).

Ich habe den Code außerdem im AVR-Studio simuliert. Hier zählt er die 
Variable "timer" immer von 0-255 hoch, vergleicht diese aber nie mit der 
Variable rot.

Vielen Dank schonmal für eure Hilfe !

von Schmitty (Gast)


Lesenswert?

Wohl der Standart-Fehler:

Die beiden Variablen
1
uint8_t timer;
2
uint8_t rot;
sollten als volatile deklariert werden.

Der Compiler sieht folgendes:
1
int main(void){
2
  // Variablen definieren
3
  timer=0;
4
  rot=0;
5
  [...]//Initialisierungen
6
  while(1){
7
    if (timer < rot) {Rot_an;}
8
    else {Rot_aus;}
9
  } //eof while
10
} //eof main
Er weiß nicht, dass timer und rot noch von einer Interrupt-Funktion, 
die er im main() nicht findet, verändert werden können. Das teilst Du 
ihm mit volatile mit.
1
volatile uint8_t timer;
2
volatile uint8_t rot;

von Schmitty (Gast)


Lesenswert?

Ergänzung:
Der Compiler bemerkt, dass er die if-Bedingung super optimieren kann. 
Beide Variablen sind aus seiner Sicht konstant =0, da muss er nicht mehr 
viel vergleichen sondern kann direkt den else-Zweig ausführen.

Durch volatile teilst Du dem Compiler mit, dass er  sich nicht darauf 
verlassen sollte, dass die Variable konstant bleibt.

von AVR-Einsteiger (Gast)


Lesenswert?

Vielen Dank!

Nun scheint alles su zu funktionieren wie ich mir das vorgestellt habe 
und ich hätte noch laaaange nach dem fehler suchen müssen, da ich C auch 
neu lerne.

von Memphis (Gast)


Lesenswert?

und noch ein tip:

in deiner Timer ISR:

if (timer > 255) {timer = 0;}

kannst Du Dir sparen. "timer" ist eine 8Bit Variable und läuft 
automatisch bei 255+1 auf 0 über. Vorausgesetzt, dass der Timer0 bei 
deinem Atmel ein 8Bit Timer ist kannst Du auch direkt das Register TCNT0 
nehmen und dir die Variable "timer" sparen.

ciao

Christian

von Stefan E. (sternst)


Lesenswert?

Memphis schrieb:
> Vorausgesetzt, dass der Timer0 bei
> deinem Atmel ein 8Bit Timer ist kannst Du auch direkt das Register TCNT0
> nehmen und dir die Variable "timer" sparen.

Wie soll das denn gehen?

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.