PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : ASURO ADC für Taster direkt auslesen



I2C
13.06.2005, 20:39
Hallo Leute,

das die Widerstände an den sechs Tastern mit ihren Toleranzen Probleme machen, ist hier im Forum mehrmals erwähnt worden. Ich wollte die Sache mal optimieren, sprich die Formel in asuro.c verbessern, doch bräuchte ich dazu die einzelnen Werte, die pro Taster konvertiert werden.

Meine Idee: die Werte per IR (serwrite) beim Drücken eines Tasters ausgebe.

Hat das schon jemand probiert? Ich bin erst dabei mich in c einzuarbeiten und krieg das auch irgend wann hin - aber warum das Rad immer wieder selbst erfinden?

So long - I2C

RCO
13.06.2005, 20:46
ASURO ist ja ganz normal in C programmiert, wenn ich mich nicht verrechnet habe, dann sind das die folgenden Werte
AD-Werte - Wert in Pollswitch()
678-682 -> 32
812-821 -> 16
903-915 -> 8
956-970 -> 4
985-1000 -> 2
1001-1015 -> 1

So siehts laut Formel aus. Wenn du die Werte anpassen willst, dann geht das natürlich nur individuell für deinen ASURO. Welcher Taster bei dir stimmt denn nciht und welcher Wert ist das in Pollswitch, der eigentlich kommen müsste.

I2C
13.06.2005, 21:15
Ich will ja gerade die genauen Werte - d.h. die zu meinen Widerständen gehörigen - zurückgemeldet bekommen. Mein Problem ist, dass Kombinationen von Tastern den Motor mit anlaufen lassen. Ich habe den Wert in der Formel auf 62 verringert, wodurch beim ersten Taster der Motor nicht mehr mit anspringt.

Also - wie komm ich an den Wert vor der Umrechnung dran bzw. wie gebe ich in an serwrite weiter?

Gruß, I2C

waste
13.06.2005, 21:22
Er meinte wohl wie er Werte über die IR-Schnittstelle an den PC senden kann.

Probier mal folgendes:
char text[6]=" ";

itoa(wert,text,10);
SerWrite(text,6); SerWrite("\n\r",2);

Hier noch die Erklärung:
char text[6] deklariert ein Feld für deinen Text
itoa wandelt integer to ascii, wobei wert in text gewandelt wird, 10 bedeutet zur Basis 10 also dezimal
mit SerWrite wird gesendet, "\n\r" ist Neue Zeile + Rücklauf, "\t" wäre Tabulator

Hoffe das hilft weiter.

Gruß waste

waste
13.06.2005, 21:31
Ich sehe gerade, das Board hat mir die Leerzeichen in den Anführungszeichen weggemacht. Also hier nochmal mit Code und etwas erweitert zur Anschauung.



char text[6]=" ";

itoa(wert,text,10);
SerWrite("Wert = ",7);SerWrite(text,6); SerWrite("\n\r",2);

izaseba
13.06.2005, 21:51
Hallo,
wie ich sehe arbeitet Ihr daran, was ich jetzt auch erreicht habe.
Ich habe mir ein kleines Programm geschrieben,
daß mir die gemessenen Spanunngswerte im Terminal ausgibt.
Alles schön und gut, es gibt leider gaanz kleine Abweichungen zwischen den Messungen.
Meine Überlegung dazu...
Da man meistens nur wissen will, ob der Asuro mit der rechten oder linken Seite hängenbleibt
und die Werte auf den rechten 3 Tastern alle über 0,950 V und auf den linken alle darunter liegen könnte man ja die ganze rumrechnerei mit float usw. weglassen und nur ein if else Konstrukt verwenden um festzustellen, ob links oder rechts ein Taster betätigt wurde...
Ich hoffe ich habe mich klar ausgedrückt.
Im Anhang ist mein Programm.
Bei Interesse sende ich noch den Code, der ist aber in Assembler

Gruß Sebastian

I2C
16.06.2005, 09:01
Hallo auch wieder in dieser Runde!

Erst mal Dank an Waste - wie gesagt lerne ich dazu, was c angeht und der Aufruf von itoa() war genau das was mir gefehlt hat.
Dazu noch ne kleine Frage: Ich bekomme vom Compiler eine Meldung wie etwa "implizit deklariert", weil ich keinen besonderen Header eingebunden habe. In welcher lib steht denn itoa() und gibt's da vielleicht noch mehr so interessante Routinen?

Meine Bemühungen zu den Schaltern ergaben auch wechselnde Werte bei Belastungen (LED, Motor etc.), weshalb ich die Selbsttestroutine um die Reaktionen gekürzt habe. Ich lass also nur noch die Werte auf serwrite raus. Programmschnipsel werden bei Gelegenheit nachgereicht.

Schön wäre es schon, wenn man die Tasten konkret zuordnen könnte - der Ansatz im ASURO auf die Art Leitungen einzusparen ist jedenfalls interessant. Wenn ich die Werte (ev. mit Streuung) protokolliert habe, schau ich mal, wie man das möglichst elegant umrechnen kann.

Hat sich jemand mit dem ADC näher auseinandergesetzt? Vielleicht kann man die Abfrage mit einer weiteren Z-Diode o.ä. optimieren. Die Referenzsspannung hat wohl schon Einfluss auf den Ausgabewert.

Gruß, I2C

I2C
16.06.2005, 09:20
Hallo Sebastian,

kannst Du die sources posten? Das hexfile ist ja ganz nett, aber Assembler könnte doch etwas aussagekräftiger sein ...

Danke, I2C

waste
16.06.2005, 09:48
Für itoa() mußt du <stdlib.h> einbinden.
Weitere Funktionen kannst du im avr-lib Manual nachlesen. Da müsste ein Symbol auf deinem Desktop sein.

Das Auslesen von Werten mittels SerWrite() verändert das Timing, weil eben die serielle Ausgabe mit 2400 Baud etwas dauert. Das mußt du berücksichtigen. Ich hab nämlich auch noch ein kleines Problem mit der Tasterabfrage. Aber immer wenn ich mir die Werte ausgeben lasse, ist es in Ordnung. Ich hab's vorerst so gelassen, werd es später mal genauer untersuchen.

Gruß waste

izaseba
16.06.2005, 20:33
Hallo,
hier ist mein Programm:



.include "m8def.inc"

;UBRR = Taktfrequenz / 16 * Baudrate -1
.def rBin1L = R1 ;Wird gebraucht um bin -> ascii zu rechnen
.def rbin1H = R2 ;Wird gebraucht um bin -> ascii zu rechnen
.def rbin2H = R3 ;Wird gebraucht um bin -> ascii zu rechnen
.def rbin2L = R4 ;Wird gebraucht um bin -> ascii zu rechnen

.def tmp = R16 ;universalregister
.def statusreg = R17 ;Statusregister um die Interrupts zu signalisieren
.def rmp = R18 ;universalregister für die Umrechnung
.equ sramanfang = 0x0060
.equ bumper = 7 ;Bit 7 von statusreg signalisiert INT1 Interrupt
.equ CLOCK = 8000000
.equ BAUD = 2400
.equ UBRRVAL = CLOCK / (BAUD*16)-1

.org 0x000
rjmp reset
.org INT1addr
rjmp kolision ;Ext Interrupt Vector Address
reset:
;Stackpointer
ldi tmp,LOW(RAMEND)
out SPL,tmp
ldi tmp,HIGH(RAMEND)
out SPH,tmp
;sram pointer
ldi ZH,HIGH(sramanfang)
ldi ZL,LOW(sramanfang)
;Baudrate einstellen
ldi tmp,UBRRVAL
out UBRRL,tmp
;di tmp,HIGH(UBRRVAL)
;ut UBRRL,tmp
;Frameformat 8Bit
ldi tmp,(1<<URSEL) | (1<<UCSZ1) | (1<<UCSZ0)
out UCSRC,tmp

sbi UCSRB,TXEN ;TX aktivieren

;AD converter Init
ldi tmp,(1<< ADEN) | (1<<ADPS1) | (1<<ADPS2)
out ADCSRA,tmp
ldi tmp,(1<<REFS0) | (1<<MUX2)
out ADMUX,tmp
;Einstellen Low Level Interrupt für Tastenabfrage
ldi tmp,(1<<INT1)
out GICR,tmp
sei
loop_:
;sram pointer
ldi ZH,HIGH(sramanfang)
ldi ZL,LOW(sramanfang)
loop:
sbrs statusreg,bumper ;prüfe statusregister ob bit 7 -> bumper gesetzt ist wenn ja dann springe
rjmp loop
in tmp,GICR ;Schalte INT1 interrupt ab
andi tmp,0x7f
out GICR,tmp
ldi statusreg,0 ;lösche statusregister bumper
cli ;Interrupts allgemein ausschalten
sbi DDRD,PD3 ;schalte pin PD3 als Ausgang
sbi PORTD,PD3 ;und setze es auf HIGH
ldi R16, $85 ; 10 ms abwarten
L1: ldi R18, $C7
L2: dec R18
brne L2
dec R16
brne L1
sbi ADCSRA,ADSC ;Starte ADC
warte:
sbis ADCSRA,ADIF
rjmp warte
;fertig und lese Ergebnis ein
in rBin1L,ADCL
in rBin1H,ADCH
cbi PORTD,PD3 ;Pin PD3 wieder LOW
cbi DDRD,PD3 ;und wieder als Eingang
sei ;Interrups wieder an
rcall berechne ;Rechne Ergebnis in ascii um und schreibe
;es in sram


rcall serout ;gib das Ergebnis über UART aus
in tmp,GICR ;Schalte Interrupts auf INT1 wieder ein
ori tmp,0x80
out GICR,tmp
rjmp loop_ ;wenn fertig wieder von vorne anfangen

serout:
ldi tmp,0x00 ;Zähler für Anzahl der CHAR
serout_:
cpi tmp,0x05 ;Vergleiche Zähler mit 0x05
breq rausuart ;Wenn gleich springe
ld R0,Z ;Hole ASCII kodierte Zahl aus den SRAM
serout__:
sbis UCSRA,UDRE ;Springe wenn UDR gesetzt ist
rjmp serout__
out UDR,R0 ;schiebe R0 in UDR
adiw ZL,1 ;Z++
inc tmp ;Zähler ++
rjmp serout_
rausuart:
sbis UCSRA,UDRE ;Springe wenn UDR gesetzt ist
rjmp rausuart
ldi tmp,10 ;sende Zeilenvorschub
out UDR,tmp
rausuart_:
sbis UCSRA,UDRE
rjmp rausuart_
ldi tmp,13 ;sende Wagerücklauf
out UDR,tmp
ret

;Diese Routine stammt von Gerd Schmidt http://www.avr-asm-tutorial.net/avr_de/index.html
;Danke dafür
berechne:
rcall Bin2ToBcd5 ; wandle Binärzahl in BCD um
ldi rmp,4 ; Zähler auf 4
mov rBin2L,rmp
Bin2ToAsc5a:
ld rmp,z ; Lese eine BCD-Ziffer
tst rmp ; prüfe ob Null
brne Bin2ToAsc5b ; Nein, erste Ziffer ungleich 0 gefunden
ldi rmp,' ' ; mit Leerzeichen überschreiben
st z+,rmp ; und ablegen
dec rBin2L ; Zähler um eins senken
brne Bin2ToAsc5a ; weitere führende Leerzeichen
ld rmp,z ; Lese das letzte Zeichen
Bin2ToAsc5b:
inc rBin2L ; Ein Zeichen mehr
Bin2ToAsc5c:
subi rmp,-'0' ; Addiere ASCII-0
st z+,rmp ; und speichere ab, erhöhe Zeiger
ld rmp,z ; nächstes Zeichen lesen
dec rBin2L ; noch Zeichen behandeln?
brne Bin2ToAsc5c ; ja, weitermachen
sbiw ZL,5 ; Zeiger an Anfang
ret ; fertig

Bin2ToBcd5:
push rBin1H ; Rette Inhalt der Register rBin1H:L
push rBin1L
ldi rmp,HIGH(10000) ; Lade 10.000 in rBin2H:L
mov rBin2H,rmp
ldi rmp,LOW(10000)
mov rBin2L,rmp
rcall Bin2ToDigit ; Ermittle 5.Stelle durch Abziehen
ldi rmp,HIGH(1000) ; Lade 1.000 in rBin2H:L
mov rBin2H,rmp
ldi rmp,LOW(1000)
mov rBin2L,rmp
rcall Bin2ToDigit ; Ermittle 4.Stelle durch Abziehen
ldi rmp,HIGH(100) ; Lade 100 in rBin2H:L
mov rBin2H,rmp
ldi rmp,LOW(100)
mov rBin2L,rmp
rcall Bin2ToDigit ; Ermittle 3.Stelle durch Abziehen
ldi rmp,HIGH(10) ; Lade 10 in rBin2H:L
mov rBin2H,rmp
ldi rmp,LOW(10)
mov rBin2L,rmp
rcall Bin2ToDigit ; Ermittle 2.Stelle durch Abziehen
st z,rBin1L ; Rest sind Einer
sbiw ZL,4 ; Setze Zeiger Z auf 5.Stelle (erste Ziffer)
pop rBin1L ; Stelle den Originalwert wieder her
pop rBin1H
ret ; und kehre zurück
Bin2ToDigit:
clr rmp ; Zähler auf Null
Bin2ToDigita:
cp rBin1H,rBin2H ; Vergleiche MSBs miteinander
brcs Bin2ToDigitc ; MSB Binärzahl kleiner, fertig
brne Bin2ToDigitb ; MSB Binärzahl größer, subtrahiere
cp rBin1L,rBin2L ; MSB gleich, vergleiche LSBs
brcs Bin2ToDigitc ; LSB Binärzahl kleiner, fertig
Bin2ToDigitb:
sub rBin1L,rBin2L ; Subtrahiere LSB Dezimalzahl
sbc rBin1H,rBin2H ; Subtrahiere Carry und MSB
inc rmp ; Erhöhe den Zähler
rjmp Bin2ToDigita ; Weiter vergleichen/subtrahieren
Bin2ToDigitc:
st z+,rmp ; Speichere das Ergebnis und erhöhe Zeiger
ret ; zurück
kolision:
ori statusreg,0x80
reti


2/3 Davon belegt die Umrechnungsroutine von bin nach ascii #-o , aber es ist ja nicht
die relevante Routine...



Gruß Sebastian

Archi
17.06.2005, 15:54
Beim Auslesen der Taster wird extra _nicht_ die interne Referenz verwendet. Ziehen die Motoren mehr Strom, dann bricht zwar die Versorgungsspannung und damit auch die Spannung an den Widerständen der Taster win, aber im gleichen Verhältnis ändert sich die Referenzspannung am AD-Wandler ("ratiometrisch"), sodass (im idealen Fall) eine Schwankung der Spannungsversorgung ohne Auswirkung bleibt.
Im realen Fall sorgen antürlich Offset-Fehler im ADC dafür, dass es nicht ganz funktioniert, aber besser als mit interner Referenz ist es allemal.

CU, Robin