Fragen zur Software

Basteleien analog und digital mit Strom und Spannung.

Moderator: radioscout

Benutzeravatar
radioscout
Geoking
Beiträge: 22799
Registriert: Mo 1. Mär 2004, 00:05
Wohnort: Aachen

Fragen zur Software

Beitrag von radioscout » Di 11. Aug 2009, 18:24

Hier kann nach Hilfe gesucht werden, wenn das selber geschriebene Programm nicht funktioniert.
Bild
Wir hätten nie uns getraut doofe Dosen anzumelden schon aus Respekt vor diesem geheimnisvollen Spiel (Dosenfischer, Die goldenen Jahre)

Werbung:
Benutzeravatar
qByter
Geocacher
Beiträge: 203
Registriert: Fr 30. Mai 2008, 23:20
Wohnort: Wadersloh, NRW

Re: Fragen zur Software

Beitrag von qByter » Do 15. Okt 2009, 21:57

Hallo,

ich hab mal eine Frage zum Pin Change Interrupt bei den Attinys - ich google nun schon seit zwei Stunden durch die Foren, aber finde nix...

Folgende Situation: Tiny soll aufgeweckt werden, wenn ein Schalter entweder aus _oder_ angeschaltet wird. Dafür würde sich ja der PCINT prima anbieten - dachte ich mir ;)
Schaltung: Masse -> Schalter -> PCINT mit Pullup-Widerstand

Prinzipiell funktioniert es auch, allerdings wird die ISR fast immer zweimal ausgeführt (Prellung?) - und das soll natürlich nicht sein. Abhilfe sollte doch eigentlich schaffen, als ersten Befehl in der ISR den Interrupt zu disablen und als letzten Befehl wieder einzuschalten?! Klappt aber nicht... Wo ist mein Denkfehler?

Die ISR ist recht lang. Dass er schon während der Tastenprellung ins Hauptprogramm zurückspringt kann ich ausschließen.

Code: Alles auswählen

On Pcint0 Aktion
Enable Pcint0
Enable Interrupts

Do
  Powerdown
Loop
End

Aktion:
  Disable PCINT0
  ...
  Enable PCINT0
Return

thomas_st
Geowizard
Beiträge: 1643
Registriert: Fr 18. Nov 2005, 16:30
Wohnort: ~ N 51°21' E 12°00'

Re: Fragen zur Software

Beitrag von thomas_st » Do 15. Okt 2009, 22:15

qByter hat geschrieben:[Pin Change IRQ]
Prinzipiell funktioniert es auch, allerdings wird die ISR fast immer zweimal ausgeführt (Prellung?) - und das soll natürlich nicht sein.
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 N
qByter hat geschrieben:Abhilfe sollte doch eigentlich schaffen, als ersten Befehl in der ISR den Interrupt zu disablen und als letzten Befehl wieder einzuschalten?!
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 :
Datenblatt Tiny 13 hat geschrieben:The I-bit is cleared by hardware after an interrupt has occurred, and is set by the RETI instruction to enable subsequent interrupts.
qByter hat geschrieben:Die ISR ist recht lang. Dass er schon während der Tastenprellung ins Hauptprogramm zurückspringt kann ich ausschließen.
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.

Viele Grüße,
Thomas(_st)

Benutzeravatar
qByter
Geocacher
Beiträge: 203
Registriert: Fr 30. Mai 2008, 23:20
Wohnort: Wadersloh, NRW

Re: Fragen zur Software

Beitrag von qByter » Do 15. Okt 2009, 22:38

Hi Thomas,
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 N
Ist ja aber keine Taste, sondern ein Schalter ;)
Also einschalten (H->L) - bleibt eingeschaltet und der Tiny soll die ISR ausführen.
Das gleiche beim Ausschalten...
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 :
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.
Ist also nicht nötig, gut...
Zunächst erstmal: eine ISR sollte eigentlich immer kurz sein!
Ich wusste, dass das kommt :D
Aber mal abgesehen davon, dass es "ugly" ist, sollte das nichts machen, oder?
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.
Zum testen hab ich da zuletzt einfach mal einige LED-Blinks reingepackt, also mindestens 2 Sekunden.

Thx,
qByter

Dr.Schmock
Geocacher
Beiträge: 36
Registriert: Fr 3. Apr 2009, 00:02
Wohnort: HD

Re: Fragen zur Software

Beitrag von Dr.Schmock » Do 15. Okt 2009, 23:04

Hallo,

ich hatte letztens genau das gleiche Problem.
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.
Danach hatte ich keine Doppelauslöser mehr. :^^:

Grüße

Benutzeravatar
qByter
Geocacher
Beiträge: 203
Registriert: Fr 30. Mai 2008, 23:20
Wohnort: Wadersloh, NRW

Re: Fragen zur Software

Beitrag von qByter » Do 15. Okt 2009, 23:31

Bingo, das war genau das, was ich gesucht hab...

Begründung hab ich mit dem Stichwort dann auch gleich gefunden:
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.
Vielen Dank!

thomas_st
Geowizard
Beiträge: 1643
Registriert: Fr 18. Nov 2005, 16:30
Wohnort: ~ N 51°21' E 12°00'

Re: Fragen zur Software

Beitrag von thomas_st » Fr 16. Okt 2009, 08:58

qByter hat geschrieben:Ist ja aber keine Taste, sondern ein Schalter ;)
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. :D
qByter hat geschrieben:Also einschalten (H->L) - bleibt eingeschaltet und der Tiny soll die ISR ausführen.
Auch beim Schalter wird daraus ein H->L->H->...->L
qByter hat geschrieben:Ok, das hatte ich gelesen - bin aber mal davon ausgegangen, dass er sich trotzdem merkt, wenn ein einzelner IRQ währenddessen ausgelöst wird.
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 hat geschrieben:
Zunächst erstmal: eine ISR sollte eigentlich immer kurz sein!
Ich wusste, dass das kommt :D
Na, nach dieser Steilvorlage ;)
qByter hat geschrieben:Aber mal abgesehen davon, dass es "ugly" ist, sollte das nichts machen, oder?
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.

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:

Code: Alles auswählen

   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
Theoretisch könnte man das auch für die gesamte ISR machen, läuft dann aber bei periodischen IRQs Gefahr, dass dieser immer während der noch laufenden ISR auftritt: damit hätte man dann den Tiny klassisch abgeschossen.
qByter hat geschrieben:Zum testen hab ich da zuletzt einfach mal einige LED-Blinks reingepackt, also mindestens 2 Sekunden.
Ok, das ist lang ;)
Dr.Schmock hat geschrieben: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.
Stimmt, ich vergaß: ein IRQ wird ja auf diese Art und Weise "gespeichert".

Eigentlich hätte ich drauf kommen müssen: merkwürdiger Weise wurde die ISR von qByter ja maximal 2x aufgerufen. Eigentlich müsste es beim Tasten-/Schalterprellen aber eine ungerade Anzahl sein (ein - aus -ein - aus - ... - ein [1x mehr "ein" als "aus"]), da aber der IRQ nur 1x gespeichert werden kann, kommt dann halt 2x raus.

Viele Grüße,
Thomas(_st)

Benutzeravatar
qByter
Geocacher
Beiträge: 203
Registriert: Fr 30. Mai 2008, 23:20
Wohnort: Wadersloh, NRW

Re: Fragen zur Software

Beitrag von qByter » Fr 16. Okt 2009, 10:40

Hi,

der Vollständigkeit halber dann hier nochmal der funktionierende Codeschnipsel:

Code: Alles auswählen

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
@Thomas:
Du verhinderst halt mit einer langen ISR, dass in der Zwischenzeit IRQs abgearbeitet werden können.
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 wild ;)
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:
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"?

cu,
qByter

thomas_st
Geowizard
Beiträge: 1643
Registriert: Fr 18. Nov 2005, 16:30
Wohnort: ~ N 51°21' E 12°00'

Re: Fragen zur Software

Beitrag von thomas_st » Fr 16. Okt 2009, 12:32

qByter hat geschrieben: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"?
Jep. So ist es zumindest geplant - überprüfen ist etwas schwierig ;) Zumindest treten keine Probleme, wie überlaufenden Empfangspuffer im RFM, auf.

Viele Grüße,
Thomas(_st)

Benutzeravatar
schnasemann
Geocacher
Beiträge: 235
Registriert: Mi 29. Okt 2008, 21:41

Re: Fragen zur Software

Beitrag von schnasemann » Di 27. Okt 2009, 21:05

so, dann melde ich mich mal wieder mit einem Problem.
Ich versuche, als schon lange nicht mehr im Basic firmen Menschen, meinem Reaktivlicht eine Lichtsequenzspeicherung zu verpassen. Diese soll so gehen, dass ich im 64ms-Raster die LED abtaste, das dann in ein Byte reinschiebe und wenn das Byte voll ist, das dann im EEPROM ablege. Sollte 32 Sekunden an Speicherei geben und wenn man vorher fertig ist, wird ein magisches Byte abgelegt, bei dem dann die abspielende Routine das Ende wieder erkennt und man nicht 32 Sekunden dunkel anschauen muss, bevor wieder neu getriggert werden kann.
Nun bekomme ich dauernd Fehlermeldungen des Compilers, mit denen ich so gar nichts anzufangen weiß.
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.
angehängt man das bisherige File in der Hoffung, auf einen Erleuchteten zu stoßen.
Danke vorab,
schnasemann

Code: Alles auswählen

 $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

Antworten

Wer ist online?

Mitglieder in diesem Forum: 0 Mitglieder