ATTINY13 Phasenanschnitt

Dmm... das mit der Niederspannung hab ich irgendwie verpennt...

Der MOC302x ist ebenso wie der MOC304x ein OptoTRIAC (also ein Optokoppler mit TRIAC-Ausgang). Die 4er-Serie hat zusätzlich 'ne integrierte Nulldurchgangsdetektion. Wieviel Spannung diese nun benötigt, hab ich nicht durchgesehen. Die letzte Ziffer (x) stellt AFAIK die unterschiedlichen Vorwärtsspannungen der internen LEDs dar.

Hmm... gabs nicht auch irgendsowas wie "photovoltaische" Koppler?

Egal - das Problem mit der Nulldurchgangsdetektion via Optokoppler sollte bei den geringeren Amplituden aber ähnlich wie bei den MOCs der 4er-Serie sein - auch hier muß ja erst die Vorwärtsspannung der LEDs erreicht werden...

Methode der Wahl sollte also irgend'ne Komperatorschaltung (wie bei meinem Dimmer) sein.

Für die Wellenpaketsteuerung blieben weiterhin 2 Möglichkeiten:
Entweder:
man verzichtet auf die Detektion, steuert die also Knallhart mit PWM an (und nimmt alle 500ms beim Anschalten den eventuellen RUMS im Scheitel in kauf), oder:
man nutzt den Timer wie beschrieben als Counter (Komperator->T0 aber irgendwie mit beiden Flanken, zB mit vorheriger Gleichrichtung) - dann ist jedes Inkrement des Timers dicht am Nulldurchgang, also insbesondere auch jedes Compare-Match (bzw auch die Timer-Takte danach), also kippt der Ausgang auch immer dicht am Durchgang...
Nachtrag:
Im Datenblatt der 4er-MOCs sind für die Nulldurchgangsdetektion typisch 5V angegeben - max allerdings bis zu 20V;)


Hab' leider gerade wenig Zeit und komme nur sporadisch zum avr-hacken ;-)
Hier hänge ich schon wieder fest. Ich dachte das Problem gestern verstanden und gelöst zu haben... War aber nix....
Folgender Versuch:
Impuls auf PB1 schaltet PB0 für 1000 ms auf high und danach sicher für 2000 ms auf Null- egal was in dieser Zeit sich
am PB1 und in Folge dessen an int0 so tut.
Doch was tut sich?
Bei dem Wechsel von 0 auf 1 am PB1 schaltet PB0 blinkt zweimal.
Das passiert auch wenn die Flanke fällt.
Verstehe ich beides nicht.
Denn, lasse ich die Stelle "_delay_ms(2000);" weg, dann blinkt es nicht.
Für ein einmaliges Triggern ist _delay_ms(2000) überflüssig, das PB0
ohnehin gelöscht wird und bleibt. Das bedeutete dann PB0 für 1000 ms auf high und für
2000 ms + unendlich auf Null.
Wo ist da mein Gedankenfehler?





Code:
void main()
{
/*
ISC01	ISC00
0	0	The low level of INT0 generates an interrupt request.
0	1	Any logical change on INT0 generates an interrupt request.
1	0	The falling edge of INT0 generates an interrupt request.
1	1	The rising edge of INT0 generates an interrupt request.
*/
GIMSK  |= (1<<INT0);        //External Interrupt Request 0 Enable
MCUCR |= ((1<<ISC01) | (1<<ISC00));              // Interrupt auslösen wenn INT0 = GND
}

ISR(INT0_vect)
{
PORTB |= (1<<PB0);
_delay_ms(1000);
PORTB &= ~(1<<PB0);
_delay_ms(2000);
}
 
Frage vorweg: An INT0 hängt Deine Nulldurchgangsdetektion, alle 20ms eine steigende Flanke?
Dann wird das Interrupt-Flag auch alle 20ms gesetzt, ist also insbesondere bei Rückkehr aus der ISR bereits wieder gesetzt -> es wird sofort der nächste Interrupt angefordert.
Das könnte also ebenso direkt in der Hauptprogrammschleife stehen (die paar Takte Sprung in die ISR und zurück mal vernachlässigt...)
 
Frage vorweg: An INT0 hängt Deine Nulldurchgangsdetektion, alle 20ms eine steigende Flanke?
Dann wird das Interrupt-Flag auch alle 20ms gesetzt, ist also insbesondere bei Rückkehr aus der ISR bereits wieder gesetzt -> es wird sofort der nächste Interrupt angefordert.
Das könnte also ebenso direkt in der Hauptprogrammschleife stehen (die paar Takte Sprung in die ISR und zurück mal vernachlässigt...)

Moin,
für den Versuch lege ich lediglich die 5 V an int0/PB1.
Also 0 V oder 5 V.
Später soll dann der Sinus drauf.
 
Und wie simulierst Du den Nulldurchgang (IRQ)? Mit 'nem Taster oder so? Dann hättest Du beim Betätigen und loslassen je zahlreiche Flanken durch Prellen...
 
Und wie simulierst Du den Nulldurchgang (IRQ)? Mit 'nem Taster oder so? Dann hättest Du beim Betätigen und loslassen je zahlreiche Flanken durch Prellen...

Scheinbar war Prellen die Ursache.... Denkfehler vom mir, ich dachte dass die Triggerung nur einmal erfolgen kann bzw. erst wieder nachdem die int0-Routine durchgelaufen ist.
Was den Effekt wohl noch verstärkt oder erst ermöglich hat ist der Spannungsteiler bzw. Tiefpass. Wobei doch 3,5 V für High-Signal ausreichen sollten.
Mit dem Frequenzgenerator läuft es jetzt.
 
Beim flankengetriggertem Interrupt wird das Interruptflag bei jeder (entsprechenden) Flanke gesetzt. Unabhängig davon, ob der Interrupt selbst bzw Interrupts global freigegeben ist. Sind sie es, wird der Interrupt ausgeführt.
Beim Sprung in die IVT werden Interrupts global unterdrückt (I in SREG, also nicht die Flags) und das Flag automatisch gelöscht. Aus der IVT wird jetzt in deine ISR gesprungen, und der Code abgearbeitet. Beim Verlassen der ISR werden die Interrupts global wieder freigegeben. Wenn der Taster also nach dem Sprung in die IVT noch prellt (sind ja nur wenige Takte), wird dort bereits wieder das Flag gesetzt, wenn Du also Sekunden später aus der ISR zurückkehrst, und die Interrupts global freigegeben werden, wartet das Flag auf Dich, und wird hier aktiv.
Deswegen blinkt es zweimal - nach den 3 Sekunden hat der Taster ausgeprellt.
Und da es beim Zurückschalten ebenso mehrere (zig) ms lang prellt, blinkts auch da zweimal.
 
Beim flankengetriggertem Interrupt wird das Interruptflag bei jeder (entsprechenden) Flanke gesetzt. Unabhängig davon, ob der Interrupt selbst bzw Interrupts global freigegeben ist. Sind sie es, wird der Interrupt ausgeführt.
Beim Sprung in die IVT werden Interrupts global unterdrückt (I in SREG, also nicht die Flags) und das Flag automatisch gelöscht. Aus der IVT wird jetzt in deine ISR gesprungen, und der Code abgearbeitet. Beim Verlassen der ISR werden die Interrupts global wieder freigegeben. Wenn der Taster also nach dem Sprung in die IVT noch prellt (sind ja nur wenige Takte), wird dort bereits wieder das Flag gesetzt, wenn Du also Sekunden später aus der ISR zurückkehrst, und die Interrupts global freigegeben werden, wartet das Flag auf Dich, und wird hier aktiv.
Deswegen blinkt es zweimal - nach den 3 Sekunden hat der Taster ausgeprellt.
Und da es beim Zurückschalten ebenso mehrere (zig) ms lang prellt, blinkts auch da zweimal.

Hallo alle zusammen,
nach langer Pause hatte ich über Weihnachten mal ein wenig Zeit für das Projekt Lötstation.
Zur Erinnerung: Trafo 230/24, OHNE Gleichtrichter ! Triacsteuerung über moc mit Triacausgang und PCINT-Abstastung.
In der Interruptroutine gibt das Verhältnis t_on/T das Tastverhältnis an. -> Wellenpaketsteuerung...
Gibt man in der main-Routine für
T=1000 und t_on=500 ein, wird der Triac im Sekundentakt sichtbar angesteuert.
Zum Testlese ich über den adc einen über ein Poti eingestellten Wert ein und lade diesen direkt in die Variable t_on.
Da müsste sich ja irgendein Wert zwischen 0 und 1024 ergeben und damit das Tastverhältnis beeinflussen, aber es tut
sich nix.

1. Die Lötleistung ergäbe sich dann durch ein Wellenpaketsteuerung.
2. Die Variable t_on gäbe dann in Verbindung mit der Periodendauer T die Länge des Durchschaltens des Triac an.
3. Die ISR-Routine soll dafür Sorge tragen, dass beim Nulldurchgang geschaltet wird.

(3 Sätze 3 mal Satzanfang mit "Die"..... eijeijei, das wäre in einer Deutscharbeit nix. aber ist ja ein Aufzählung ;-))



Code:
uint16_t temp_ist, temp_soll;
uint16_t imax;
volatile uint16_t T;
volatile uint16_t t_on;

//Hier die ADC-Routine.... die läuft in anderen Programmen

uint16_t ADCsingleREAD(uint8_t adc)
{
int ADCval;
int result;
uint16_t i;
imax=10;
/*
ACME = 1
ADEN = 1

ADMUX1	|	ADMUX0
---------------
0	|	0	ADC0 PB5 RESET !!!!
0	|	1	ADC1 PB2 Pin 7
1	|	0	ADC2 PB4 Pin 3
1	|	1	ADC3 PB3 Pin 2

*/
//    ADMUX |= (1 << MUX0);         // use #1 ADC
//    ADMUX |= (1 << MUX1);         // use #1 ADC	PB3

    
ADCSRA |= (1 << ADPS2) | (1 << ADPS1) | (1 << ADPS0);    // 128 prescale for 8Mhz
ADMUX |= (1 << REFS0);    // use AVcc as the reference
ADMUX &= ~(1 << ADLAR);   // clear for 10 bit resolution
    
ADCSRA |= (1 << ADEN);    // Enable the ADC
ADMUX |= adc;         		// use #1 ADC	PB3
ADCSRA |= (1 << ADSC);    // Start the ADC conversion
while(!(ADCSRA & (1 << ADIF)));    
ADCval = ADCL;
ADCval = (ADCH << 8) + ADCval;    // ADCH is read so ADC can be updated again


//
//result=0;

	for(i=1;i<=imax;i++)
	{

ADCSRA |= (1 << ADSC);    // Start the ADC conversion
while(ADCSRA & (1 << ADSC));      // Thanks T, this line waits for the ADC to finish 
ADCval = ADCL;
ADCval = (ADCH << 8) + ADCval;    // ADCH is read so ADC can be updated again
	result=result+ADCval;
	}
	ADCval=result/10;
  
    ADCSRA &= ~(1<<ADEN);           // ADC deaktivieren (2)
    ADMUX = 0x00;              // ADMUX löschen
      
     result=result/imax;
     return result;
}



// Hier die Sinus-Abtastroutine

ISR(INT0_vect)
{

PORTB |= (1<<PB0);
for(i=0;i<=t_on;i++)
{
_delay_ms(1);
}
PORTB &= ~(1<<PB0);
for(i=0;i<=T-t_on;i++)
{
_delay_ms(1);
}

}
// HIER die Main-Routine

DDRB   |= (1<< PORTB0); //(Pin 5) -> Triac
DDRB   &= ~(1<< PORTB1); //(Pin 6) -> Abtastung
DDRB   &= ~(1<< PORTB3); //(Pin 2) -> Sollgröße
DDRB   &= ~(1<< PORTB4); //(Pin 3) -> Istgröße

GIMSK  |= (1<<INT0);        //External Interrupt Request 0 Enable
MCUCR |= ((1<<ISC01) | (1<<ISC00));              // Interrupt auslösen wenn INT0 = GND
//sei(); hier oder in der While-Schleife?

while(1)
{
temp_soll=ADCsingleREAD(PB3); //3=11b für Pin 2 PB3 ADC3

sei();
t_on=temp_soll; // da tut sich nix
//t_on=500; // so schon !
T=1000;
}
return(0);
}


Meine Frage ist nun wie man die ISR-Routine mit der adc-Abfrage kombinieren kann.
Nochmal, wenn ich t_on einen Wert zuweise ergibt sich eine Änderung, ein Auslesung mit
dem adc ergibt nichts.

Euch allen schöne Tage zwischen den Jahren und guten Rutsch !
Ralf
 
Hallo alle zusammen,
nach langer Pause hatte ich über Weihnachten mal ein wenig Zeit für das Projekt Lötstation.
Zur Erinnerung: Trafo 230/24, OHNE Gleichtrichter ! Triacsteuerung über moc mit Triacausgang und PCINT-Abstastung.
In der Interruptroutine gibt das Verhältnis t_on/T das Tastverhältnis an. -> Wellenpaketsteuerung...
Gibt man in der main-Routine für
T=1000 und t_on=500 ein, wird der Triac im Sekundentakt sichtbar angesteuert.
Zum Testlese ich über den adc einen über ein Poti eingestellten Wert ein und lade diesen direkt in die Variable t_on.
Da müsste sich ja irgendein Wert zwischen 0 und 1024 ergeben und damit das Tastverhältnis beeinflussen, aber es tut
sich nix.

1. Die Lötleistung ergäbe sich dann durch ein Wellenpaketsteuerung.
2. Die Variable t_on gäbe dann in Verbindung mit der Periodendauer T die Länge des Durchschaltens des Triac an.
3. Die ISR-Routine soll dafür Sorge tragen, dass beim Nulldurchgang geschaltet wird.

(3 Sätze 3 mal Satzanfang mit "Die"..... eijeijei, das wäre in einer Deutscharbeit nix. aber ist ja ein Aufzählung ;-))



Code:
uint16_t temp_ist, temp_soll;
uint16_t imax;
volatile uint16_t T;
volatile uint16_t t_on;

//Hier die ADC-Routine.... die läuft in anderen Programmen

uint16_t ADCsingleREAD(uint8_t adc)
{
int ADCval;
int result;
uint16_t i;
imax=10;
/*
ACME = 1
ADEN = 1

ADMUX1	|	ADMUX0
---------------
0	|	0	ADC0 PB5 RESET !!!!
0	|	1	ADC1 PB2 Pin 7
1	|	0	ADC2 PB4 Pin 3
1	|	1	ADC3 PB3 Pin 2

*/
//    ADMUX |= (1 << MUX0);         // use #1 ADC
//    ADMUX |= (1 << MUX1);         // use #1 ADC	PB3

    
ADCSRA |= (1 << ADPS2) | (1 << ADPS1) | (1 << ADPS0);    // 128 prescale for 8Mhz
ADMUX |= (1 << REFS0);    // use AVcc as the reference
ADMUX &= ~(1 << ADLAR);   // clear for 10 bit resolution
    
ADCSRA |= (1 << ADEN);    // Enable the ADC
ADMUX |= adc;         		// use #1 ADC	PB3
ADCSRA |= (1 << ADSC);    // Start the ADC conversion
while(!(ADCSRA & (1 << ADIF)));    
ADCval = ADCL;
ADCval = (ADCH << 8) + ADCval;    // ADCH is read so ADC can be updated again


//
//result=0;

	for(i=1;i<=imax;i++)
	{

ADCSRA |= (1 << ADSC);    // Start the ADC conversion
while(ADCSRA & (1 << ADSC));      // Thanks T, this line waits for the ADC to finish 
ADCval = ADCL;
ADCval = (ADCH << 8) + ADCval;    // ADCH is read so ADC can be updated again
	result=result+ADCval;
	}
	ADCval=result/10;
  
    ADCSRA &= ~(1<<ADEN);           // ADC deaktivieren (2)
    ADMUX = 0x00;              // ADMUX löschen
      
     result=result/imax;
     return result;
}



// Hier die Sinus-Abtastroutine

ISR(INT0_vect)
{

PORTB |= (1<<PB0);
for(i=0;i<=t_on;i++)
{
_delay_ms(1);
}
PORTB &= ~(1<<PB0);
for(i=0;i<=T-t_on;i++)
{
_delay_ms(1);
}

}
// HIER die Main-Routine

DDRB   |= (1<< PORTB0); //(Pin 5) -> Triac
DDRB   &= ~(1<< PORTB1); //(Pin 6) -> Abtastung
DDRB   &= ~(1<< PORTB3); //(Pin 2) -> Sollgröße
DDRB   &= ~(1<< PORTB4); //(Pin 3) -> Istgröße

GIMSK  |= (1<<INT0);        //External Interrupt Request 0 Enable
MCUCR |= ((1<<ISC01) | (1<<ISC00));              // Interrupt auslösen wenn INT0 = GND
//sei(); hier oder in der While-Schleife?

while(1)
{
temp_soll=ADCsingleREAD(PB3); //3=11b für Pin 2 PB3 ADC3

sei();
t_on=temp_soll; // da tut sich nix
//t_on=500; // so schon !
T=1000;
}
return(0);
}


Meine Frage ist nun wie man die ISR-Routine mit der adc-Abfrage kombinieren kann.
Nochmal, wenn ich t_on einen Wert zuweise ergibt sich eine Änderung, ein Auslesung mit
dem adc ergibt nichts.

Euch allen schöne Tage zwischen den Jahren und guten Rutsch !
Ralf


Ergänzung:
In dem oben aufgeführten Code ist eine Reglung noch nicht drin.
Diese wird dann über die Abfrage eines Termoelementwandlers realisiert.
Dazu muss aber zuerst das hier genannte Problem gelöst worden sein.
 
Hallo!

Das Bit REFS0 ist gesetzt, du nutzt die interne Spannungsreferenz, dies möchtest du sicherlich nicht.

Da die ADC-Routine uint16_t (2 Byte) zurückgibt, solltest du sicher stellen, dass die Interruptroutine nicht ein Teilbyte des volatile uint16_t t_on übernehmen.
Das geht zum Beispiel so:

[CCODE]temp_soll=ADCsingleREAD(PB3); //3=11b für Pin 2 PB3 ADC3

cli();
t_on=temp_soll;
sei();[/CCODE]

Du solltest dafür sorgen, dass t_on nicht größer werden kann als T. Dies könnte in der ISR bei der zweiten for-next-Schleife Probleme geben.




Noch ein paar Sachen, die mir aufgefallen sind ... müssen aber nicht direkt etwas mit dem Fehler zu tun haben :

Bei der ersten Dummy-Wandlung nachdem du den ADC aktivierst, wertest du das Interruptanforderungsflag ADIF aus, um zu erkennen, wann die Wandlung beendet ist. Das kann man machen, allerdings wird dieses Flag nie zurückgesetzt. Dadurch geht es beim zweiten mal sofort zur for-next-Schleife weiter.

Du verwendets int und uint16 für Variablen, die gegenseitig Werte übernehmen, das ist nicht so schön. Verwende einfach immer uint16_t.

Das ADC Ergebnis möglichst mit '2 hoch n' summieren, also 2mal, 4mal, 8, 16, 32... Dann kann man nämlich durch rechts shiften eine Division erreichen, was schneller geht, als eine herkömmliche 16 Bit Division.

Wenn du in der ISR zu viele Delays hast, kann dies dein Hauptprogramm "blockieren" oder im extremen Fall könnten auch Interrupts "verloren gehen".

Dirk :ciao:
 
Hallo!

Das Bit REFS0 ist gesetzt, du nutzt die interne Spannungsreferenz, dies möchtest du sicherlich nicht.

Da die ADC-Routine uint16_t (2 Byte) zurückgibt, solltest du sicher stellen, dass die Interruptroutine nicht ein Teilbyte des volatile uint16_t t_on übernehmen.
Das geht zum Beispiel so:

[CCODE]temp_soll=ADCsingleREAD(PB3); //3=11b für Pin 2 PB3 ADC3

cli();
t_on=temp_soll;
sei();[/CCODE]

Du solltest dafür sorgen, dass t_on nicht größer werden kann als T. Dies könnte in der ISR bei der zweiten for-next-Schleife Probleme geben.




Noch ein paar Sachen, die mir aufgefallen sind ... müssen aber nicht direkt etwas mit dem Fehler zu tun haben :

Bei der ersten Dummy-Wandlung nachdem du den ADC aktivierst, wertest du das Interruptanforderungsflag ADIF aus, um zu erkennen, wann die Wandlung beendet ist. Das kann man machen, allerdings wird dieses Flag nie zurückgesetzt. Dadurch geht es beim zweiten mal sofort zur for-next-Schleife weiter.

Du verwendets int und uint16 für Variablen, die gegenseitig Werte übernehmen, das ist nicht so schön. Verwende einfach immer uint16_t.

Das ADC Ergebnis möglichst mit '2 hoch n' summieren, also 2mal, 4mal, 8, 16, 32... Dann kann man nämlich durch rechts shiften eine Division erreichen, was schneller geht, als eine herkömmliche 16 Bit Division.

Wenn du in der ISR zu viele Delays hast, kann dies dein Hauptprogramm "blockieren" oder im extremen Fall könnten auch Interrupts "verloren gehen".

Dirk :ciao:

Hallo Dirk,
Danke für die Antwort.
Alle int sind nun auf uint16_t geändert worden.
Die interne Ref-Spannung hatte ich mal zum Test gesetzt und führt bei u>3 Volt zu einem Überlauf.
Habe ich nun wieder zurückgenommen.

t_on muss immer größer als T sein, das ist klar. t_on/T ist sozusagen ja das Tastverhältnis.
Der Wert müsste sich doch zwischen 0 und 1024 einstellen, oder?
Irgendwann müsste es doch zwischen 0 und 5 V ein gültiger Wert einstellen, der Triac bleibt jedoch gesperrt.
Die adc-Wandlung kollidiert mit Interrupt-Routine.
Das mit der 2^n-Summierung ist eine gute Idee, da die adc-Wandlung ordentlich bremst. Mach ich mich die Tage mal dran.


Den Code [CCODE]temp_soll=ADCsingleREAD(PB3); //3=11b für Pin 2 PB3 ADC3

cli();
t_on=temp_soll;
sei();[/CCODE]
habe ich mal probiert aber ohne Ergebnis.

Da klemmts bei mir jetzt gerade....
Gruß
Ralf

Nachtrag:
HaHa !
Hallo Dirk,
hab' mal aus den Zeiten in der Interruptroutine einfach mal ms durch us ersetzt und voila.
Das hattest Du ja geschrieben.... Super ! Danke.... jetzt noch die Regelung....
Gruß
Ralf
 
Hallo Ralf!
Nachtrag:
HaHa !
Hallo Dirk,
hab' mal aus den Zeiten in der Interruptroutine einfach mal ms durch us ersetzt und voila.
Das hattest Du ja geschrieben.... Super ! Danke.... jetzt noch die Regelung....
Gruß
Ralf

Ja, bei einem Delay von 20ms und länger in der ISR, wird das Hauptprogramm "blockiert" und es kann dann auch vorkommen, dass Interrupts "verpasst" werden.

Dirk :ciao:
 
Zum Testen....
Wenn nun der Pegel an PB4 kippt müsste sich doch was am Port Ausgang tut?
Machts aber nicht....
Gleich geb' ich es auf und nehme einen Längstransistor parallel zum Thyristor und steuere den mit ner PWM an.
Nach der Einschaltphase übernimmt dann der Thyristor....
Gruß Ralf
Code:
ISR(PCINT0_vect)        // interrupt service routine
{              // called when PCINT0 changes state
_delay_ms(2);
PORTB |= (1 << Ausgang);
_delay_ms(2);
return;
}

Im Hauptprogramm:
GIMSK |= (1<<PCIE);   // enable PCINT interrupt
//PCMSK |= (1<<PCINT4);   // pin change mask: listen to portb bit 2
PCMSK |= (1<<PB4);   // pin change mask: listen to portb bit 2
sei();         // enable all interrupts
}

BTW:
Wusstet Ihr, dass bei den Selengleichrichtern diese Kühllamellen NICHT auf dem selben Potential liegen?
Also Masse ist nicht überall....
Ich auch nicht, die Hirschmannklemme weiß es nun...:)

Wozu das "return;"?
 
War da nicht was bei Bascom? kA ob es bei C auch so ist.
Das ist ja in einer ISR, da wäre RETI richtig und wird vom Compiler generiert ( die } ), return wäre denn ein normales RET.

Wenn dem so ist sollte der Code zwar so funktionieren, aber du musst in der Hauptschleife immer wieder die Interrupts aktivieren (SEI) da sie durch das nicht-erreichen von dem RETI nicht wieder aktiviert werden.
 
Das ist ja in einer ISR, da wäre RETI richtig und wird vom Compiler generiert ( die } ), return wäre denn ein normales RET.

Wenn dem so ist sollte der Code zwar so funktionieren, aber du musst in der Hauptschleife immer wieder die Interrupts aktivieren (SEI) da sie durch das nicht-erreichen von dem RETI nicht wieder aktiviert werden.
Es ist doch eine Hochsprache, ein ret oder reti gibts da erst mal nicht, auch kein sei. Es ist auch egal ob es auf einem AVR, ARM oder sonstwas läuft. Der Compiler übersetzt das dann richtig, im Idealfall wird es einfach wegoptimiert. Auch um ein Push und Pop von vom Compiler genutzten Registern oder Speicherbereichen muss man sich nicht kümmern.
 
http://avrhelp.mcselec.com/index.html?on_interrupt.htm

The first RETURN statement that is encountered that is outside a condition will generate a RETI instruction. You may have only one such RETURN statement in your interrupt routine because the compiler restores the registers and generates a RETI instruction when it encounters a RETURN statement in the ISR. All other RETURN statements are converted to a RET instruction.
Problem ist jetzt dass es 2 sind, einmal das return und einmal die } was ja das selbe generiert. Die Frage stellt sich jetzt wie sich der Compiler entscheidet.

Beispiel (Pseudocode!)
Code:
ISR OnADC
  If a = 0 Then
    Return ' RET
  ElseIf a = 1 Then
    'whatever
    Return ' RET
  ...
  End If
EndISR ' RETI

Ok, es steht "das erste Return außerhalb einer Kondition" und da steht das Return. ... Trotzdem würde ich niemals blind dem Compiler trauen. Ich hatte tatsächlich auch schon mal einen Fehler in einem LunaAVR Programm. Da war ein "Print(a + b)" nicht das Selbe wie "Print a + b". Erstrecht traue ich nicht den Optimierungen. Da bin ich auf Arbeit mal in ein tiefes Fettnäpchen getreten. (zugegeben bei PC Software)
 
Also das Thema ist ja schon uuuuuralt, ich möchte es mir auch nicht nochmal durchlesen, es geht jetzt auch nur um ein return in einer ISR.

Wenn der Compiler mit einem return vor der Geschlossen-Klammer nicht zurechtkommt, also dann weiß ich auch nicht. Im Normalfall wird es wegoptimiert. Assembler-Instruktionen oder irgendwelche Register oder Flags müssen hier dem Softwareentwickler egal sein. Theoretisch weiß man garnicht, dass es einen Unterschied beim Rücksprung von einer Funktion/Routine oder einer Interruptservice-Routine beim AVR gibt. Mir nun darüber Gedanken zu machen, was der Compiler für einen Code erzeugt, wenn er garnicht (weg)optimieren würde ... das ist mir zu müßig und würde Janix auch sicher nicht weiterhelfen.
 
Da der beitrag schon alt ist, schadet OT sicher nicht mehr...
War da nicht was bei Bascom?
Das hier?
BASCOM ersetzt "Return" durch RET oder RETI, je nachdem ob das "Return" in einer ISR steht, oder woanders. Und woran erkennt Bascom das?
(Was ist 'ne ISR eigentlich wirklich - sowas gibt's doch strenggenommen(!) gar nicht. Was soll das sein? Code, der nach einem IRQ ausgeführt wird, und nur(!) dann? Wenn der Code im Flash steht, kann er auch von woanders her angesprungen werden).
@laplace hatte AFAIR irgendwelche Probleme damit, weil irgendwelche Anteile des Codes in ASM-Blöcken stand, und BASCOM die ISR nicht erkannt hatte.
 
Ne, den Thread kannte ich noch nicht. Ich meinte den zitierten Part aus der Bascom Hilfe.

Aber jo, haste Recht, dem Controller isses Latte. Der kennt keine ISR (von den Vektoren abgesehen). Einzige Ausnahme halt dass man mit RETI zurück springen muss wenn fertig, sonst bleiben die Interrupts deaktiviert. Andere Unterschiede gibt es nicht. Klar könnte der Main Code auch Teile der ISR nutzen. Hmm. Würde aber n schönes Durcheinander geben wenn man nicht aufpasst.

Wobei ... dir ... dir traue ich sowas zu :D :p
Allerdings auch dass es nachher funktioniert :)
 
Wobei ... dir ... dir traue ich sowas zu
Zumindest hatte ich schonmal irgendwo für 2 verschiedene Timer-IRQs eine gemeinsame ISR verwendet. Wenn ich mich recht erinner hatte ich damit quasi PWM auf anderen Beinen realisiert (und ausgenutzt, daß die Vektoren direkt hintereinander liegen). Grund war, daß die HW-PWM-Beine 'ne andere Funktion nutzten...
Einzige Ausnahme halt dass man mit RETI zurück springen muss wenn fertig, sonst bleiben die Interrupts deaktiviert.
Als Assemblerer unterliegst Du derlei Regularien nicht - Du kannst auch zu irgendnem anderen Zeitpunkt in(!) einer ISR IRQs freigeben - mußt dann halt nur mit den Konsequenzen leben. Verschachtelte IRQs? Kein Thema, solange der Stack reicht.
 

Über uns

  • Makerconnect ist ein Forum, welches wir ausschließlich für einen Gedankenaustausch und als Diskussionsplattform für Interessierte bereitstellen, welche sich privat, durch das Studium oder beruflich mit Mikrocontroller- und Kleinstrechnersystemen beschäftigen wollen oder müssen ;-)
  • Dirk
  • Du bist noch kein Mitglied in unserer freundlichen Community? Werde Teil von uns und registriere dich in unserem Forum.
  •  Registriere dich

User Menu

 Kaffeezeit

  • Wir arbeiten hart daran sicherzustellen, dass unser Forum permanent online und schnell erreichbar ist, unsere Forensoftware auf dem aktuellsten Stand ist und der Server regelmäßig gewartet wird. Auch die Themen Datensicherheit und Datenschutz sind uns wichtig und hier sind wir auch ständig aktiv. Alles in allem, sorgen wir uns darum, dass alles Drumherum stimmt :-)

    Dir gefällt das Forum und unsere Arbeit und du möchtest uns unterstützen? Unterstütze uns durch deine Premium-Mitgliedschaft!
    Wir freuen uns auch über eine Spende für unsere Kaffeekasse :-)
    Vielen Dank! :ciao:


     Spende uns! (Paypal)