-         

Ergebnis 1 bis 8 von 8

Thema: Timer und Interrupt

  1. #1

    Timer und Interrupt

    Anzeige

    Hallo,

    ich habe hier erstmals ein AtMega16 vorliegen und tue mich zur Zeit noch etwas schwer.
    Ich habe in der Vergangenheit nur mit Mikroprozessoren der 8051Serie gearbeitet.

    Und zwar möchte ich zur Einarbeitung erst mal eine ISR jede sekunde ausführen.

    Ich habe mir dazu gedacht den 16Bit zähler hochzählen zu lassen und sobald der Wert mit meinem Errecheneten Wert übereinstimmt soll die ISR aufgerufen werden.

    Nun meine erste frage, wie erechene ich den Wert.
    Meine annahme: Vergleichswert = 8MHz * 1s / 1024
    Wenn ich den Vorteiler auf 1024 setze.
    Das macht bei mir 7812,5 -> 7812

    Falls das richtig ist, was ist dann an meinem Code falsch bzw, was habe ich vergessen:
    Code:
        TCCR1B = (1<<WGM12) | (1<<CS12) | (1<<CS10);
        
        OCR1AH = 30;
        OCR1AL = 132;	/*Representiert 7812*/
        
        TIMSK |= (1<<OCIE1A); /*Interrupt bei gleichheit*/
        sei();
    Meine ISR wird angesprungen aber häufiger als jede sekunde.
    CS12 und CS10 setzen den Vorteiler auf 1024.
    WGM12 sorgt dafür das der Zähler geleert wird bei gleichheit.

    Meine ISR sieht folgendermaßen aus:
    Code:
    SIGNAL(SIG_OUTPUT_COMPARE1A)
    {
        /*mach was...*/
    }
    mfg C-M-M

  2. #2
    Erfahrener Benutzer Robotik Einstein Avatar von SprinterSB
    Registriert seit
    09.06.2005
    Ort
    An der Saar
    Beiträge
    2.801
    Sieht doch ok aus, bis auf den Rundungsfehler. Der ini-Wert für OCR1A:
    Code:
    #define F_CPU 8000000
    #define INTS_PER_SECOND 1
    #define PRESCALE 1024
    
    ...
       OCR1A = (uint16_t) ((uint32_t) F_CPU*INTS_PER_SECOND/PRESCALE-1);
    Evtl. liegts an der Reihenfolge, in der OCR1AH und OCR1AL geschrieben werden. Das ist nicht egal. Lass das GCC machen mit OCR1A=..., der weiß die richtige Reihenfolge.

    Mit Prescale = 256 gibt's auch keinen Rundungsfehler mehr.
    Disclaimer: none. Sue me.

  3. #3
    Danke schon mal für die schnelle Antwort.
    Leide hat es nicht geholfen.
    Laut ATmega16 dukumentation hatte ich den Wert auch in richtiger Reihenfolge geschrieben(zufall ).
    Die ISR wird scheinbar ständig aufgerufen. Das interrupt flag muß doch in der SIGNAL routine nicht extra gelöscht werden oder? (hat jedenfalls auch nichts gebracht)

    Könnte es sein das die Fusebits vieleicht falsch gesetzt sind?
    Ich bin mit meinem Latain am Ende, ich wollte nur mal kurz ein kleines Programm schreiben um mich einzuarbeiten. Wenn das nicht mal klappt weiß ich nicht wie ich ein Funktionsfähiges Programm schreiben soll.....

    mfg c-m-m

  4. #4
    Erfahrener Benutzer Roboter Genie
    Registriert seit
    04.04.2005
    Ort
    Hamburg
    Alter
    29
    Beiträge
    826
    Also mein Problem, war mal, dass es einfach um das 8-fach zu langsam war und zwar weil ich halt die Fuses ncoh auf 1 Mhz internen Oszi hatte.

    Das fiese war auch noch, dass es halt invertiert ist. D.h. ein Haken bedeutet, dass das Fuse NICHT gesetzt ist. Das ist allerdings nicht bei jedem µC gleich, aber bei nem Mega16 ist es so. (Bin ich mir ziemlich sicher)

    Andun
    www.subms.de
    Aktuell: Flaschcraft Funkboard - Informationssammlung

  5. #5
    Erfahrener Benutzer Robotik Einstein Avatar von SprinterSB
    Registriert seit
    09.06.2005
    Ort
    An der Saar
    Beiträge
    2.801
    Zitat Zitat von c-m-m
    Die ISR wird scheinbar ständig aufgerufen. Das interrupt flag muß doch in der SIGNAL routine nicht extra gelöscht werden oder?
    So ist es; das Flag muss nicht extra gelöscht werden, wenn man über IRQ geht.

    Bist du sicher, daß die ISR immer wieder aufgerufen wurd? Oder landest du immer wieder im RESET? In letzterem Falle tritt warscheinlich eine nicht implementierte IRQ auf, was nach __bad_interrupt abgebildet wird und nen Warmstart macht.

    Poste man den kompletten Code, ist ja net so viel.
    Disclaimer: none. Sue me.

  6. #6
    Hier mal mein Programm.
    Ich weiß das es schlecht programmiert ist und der Interrupt eigentlich wenig Sinn macht weil der Contoller aktiv wartet.
    Das programm stellt ein Lauflicht dar, welches funktioniert hat als ich in der wait() funktion noch mit Schleifen gewartet habe.

    Code:
    #include <inttypes.h>
    #include <avr/io.h>
    #include <avr/wdt.h>
    #include <avr/signal.h>
    #include <avr/interrupt.h>
    
    #define F_CPU 8000000
    #define INTS_PER_SECOND 1
    #define PRESCALE 256
    
    void wait(void);
    
    volatile uint8_t wasinterrupted;
    
    main()
    {
        wdt_disable();
    
        TCCR1B = (1<<WGM12) | (1<<CS11) | (1<<CS10);
        
        OCR1A = (uint16_t) ((uint32_t)F_CPU*INTS_PER_SECOND/PRESCALE);
        
        TIMSK |= (1<<OCIE1A);
    
        wasinterrupted = 0;
        sei();
    
    
        DDRC = 0xff;
        PORTC = 0xFE;
        while(1)
        {
    	PORTC = 0xFE;
    	wait();
    	PORTC = 0xFD;
    	wait();
    	PORTC = 0xFB;
    	wait();
    	PORTC = 0xF7;
    	wait();
    	PORTC = 0xEF;
    	wait();
    	PORTC = 0xDF;
    	wait();
    	PORTC = 0xBF;
    	wait();
    	PORTC = 0x7F;
    	wait();
        	}
    }
    
    void wait()
    {
        while(!wasinterrupted);
        wasinterrupted = 0;
    }
    
    
    SIGNAL(SIG_OUTPUT_COMPARE1A)
    {
        wasinterrupted++;
    }

  7. #7
    Erfahrener Benutzer Robotik Einstein Avatar von SprinterSB
    Registriert seit
    09.06.2005
    Ort
    An der Saar
    Beiträge
    2.801
    Da gehen mir langsam die Ideen aus...
    Mit dem WDT hab ich noch nicht gearbeitet, evtl schlägt er zu, bevor du in main() ankommst. In diesem Falle musst du das WDT-Disable früh machen, also vor der Initialisierung und bevor du nach main kommst.

    Einige kleine Änderungen, die aber nicht groß was zur Sache tun. Aber man weiß ja nie
    Ist jetzt ein 7-stelliges Lauflicht und die 8. LED blinkt.

    Code:
    #include <avr/io.h>
    #include <avr/wdt.h>
    #include <avr/signal.h>
    #include <avr/interrupt.h>
    
    #define F_CPU 8000000
    #define INTS_PER_SECOND 1
    #define PRESCALE 256
    
    void wait(void);
    
    volatile uint8_t wasinterrupted = 0;
    
    main()
    {
        wdt_disable();
    
        DDRC = 0xff;
        PORTC = 0xbf;
    
        TCCR1A = 0;
        TCCR1B = (1<<WGM12) | (1<<CS11) | (1<<CS10);
        
        OCR1A = (uint16_t) ((uint32_t)F_CPU*INTS_PER_SECOND/PRESCALE);
        
        TIFR = (1<<OCF1A);
        TIMSK = (1<<OCIE1A);
    
        sei();
    
        while(1)
        {
    	PORTC ^= 0x41;
    	wait();
    	PORTC ^= 3<<0;
    	wait();
    	PORTC ^= 3<<1;
    	wait();
    	PORTC ^= 3<<2;
    	wait();
    	PORTC ^= 3<<3;
    	wait();
    	PORTC ^= 3<<4;
    	wait();
    	PORTC ^= 3<<5;
    	wait();
        	}
    }
    
    void wait()
    {
        wasinterrupted = 0;
        while (!wasinterrupted);
    }
    
    
    SIGNAL(SIG_OUTPUT_COMPARE1A)
    {
        wasinterrupted = 1;
        PORTC ^= 0x80;
    }
    Disclaimer: none. Sue me.

  8. #8
    Schönen dank an alle, ich habe mein Problem gelöst.
    Es hatte nichts mit der Programmierung zu tun.
    Ich habe die Fuse bits nun so gesetzt das ich die interne Clock verwende.
    Jetzt muß ich nur noch herausfinden ob ich die Fusebits falsch gesetzt hatte oder ob ich ein Fehler auf meine Board habe.

    mfg c-m-m

Berechtigungen

  • Neue Themen erstellen: Nein
  • Themen beantworten: Nein
  • Anhänge hochladen: Nein
  • Beiträge bearbeiten: Nein
  •