PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : 1 interrupt vom avr16 für 2 aufgaben ?



pebisoft
08.03.2005, 20:22
hallo, unten die beiden befehle werden für 2 verschiedene aktion gebraucht,
der eine für den rc5-code und er andere für den ultra srf04.
kann man die beiden gleichzeitig so einsetzen?

TIMSK = 1<<TOIE0;
TIMSK|= (1<<TICIE1);

ich habe 2x die interrupt-routine mit verschiedenen aufgaben,
kann man ein interrupt so für verschiedene aufgaben nutzen?

void erster_i(void){
SIGNAL (SIG_OVERFLOW0)
{}

}

void zweiter_i(void){
SIGNAL (SIG_OVERFLOW0)
{}

}


void main(void){
sei;
zweiter_i;
erstrer_i;
;

mfg
pebisoft

Kjion
08.03.2005, 20:48
Ich versteh ehrlich gesagt nicht was du genau machen willst. So wie du es im Moment geschrieben hast kannst du das auf keine Fall machen. Man kann nicht einfach eine Funktion zweimal definieren...

Du kannst natürlich eine Interruptroutine für verschiedene Sachen nutzten, allerdings musst du da dann in der Routine auswählen welche Aktion gerade durchgeführt wird.


volatile uint8_t aktion;

SIGNAL (SIG_OVERFLOW0)
{
if (aktion == 1)
// mach irgendwas....
else if (aktion == 2)
// mach was anderes...
}

MfG Kjion

bluebrother
08.03.2005, 21:05
so wie ich das lese will er einfach nur 2 Dinge in einem IRQ machen. Aber wo liegt das Problem 2 Funktionen zu schreiben und die dann im IRQ aufzurufen?

void tu_was( void ) { foobar; }
void tu_wasanderes( void ) { blah; }

void irq_handler( void )
SIGNAL( irgendeins )
{
tu_was();
tu_wasanseres();
}

Warum er versucht die Funktionen vom main() aus aufzurufen ist mir aber absolut nicht klar.

Dino Dieter
08.03.2005, 21:19
Hallo

Schade das die Leute oft nicht genauer sagen, was sie erreichen wollen.

Mit solchen Code Fetzen kann man nicht richtig helfen.

@bluebrother

Den Tip, aus einem INT Funktionen aufzurufen halte ich aber für sehr gefährlich. Lieber in der INT ein Bit setzen in einem eigenen Staus Reg. und dann im Hauptprogramm auswerten, oder so wie Kjörn es gemacht hat.

Und INT so kurz wie möglich halten

MFG
Dieter

pebisoft
08.03.2005, 21:36
hallo kjion, der rc5 braucht eine genaue zeitmessung von einer bestimmten zeit um die daten auszuwerten. die sendediode braucht zum senden auch eine bestímmte frequenz. ich wollte beim senden die frequenz haben für die diode und beim empfangen die zeit um die bits aus den tsop rausholen und umwandeln. sonst braucht jeder seinen eigenen timer.
mfg pebisoft

pebisoft
08.03.2005, 21:45
hallo, kann man innerhalb des interrupt bei der jeweiligen funktion tu_was() den timer auf 0 setzen, damit der zähler hier dann wieder von neuem beginnen kann bis zum überlauf.
mfg pebisoft

Kjion
09.03.2005, 08:07
hallo, kann man innerhalb des interrupt bei der jeweiligen funktion tu_was() den timer auf 0 setzen, damit der zähler hier dann wieder von neuem beginnen kann bis zum überlauf.

Klar kann man das. Warum auch nicht ?? Allerdings halte ich es für keine gute Idee in den Interrupts Funktionen aufzurufen. Dies hat zwei Gründe:
1.) Man weiß nicht genau/vergisst es wie lange diese Funktion die man aufruft dauert. Das kann insbesondere bei UART oder dem Timer zu sehr seltsamen Effekten führen, da dann quasi ständig die Interrupts aufgerufen werden ( der eine ist zum Beispiel noch nicht fertig während der nächste schon wieder ausgelöst wird. )
2.) Der Compiler weiß nicht welche Register in der Int Routine benutzt werden und sichert deswegen alle! auf den Stack. Diese dauert einfach ein bißchen, wenn man also eine kurze Interruptroutine haben will so sollte man den ganzen Code dort hineinschreiben!

Ob sich die RC5 Auswertung und die Frequenzerzeugung für die Sendediode in einem Interrupt verarbeiten lassen musst du selbst wissen. Entweder du wählst den Int so, dass er dem kleinsten gemeinsamen Takt entspricht ( geht nicht immer, ist aber einfacher ), oder du musst dir das ganze so genau zusammenbasteln, dass das Timing wieder stimmt.

MfG Kjion

PS: Könntest du nicht ab und zu die Großschreibetaste benutzten ?? Das würde deine Text wesentlich leserlicher machen..

muraad
09.03.2005, 09:21
Pepisoft was du doch willst ist mit einem Timer mehrer Zeiten messen. Also Ultraschall, rc5 und PWM von deinem Kompass. Der Timer1 hat hat nur einen Input Capture Pin (für srf04). Du kannst aber die Externen Interrupt Pins benutzen.
Ich hab hier mal Code:


// geändert auf 8MHZ
#include <io.h>
#include <avr/delay.h>

#define US_PORT PORTD
#define US_PORT_RICHTUNG DDRD
#define US_PIN PD7 // Der Pin kommt zum Trigger-Puls Eingang

volatile unsigned int us_zeit=0;
volatile unsigned int zeit_int0=0,zeit_int1=0; // geändert

SIGNAL(SIG_INTERRUPT0)
{
zeit_int0=TCNT1; // geändert
TCCR1B= ~(1<<CS12) & ~(1<<CS11) & ~(1<<CS10); // Timer wieder aus
TCNT1=0;
}

SIGNAL(SIG_INTERRUPT1)
{
zeit_int1=TCNT1; // geändert
TCCR1B= ~(1<<CS12) & ~(1<<CS11) & ~(1<<CS10); // Timer wieder aus
TCNT1=0;
}

SIGNAL(SIG_INPUT_CAPTURE1) // Interrupt für US Zeitmessung
{
us_zeit=ICR1;
TCCR1B= ~(1<<CS12) & ~(1<<CS11) & ~(1<<CS10); // Timer wieder aus
TCNT1=0;
}

unsigned char start_us_messung(void) // Ultraschallmessung
{
unsigned char wert,wert_in_cm;

// PD6 ist Input Capture Pin beim ATMega8, hier kommt der Echo-Pulse Ausgang hin
TIMSK|= (1<<TICIE1); // Input Capture Interrupt enable
TCCR1B&=~(1<<ICES1); // Fallende Flanke für Input Capture
US_PORT|=(1<<US_PIN); // Trigger-Puls Eingang high
_delay_us(15); // Laut Datenblatt Trigger-Puls min 10us auf high
_delay_us(15); // Laut Simulator ist wartet _delay_us() nur die
// hälfte der Zeit
US_PORT&=~(1<<US_PIN); // Trigger-Puls Eingang wieder auf low
_delay_us(185); // Erst wird ein 200us langer 40kHz Burst vom srf04 gesendet
_delay_us(185);
TCCR1B|=(1<<CS11); // Prescaler 8, startet Timer
while(us_zeit==0); // Warten bis Ergebnis
if(us_zeit>19000) // Dann kein Objekt vor den Sensor
{
wert=0;
us_zeit=0;
return wert;
}
else
{
wert=172*us_zeit/10000; // wert ist nun in cm
us_zeit=0;
return wert;
}
}


// Zeitmessung mithilfe von Externem Interrupt 0 und Timer1
unsigned long long star_zeitmessung_int0(unsigned char flag) // flag = 1 fallende Flanke generiert Interrup
{ // flag = 2 gegenteil
unsigned long long wert;
if(flag==1)
MCUCR|=(1<<ISC01);
if(flag==2)
MCUCR=(1<<ISC01|(1<<ISC00);
GICR |=(1<<INT0); // Externer Interrupt an
TCCR1B|= (1<<CS11); // Timer an, Prescaler 8 damit Zeitäuflösung genau 1 micro sekunde !!! geändert
while(zeit_int0==0); // Warten bis Ergebnis
wert=zeit_int0; // Wert in micro sekunden
zeit_int0=0; // Wieder auf 0 setzen für nächste Messung
return wert;
}

// Zeitmessung mit Externem Interrupt1 und Timer1
unsigned long long start_zeitmessung_int1(unsigned char flag)
{
unsigned long long wert;
if(flag==1)
MCUCR|=(1<<ISC11);
if(flag==2)
MCUCR=(1<<ISC11) | (1<<ISC10);
GICR|=(1<<INT1);
TCCR1B|= (1<<CS11); // Timer an, Prescaler 8 geändert
while(zeit_int1==0);
wert=zeit_int1;
zeit_int1=0;
return wert;
}

void main (void)
{
unsigned char wert;
unsigned long long wert1,wert2;
US_PORT_RICHTUNG|=(1<<US_PIN); // US_PIN auf Ausgang
wert=start_messung();
wert1=start_zeitmessung_int0();
wert2=start_zeitmessung_int1();
}

Damit kann man mit einem Timer alle deine drei Ereignisse messen. Die Funktionen start_zeitmessung_intX() geben dir nur die Zeit in micro sekunden zurück. Was du damit machst (umrechnen in Grad bei Kompass, rc5 usw.) ist dir überlassen. In deinem Fall muss halt z.B. den Out Pin von deim TSOP auf einen der Externen Interrupt Pins von deinem ATMega. Allerdings weis ich immer noch nicht was passiert wenn der Timer mehr als 1mal durchläuft, also nach 262,144 millisekunden. Um den sozusagen Höchsmesswert zu erhöhen kann man den Prescaler in den Funktionen start_zeitmessung_intX() verändern und in den Interrupts in den Zeilen zeit_intX=TCNT1*4; das *4 dementsprechend ändern. Hoffe man hats verstanden.
Gruß Muraad

EDIT: nochmal geändert, das mit TCCRB1 und TICIE1

EDIT: Code funktioniert nicht richtig. Bitte in den Thread schauen:
https://www.roboternetz.de/phpBB2/viewtopic.php?p=67114#67114

pebisoft
09.03.2005, 09:27
hallo, vielen. ich bewundere dich, wie du das mit den timern so machen kannst. alle achtung. bei mir wird es noch länger dauern, bis ich das begriffen habe. ich schlage dauernd in der avr-datei nach für den avr16, ist in englisch und hat wie du weisst über 300 seiten. eine bitte ,ich habe den avr16 mit 8mhz. was muss ich jetzt an deinen zeiten noch ändern.
extern habe ich 16mhz dran, weis aber nicht, wie ich die fusebits für diesen externen einstellen soll???
danke
mfg pebisoft

muraad
09.03.2005, 09:43
Also ich hab den Code oben geändert.
Aber die max. Zeit die du jetzt messen kannst ist bei 65535us also 65,535 millisekunden. Wobei sich das auch irgendwie ändern liese. Und das Warten auf ein neues Ergebniss mit while(zeit_int0==0); ist auch nicht sehr elegant. In einem Roboter würde ich in regelmäßigen abständen (geregelt durch Timer0 oder Timer2) eine neue Messung starten und gleichzeitig das Ergebniss der alten Messung abholen.
Gruß Muraad

EDIT: Ich hab hier die start_us_messung() auch nochmal auf 8Mhz geändert da im Datenblatt vom srf04 steht das es eine Pulsweite von max. 40ms zu messen gibt. Womit hier die 65,535ms max. Messzeit ausreichen. Nochmal zur Höchstmesszeit: 8Mhz/8 Prescaler= 1.000.000Hz
1/1.000.000Hz=1micro sekunde Takt. Timer1 hat 16Bit also 2<hoch>16=65536 Takte bis er überläuft. Da ich nicht weis was in dem Fall passiert wenn er überläuft "Höchstmesszeit".
Wobei es sich auch ändern lassen würde aber da müsst ich jetzt mehr drüber nachdenken. Mit Fusebits kenn ich mich nicht so gut aus. Ich hab sie bei meinem RN-Control noch nie verändert. Aber auch weil bei mir PonyProg nicht funktioniert und ich sie, wenn überhaupt, damit verändert hätte.

muraad
09.03.2005, 10:31
Kann man eigentlich zwei Interrupt´s gleichzeitig auf eine Timer einstellen? z.B.
SIGNAL(SIG_INPUT_CAPTURE1){ }
und
SIGNAL(SIG_OVERFLOW1){ }
Gruß Muraad

bluebrother
09.03.2005, 13:55
@muraad: was meinst du genau?

muraad
09.03.2005, 15:22
Was passiert wenn ich den Timer so einstelle das er bei einem Input Capture Event in den Interrupt geht und bei einem Überlauf in den Interrupt geht, also beides gleichzeitig aktiv ist. Konkretes Beispiel:
Ich benutze den Input Capture Pin von Timer1 um eine Ultrasschalllaufzeit zu messen. Wie im Beitrag über dir steht geht das nur bis 65,535ms. Wird bis dahin kein Input Capture Interrupt ausgelöst läuft der Timer über. Nun würde ich gerne noch zusätzlich den Overflow Interrupt aktivieren um sobald der Timer übergelaufen ist eine Variable zu inkrementieren. Die gemessene Zeit währe dann
(Variable*65,535ms)+aktuellerTimerwert. Meine Frage ist nun ob auf einem Timer gleichzeit 2 Interrupts aktiv sein können?
Hoffe du hast es verstanden.
Gruß Muraad

Arexx-Henk
09.03.2005, 22:22
Ich glaube das geht schon.


gruss

Henk