PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Taster interrupt



Bastian90
09.05.2013, 19:27
Hallo zusammen,
ich beschäftige mich gerade mit µP und arbeite mit einem Asuro für einige Tests.
Als ich den Interrupt für die Schalter gesetzt habe hat das auch alles wunderbar funktioniert. Wenn ich jetzt aber versuche über den AD Wandler zu bestimmen, welcher Taster gedrückt wurde läuft das ganze in eine Endlosschleife.


taster_interrupt:
push R16
push R17
in R16, SREG ;statusreg saven
push R16
MOTOR_BREAK
SET_BUMPER_TO_ADC_SOURCE
SBI DDRD, PD3
;SBI PORTD, PD3 ;if set the interrupt will not stop

rcall delay_short ;give the capacitor a bit time
GET_ADC_VALUE R17, R16 ;r17=high, r16=low

CBI PORTD, PD3
CBI DDRD, PD3
TRANSMIT R17 ;and send the high result
TRANSMIT R16 ; and send the low result

pop R16
out SREG, R16; restore status bits
pop R17
pop R16
reti

Folgendes Problem. Um die Spannung erfassen zu können muss ich PD3 ja zum Ausgang machen und auf High setzen und nach der Ermittlung das ganze wieder rückgängig machen.
Wenn ich aber

SBI PORTD, PD3
mache läuft die ISR in einer Endlosschleife und sendet durchgehend Werte, obwohl ich den Wert ja wieder zurücksetze und Interrupts solange deaktiviert sein sollten.
Setze ich das Bit nicht funktioniert alles aber der ADC gibt natürlich nur 0 zurück.
In der asuro.h steht in PollSwitch() oder so auch, das PD3 so gesetzt werden muss.
Kann mir bitte jemand sagen, wo mein Fehler liegt?
Vielen Dank im Voraus

Bastian

HeXPloreR
09.05.2013, 19:55
Hallo,

unabhängig davon das es anscheinend ASM und auf dem Asuro ist, von denen ich jeweils sehr wenig verstehe - muss PD3 nicht eher zum Eingang gemacht werden um Spannnung zum messen? Also eigentlich müsste es ja anderrum sein, denn es fliest ja etwas in den µC hinein... ;)
Und wenn man dann noch den PullUp benötigt wird der auf High geschaltet. Das nennt sich Tri-State. Allerdings ist das jetzt nicht der Ausgang, denn den Ausgang auf High schalten bedeutet er führt die Betriebsspannung.

Ansonsten produzierst Du wohl ungewollt einen Kurzschluss zwischen PD3 und Batterien/Akkuspannung.

EDIT:
PD3 müsste wenn dann als Ausgang aber LOW sein? Vermute ich. Dann müsste es gehen über PC4(ADC4) die einfliessende Spannung (über den spannungsteiler) zu messen.

Bastian90
09.05.2013, 20:17
Hallo,
muss PD3 nicht eher zum Eingang gemacht werden um Spannnung zum messen?
Nein, der AD Wandler ist an einem Pin angeschlossen :) Deshalb muss ich verhindern, dass über den Port Spannung abfällt und alles zum AD Wandler "fließt".
Ob da ein Kurzschluss ist kann ich nicht sagen, alles andere hat bisher aber immer funktioniert, würde also erstmal auf unschuldig tippen^^

HeXPloreR
09.05.2013, 20:25
Ja, habe oben gleichzeitig zu Deiner Antwort editiert. Habe mir den Schaltplan angesehen (Seite 74 (http://www.arexx.com/downloads/asuro/asuro_manual_en.pdf))... allerdings wie gesagt habe den selber nicht.

Bin der Meinung es müsste wenn es ein Ausgang sein soll mit Low klappen. Dann sollte der ADC die Messung in der ISR durchführen, insofern er dort eingestellt wird.
Keine Gewähr ;)

Bastian90
09.05.2013, 21:05
Hab es getestet, mit LOW bei PD3 geht es leider nicht funktioniert es leider nicht. Man bekommt dann nur 0 vom ADC

radbruch
09.05.2013, 22:41
Als ich den Interrupt für die Schalter gesetzt habe...Welchen Interrupt hast du denn gesetzt? Wäre es nicht besser in der ISR ein Flag zu setzen und dann in der Hauptschleife den ADC-Wert zu ermitteln und zu senden?

Bastian90
10.05.2013, 01:14
Der einzige gesetzte Interrupt ist INT1. Er wird ja auch richtig ausgelöst. Aber da ich für die Messung am AD Wandler den Port, auf dem der Interrupt ist, manipulieren muss lande ich dann in der endlosschleife von diesem Interrupt, obwohl ja beim Aufruf der ISR automatisch das Interrupt Flag auf 0 gesetzt wird. Später soll die ISR dann natürlich kleiner werden, ging jetzt erstmal grundsätzlich um den Test.

HeXPloreR
10.05.2013, 09:44
Der Interupt ist auf PD3 ... ADC Messung ist auf PC4 (ADC4) - bedeutet, allein mit Portmanipulation auf PD3 wird es nicht funktionieren.

Bastian90
10.05.2013, 12:38
SET_BUMPER_TO_ADC_SOURCE
stellt ein, das PC4 dann als Quelle für den ADC funktioniert. Eine Messung geht ja auch, nur hört die nicht mehr auf^^

HeXPloreR
10.05.2013, 12:56
SET_BUMPER_TO_ADC_SOURCE
stellt ein, das PC4 dann als Quelle für den ADC funktioniert. Eine Messung geht ja auch, nur hört die nicht mehr auf^^


;SBI PORTD, PD3 ;if set the interrupt will not stop

rcall delay_short ;give the capacitor a bit time

Was bedeutet das? Welcher Capacitor soll geladen werden?
Und wie lange?
Wird hier die Aufladezeit gegengerechnet, um auf die Batteriespannung zuschliessen?

Bastian90
10.05.2013, 13:38
Im Schaltplan bei den Kondensatoren ist ein Kondensator, der Betriebsspannung hat. Wird jetzt ein Schalter gedrückt, wird dieser Kondensator Entladen und gibt so einen Wert an den ADC. Zumindest habt ich den Schaltplan so verstanden. Und weil die Kondensatorspannung träge ist (ic=c*du/dt nicht) muss man dem kurz Zeit geben, sich zu entladen.

- - - Aktualisiert - - -

Es wird immer skurriler...
Habe die ISR jetzt nur mit einer Flag änderung belegt die dann im Hauptprogramm abgefragt werden soll.


taster:
ldi r20,1
reti

Aufgerufen wird dann:

.include "m8def.inc"

;############## M A I N ###########################


.CSEG
.org 0x0000
rjmp main ; Reset Handler
reti; interrupt for into
.org INT1addr
rjmp taster;_interrupt ; IRQ1 Handler
reti; interrupt timer2 comp
reti; interrupt for timer2 ovf
reti; interrupt for timer1 capt
reti; interrupt for timer1 compa
reti; interrupt for timer1 compb
reti; interrupt for timer1 ovf
reti; interrupt for timer ofv
reti; interrupt for spi,stc
reti; interrupt for usart,rxc
reti; interrupt for usart,udre
reti; interrupt for usart, txc
reti; interrupt for adc
reti; interrupt for ee_rdy
reti; interrupt for ana_comp
reti; interrupt for twi
reti; interrupt for spm_rdy

.include "macros.inc"
.include "functions.inc"
.include "interrupts.inc"

main:

init:
;hier stehen alle möglichen inits
sei

start:
ldi R16, 100
mov R2, R16
mov R3, R16
rcall change_motorspeed
MotorDir_FWD_FWD
clr r20 ;test anderer interrupt

wait:
sbrc R20,0 ;if r20 bit 0 is clear dont go to get it
rjmp get_it
SWITCH_LEFT_BACKLED_ON
rcall delay_turn
SWITCH_LEFT_BACKLED_OFF
rcall delay_turn
rjmp wait


get_it:
cli ;dont make another interrupt here
;dont save r16 and r17 here just a test
clr r20
MOTOR_BREAK
SBI DDRD, PD3
SBI PORTD, PD3 ;if set the interrupt will not stop
SET_BUMPER_TO_ADC_SOURCE
;rcall delay_short ;give the capacitor a bit time
GET_ADC_VALUE R17, R16 ;r17=high, r16=low
CBI PORTD, PD3
CBI DDRD, PD3 ;so now that the value is in done by the adc make it again
TRANSMIT R17 ;and send the high result
TRANSMIT R16 ; and send the low result
sei ;ok now you can interrupt again
ret


Hier tritt jetzt folgender Fehler auf:
- Anstatt nach dem drücken eines Tasters in der Wait weiterzumachen, wird offenbar Resetet und das Teil fängt wieder an zu fahren... Mit dem anderen ISR ist er wenigstens stehen geblieben.
- Dabei sendet er aber richtig die beiden Werte vom ADC (ob die Werte auch richtig sind, kann ich nicht sagen).
- Bei einem bestimmten Schalter wird sporadisch wieder wie mit der anderen ISR plötzlich eine Endlosschleife ausgelöst.

Kann es sein, das der Taster hängt, und so tatsächlich einen Dauerinterrupt auslöst? Aber wenn ja wieso bei der 2. ISR Routine nur ab und zu und bei der anderen immer? Und warum Resetet der µP bei der 2. Routine?
Ich habe das gefühl irgendwie stimmt was mit den Sprüngen nicht so ganz...

HeXPloreR
10.05.2013, 15:49
Du könntest mal z.B. mit einem Multimeter prüfen ob der Taster hängt.

Welche beiden Werte - sollte das nicht nur ein Wert sein? Vielleicht muss man hier etwas warten, bis zum nächsten Tastendruck. Beim RP6 sagt man auch, das ja nicht direkt wieder ein Hinderniss da sein kann wenn z.B. garde ausgelöst wurde und/oder Rückwärts gefahren wird und gibt etwas zeit dazwischen.

Also ich denke das der Kondensator C7 einfach zum Tastenentprellen da ist,da er parallel zu den tastern ist - und der muss sich wieder aufladen (give a bit time), damit er auch wiederholt das Tastenprellen abfangen kann. Also Aufgeladen wird er schon, aber diese Spannung wird ja nicht zum ADC zurückgeführt, denn dann würde annährend die Betreibsspannung gemessen - was in diesem Fall ja keinen Sinn macht ;) Der entläd sich also über GND des gedrückten Tasters. Sonst würde der Interrupt auf PD3 vielleicht auch garnicht reagieren.
Ist der Interrupt vielleicht noch falsch eingestellt - er müsste so eingestellt sein das immer bei fallender Flanke ausgelöst wird. Aber nicht bei steigender. Hast da vielleicht was verstellt (umprogrammiert)?
Wenn also ein Interrupt (spannung geht zu GND) an PD3 erkannt wird (Tasterdruck) dann schaltet er den ADC4 ein - bzw eher übergibt den Wert der am ADC ansteht in eine Variable ein.

