mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik Leuchtdiode blinken


Autor: bin_ich_blöd_oder_was (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich trau mich schon fast nicht zu fragen...
Wo ist mein Denkfehler. Ich möchte nur ne Led zum Blinken bringen. Die 
Led leuchtet allerdings ständig.
Ich verwende ATMega16 und 11MHz Quarz. Fuse ist auf externer Quarz 
eingestellt.

#include <avr/io.h>
#include <avr/interrupt.h>
#include <inttypes.h>
volatile unsigned char zeit;

//Hauptprogramm
int main (void) {
  DDRB= 0xff;               //alle Pins als Ausgang
  PORTB= 0x00;

  zeit=0;

  TIMSK |= (1<<TOIE1);          //Timer1 Overflow Interrupt enable
  TCCR1B |= (1<<CS12|1<<CS10);  //fosc=1/1024
  sei();                        //Interrupts enable
                                //Global Interrupt Enable Bit im Status
                                //Register gesetzt

  while(1) {

    if(zeit==2){
    if ( PINB & (1<<PINB2) ) PORTB &= ~(1<<PB2);
                                //wenn PB2 gesetzt, PB2 auf Null setzen
    else PORTB |= (1<<PB2);     //sonst PB2 auf Eins setzen
    zeit=0;
    }
  }    //while Ende
}    //main Ende


  ISR (TIMER1_OVF_vect){      //Interrupt alle 6s (1/(11MHz/65536))*1024
    zeit++;
    return;
    }

Autor: Der Micha (steinadler)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

du hast vergessen TMRON zu setzen.

Autor: Der Micha (steinadler)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wenn du Abfragen willst, ob der Port gesetzt ist oder nicht, benutzt man 
meines Wissens nach trotzdem das PORTx-Register.
PIN nur, wenn man den Port als Eingang benutzt. Lasse mich hier aber 
auch gern verbessern.

Autor: Lothar Miller (lkmiller) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Und: frag doch besser nicht den Pin sondern das Portregister ab.

Falls der Ausgangstreiber es nicht schafft, den Pin richtig auf Hi oder 
Lo zu ziehen, könntest du dir über den Pin den falschen Pegel 
zurücklesen.
    if(zeit==2){
       PORTB ^= (1<<PB2);  // einfach mal invertieren
       zeit=0;
    }

Autor: willi (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
deine led wird aber nur dann aus sein wenn zeit == 2 ist,  und das sind 
(11MHz / 1024) / 256 = 41,9 Hz ^= 0,0138s. ich denke da ist nicht all zu 
viel zu sehen

Autor: Johannes M. (johnny-m)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
bin_ich_blöd_oder_was wrote:
>     if ( PINB & (1<<PINB2) ) PORTB &= ~(1<<PB2);
>                                 //wenn PB2 gesetzt, PB2 auf Null setzen
>     else PORTB |= (1<<PB2);     //sonst PB2 auf Eins setzen
Erstens wie Micha schon sagte: Du willst den Zustand des Porttreibers 
abfragen, und das geht mit PORTx und nicht mit PINx (was hier aber 
keinen Unterschied machen dürfte). Zweitens kann man das viel kürzer und 
einfacher schreiben:
PORTB ^= 1 << PB2;

@ Micha R.:
Was zum Geier ist TMRON?

Autor: Johannes M. (johnny-m)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
willi wrote:
> deine led wird aber nur dann aus sein wenn zeit == 2 ist,  und das sind
> (11MHz / 1024) / 256 = 41,9 Hz ^= 0,0138s. ich denke da ist nicht all zu
> viel zu sehen
Richtig. Das geht an sich schon schief. Schalte mal direkt in der ISR 
den Portpin um, das müsste eigentlich klappen.

Autor: Der Micha (steinadler)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
willi wrote:
> deine led wird aber nur dann aus sein wenn zeit == 2 ist,  und das sind
> (11MHz / 1024) / 256 = 41,9 Hz ^= 0,0138s. ich denke da ist nicht all zu
> viel zu sehen

Na regelmäßig blinkt die schon, bei 2 wird immer getoggelt.

Sie sollte zumindest dunkler sein.

Ich kommm allerdings auf 72 ms.
(1000ms / (11MHz  1024  256)) * 3 = 71,5ms

Autor: Johannes M. (johnny-m)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Micha R. wrote:
> Ich kommm allerdings auf 72 ms.
> (1000ms / (11MHz  1024  256)) * 3 = 71,5ms
Timer 1 hat beim ATMega16 16 Bit (65536)...

Autor: Johannes M. (johnny-m)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Micha R. wrote:
> Na regelmäßig blinkt die schon, bei 2 wird immer getoggelt.
Nö, sie wird (in der Originalfassung) bei 2 in einen Zustand geschaltet 
und bei "nicht 2" wieder in den anderen. Da die Variable immer zu Null 
gesetzt wird, wenn der Wert 2 erreicht wurde, ist sie sofort danach 
wieder "nicht 2"...

Wenn der OP die Abfrage so ändert, dass nur bei 2 getoggelt wird und 
sonst gar nichts, dann dürfte es klappen.

Autor: Der Micha (steinadler)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Johannes M. wrote:
> Micha R. wrote:
>> Ich kommm allerdings auf 72 ms.
>> (1000ms / (11MHz  1024  256)) * 3 = 71,5ms
> Timer 1 hat beim ATMega16 16 Bit (65536)...

Dann wärens ja sogar 18 Sekunden????

Autor: Der Micha (steinadler)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Johannes M. wrote:
> Micha R. wrote:
>> Na regelmäßig blinkt die schon, bei 2 wird immer getoggelt.
> Nö, sie wird (in der Originalfassung) bei 2 in einen Zustand geschaltet
> und bei "nicht 2" wieder in den anderen. Da die Variable immer zu Null
> gesetzt wird, wenn der Wert 2 erreicht wurde, ist sie sofort danach
> wieder "nicht 2"...
>
> Wenn der OP die Abfrage so ändert, dass nur bei 2 getoggelt wird und
> sonst gar nichts, dann dürfte es klappen.

Ein besser formatierter Original-Code sagt anderes:

if(zeit==2)
{
    if ( PINB & (1<<PINB2) )
        PORTB &= ~(1<<PB2);
                             //wenn PB2 gesetzt, PB2 auf Null setzen
    else
        PORTB |= (1<<PB2);     //sonst PB2 auf Eins setzen
    zeit=0;
}

Also wenn Zeit = 2 wird der Port getoggelt und anschließend wird wieder 
von vorn begonnen.

Autor: Johannes M. (johnny-m)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Micha R. wrote:
> Dann wärens ja sogar 18 Sekunden????
Hä?

Autor: Johannes M. (johnny-m)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Micha R. wrote:
> Ein besser formatierter Original-Code sagt anderes:
Autsch, ja, hast Recht...

Autor: Der Micha (steinadler)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Johannes M. wrote:
> Micha R. wrote:
>> Dann wärens ja sogar 18 Sekunden????
> Hä?
>

Dazu kommt aber noch das Zählen von 0 bis 2.
Also hab ich die 6s mit 3 multipliziert?

Autor: Johannes M. (johnny-m)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Micha R. wrote:
> Dazu kommt aber noch das Zählen von 0 bis 2.
> Also hab ich die 6s mit 3 multipliziert?
Und warum mit 3? zeit ist am Anfang Null und wird nach dem ersten 
Überlauf auf 1 erhöht. Beim zweiten Überlauf wird auf 2 erhöht und damit 
im Hauptprogramm nach zwei Überläufen das Umschalten durchgeführt. Und 
nicht nach 3 Überläufen...

Autor: Der Micha (steinadler)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Johannes M. wrote:
> Micha R. wrote:
> Und warum mit 3? zeit ist am Anfang Null und wird nach dem ersten
> Überlauf auf 1 erhöht. Beim zweiten Überlauf wird auf 2 erhöht und damit
> im Hauptprogramm nach zwei Überläufen das Umschalten durchgeführt. Und
> nicht nach 3 Überläufen...

Stimmt, hast recht. Es sind zwei Durchläufe... also 12 Sekunden. ;-)

Autor: Elbegucker (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi

>Wenn du Abfragen willst, ob der Port gesetzt ist oder nicht, benutzt man
>meines Wissens nach trotzdem das PORTx-Register.
>PIN nur, wenn man den Port als Eingang benutzt. Lasse mich hier aber
>auch gern verbessern.

Also das mit PORT und PIN wusste ich nicht. Danke für den Hinweise.
Würde das nun bedeuten (mal abgesehen vom Sinn oder nicht), dass ich 
auch

    if ( PORTB & (1<<PORTB2) )
        PORTB &= ~(1<<PB2);
                             //wenn PB2 gesetzt, PB2 auf Null setzen
    else
        PORTB |= (1<<PB2);     //sonst PB2 auf Eins setzen

anstatt

    if ( PINB & (1<<PINB2) )
        PORTB &= ~(1<<PB2);
                             //wenn PB2 gesetzt, PB2 auf Null setzen
    else
        PORTB |= (1<<PB2);     //sonst PB2 auf Eins setzen

schreiben könnte?

Leider funktioniert das Blinken im 12s Takt immer noch nicht.

Autor: Der Micha (steinadler)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ja, das müsste funktionieren.

Füg mal den kompletten Code an.

Autor: Elbegucker (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Also mehr ist das nicht.

#include <avr/io.h>
#include <avr/interrupt.h>
#include <inttypes.h>
volatile unsigned char zeit;

//Hauptprogramm
int main (void) {
  DDRB= 0xff;             //alle Pins als Ausgang
  PORTB= 0xff;

  zeit=0;

  TIMSK |= (1<<TOIE1);            //Timer1 Overflow Interrupt enable
  TCCR1B |= (1<<CS12|1<<CS10);
  sei();                          //Interrupts enable


  while(1) {

    if(zeit==2){
       PORTB ^= (1<<PB2);        //invertieren
       zeit=0;
    }
  }    //while Ende
}    //main Ende


ISR (TIMER1_OVF_vect){    //Interrupt alle (1/(CPU/65536))*Vorteiler
    zeit++;
    return;
  }

Autor: Der Micha (steinadler)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ja...

beim Toggeln hast du den else-Zweig vergessen.

    if ( PORTB & (1<<PORTB2) )
        PORTB &= ~(1<<PB2);
                             //wenn PB2 gesetzt, PB2 auf Null setzen
    else
        PORTB |= (1<<PB2);     //sonst PB2 auf Eins setzen

Autor: Detlev T. (detlevt)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Übrigens kann man bei den Atmel Prozessoren die Ausgänge auch toggeln, 
indem man eine 1 an der entprechenden Stelle in das PINx-Register 
schreibt. Also

PINB = (1<<PB2);

Autor: nixversteh (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Öhm... wozu soll das "return" am Ende der ISR gut sein?!

Autor: Elbegucker (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>Ja...

>beim Toggeln hast du den else-Zweig vergessen.

>    if ( PORTB & (1<<PORTB2) )
>        PORTB &= ~(1<<PB2);
>                             //wenn PB2 gesetzt, PB2 auf Null setzen
>    else
>        PORTB |= (1<<PB2);     //sonst PB2 auf Eins setzen

Häää???? Was meinst du? Ich habs doch nun nach euren Vorschlägen hin auf

  while(1) {

    if(zeit==2){
       PORTB ^= (1<<PB2);        //invertieren
       zeit=0;
    }
  }    //while Ende

geändert.

Autor: willi (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>beim Toggeln hast du den else-Zweig vergessen.

nönö er macht ja jetzt nen exclusiv-oder, da brauchts kein else

Autor: Johannes M. (johnny-m)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Detlev T. wrote:
> Übrigens kann man bei den Atmel Prozessoren die Ausgänge auch toggeln,
> indem man eine 1 an der entprechenden Stelle in das PINx-Register
> schreibt. Also
>
> PINB = (1<<PB2);
Beim Mega16 geht das aber nicht! Deshalb ist die Aussage "Bei den 
ATMEL-Prozessoren..." nicht nur wegen der Verallgemeinerung "ATMEL = 
AVR" falsch. ATMEL baut auch andere "Prozessoren" als AVRs...

Das return ist tatsächlich flüssiger als Wasser, dürfte so aber auch 
zumindest nicht zu Fehlfunktionen führen.

Autor: Detlev T. (detlevt)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@Johannes M.:
Du hast in allen Punkten recht. Das geht tatsächlich nur mit Tiny-AVRs. 
Mein Irrtum.

Autor: Johannes M. (johnny-m)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Detlev T. wrote:
> @Johannes M.:
> Du hast in allen Punkten recht. Das geht tatsächlich nur mit Tiny-AVRs.
> Mein Irrtum.
Auch das ist falsch. Es geht mit allen neueren AVRs, auch mit ATMegaXYZ, 
aber es sind nach wie vor einige AVRs älteren Entwicklungsdatums auf dem 
Markt, die dieses Feature noch nicht haben (z.B. ATMega8, ATMega16/32, 
ATMega162, ATMega64/128). Der aktuelle ATMega16-Nachfolger ATMega164 hat 
z.B. die von Dir angesprochene Möglichkeit, über die PINx-Register die 
Pins zu toggeln. Gleiches gilt z.B. für ATMega48/88/168 usw.

Autor: saeckereier (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Müssen die Interrupts nicht auch erst per FUSE angeschaltet werden? Ist 
das sei nicht überflüssig?

Autor: Johannes M. (johnny-m)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
saeckereier wrote:
> Müssen die Interrupts nicht auch erst per FUSE angeschaltet werden? Ist
> das sei nicht überflüssig?
Unsinn. Die globale Interrupt-Freigabe erfolgt durch sei() und nicht 
anderes. Die Fuses haben nichts mit der Interrupt-Bearbeitung zu tun.

Autor: Philipp Burch (philipp_burch)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Könnte es sein, dass dein Proz immer noch mit 1MHz läuft? Dann wird die 
LED zwar blinken, jedoch nur alle 11*12=132s. Das kann man schon fast 
als Dauerleuchten interpretieren... Überprüf mal die Fuses.

Autor: Michael K. (mmike)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Probiers mal so:

#include <avr/io.h>
#include <avr/interrupt.h>
#include <inttypes.h>

//Interrupt alle (1/(CPU/65536))*Vorteiler
ISR (TIMER1_OVF_vect)
{
  static uint8_t zeit = 0;
  if (++zeit >= 2)
  {
    PORTB ^= ( 1 << PB2 );
    zeit = 0;
  }
}


//Hauptprogramm
int main (void)
{
  DDRB= 0xff;             //alle Pins als Ausgang
  PORTB= 0xff;

  TIMSK |= (1<<TOIE1);            //Timer1 Overflow Interrupt enable
  TCCR1B |= (1<<CS12|1<<CS10);

  sei();                          //Interrupts enable

  while(1)
  {
    // ggf. noch nen sleep um Energie zu sparen
  }
}

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.