Forum: Analoge Elektronik und Schaltungstechnik adc vom atmega mit mehreren Spannungen


von Aladin M. (djas020)


Lesenswert?

Hallo,

erstmal danke ich euch das ihr euch die Zeit nehmt mir zu Helfen.
Ich habe mir das Programm aus dem Tutorial genommen um den ADC vom 
Atmega zu benutzen. Meine Taktfrequenz beträgt 12MHz, und ich kriege 
alles einwandfrei auf dem Hyperterminal, also mit einer Spannung von 
3,8V (mit der mein µC betrieben wird) kriege ich eine Zahl von 1023.

Das Programm sieht folgendermaßen aus:
1
.include "m8def.inc"
2
 
3
.def temp1  = r16
4
.def temp2  = r17
5
.def temp3  = r18
6
.def temp4  = r19
7
.def adlow  = r20
8
.def adhigh = r21
9
.def temp5  = r22
10
.def temp6  = r23
11
.def temp7  = r24
12
.def temp8  = r25
13
.equ quartz = 12000000       ; Taktfrequenz
14
.equ baud   = 9600          ; Baudrate
15
 
16
 
17
    ldi  temp1, LOW(RAMEND)     ; Stackpointer initialisieren
18
    out  SPL, temp1
19
    ldi  temp1, HIGH(RAMEND)
20
    out  SPH, temp1
21
 
22
;UART Initalisierung
23
 
24
    sbi  UCSRB, TXEN        ; enable transmit
25
    ldi  temp1, quartz / (baud * 16) - 1
26
    out  UBRRL, temp1       ; BAUD Rate
27
 
28
; ADC initialisieren: Single Conversion, Vorteiler 128
29
    ldi  temp1, (1<<REFS0)  ; Kanal 0, interne Referenzspannung 5V
30
    out  ADMUX, temp1
31
    ldi  temp1, (1<<ADEN) | (1<<ADPS2) | (1<<ADPS1) | (1<<ADPS0)
32
    out  ADCSRA, temp1
33
 
34
Main:
35
    clr  temp1
36
    clr  temp2
37
    clr  temp3
38
    clr  temp4
39
    ldi  temp5, 0           ; 256 Schleifendurchläufe
40
 
41
; neuen ADC-Wert lesen  (Schleife - 256 mal)
42
sample_adc:
43
    sbi  ADCSRA, ADSC       ; den ADC starten
44
 
45
wait_adc:
46
    sbic ADCSRA, ADSC       ; wenn der ADC fertig ist, wird dieses Bit gelöscht
47
    rjmp wait_adc
48
 
49
; ADC einlesen:
50
    in   adlow, ADCL        ; immer zuerst LOW Byte lesen
51
    in   adhigh, ADCH       ; danach das mittlerweile gesperrte High Byte
52
 
53
; alle 256 ADC-Werte addieren
54
    add  temp2, adlow       ; addieren
55
    adc  temp3, adhigh      ; addieren über Carry
56
    adc  temp4, temp1       ; addieren über Carry, temp1 enthält 0
57
    dec  temp5              ; Schleifenzähler MINUS 1
58
    brne sample_adc         ; wenn noch keine 256 ADC Werte -> nächsten Wert einlesen
59
 
60
; Aus den 256 Werten den Mittelwert berechnen
61
; Bei 256 Werten ist das ganz einfach: Das niederwertigste Byte
62
; (im Register temp2) fällt einfach weg
63
;
64
; allerdings wird der Wert noch gerundet
65
    cpi  temp2,128          ; "Kommastelle" kleiner als 128 ?
66
    brlo no_round           ; ist kleiner ==> Sprung
67
 
68
; Aufrunden
69
    subi temp3, low(-1)       ; addieren von 1
70
    sbci temp4, high(-1)      ; addieren des Carry
71
 
72
no_round:
73
;   Ergebnis nach adlow und adhigh kopieren
74
;   damit die temp Register frei werden
75
    mov  adlow, temp3
