mikrocontroller.net

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


Autor: AVR-Einsteiger (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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:
#ifndef F_CPU
#define F_CPU 1000000UL 
#endif

#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>

#define Rot_an    PORTA |= (1 << PA2)
#define Rot_aus    PORTA &= ~(1 << PA2)

// Variablen definieren
uint8_t timer;
uint8_t rot;

// Interrupt vom Taster 
ISR(INT2_vect)
{ 
rot = rot + 10;
// warte und lösche Interruptflag von Int2 um Tastenprellen zu entgehen
_delay_ms(50);
GIFR = (1<<INTF2); 
}

// Timer-Overflow-Interrupt
ISR (TIMER0_OVF_vect)
{ 
// zähle die Variable Timer von 0-255
timer++;
if (timer > 255) {timer = 0;}
}

int main(void){

// Variablen definieren
timer=0;
rot=0;

// PortA zu Ausgängen
DDRA= 0xff; 
PORTA= 0b00000000; 

// PB0 als Eingang, Pull-Up aktivieren
DDRB  &= ~(1<<PB2);  
PORTB |= (1<<PB2);     

// Int2 aktivieren
GICR|=(1<<INT2);     
//Low Level erzeugt  Interrupt            
MCUCR &= ~(1<<ISC01)|(1<<ISC00);   
                  
// Timer 0 konfigurieren: Prescaler aus, FastPWM-Modus an
  TCCR0 = (1<<CS00);

// Overflow Interrupt aktivieren
    TIMSK |= (1<<TOIE0);

// Global Interrupts aktivieren
   sei();


while(1){

if (timer < rot) {Rot_an;}
else {Rot_aus;}

} //eof while

} //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 !

Autor: Schmitty (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wohl der Standart-Fehler:

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

Der Compiler sieht folgendes:
int main(void){
  // Variablen definieren
  timer=0;
  rot=0;
  [...]//Initialisierungen
  while(1){
    if (timer < rot) {Rot_an;}
    else {Rot_aus;}
  } //eof while
} //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.
volatile uint8_t timer;
volatile uint8_t rot;

Autor: Schmitty (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: AVR-Einsteiger (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Memphis (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Stefan Ernst (sternst)
Datum:

Bewertung
0 lesenswert
nicht 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?

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.