Mein Interupt macht nicht das was ich will (atmega 328p @20 MHz)

Gast #3389157
Schönen guten Abend,

ich versuche seit 2 Stunden dieses Interrupt im ctc modus zum laufen zu 
bringen. Aber egal welche Zahl ich ins Register schreibe, die LED blinkt 
immer gleich schnell (bei dem geschriebenen Programm im Sekundentakt). 
Hat vielleicht jemand einen Tip für mich? Ich habe den verdacht dass 
mein Timer irgendwie nicht zurück gesetzt wird. Kann es sein dass der 
Timer nicht mit dem 20MHz quarz läuft?

Vielen Dank im Vorraus

Markus

#include <avr/io.h>
#include <asf.h>
#include <math.h>
#include <stdlib.h>
#ifndef F_CPU
#define F_CPU 20000000UL
#endif
#include <util/delay.h>
#include <avr/interrupt.h>


void servo_init(void);

#define SERVOPIN 1
#define SERVOPORT PORTD
#define DDRSERVO DDRD

long double t=0;


ISR(TIMER0_COMPA_vect)        //interrupt
{

  t++;

}

void servo_init(void)
{
  TIMSK0|=(1<<OCIE0A);          //interrupts
  TCCR0B |= (1<<CS00);          //Prescale=1,
  TCCR0A |= (1<<WGM01);          // CTC mode
  OCR0A = 200;      //alle 10µs ein IRQ 0,00001s
  DDRSERVO|=(1<<SERVOPIN);        //LED Pin als ausgang

}

int main (void)
{


  servo_init();
  sei ();        //interrups an

  while(1)
  {

    if (t<20000)SERVOPORT|=(1<<SERVOPIN);  //bis zum 20000. durchlaufen 
des Interrupts LED AN (200ms)
    else SERVOPORT &=(0<<SERVOPIN);    //ab dann LED AUS
    if (t>40000) t=0;      // bei 40000. interruptdurchlauf t 
zurücksetzen (insg. 400ms)

  }
}
Sieht mir eigentlich alles gut aus, grad nochmal ins Datenblatt 
geschaut.
Das mit dem Volatile kann eigentlich deshalb nicht das Problem sein, 
weil man sonst im Main den Counter gar nicht erhöht bekäme.
Trotzdem sollte man lieber das Volatile verwenden.

Aber probier mal die Register mit = statt |= zu setzen um sicherzugehen, 
dass sie anderen Bits auch 0 sind.
Gast
Hi

>Das mit dem Volatile kann eigentlich deshalb nicht das Problem sein,
>weil man sonst im Main den Counter gar nicht erhöht bekäme.

Wieso Main? t wird im Interrupt erhöht.

MfG Spess
Gast
Hi

>Danke für die schnelle Antwort aber die Kiste blinkt immer noch im
>sekundentakt. Eigentlich sollten es ja 200ms sein.

CKDIV8-Fuse noch gesetzt?

MfG Spess
@ Markus (Gast)

>ich versuche seit 2 Stunden dieses Interrupt im ctc modus zum laufen zu
>bringen. Aber egal welche Zahl ich ins Register schreibe, die LED blinkt
>immer gleich schnell (bei dem geschriebenen Programm im Sekundentakt).
>long double t=0;

Willst du damit andeuten, den Allerlängsten zu haben? ;-)
long double, die es auf dem AVR sowieso nicht gibt, sind in den 
seltesten Fällen sinnvoll. Ein einfacher uint16_t tut es locker. Mal 
ganz abgesehen davon, dass man Servos anders ansteuert. Ausserdem fehlt 
ein volatile, siehe Interrupt.

>Danke für die schnelle Antwort aber die Kiste blinkt immer noch im
>sekundentakt. Eigentlich sollten es ja 200ms sein.

Möglicherweise ist die Arithmetik mit float so aufwändig und langsam, 
dass Interrupts verschluckt werden.
Gast
Hi

>long double t=0;

Brauchst du an der Stelle eine Gleitpunktzahl?

>OCR0A = 200;      //alle 10µs ein IRQ 0,00001s

Genaue 10µs erhälst du aber mit 199.

MfG Spess
Gast
spess53 schrieb:

>>long double t=0;
>
> War da nicht was mit volatile?
>
> MfG Spess

Hehe Spess, bist du jetzt auch zu den C-Kryptographen übergelaufen, oder 
leistest du bloß mal Entwicklungshilfe ;-)
Bin ich dann der Letzte, der das Licht ausmacht?
Gast
Hi

>Hehe Spess, bist du jetzt auch zu den C-Kryptographen übergelaufen, oder
>leistest du bloß mal Entwicklungshilfe ;-)

Letzteres. Hilft auch um C-Programme nach Assembler umzusetzen.

MfG Spess
Markus schrieb:
> ich versuche seit 2 Stunden dieses Interrupt im ctc modus zum laufen zu
> bringen. Aber egal welche Zahl ich ins Register schreibe, die LED blinkt
> immer gleich schnell (bei dem geschriebenen Programm im Sekundentakt).

Du benutzt AVR Studio 6.x? Versuch mal mit Device Programming -> Memory 
dein Programm auf den Atmega328 zu laden. Der Upload aus der 
Entwicklungsumgebung geht in AVR Studio 6.x manchmal schief, 
insbesonders wenn man mal den Zielprozessor geändert hat.

Markus schrieb:
> if (t<20000)SERVOPORT|=(1<<SERVOPIN);
> else SERVOPORT &=(0<<SERVOPIN);
> if (t>40000) t=0;

Du darfst in main() nicht einfach so auf t zugreifen. Da t größer als 
ein Byte ist, besteht der Zugriff aus mehreren Assemblerbefehlen. Der 
TIMER0_COMPA_vect kann dann zwischen diesen Befehlen stattfinden, so 
dass du unter Umständen sehr seltsame Werte in t beobachten wirst. Um 
jeden Zugriff auf t herum muss darum der Interrupt ausgeschaltet sein. 
volatile allein hilft da nicht.

LG, Sebastian

Antwort schreiben

Eine eigene Frage? Dieser Thread ist über 12 Jahre alt. Stell sie in einem eigenen Thread – dort lesen mehr Leute mit, und sie wird öfter und schneller beantwortet.

Neuen Thread starten

Eine Lösung, Ergänzung oder Rückmeldung zu diesem Thread? Dann antworte hier.

Formatierung
  • [c]C-Code[/c]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] – Link zu einem Artikel
  • Verweis auf einen anderen Beitrag: Rechtsklick auf dessen Beitrags-ID (#8078628), „Adresse kopieren“, in den Text einfügen

Mehr zur Formatierung

Längeren Sourcecode als Anhang, nicht in den Text. JPG nur für Fotos und Scans; Zeichnungen und Screenshots als PNG oder GIF. Siehe Bildformate.

Schon registriert? Anmelden

Wird nicht angezeigt. Wir schicken dir einen Link; sobald du damit bestätigst, erscheint dein Beitrag.

Mit dem Abschicken legst du einen kostenlosen Account an und erkennst die Nutzungsbedingungen und die Datenschutzerklärung an.