PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Int0 gibt 2 Impulse?!



stfan1409
07.01.2012, 22:20
Hallo,
ich möchte LEDs zur Musik ansteuern(bassgetaktet).
Eine Elektronik wertet das Basssignal aus und gibt das Signal auf den INT0 eingang vom µC (NPN Transistor schaltet bei aktiv gegen Masse).

Leider bekomme ich immer 2 Signale vom INT0 Eingang. Also 1 Signal zu viel. Das möchte ich softwaremäßig ändern!

Meine Idee:
Sobald der INT0 aufgerufen wird, wird der INT0 deaktiviert - leider kommen immer noch 2 Impulse!
Nun habe ich einen Zähler und einen Printbefehl in die INT0_ISR reingeschrieben - der Zähler zählt bis 1 und es kommen 2 Printbefehle! Aber warum zählt der Zähler dann nicht bis 2?
Kann mir das bitte einer erklären?

Tobi

hier die empfangenen Daten über die serielle Schnittstelle
==============<\r><\n>
0<\r><\n>
==============<\r><\n>
0<\r><\n>
==============<\r><\n>
0<\r><\n>
==============<\r><\n>
int0 Aufruf<\r><\n>
1<\r><\n>
==============<\r><\n>
int0 Aufruf<\r><\n>
1<\r><\n>
==============<\r><\n>
0<\r><\n>
==============<\r><\n>
0<\r><\n>
==============<\r><\n>




$regfile = "m32def.dat"
$hwstack = 40
$swstack = 40
$framesize = 40

$crystal = 14745600
$baud = 19200
Wait 2 'damit erst die Spannung anliegt und dann der µC startet
'-------------------------------------------------------------------------------
'Ein- Ausgänge:

Ddra = &B00000000
Ddrb = &B00000000 '1 Ausgang, 0 Eingang => Pin PB5-0 als Ausgang 6&7 als Eingang
'Ddrc = &B00000000 '1 Ausgang, 0 Eingang => Pin PC7-0 als Ausgang
Ddrd = &B00000000 '1 Ausgang, 0 Eingang

'-------------------------------------------------------------------------------

'Interrupt von Bassauswertung
On Int0 Irq0
'Enable Int0
Config Int0 = Falling 'wechsel von High auf Low
Enable Interrupts



Dim Zaehler_do As Single
Dim Zaehler_int0 As Byte

Enable Int0


'Do - Looproutiene:
Do

Incr Zaehler_do

If Zaehler_do > 50000 Then

Print Zaehler_int0
Print "=============="

Zaehler_do = 0
Zaehler_int0 = 0

Enable Int0

End If



Loop


'_________________________________________________ ______________________________
Irq0:
Disable Int0
Incr Zaehler_int0
Print "int0 Aufruf"

Return

MagicWSmoke
07.01.2012, 22:49
Wenn ein weiteres Int0-Ereignis nach dem Disablen des Int0 eintritt, so wird es doch im INTF0-Flag des GIFR-Registers gemerkt.
Sobald der Int0 wieder freigegeben wird, sorgt dies dafür dass unmittelbar nach Freigabe die Int0-ISR ein weiteres Mal ausgeführt wird.
Kann vermieden werden, indem ab geeigneter Stelle durch GIFR.INTF0 = 1 das Flag gelöscht wird.

stfan1409
08.01.2012, 13:32
Hallo MagicWSmoke,
genau das war der Grund! Vielen Dank!
Nun läut das Programm. Erst lösche ich das Flag und dann setzte ich den INT0 wieder auf Enable.

Tobi

PS. Wo finde ich etwas zu dem Befehl?
In der Bascomhilfe habe ich dazu nichts gefunden.
Im Datenblatt steht, dass man das Flag setzen muss, aber natürlich nicht, wie der Bascom-Befehl heißt.

Kampi
08.01.2012, 13:40
Ich glaube es gibt keinen Bascom Befehl der das Interruptflag löscht. Im zweifelsfall rufst du eine ASM-Routine auf und machst es per Hand.

MagicWSmoke
08.01.2012, 13:53
Ich glaube es gibt keinen Bascom Befehl der das Interruptflag löscht.
Da glaubst Du falsch.

Wobei ich zugebe, dass ich es auch schon mal besser gewusst habe.
Das macht zwar am hier gezeigten Beispiel keine Probleme, aber ansonsten führt GIFR.INTF0 = 1 dazu, dass intern das Register gelesen, das Bit gesetzt und somit mit dem Originalregisterinhalt ver-odert und zurückgeschrieben wird.
Dies führt bei einem Flag-Register zum Löschen aller anderen gesetzten Flags, bei mehreren Interrupt-Ereignissen will man das natürlich nicht.

Richtig ist also: GIFR = Bits(INTF0)

Damit gibt's das Problem nicht.

Im zweifelsfall rufst du eine ASM-Routine auf und machst es per Hand.
Völlig sinnfrei.

Edit:
@stfan1409,