Ich hoffe das ist in etwa so ;)

radbruch
10.05.2013, 16:12
Hallo

Beim Tastendruck wird ein Spannungsteiler zwischen dem Tasterwiderstand und R24 gebildet. R24 liegt dann über PD3 an Vcc (Ausgang, high), C7 dient zum Entprellen und die an ihm anliegende Spannung wird dann über PC4 eingelesen. Beim asuro sind die Tastenwiderstände so gewählt, dass man auch das gleichzeitige Drücken mehrerer Tasten erkennen und die beteiligten Tasten ermitteln kann.

"Kann es sein, das der Taster hängt..." Ich vermute, du verwendest einen Pinchange-Interrupt beim INT1 und der wird ausgelöst, wenn du eine Taste drückst (Eingang PD3 mit internem Pullup? wird low) und aber auch, wenn du PD3 zur Messung der Tastenspannung auf High setzt. Am Ende der ADC-Messung wird PD3 dann wieder auf Interrupteingang geschaltet und das Spielchen beginnt von vorne, solange ein Taster gedrückt ist.

Gruß

mic

Bastian90
10.05.2013, 19:01
Am Ende der ADC-Messung wird PD3 dann wieder auf Interrupteingang geschaltet und das Spielchen beginnt von vorne, solange ein Taster gedrückt ist.
So sollte es ja auch sein :) Aber bei mir bleibt er im Interrupt obwohl der Taster losgelassen wurde...

Der ADC wird so initialisiert:


init_adc:
ldi R16, (1 << ADEN) | (1 << ADPS1) | (1 << ADPS2)
out ADCSRA, R16

Und dann wird im Interrupt, oder auch außerhalb der ADC Eingang eingestellt:


.macro SET_BUMPER_TO_ADC_SOURCE
push R16 ;save R16
ldi R16, (1 << REFS0)|(1 << MUX2)|(1 << ADLAR);set ADC4 to source
;ldi R16, (1 << REFS0)|(1 << MUX2) ;set ADC4 to source
out ADMUX, R16 ;send the definition to ADMUS
pop R16; restore R16
.endm

Der Interrupt ist auch auf eine fallende Flanke gestellt:


init_interupt:
in R16 , MCUCR
SBR R16, (1 << ISC11)
CBR R16, (1 << ISC10) ;faling will trigger an interrupt
out MCUCR, R16
in R16, GICR
sbr R16, (1 << INT1);activate interupt1
out GICR, R16