8bit ADC-Wert verarbeiten/umrechnen

Gast #4367775
Lesenswert?

Hallo liebes Forum.

Ich wollte ein altes Volume-Pedal um eine MIDI-Funktionalität erweitern.
Leider habe ich nach der Entwicklung auf dem Steckbrett mit einem Poti, 
welches den vollen Weg fahren kann, festgestellt dass das Pedal das 
nicht tut.
Bislang sieht mein Code so aus:
1
loop_adc:
2
  ;Referenzspannung AVCC - Ergebnis Linksbündig - Kanal 0
3
  ldi   TMP1, (0<<REFS1) | (1<<REFS0) | (1<<ADLAR) | (0<<MUX4) | (0<<MUX3) | (0<<MUX2) | (0<<MUX1) | (0<<MUX0)
4
  out   ADMUX, TMP1
5
  ;Zähler laden
6
  ldi    TMP2, 8
7
  ;Ergebnisregister löschen
8
  clr    TMP3
9
  ;Zeiger setzen
10
  ldi    XL, LOW(adc0)
11
  ldi    XH, HIGH(adc0)
12
loop_adc_check:
13
  ;Vergleiche den Zähler mit 0
14
  cpi    TMP2, 0
15
  ;Wenn auf 0 springe zum Ende
16
  breq  loop_btn_right
17
  ;Den ADC starten
18
  sbi   ADCSRA, ADSC
19
loop_adc_load_wait:
20
  ;Überprüfen ob fertig konvertiert
21
  sbic  ADCSRA, ADSC
22
  ;Und Schleife neu starten falls noch nicht fertig konvertiert
23
  jmp    loop_adc_load_wait
24
  ;Das Low-Byte muss immer zuerst ausgelesen werden. Da drin stehen die 2 niederwertigsten Bits der Ergebnisses
25
  in    TMP3, ADCL
26
  ;Jetzt kommt das High-Byte. Das Low-Byte wird überschrieben um ein Zittern zu vermeiden. Wir haben also nur noch 8bit
27
  in    TMP3, ADCH
28
  ;Linksschieben, da wir nur 7 bit verarbeiten können
29
  lsr    TMP3
30
  ;Speichern des Ergebnisses und inkrementieren des Zeigers
31
  st    X+, TMP3
32
  ;Dekrementieren des Zählers
33
  dec    TMP2
34
  ;Inkrementieren des ADMUX-Registers
35
  inc    TMP1
36
  out    ADMUX, TMP1
37
  ;Schleife von neu beginnen
38
  jmp    loop_adc_check
39
    
40
loop_btn_right:
Den Befehl
1
  ;Linksschieben, da wir nur 7 bit verarbeiten können
2
  lsr    TMP3
muss ich nun durch eine Routine ersetzen, welche mir einem Eingangs-Wert 
von, sagen wir mal, 60 bis 150 in einen Wert von 0 bis 127 umrechnet.
Wie stelle ich das am besten an? Ich stehe da ein bissl aufm Schlauch.
Entwickelt wurde und wird das ganze auf einem ATMEGA32. Später soll 
alles auf einen Tiny25/45/85 portiert werden. Da hätte ich auch keinen 
Hardware-Multiplizierer.

Danke für Antworten und ein schönes Wochenende.
Moderator (Firma: Titel) Persönliche Seite #4367789
Lesenswert?

TBI schrieb:
> Später soll alles auf einen Tiny25/45/85 portiert werden. Da hätte ich
> auch keinen Hardware-Multiplizierer.
Aber genug Speicher: ich würde eine Tabelle mit 256 Einträgen anlegen 
und dort direkt mit dem AD-Wert den "umgerechneten" Midi-Wert abholen. 
Dann könntest du sogar irgendwelche Nichtlinearitäten ganz einfach 
geradebiegen...
#4367790
Lesenswert?

@ TBI (Gast)

>Ich will hier keinen Thread über C vs. ASM vs. Bascom vs. was weiss ich.

Will auch keiner.

>Lediglich einen Denkanstoß, damit ich weiterkomme.

Nimm eine Softwarefunktion zur Multiplikation, die läuft auch auf den 
Tinys.
Die gibt es in einer App-Note von Atmel, musst du mal suchen.
Gast #4367792
Lesenswert?

Lothar M. schrieb:
> Aber genug Speicher: ich würde eine Tabelle mit 256 Einträgen anlegen
> und dort direkt mit dem AD-Wert den "umgerechneten" Midi-Wert abholen.

Ich wollte einen Kalibrierungstaster anbringen um die Minimalen und 
Maximalen Werte zu erhalten. Daher geht das leider nicht ohne weiteres.
#4367796
Lesenswert?

Hallo,

hier würde ich auch eine Tabelle nehmen.
Tabellenstart in Z rein, ADC-Wert dazu addeiren und den MIDI-Wert 
abholen.
Kann man vor allem genau passend basteln oder in Excel berechnen oder 
wie auch immern. Macht man ja nur einmal.
Wenn man den Tiny85 nimmt kann man das vermutlich auch beim Start 
berechnen und im Ram anlegen, dann spielt hinterher Laufzeit auch keine 
Rolle mehr.

Gruß aus Berlin
Michael
Gast #4367827
Lesenswert?

TBI schrieb:
> Wie stelle ich das am besten an?

Ob es am besten für dich ist, weiss ich nicht, aber üblicherweise würde 
man eine lineare Umrechnung der Form y =x * m + b machen. In deinem Fall 
also als Ganzzahlrechnung mit y = x * m1 / m2 + b mit z.B. m1=361, 
m2=256 und b=-84. Das spart dir schon mal Float-Rechnung und Division.