aber natürlich nicht, wie der Bascom (http://www.rn-wissen.de/index.php/Bascom)-Befehl heißt
Der Bascom Befehl lautet genauso wie ich ihn geschrieben habe. Die Abfolge RegisterX.BitX = WertX ist Bascom-Standard, nennt sich Bitmanipulation. Aus besagten Grund verwende allerdings Bits(), Info dazu findest Du in der Hilfe.

Kampi
08.01.2012, 14:00
Ah ok. Danke für die Korrektur ;)

MagicWSmoke
08.01.2012, 14:09
Ah ok. Danke für die Korrektur ;)
Kein Problem ;-)
Vielleicht meintest Du auch einen ganz speziellen Befehl zum speziellen Löschen von Flag-Registern. So etwas wie "Clearbit RegisterX.BitX" gibt's natürlich nicht. Auch nicht notwendig, da einfachst per Bits() umzusetzen.

Searcher
08.01.2012, 17:13
Das macht zwar am hier gezeigten Beispiel keine Probleme, aber ansonsten führt GIFR.INTF0 = 1 dazu, dass intern das Register gelesen, das Bit gesetzt und somit mit dem Originalregisterinhalt ver-odert und zurückgeschrieben wird.
Dies führt bei einem Flag-Register zum Löschen aller anderen gesetzten Flags, bei mehreren Interrupt-Ereignissen will man das natürlich nicht.

Das wäre ja eine üble Falle. Zumindest in der BASCOM Version 2.0.5.0 sieht es nicht so aus. Hab dazu ein kleines Programm gemacht, compiliert und die hex-Datei mit ReAVR disassemblieren lassen. Relevante ASM Befehle unten im Code.
Weder bei Gifr.intf0 = 1, Gifr = Bits(intf0) oder Set Gifr.intf0 wird Gifr geladen.

Gifr = Gifr Or &B01000000 muß man aber vermeiden


'################################################# ##############################
'IDE: BASCOM-AVR Demoversion 2.0.5.0
'################################################# ##############################
$regfile = "attiny45.dat"
$framesize = 32 'default?
$swstack = 32 'default?
$hwstack = 34 'default?
$crystal = 8000000

!nop 'nop zum code auffinden in ASM
Gifr.intf0 = 1
!nop
Gifr = Bits(intf0)
!nop
Set Gifr.intf0
!nop
Gifr = Gifr Or &B01000000
!nop

End



ASM von ReAVR V3.2.0

nop 'Gifr.intf0 = 1
ldi r24,k40
out p3A,r24 '3A ist Adresse von GIFR im ATtiny45
nop 'Gifr = Bits(intf0)
ldi r24,k40
out p3A,r24
nop 'Set Gifr.intf0
ldi r24,k40
out p3A,r24
nop 'Gifr = Gifr Or &B01000000
in r24,p3A
ori r24,k40
out p3A,r24
nop



Gruß
Searcher

MagicWSmoke
08.01.2012, 19:33
Searcher

Das wäre ja eine üble Falle.
das war eine Falle, die zumindest für Flag-Register im normalen IO-Bereich beseitigt wurde.

Um das wieder rauszukramen musste ich weiter zurückgehen als ich annahm. Ver 1.11.9.8 zeigt den Fehler noch, Ver 2.0.0.0 dagegen nicht mehr.
Gemeldet hab' ich den Bug an Mark im Feb 2010, in der von mir damals moderierten Rubrik steht's zum 21.2.2010, Ver 1.11.9.8, das könnte so passen.

Wie ich gerad' festgestellt hab', gibt's das Problem aber immer noch, sobald auf Ext IO zugegriffen wird.

Bei der von Dir verwendeten Version 2.0.5.0 ist das noch so, genauso in 2.0.7.3
Compilier' doch mal für 'nen ATM128 das hier: ETIFR.OCIE1C = 1, da kommt dann raus:

ETIFR.OCIE1C = 1
LDS R24,0x007C
ETIFR.OCIE1C = 1
ORI R24,0x01
STS 0x007C,R24

Da, wo der Zugriff nicht über ON/OUT stattfindet, sondern per LDS/STS hat sich das Problem wohl gehalten.
Für alle Fälle liegst Du mit meinem Vorschlag auf der sicheren Seite.

Werd' das gleich mal melden...

Searcher
08.01.2012, 19:51
Für alle Fälle liegst Du mit meinem Vorschlag auf der sicheren Seite.
Vielen Dank für die Tipps! Ich hab mit Ver 1.11.9.8 angefangen und nichts davon gewusst. Werde mich nun sicher an die BITS Funktion gewöhnen.

Gruß
Searcher

MagicWSmoke
08.01.2012, 20:03
Vielen Dank für die Tipps!
Bitteschön, gerne ;-)

Werde mich nun sicher an die BITS Funktion gewöhnen.
Um ein einzelnes Flag zu löschen, ginge übrigens auch:

ETIFR = 2 ^ OCIE1C
Für mehrere Flags:

Const Clear_Flags = 2 ^ OCIE1C or 2 ^ OCIE3C
ETIFR = Clear_Flags