76
    mov  adhigh, temp4
77
78
;in ASCII umwandeln
79
outp:
80
    ldi  temp5, -1 + '0'
81
_a6ser:
82
    inc  temp5
83
    subi adlow, low(10000)   ; -10,000
84
    sbci adhigh, high(10000)
85
    brcc _a6ser
86
 
87
    ldi  temp6, 10 + '0'
88
_a7ser:
89
    dec  temp6
90
    subi adlow, low(-1000)   ; +1000
91
    sbci adhigh, high(-1000)
92
    brcs _a7ser
93
 
94
    ldi  temp7, -1 + '0'
95
_a8ser:
96
    inc   temp7
97
    subi  adlow, low(100)    ; -100
98
    sbci  adhigh, high(100)
99
    brcc  _a8ser
100
 
101
    ldi  temp8, 10 + '0'
102
_a9ser:
103
    dec  temp8
104
    subi adlow, -10          ; +10
105
    brcs _a9ser
106
    subi adlow,-'0'
107
108
;an UART Senden
109
    mov   temp1, temp5       ; Zehntausender Stelle
110
    rcall transmit
111
    mov   temp1, temp6       ; Tausender Stelle
112
    rcall transmit
113
    mov   temp1, temp7       ; Hunderter Stelle
114
    rcall transmit
115
    mov   temp1, temp8       ; Zehner Stelle
116
    rcall transmit
117
    mov   temp1, adlow       ; Einer Stelle
118
    rcall transmit
119
    ldi   temp1, 13          ; CR
120
    rcall transmit
121
    ldi   temp1, 10          ; LF
122
    rcall transmit
123
 
124
    rjmp  Main
125
 
126
transmit:
127
    sbis  UCSRA,UDRE      ; Warten, bis UDR bereit ist ...
128
    rjmp  transmit
129
    out   UDR, temp1      ; und Zeichen ausgeben
130
    ret

Meine Frage lautet nun, wie ich das Programm so umschreiben könnte, dass 
ich 3 Spannungen an 3 verschiedenen Ports messen und ausgeben kann. 
Theoretisch könnte ich mir am Anfang einfach weitere Register definieren 
und die Schleife, in der der Wert des ADC berechnet wird einfach 3 mal 
ausführen mit verschiedenen "temp-s". Wie viele Register stehen mir zur 
Verfügung? Oder kennt wer einen eleganteren Weg dies zu realisieren?
Wäre sehr dankbar für hilfreiche Tipps. Danke im vorhinein.

von Falk B. (falk)


Lesenswert?

@ Aladin Mujovic (djas020)

>Meine Frage lautet nun, wie ich das Programm so umschreiben könnte, dass
>ich 3 Spannungen an 3 verschiedenen Ports messen und ausgeben kann.

Naja, dazu musst du die MUX im ADC auf einen anderen Kanal schalten und 
dann ganz normal wie jetzt auch messen.

MFG
Falk

von Aladin M. (djas020)


Lesenswert?

Das ist also das hier:

    ldi  temp1, (1<<REFS0)  ; Kanal 0, interne Referenzspannung 5V
    out  ADMUX, temp1
    ldi  temp1, (1<<ADEN) | (1<<ADPS2) | (1<<ADPS1) | (1<<ADPS0)
    out  ADCSRA, temp1

ok, dann schreibe ich das halt 3 mal und nenne es temp1,temp2,temp3 - 
aber wenn ich dann die berechnung durchführe, wie weiss ich welcher 
kanal vom adc in welchem register ist?

von Falk B. (falk)


Lesenswert?

@ Aladin Mujovic (djas020)

>ok, dann schreibe ich das halt 3 mal und nenne es temp1,temp2,temp3 -
>aber wenn ich dann die berechnung durchführe, wie weiss ich welcher
>kanal vom adc in welchem register ist?

???
Es gibt nur ein Register für die ADC-Daten.

MfG
Falk

von Aladin M. (djas020)


Lesenswert?

Ich meine das hier:
1
  mov   temp1, temp5       ; Zehntausender Stelle
2
    rcall transmit
3
    mov   temp1, temp6       ; Tausender Stelle
4
    rcall transmit
5
    mov   temp1, temp7       ; Hunderter Stelle
6
    rcall transmit
7
    mov   temp1, temp8       ; Zehner Stelle
8
    rcall transmit
9
    mov   temp1, adlow       ; Einer Stelle
10
    rcall transmit
11
    ldi   temp1, 13          ; CR
12
    rcall transmit
13
    ldi   temp1, 10          ; LF
14
    rcall transmit

Wenn ich jetzt den MUX 3 mal anspreche, wie weiss ich wo ich mich grade 
befinde, das ich die daten dann in die vordefinierten plätze also wie 
gesagt temp1,temp2,temp3 reinkopieren kann und nachher ausgeben?

von Falk B. (falk)


Lesenswert?

@ Aladin Mujovic (djas020)

>Wenn ich jetzt den MUX 3 mal anspreche, wie weiss ich wo ich mich grade
>befinde, das ich die daten dann in die vordefinierten plätze also wie
>gesagt temp1,temp2,temp3 reinkopieren kann und nachher ausgeben?

???
Kann es sein, dass du das Programm einfach nur k_O_piert hast, ohne es 
ein Stückchen zu k_A_pieren?

Das Prinzip ist doch immer das gleiche.

ADC MUX programmieren
AD-Wandlung vornehmen
Messwert in ASCII wandeln und zum PC senden

Wo ist das Problem?

Wenn dein Programm jweil die MUX setzt, "weiss" es doch, welchem Kanal 
die Daten entsprechen.
Du musst also dein Programm, was jetztgerade durchläuft, sinnvoll in 
Unterprogramme aufteilen.

MFg
Falk

von Aladin M. (djas020)


Lesenswert?

du verstehst meine frage nicht..

ich meine wieviele rxx stehen mir zur verfügung? von r16 bis?

32 gibt es insgesamt oder?

von JensG (Gast)


Lesenswert?

Schau doch mal ins Datenblatt rein - da steht es für jeden µC explizit 
drin (pauschal kann man es wohl nicht sagen)

von Falk B. (falk)


Lesenswert?

@ Aladin Mujovic (djas020)

>du verstehst meine frage nicht..

Das liegt vielleicht auch daran, dass du dich falsch ausdrückst.

>ich meine wieviele rxx stehen mir zur verfügung? von r16 bis?

Ahhhh, wieviele Register die CPU hat? Steht im Datenblatt.

>32 gibt es insgesamt oder?

Ja.  r0..r31.

MFG
Falk

P.S. Kleiner Tip. R16..R31 sind die "besseren" Register, weil nur mit 
diesen alle Befehle funktionieren. ldi und einige andere gehen NICHT mit 
r0..r15.

von Aladin M. (djas020)


Lesenswert?

das genau ist ja jetzt das problem, ich brauche für jeden spannungswert 
8 registerplätze, es stehen mir zwar 32 zur verfügung, würde sich von 
der zahl her ausgehen..nur kann ich für meine befehle nur die register 
r16 bis r31 benutzen..

von Falk B. (falk)


Lesenswert?

@ Aladin Mujovic (djas020)

>das genau ist ja jetzt das problem, ich brauche für jeden spannungswert
>8 registerplätze, es stehen mir zwar 32 zur verfügung, würde sich von
>der zahl her ausgehen..nur kann ich für meine befehle nur die register
>r16 bis r31 benutzen..

Das sollte doch wohl reichen, oder? Die Lösung deines "Problems" lautet 
SRAM.

AVR-Tutorial: SRAM
AVR-Tutorial: Speicher

MfG
Falk

von Michael Wilhelm (Gast)


Lesenswert?

>das genau ist ja jetzt das problem, ich brauche für jeden spannungswert
>8 registerplätze, es stehen mir zwar 32 zur verfügung, würde sich von
>der zahl her ausgehen..nur kann ich für meine befehle nur die register
>r16 bis r31 benutzen..

Wenn du die volle Auflösung (10 bit) benötigst, brauchst du nur 2 
Register pro Spannungswert. Nach der Verarbeitung speichert man die 
Werte im RAM.

MW

von Michael Wilhelm (Gast)


Lesenswert?

Edit:
nicht 2 Register pro Spannungswert, sondern nur 2 Register.

MW

von Aladin M. (djas020)


Lesenswert?

könnt ihr euch bitte das programm anschauen, was ich eingefügt habe.. 
ich weiss nicht wie das reichen kann, weil ich brauche ja für eine 
berechnung
.def temp1  = r16
.def temp2  = r17
.def temp3  = r18
.def temp4  = r19
.def adlow  = r20
.def adhigh = r21
.def temp5  = r22
.def temp6  = r23
.def temp7  = r24
.def temp8  = r25

10 Register
Wenn ich diese berechnung jetzt 3 mal wiederhole, auf 3 verschiedenen 
kanälen, brauche ich dann 30.
aber r0 bis r15 unterstützen befehle wie ldi nicht, die die ich brauche 
(glaube ich). oder?

von Johannes M. (johnny-m)


Lesenswert?

Ich kann nur noch mal auf Falks Hinweis verweisen: Der Mega8 hat 1 KiB 
SRAM, da kannste gaaaanz viele Werte speichern. Eine Operation kann 
immer nur maximal zwei Werte betreffen. Wenn Du 10-Bit-Werte hast (also 
2 Bytes pro Wert), dann brauchst Du wahrscheinlich für keine Operation 
mehr als 4 oder 5 Register! Und mit ein bisschen Hin-und-herschieberei 
sogar noch weniger...

von JensG (Gast)


Lesenswert?

Also wenn Du die (ADC- oder Ergebnis-) Werte unbedingt für längere Zeit 
speichern  must, dann nehme SRAM wie oben schon angeklungen.
Wenn nicht, dann hole doch immer nur einen ADC-Wert, berechne den, mache 
irgendwas mit dem Ergebnis, dann hole den nächsten (in die selben 
register), berechne den wieder, mache wieder was mit dem Ergebnis, hole 
den nächsten .... usw.

von Falk B. (falk)


Lesenswert?

@ Aladin Mujovic (djas020)

>10 Register
>Wenn ich diese berechnung jetzt 3 mal wiederhole, auf 3 verschiedenen
>kanälen, brauche ich dann 30.

HALLLOOOOOOO!!!!

Hast du die Artikel mal gelesen? Und verstanden? Und hast du dich mal 
ein wenig mit den Grundlagen der Programmierung beschäftigt?

In den CPU Registern hält nam nur die Daten, die man für die im Moment 
auszuführende Operation benötigt. Alles andere liegt Variablen im RAM. 
Und wenn du dreimal die Funktion aufrufen willst, braucht du nicht 30 
Register, sonder nur 10, weil ja die Berechnung NACHEINANDER erfolgt.

MFG
Falk

von Aladin M. (djas020)


Lesenswert?

ok.. tut mir leid das ich mich wenig damit auskenne.
was soll ich deiner meinung nach machen?

ich definiere anfangs die 10 register. spreche den kanal im mux an, 
mache die berechnung, gebe den wert aus. springe auf den nächsten 
kanal,berechnung,ausgabe, springe auf den dritten, berechnung -> 
ausgabe.

passt?

von Falk B. (falk)


Lesenswert?

@ Aladin Mujovic (djas020)

>was soll ich deiner meinung nach machen?

Das habe ich mehrfach geschrieben. LESEN!

>ich definiere anfangs die 10 register. spreche den kanal im mux an,
>mache die berechnung, gebe den wert aus. springe auf den nächsten
>kanal,berechnung,ausgabe, springe auf den dritten, berechnung ->
>ausgabe.

>passt?

So in etwa.

MFG
Falk

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.