> Da hätte ich auch keinen Hardware-Multiplizierer.
Dann wirst du die Multiplikation wohl in Software, ggf. hart kodiert mit 
Addieren und Schieben machen müssen, also
1
(((((x << 2) + x) << 1) + x) << 2) + x) << 3) + x
#4367867
Lesenswert?

Servus,

in meinem alten picalic-Projekt benutze ich eine lineare Interpolation, 
um den Y-Wert einer Geraden für einen bestimmten X-Wert (im Bereich 
X=0..X2) zu bestimmen. Einen Offset auf die X-Werte (wenn X1 nicht Null 
sein soll) kann man ja leicht durch Addition erschlagen.

Ist zwar PIC-Assembler, aber vielleicht als Denkanstoss...:
1
;================ Linear Interpolation
2
;computes Y-value for given X-val. 
3
;input:
4
;y1 = Y-value for X=0
5
;y2 = Y-value for X=x2
6
;x2 = X-value: length of interval
7
;x = x input value (1 ... x2-1)
8
;output:
9
;y = Y-value for given x
10

11
interpolate
12
  clrf  x1
13
  btfsc  x2,7
14
  goto  interp_loop  ;x2 >= 0x80
15

16
  bcf  STATUS,C
17
interp_max        
18
  rlf  x2,F    ;maximize for higher precision
19
  rlf  x,F
20
  btfss  x2,7
21
  goto   interp_max
22

23
interp_loop
24
  movf  y1,W
25
  addwf  y2,W
26
  movwf  y
27
  rrf  y,F    ;= mean val. of y1, y2
28

29
  movf  x1,W
30
  addwf  x2,W
31
  movwf  temp    
32
  rrf  temp,F    ;= mean val. of x1, x2
33
  movf  temp,W
34
  subwf  x,W
35
  btfsc  STATUS,Z
36
  return      ;exact match -> iteration complete
37

38
  movf  y,W
39
  xorwf  y1,W
40
  btfsc  STATUS,Z  ;y == y1?
41
  goto  interp_exit  ;Y: result is y1 or y2
42

43
  movf  y,W
44
  xorwf  y2,W
45
  btfsc  STATUS,Z  ;y == y2?
46
  goto  interp_exit  ;Y: result is y1 or y2
47
 
48
  movf  temp,W    ;mean(x1,x2) -> W
49
  btfss  STATUS,C
50
  goto  interp_less  ;C=0 => x < mean(x1,x2) 
51
;x > mean(x1,x2):
52
  movwf  x1    ;new interval = mean..x2
53
  movf  y,W
54
  movwf  y1    ;new y within y..y2
55
  goto  interp_loop
56

57
;x < mean(x1,x2):
58
interp_less
59
  movwf  x2    ;new interval = x1..mean
60
  movf  y,W
61
  movwf  y2    ;new y within y1..y
62
  goto  interp_loop
63

64
;difference(y1,y2) <= 1, use y1 or y2 depending on x < or > mean(x1,x2)
65
interp_exit
66
  movf  y1,W
67
  btfsc  STATUS,C
68
  movf  y2,W    ;x > mean(x1,x2)
69
  movwf  y
70
  return
#4368346
Lesenswert?

Bei Werten von 60 bis 150 würde ich zunächst die 60 abziehen.
Bleibt 0 - 90
Dies würde ich mit 182 multiplizieren und vom Ergebnis die Bits 7-14 
benutzen.

Natürlich kannst Dur diese Werte auch nachträglich kalibrieren.
Unterster Wert ist derjenige, der abgezogen wird.
Und 16352 geteilt durch das was nach Abzug vom obersten Wert übrig 
bleibt ist die Zahl, mit der multipliziert werden muss.


Gruß

Jobst
Gast #4368454
Lesenswert?

Ich würde schauen, dass ich das Poti im Pedal so verdrehe, dass es 0-90 
Verstellweg hat und eine ext. ADC-Referenz erzeugen, welche dem 
Spannungswert bei 90 entspricht. Dann hast du von 0-90 den vollen 
ADC-Bereich von 0-255, machst einen Rechtsshift und hast 0-127.
Gast #4369465
Lesenswert?

Ich werde die Routine neu schreiben und dabei den jeweiligen MIDI-Wert 
aus dem ADC-Wert live berechnen. Selbst ein Tiny25 hat dazu genug Kraft.

Den im Ursprungspost geposteten Quellcode habe ich auf einen Kanal 
reduziert und das Linksschieben verworfen. Jetzt bekomme ich zwar im 
Moment nur Blödsinn, aber morgen werde ich mich mal in die 
SW-Multiplikation und Division einlesen. Dann sollte das auch ganz 
schnell klappen.

Ich habe das erstmal so vor:
TMP1 = ADC - Kalibrierung(Min)
TMP1 = TMP1 * 127
TMP2 = Kalibrierung(Max) - Kalibrierung(Min)
TMP1 = TMP1 / TMP2 (Rest wird verworfen)

Ob die Register gerade in Benutzung (bzgl. des geposteten SC) sind, oder 
ob ich nachher noch den Rest der Division nutzen muss stelle ich fest 
während/wenn ich das gecoded und ausprobiert habe. Aber erst morgen. Ein 
Problem nach dem anderen...

Ich bedanke mich für alle Antworten und wünsche einen schönen restlichen 
Sonntag.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren