sei(); eingegeben? Aktiviert die Interrupts global.
sonst sind die Interrupts nicht aktiviert!
Zeig ansonsten mal bitte deinen ganzen Code, dann kann man besser
helfen.
Ersetze die Konstanten wie z.B. 0x12 usw. in Zukunft durch so etwas wie
z.B. (1 << INTF0) oder was du da gerade machst. Man sieht es viel besser
was passiert.
Johannes O. schrieb:> sei(); eingegeben? Aktiviert die Interrupts global.>> sonst sind die Interrupts nicht aktiviert!>> Zeig ansonsten mal bitte deinen ganzen Code, dann kann man besser> helfen.>> Ersetze die Konstanten wie z.B. 0x12 usw. in Zukunft durch so etwas wie> z.B. (1 << INTF0) oder was du da gerade machst. Man sieht es viel besser> was passiert.
hier ist die Anpassung:
//Interrupt INT1 auf fallende Flanke definiert
EICRA = (1 << ISC11);
EIMSK = (1 << INT1);
ISR (INT1_vect)
{
ChargeCurrent_Write_Speed();
ChargeVoltage_Write();
InputCurrent_Write();
}
geht leider aber immer noch nicht.
Muss ich noch was definieren ? Habe ich was übersehen?
Amateur schrieb:> Johannes O. schrieb:>> Bitte mal den GANZEN Code. Hast du sei() drin?>>> das ist der gesamte relevante code:
glaub ich kaum.
>> //Interrupt INT1 auf fallende Flanke definiert> EICRA = (1 << ISC11);> EIMSK = (1 << INT1);>>> ISR (INT1_vect)> { __enable_interrupt;
in der ISR die Interrupts freigeben?
Das kann aber nicht dein Ernst sein.
Zeig halt mal alles oder bau dir ein abgespecktes Beispiel, wenn dir der
Code insgesamt als zu viel vorkommt.
Ein einfaches Beispiel, bei dem der Interrupt eine LED einschaltet und
sonst nichts im Programm ist, reicht ja schon um die Funktionsgruppe
'externer Interrupt' zu testen, zu debuggen und in Betrieb zu nehmen.
Das was man dann daran lernt wendet man aufs eigentliche Programm an.
Amateur schrieb:> Johannes O. schrieb:>> Bitte mal den GANZEN Code. Hast du sei() drin?>>> das ist der gesamte relevante code:
Den ganzen Code. Nicht was du für relevant hältst.
Wie oft denn noch?
>> //Interrupt INT1 auf fallende Flanke definiert> EICRA = (1 << ISC11);> EIMSK = (1 << INT1);>>> ISR (INT1_vect)> { __enable_interrupt;
Was ist denn das für ein Unsinn?
> ChargeCurrent_Write_Speed();> ChargeVoltage_Write();> InputCurrent_Write();> }>> Passt das soweit mit den Registern?
mfg.
Johannes O. schrieb:> Amateur schrieb:>> Was fehlt noch was damit diese "einfache" InterruptFunktion aufgerufen>> wird?>> Eine main Funktion.
in der zumindest ein "sei()" steht
Den Port C auf Ausgang schalten.
Sag mal wird das eine Verarsche?
Was ist denn bitte an
1
....
2
3
intmain()
4
{
5
DDRC|=(1<<PC0);
6
7
DDRD&=(1<<PD3);
8
PORTD|=(1<<PD3);
9
10
EICRA=(1<<ISC11);
11
EIMSK=(1<<INT1);
12
13
__enable_interrupt;
14
15
PORTC&=~(1<<PC0);
16
17
while(1)
18
;
19
}
das große Problem? Jeder der schon mal eine LED ein/ausgeschaltet hat,
muss doch die restlichen Zutaten für ein simples Testprogramm im Schlaf
runterbeten können.
Hallo hier ist der Quellcode der soweit auch funktioniert beim betätigen
der Taste wird der Interrupt ausgelöst und die LED leuchtet.
Jetzt möchte ich aber aus dem Interrupt raus und die LED ausmachen. Wie
setze ich das um?
Amateur schrieb:> Jetzt möchte ich aber aus dem Interrupt raus und die LED ausmachen. Wie> setze ich das um?
Du willst nicht 'aus dem Interrupt raus'.
Du willst dir im Interrupt in einer globalen Variablen (die volatile
sein muss) vermerken, dass die LED auzuschalten ist.
Und die Hauptschleife sieht sich diese globale Variable an und wenn dort
der 'Befehl' zum ausmachen der LED auftaucht, dann macht sie das und
setzt den 'Befehl' wieder zurück.
> P.S bitte nicht gleich "steinigen" wenn es zu einfach ist .....
Es geht nicht um "einfach".
Es geht darum, dass diese Taktik der Problem-Präsentation in
homöopathischen Dosen einfach nur nervt. Speziell wenn schon x-mal nach
komplettem Code nachgefragt wurde und du dann immer noch nicht
reagierst.
(gemeint ist der _disable_interrupt) bringt dir genau gar nichts.
Denn der Code ist hier in einer ISR.
* während des Betretens der ISR werden die Interrupts abgeschaltet. d.h.
alleine dadurch, dass das eine ISR ist, ist damit implizit verknüpft,
dass vor deinem Code ein __disable_interrupt() gemacht wird
* beim Verlassen der ISR werden Interrupts automatisch wieder
zugelassen. D.h. alleine dadurch, dass das eine ISR ist, ist damit
implizit verknüpft, dass am Ende der Funktion, als allerletztes (also
nachdem alle Aufräumarbeiten der Funktion gemacht wurden) als Teil der
Returns ein __enable_interrupt() durchgeführt wird. Tatsächlich ist es
so, dass es für diesen Fall eine spezielle Prozessorinstruktion gibt,
die beides gleichzeitig macht: Return und Interrupts freigeben. Weil es
eben wichtig ist, das hier die zeitliche Reihenfolge stimmt.
Fazit:
1) dein __disable_interrupt() bringt überhaupt nichts
2) vergreifst du dich innerhalb einer ISR an dieser Freigabe, dann
kannst du maximal auf die Schnauze fallen (wenn du nicht exakt und 100%
weißt was du tust).
hilmar schrieb:> Kurz nachdem du die LED eingeschaltet hast, bist du doch schon> wieder> aus dem Interrupt raus.> Warum hast du eigentlich __disable_interrupt();> in der Interruptroutine stehen?> Und ganz abgesehen davon, warum ersetzt ducli();> durch> __disable_interrupt();> undsei();> durch> __enable_interrupt();>> Ist dir cli(); und sei(); zu kurz? :-)
hat der Compiler(AVR-Studio 6.1) erst nicht genommen jetzt komischer
weise schon
>> LED ausschalten:> Fallende Flanke auswerten und dann mitPORTB &= ~(1 << PB2);> die LED wieder ausmachen.
wie werte ich denn die fallende Flanke aus?
Du mußt in deiner Interrupt-Routine umschalten von steigender auf
fallende Flanke und umgedreht. Also immer abwechselnd. Dafür hast du ja
den Marker eingeführt. Das Bit ISC11=1 und ISC10=0 sagt dem Interrupt,
daß er die fallende Flanke auswerten soll (so wie du es jetzt hast).
Wenn du ISC11 auch auf 1 setzt, wird die steigende Flanke ausgewertet.
Und das mußt du immer umschalten. Das heißt, erst fallende Flanke und
beim nächten Interrupt steigende Flanke usw.
Du kannst auch nur die fallende Flanke auswerten und dann in der
Interrupt-Routine die LED einmal ein- und das nächste Mal ausschalten.
Bei deinen Versuchen wirst du bestimmt merken, daß du manchmal mehrmals
drücken mußt, damit was passiert. Dann kommt das Thema Entprellung zum
Tragen. Aber dazu wurde hier im Forum schon eine ganze Menge
geschrieben.
du schaltest die LED ein und gleich darauf wieder aus?
(oder umgekehrt, je nachdem wie die LED angeschlossen ist)
Wenn du nicht sehr gute Augen hast, dann wirst du das nicht wirklich
feststellen können. Eigentlich, das kann nur Superman.
Gemeint war das ganze zb so
1
...
2
3
#define LED_ON 0x01
4
5
volatileuint8_tCommand;
6
7
intmain()
8
{
9
10
....
11
12
while(1)
13
{
14
15
if(Command==LED_ON)
16
{
17
Command=0;
18
_delay_ms(1000);
19
PORTB&=~(1<<PB0);// und wieder aus
20
}
21
}
22
}
23
24
ISR(....)
25
{
26
PORTB|=(1<<PB0);// LED ein ....
27
Command=LED_ON;// Hauptschleife benachrichtigen, dass die LED brennt
28
}
der delay_ms da drinnen ist natürlich nicht der Weisheit letzter
Schluss. Er dient nur dazu, dass die LED eine gewisse wahrnehmbare Zeit
leuchtet. Um mit externen Interrupts zu experimentieren reicht das, mehr
aber auch nicht. Zumal man Tasten sowieso anders auswertet und nicht mit
externen Interrupts. Aber so wie ich das im Moment noch verstehe, geht
es nicht im eigentlichen Sinn um Tasten (die Taste ist nur Mittel zum
Test-Zweck) sondern darum, dass irgendein Signal einen Interrupt
auslösen soll.
Edit: Ach ja. Weil ich es gesehen habe.
Gewöhn dir diese int-Rundumschläge gleich wieder ab. Es ist sinnlos,
wenn du den µC in 16-Bit Arithmetik treibst, wenn es 8 Bit auch tun. UNd
an dieser Stelle ist das sogar ziemlich wichtig, weil der µC einen 8-Bit
Wert atomar (in einem Rutsch ohne Unterbrechung) auswerten kann, einen
16 Bit Wert aber nicht.
Karl Heinz Buchegger schrieb:> ISR (INT1_vect)> {> PORTB |= ( 1 << PB2);>> Merker = PORTB &= ~ ( 1 << PB2);> }>> du schaltest die LED ein und gleich darauf wieder aus?> (oder umgekehrt, je nachdem wie die LED angeschlossen ist)>> Wenn du nicht sehr gute Augen hast, dann wirst du das nicht wirklich> feststellen können. Eigentlich, das kann nur Superman.>> Gemeint war das ganze zb so> ...>> #define LED_ON 0x01>> volatile uint8_t Command;>> int main()> {>> ....>> while( 1 )> {>> if( Command == LED_ON )> {> Command = 0;> _delay_ms( 1000 );> PORTB &= ~(1 << PB0); // und wieder aus> }> }> }>> ISR( .... )> {> PORTB |= (1 << PB0); // LED ein ....> Command = LED_ON; // Hauptschleife benachrichtigen, dass die LED> brennt> }>> der delay_ms da drinnen ist natürlich nicht der Weisheit letzter> Schluss. Er dient nur dazu, dass die LED eine gewisse wahrnehmbare Zeit> leuchtet. Um mit externen Interrupts zu experimentieren reicht das, mehr> aber auch nicht. Zumal man Tasten sowieso anders auswertet und nicht mit> externen Interrupts. Aber so wie ich das im Moment noch verstehe, geht> es nicht im eigentlichen Sinn um Tasten (die Taste ist nur Mittel zum> Test-Zweck) sondern darum, dass irgendein Signal einen Interrupt> auslösen soll.>> Edit: Ach ja. Weil ich es gesehen habe.> Gewöhn dir diese int-Rundumschläge gleich wieder ab. Es ist sinnlos,> wenn du den µC in 16-Bit Arithmetik treibst, wenn es 8 Bit auch tun. UNd> an dieser Stelle ist das sogar ziemlich wichtig, weil der µC einen 8-Bit> Wert atomar (in einem Rutsch ohne Unterbrechung) auswerten kann, einen> 16 Bit Wert aber nicht.
okay super Danke! Funktioniert soweit.
Jetzt möchte ich gerne das bei Tastendruck die Anweisungen in der
Interruptroutine dauerhaft in eine Schleife ausgeführt wird.
Finde aber keinen Ansatz ...
> Jetzt möchte ich gerne das bei Tastendruck die Anweisungen in der> Interruptroutine dauerhaft in eine Schleife ausgeführt wird.
Also immer wieder
> Merker = Zustand;
bis zum Sanktnimmerleinstag...
Grundsatz: So wenig wie möglich im Interrupt machen und alles andere
außerhalb. Flags setzen (so wie du es machst) ist ok. Und dann außerhalb
auf die Flags reagieren.
Also was soll wiederholt werden?
Amateur schrieb:>> Ist dir cli(); und sei(); zu kurz? :-)> hat der Compiler(AVR-Studio 6.1) erst nicht genommen jetzt komischer> weise schon
Das ist nicht komisch. Ein Compiler ist das humorloseste, was es gibt.
Die beiden sind in "interrupt.h" definiert. Und die muß natürlich auch
included sein.
War sie aber vorher nicht:
> // ***** Anfang allgemeine Includes> #include <avr/io.h> // ATmega88 Definitionen> //#include <inavr.h> // IAR Definitionen> #include <stdio.h> // Standard I/O Definitionen> // ***** Ende allgemeine Includes
Wenn der Compiler etwas nicht kennt, was er kennen sollte, bastelt man
sich keine Würgeraunds. Damit kann man sich ganz üble Probleme schaffen.
mfg.
Amateur schrieb:> void schnellladen (void)> {> while ( Merker == Zustand)> {> Merker = 0;> ChargeCurrent_Write_Speed()> ChargeVoltage_Write();> InputCurrent_Write()> }> }
Nicht
while ( Merker == Zustand )
in deinem Fall dann eben einfach
1
if(Merker==Zustand)
2
ChargeCurrent_Write_Speed()
3
ChargeVoltage_Write();
4
InputCurrent_Write()
5
}
die Schleife drummherum besorgt dann sowieso die Hauptschleife in main.
Du musst dir dann halt nur überlegen, wann 'Merker' wieder auf 0
zurückgesetzt werden soll. Also: Wann genau sollen die Texte wieder
verschwinden bzw. nicht mehr upgedatet werden? Was ist die Bedingung
dafür? Könnte es sein, dass dieses genau dann der Fall ist, wenn die
Akkus voll sind? Dann kommt dann eben dort das Rücksetzen dieses Flags
dazu, wo dieses festgestellt wird.
PS: Nenn das nicht Merker. Das ist ein selten dämlicher Name, der genau
gar nichts aussagt. Was ist seine Funktion? Und nach der benennst du
ihn. Zb ShowValues oder ChargeAkku oder .... Benenne Variablen nach
ihrer logischen Funktion und nicht danach, wie sie intern implementiert
sind.