Forum: Mikrocontroller und Digitale Elektronik Mein Interupt macht nicht das was ich will (atmega 328p @20 MHz)


von Markus (Gast)


Lesenswert?

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)

  }
}

von Markus (Gast)


Lesenswert?

&=(0<<SERVOPIN) sollte natürlich &=~(1<<SERVOPIN) sein.
entschuldigung

von spess53 (Gast)


Lesenswert?

Hi

>long double t=0;

War da nicht was mit volatile?

MfG Spess

von Conny G. (conny_g)


Lesenswert?

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.

von spess53 (Gast)


Lesenswert?

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

von Markus (Gast)


Lesenswert?

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

von spess53 (Gast)


Lesenswert?

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

von Markus (Gast)


Lesenswert?

Leider nein... delay ms zb. funktionniert. und des rechnet doch auch mit 
dem Takt oder?

von Hubert G. (hubertg)


Lesenswert?

Wenn du anstelle des long double (wozu eigentlich) ein unsigned int 
nimmst, dann funktioniert es.

von Falk B. (falk)


Lesenswert?

@ 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.

von spess53 (Gast)


Lesenswert?

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

von ASM (Gast)


Lesenswert?

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?

von Markus (Gast)


Lesenswert?

Volatile steht drin. Und ich versuchs mit uint16_t. Sobald ein neues 
Board da is. Des jetzige is mir gerade abgeraucht.
danke für die Hilfe

von spess53 (Gast)


Lesenswert?

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

von Sebastian W. (wangnick)


Lesenswert?

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

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.