radioscout
Geoking
Hier kann nach Hilfe gesucht werden, wenn das selber geschriebene Programm nicht funktioniert.
On Pcint0 Aktion
Enable Pcint0
Enable Interrupts
Do
Powerdown
Loop
End
Aktion:
Disable PCINT0
...
Enable PCINT0
Return
Eigentlich muss die zweimal aufgerufen werden. Wenn Du die Taste drückst ändert sich der Pegel von H auf L -> 1. IRQ, wenn Du sie los lässt ändert sich der Pegel von L auf H -> 2. IRQ. Hinzukommt dann noch das eigentlich unvermeidliche Prellen des Tasters -> IRQ 3 bis NqByter schrieb:[Pin Change IRQ]
Prinzipiell funktioniert es auch, allerdings wird die ISR fast immer zweimal ausgeführt (Prellung?) - und das soll natürlich nicht sein.
Damit erreichst Du nur, dass solange die ISR abgearbeitet wird, ein erneuter IRQ unterbleibt -> das ist aber sowiso gegeben, da der Tiny beim Eintritt in eine ISR das Global Interrupt Enable - Flag im SREG löscht und erst beim Beenden der ISR dieses wieder herstellt :qByter schrieb:Abhilfe sollte doch eigentlich schaffen, als ersten Befehl in der ISR den Interrupt zu disablen und als letzten Befehl wieder einzuschalten?!
Datenblatt Tiny 13 schrieb:The I-bit is cleared by hardware after an interrupt has occurred, and is set by the RETI instruction to enable subsequent interrupts.
Zunächst erstmal: eine ISR sollte eigentlich immer kurz sein! (ist sie bei mir auch nicht immer ) Ich frage mich an der Stelle: wie lang ist sie den wirklich? Eine "lange" ISR kann nämlich im Vergleich zum noch längeren Prellen dennoch kurz sein.qByter schrieb:Die ISR ist recht lang. Dass er schon während der Tastenprellung ins Hauptprogramm zurückspringt kann ich ausschließen.
Ist ja aber keine Taste, sondern ein SchalterEigentlich muss die zweimal aufgerufen werden. Wenn Du die Taste drückst ändert sich der Pegel von H auf L -> 1. IRQ, wenn Du sie los lässt ändert sich der Pegel von L auf H -> 2. IRQ. Hinzukommt dann noch das eigentlich unvermeidliche Prellen des Tasters -> IRQ 3 bis N
Ok, das hatte ich gelesen - bin aber mal davon ausgegangen, dass er sich trotzdem merkt, wenn ein einzelner IRQ währenddessen ausgelöst wird (Zitat AVR-GCC-Tutorial: "Wenn in der Zwischenzeit weitere Interrupts eintreffen, werden die zugehörigen Interrupt-Bits gesetzt und die Interrupts bei Beendigung der laufenden Interrupt-Routine in der Reihenfolge ihrer Priorität ausgeführt."). Daher die Idee mit dem disable.Damit erreichst Du nur, dass solange die ISR abgearbeitet wird, ein erneuter IRQ unterbleibt -> das ist aber sowiso gegeben, da der Tiny beim Eintritt in eine ISR das Global Interrupt Enable - Flag im SREG löscht und erst beim Beenden der ISR dieses wieder herstellt :
Ich wusste, dass das kommtZunächst erstmal: eine ISR sollte eigentlich immer kurz sein!
Zum testen hab ich da zuletzt einfach mal einige LED-Blinks reingepackt, also mindestens 2 Sekunden.Ich frage mich an der Stelle: wie lang ist sie den wirklich? Eine "lange" ISR kann nämlich im Vergleich zum noch längeren Prellen dennoch kurz sein.
Even if the relevant interrupt is not enabled, the moment an Int0/Int1 interrupt occurs it is stored in the General Interrupt Flag Register. ...
In the interrupt routine, when interrupts are disabled, new interrupts arrive due to button 'bounce'. The interrupts are flagged as zero bit in the Gifr register.
Prellen ist aber keine Frage von Taster oder Schalter Beide prellen im Allgemeinen. Prellen kommt ja vom mechanischen zurückfedern der Schaltkontakte beim Schalten ... und dass machen die Schaltkontakte eines Tasters genauso, wie die eines Schalters.qByter schrieb:Ist ja aber keine Taste, sondern ein Schalter
Auch beim Schalter wird daraus ein H->L->H->...->LqByter schrieb:Also einschalten (H->L) - bleibt eingeschaltet und der Tiny soll die ISR ausführen.
Stimmt (hat ja Dr.Schmock schon ausgeführt) das Interruptflag wird gesetzt, so dass der Tiny gleich wieder einen IRQ auslöst. Hatte ich übersehen.qByter schrieb:Ok, das hatte ich gelesen - bin aber mal davon ausgegangen, dass er sich trotzdem merkt, wenn ein einzelner IRQ währenddessen ausgelöst wird.
Na, nach dieser SteilvorlageqByter schrieb:Ich wusste, dass das kommtZunächst erstmal: eine ISR sollte eigentlich immer kurz sein!
In Deinem Beispiel macht es vermutlich nichts. Du verhinderst halt mit einer langen ISR, dass in der Zwischenzeit IRQs abgearbeitet werden können. Und da man oft noch andere (dann ebenfalls deaktivierte) IRQ-Quellen hat und diese oft zeitkritische Aufgaben zu erledigen haben, könnte dies zu Problemen führen.qByter schrieb:Aber mal abgesehen davon, dass es "ugly" ist, sollte das nichts machen, oder?
u8sreg = SREG; // SREG sichern
sei(); // Interrupts wieder freigeben -> damit kann die folgende Schleife durch einen
// IRQ unterbrochen werden
// Warten bis die AD-Wandlung beendet ist
while(ADCSRA&_BV(ADSC));
SREG = u8sreg; // alten Zustand des SREG wieder herstellen
Ok, das ist langqByter schrieb:Zum testen hab ich da zuletzt einfach mal einige LED-Blinks reingepackt, also mindestens 2 Sekunden.
Stimmt, ich vergaß: ein IRQ wird ja auf diese Art und Weise "gespeichert".Dr.Schmock schrieb:Die Lösung war bei mir, das "Pin Change Interrupt Flag" (GIFR) kurz vor dem "wieder-enablen" von Interrupts zu löschen. Dazu schreibt man eine '1' (!) in das Flag.
On Pcint0 Aktion
Enable Pcint0
Enable Interrupts
Do
Powerdown
Loop
End
Aktion:
... ' Code mit Dauer > Entprellzeit
GIFR = 32 ' Bit 5 vom General Interrupt Flag Register setzen (PCINT0 beim Attiny13)
Return
Ok, das ist klar... Da der Tiny aber nix anderes zu tun hat, außer auf diesen einen IRQ zu warten, ist das nicht weiter wildDu verhinderst halt mit einer langen ISR, dass in der Zwischenzeit IRQs abgearbeitet werden können.
Mal so rein interessehalber: Wie verhält er sich, wenn dieser Fall eintritt?Ich habe so etwas mies programmiertes im Geteilten RL. Hier wird ja innerhalb der WD-ISR der aktuelle Analogwert abgefragt. Hierbei muss man ja warten, bis das entsprechende Bit gesetzt ist ... und das kann ja auch lange sein. Da aber auch das Funkmodul sich in dieser Zeitspanne mit einem IRQ melden könnte, habe ich zumindest über die Polling-Schleife der ADC-Wandlung das globale I-Flag wieder aktiviert:
Jep. So ist es zumindest geplant - überprüfen ist etwas schwierig Zumindest treten keine Probleme, wie überlaufenden Empfangspuffer im RFM, auf.qByter schrieb:Mal so rein interessehalber: Wie verhält er sich, wenn dieser Fall eintritt?
Springt er dann während er auf die Wandlung wartet in die 2. ISR und anschließend wieder in die 1. ISR zurück und hat sich dann den ADC-Wert "gemerkt"?
$regfile = "ATtiny13.DAT"
$crystal = 128000 'Reale Frequenz des internen 128kHz-Oszillators
$hwstack = 10 ' default use 32 for the hardware stack
$swstack = 20 'default use 10 for the SW stack
$framesize = 20 'default use 40 for the frame
Stop Ac
Config Portb = &B11101110 'Portb.4 und Portb.0 auf 'Eingang' schalten
Portb = &B00000001 'keine Pullups zuschalten, nur PB0
Wdtcr = &B11010100 'Watchdog auf 250ms einstellen
Enable Interrupts
Config Adc = Single , Prescaler = Auto , Reference = Internal 'referenzspannung Des Adc Auf "Internal" = 1,1 V
Dim Wert1 As Word
Dim Wert2 As Word
Dim Schwelle As Word
Dim Anzahl As Byte
Dim Runde As Byte
Dim Akku As Byte
Dim Eepromz As Byte
Dim Zaehler As Byte
Const Dunkelwert = 18 ' Wert, ab dem Nacht erkannt wird
Const Hub = 10
Runde = 0
Portb.1 = 0 'Masse für portb.0
Do
Gosub Warte250ms
Gosub Einlesen
Schwelle = Wert1 + Hub 'Schwelle heller als Signal festlegen, je kleiner desto empfindlicher
If Wert1 < Dunkelwert And Wert2 >= Schwelle Then 'Dunkelschwelle festlegen, je kleiner desto dunkler
Gosub Blinken
End If
If Wert1 >= Dunkelwert And Wert2 >= Dunkelwert Then 'bei Tag oder Dauerlicht Watchdog x n aktivieren
Runde = Runde + 1
Gosub Warte8s
End If
If Runde >= 7 Then ' alle gute Minute einmal blitzen am Tag
Config Portb.4 = Output
Portb.4 = 1
Gosub Warte16ms
Portb.4 = 0
Runde = 0
End If
If Pinb.0 = 0 Then ' Teachin beginnt
Gosub Blitz
For Eepromz = 0 To 63
Akku = 0
For Zaehler = 1 To 8
Gosub Einlesen
If Wert2 > 800 Then Akku = 1 End If
If Zaehler < 8 Then Rotate Akku , Left End If
Gosub Warte65ms
Next Zaehler
Writeeeprom Eepromz , Akku
If Pinb.0 = 0 Then
If Eepromz < 63 Then
Eepromz = Eepromz + 1
Writeeeprom Eepromz , &B01010101
Exit For
End If
End If
End If ' teachin ende
Wert1 = Wert2 'Wert2 nach Wert1 verschieben
Loop
Blitz: 'LED getaktet blinken lassen
Config Portb.4 = Output
Portb.4 = 0
For Anzahl = 1 To 20
Portb.4 = 1
Gosub Wait16ms
Portb.4 = 0
Gosub Warte250ms
Next Anzahl
Return
Einlesen:
Start Adc
Config Portb.4 = Output 'LED "entladen"
Portb.4 = 0
Gosub Warte16ms
Config Portb.4 = Input
Portb.4 = 0
cbi adcsra,7 'ADEN = 0
Gosub Warte16ms
sbi adcsra,7 'ADEN = 1
Wert2 = Getadc(2) 'Spannung der LED messen
Stop Adc
Return
Blinken:
Config Portb.4 = Output
Portb.4 = 0
Return
Warte8s:
Wdtcr = &B11110001 'Watchdog auf 8s einstellen
Reset Watchdog
Powerdown
Return
Warte16ms:
Wdtcr = &B11010000 'Watchdog auf 16ms einstellen
Reset Watchdog
Powerdown
Return
Warte64ms:
Wdtcr = &B11010010 'Watchdog auf 64ms einstellen
Reset Watchdog
Powerdown
Return
Warte 250ms:
Wdtcr = &B11010100 'Watchdog auf 250ms einstellen
Reset Watchdog
Powerdown
End
Ich bin zwar nicht der Bascom Experte, aber an dem Vergleich kann ich erstmal nichts Falsches erkennen. Allerdings habe ich in Deinem Programmcode kein "Akku = Akku+1" gefunden, sondern nur ein Eepromz = Eepromz + 1. Ist das gemeint?schnasemann schrieb:Der Vergleich einer Word Variable mit dem Wert 800 wird moniert, auch darf ich anscheinend nicht schreiben Akku = Akku+1, ein incr akku wird auch moniert.
$regfile = "ATtiny13.DAT"
$crystal = 128000 'Reale Frequenz des internen 128kHz-Oszillators
$hwstack = 10 ' default use 32 for the hardware stack
$swstack = 20 'default use 10 for the SW stack
$framesize = 20 'default use 40 for the frame
$eeprom'the following DATA lines data will go to the EEP file
Data &B01010101 , &B01010101 , &B01010101
$data
Stop Ac
Config Portb = &B11101110 'Portb.4 und Portb.0 auf 'Eingang' schalten
Portb = &B00000001 'keine Pullups zuschalten, nur PB0
Wdtcr = &B11010100 'Watchdog auf 250ms einstellen
Enable Interrupts
Config Adc = Single , Prescaler = Auto , Reference = Internal 'referenzspannung Des Adc Auf "Internal" = 1,1 V
Dim Wert1 As Word
Dim Wert2 As Word
Dim Schwelle As Word
Dim Anzahl As Byte
'Dim Runde As Byte
Dim Merker As Byte
Dim Eepromz As Byte
Dim Zaehler As Byte
Dim Teachin As Bit
Dim Entprell As Byte
Dim Result As Byte
Const Dunkelwert = 18 ' Wert, ab dem Nacht erkannt wird
Const Hub = 10
'Runde = 0
Portb.1 = 0 'Masse für portb.0
Do
Gosub Warte250ms
Gosub Einlesen
Schwelle = Wert1 + Hub 'Schwelle heller als Signal festlegen, je kleiner desto empfindlicher
If Wert1 < Dunkelwert And Wert2 >= Schwelle Then 'Dunkelschwelle festlegen, je kleiner desto dunkler
Gosub Blinken
End If
If Wert1 >= Dunkelwert And Wert2 >= Dunkelwert Then 'bei Tag oder Dauerlicht Watchdog x n aktivieren
Teachin = Pinb.0
If Teachin = 0 Then ' Teachin beginnt
Gosub Blitz
Teachin = Pinb.0 ' immer noch gedrückt? Dann löschen, sonst einlernen
If Teachin = 1 Then
Config Portb.4 = Output
Portb.4 = 0
For Eepromz = 1 To 63
Merker = 0
For Zaehler = 1 To 8 'bitzähler
Result = 0
Rotate Merker , Left
For Entprell = 1 To 5
If Entprell > 1 Then
Gosub Warte16ms
End If
Teachin = Pinb.0
If Teachin = 0 Then
Result = Result + 1
Portb.4 = 1
Else
Portb.4 = 0
End If
Next Entprell
If Result > 2 Then
Merker = Merker + 1
End If
Next Zaehler
Writeeeprom Merker , Eepromz
Next Eepromz
Gosub Blitz
Else ' Teachin immer noch gedrückt
Merker = &B01010101 ' Magic byte schreiben
Writeeeprom Merker , 1
Gosub Warte250ms
Gosub Warte250ms
Gosub Warte250ms
Gosub Warte250ms
Gosub Blitz
Gosub Blitz
Gosub Warte8s
End If
Gosub Blinken
Else
' Runde = Runde + 1
Gosub Warte8s
End If
End If
'(
If Runde >= 8 Then ' alle gute Minute einmal blitzen am Tag
Config Portb.4 = Output
Portb.4 = 1
Gosub Warte16ms
Portb.4 = 0
Runde = 0
End If
')
Wert1 = Wert2 'Wert2 nach Wert1 verschieben
Loop
Blitz: 'LED getaktet blinken lassen
Config Portb.4 = Output
Portb.4 = 0
For Anzahl = 1 To 10
Portb.4 = 1
Gosub Warte16ms
Portb.4 = 0
Gosub Warte250ms
Next Anzahl
Return
Einlesen:
Start Adc
Config Portb.4 = Output 'LED "entladen"
Portb.4 = 0
Gosub Warte16ms
Config Portb.4 = Input
Portb.4 = 0
cbi adcsra,7 'ADEN = 0
Gosub Warte16ms
sbi adcsra,7 'ADEN = 1
Wert2 = Getadc(2) 'Spannung der LED messen
Stop Adc
Return
Blinken:
Config Portb.4 = Output
Portb.4 = 0
For Eepromz = 1 To 63
Readeeprom Merker , Eepromz 'Byte lesen aus Eeprom
If Merker = &B01010101 Then ' Abprüfen, ob Endsequenz erreicht
Gosub Blitz
Exit For
End If
For Zaehler = 1 To 7 ' ansonsten bitweise schieben
If Merker > 127 Then ' und blinken
Portb.4 = 1
Gosub Warte64ms
Portb.4 = 0
Else
Gosub Warte64ms ' oder Pause
nop
nop
nop
nop
End If
Rotate Merker , Left
Next Zaehler
Next Eepromz
Return
Warte8s:
Wdtcr = &B11110001 'Watchdog auf 8s einstellen
Reset Watchdog
Powerdown
Return
Warte16ms:
Wdtcr = &B11010000 'Watchdog auf 16ms einstellen
Reset Watchdog
Powerdown
Return
Warte64ms:
Wdtcr = &B11010010 'Watchdog auf 64ms einstellen
Reset Watchdog
Powerdown
Return
Warte250ms:
Wdtcr = &B11010100 'Watchdog auf 250ms einstellen
Reset Watchdog
Powerdown
Return
End