www.mikrocontroller.net

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


Autor: Aladin Mujovic (djas020)
Datum:

Bewertung
0 lesenswert
nicht 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:
.include "m8def.inc"
 
.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
.equ quartz = 12000000       ; Taktfrequenz
.equ baud   = 9600          ; Baudrate
 
 
    ldi  temp1, LOW(RAMEND)     ; Stackpointer initialisieren
    out  SPL, temp1
    ldi  temp1, HIGH(RAMEND)
    out  SPH, temp1
 
;UART Initalisierung
 
    sbi  UCSRB, TXEN        ; enable transmit
    ldi  temp1, quartz / (baud * 16) - 1
    out  UBRRL, temp1       ; BAUD Rate
 
; ADC initialisieren: Single Conversion, Vorteiler 128
    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
 
Main:
    clr  temp1
    clr  temp2
    clr  temp3
    clr  temp4
    ldi  temp5, 0           ; 256 Schleifendurchläufe
 
; neuen ADC-Wert lesen  (Schleife - 256 mal)
sample_adc:
    sbi  ADCSRA, ADSC       ; den ADC starten
 
wait_adc:
    sbic ADCSRA, ADSC       ; wenn der ADC fertig ist, wird dieses Bit gelöscht
    rjmp wait_adc
 
; ADC einlesen:
    in   adlow, ADCL        ; immer zuerst LOW Byte lesen
    in   adhigh, ADCH       ; danach das mittlerweile gesperrte High Byte
 
; alle 256 ADC-Werte addieren
    add  temp2, adlow       ; addieren
    adc  temp3, adhigh      ; addieren über Carry
    adc  temp4, temp1       ; addieren über Carry, temp1 enthält 0
    dec  temp5              ; Schleifenzähler MINUS 1
    brne sample_adc         ; wenn noch keine 256 ADC Werte -> nächsten Wert einlesen
 
; Aus den 256 Werten den Mittelwert berechnen
; Bei 256 Werten ist das ganz einfach: Das niederwertigste Byte
; (im Register temp2) fällt einfach weg
;
; allerdings wird der Wert noch gerundet
    cpi  temp2,128          ; "Kommastelle" kleiner als 128 ?
    brlo no_round           ; ist kleiner ==> Sprung
 
; Aufrunden
    subi temp3, low(-1)       ; addieren von 1
    sbci temp4, high(-1)      ; addieren des Carry
 
no_round:
;   Ergebnis nach adlow und adhigh kopieren
;   damit die temp Register frei werden
    mov  adlow, temp3
    mov  adhigh, temp4

;in ASCII umwandeln
outp:
    ldi  temp5, -1 + '0'
_a6ser:
    inc  temp5
    subi adlow, low(10000)   ; -10,000
    sbci adhigh, high(10000)
    brcc _a6ser
 
    ldi  temp6, 10 + '0'
_a7ser:
    dec  temp6
    subi adlow, low(-1000)   ; +1000
    sbci adhigh, high(-1000)
    brcs _a7ser
 
    ldi  temp7, -1 + '0'
_a8ser:
    inc   temp7
    subi  adlow, low(100)    ; -100
    sbci  adhigh, high(100)
    brcc  _a8ser
 
    ldi  temp8, 10 + '0'
_a9ser:
    dec  temp8
    subi adlow, -10          ; +10
    brcs _a9ser
    subi adlow,-'0'

;an UART Senden
    mov   temp1, temp5       ; Zehntausender Stelle
    rcall transmit
    mov   temp1, temp6       ; Tausender Stelle
    rcall transmit
    mov   temp1, temp7       ; Hunderter Stelle
    rcall transmit
    mov   temp1, temp8       ; Zehner Stelle
    rcall transmit
    mov   temp1, adlow       ; Einer Stelle
    rcall transmit
    ldi   temp1, 13          ; CR
    rcall transmit
    ldi   temp1, 10          ; LF
    rcall transmit
 
    rjmp  Main
 
transmit:
    sbis  UCSRA,UDRE      ; Warten, bis UDR bereit ist ...
    rjmp  transmit
    out   UDR, temp1      ; und Zeichen ausgeben
    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.

Autor: Falk Brunner (falk)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Aladin Mujovic (djas020)
Datum:

Bewertung
0 lesenswert
nicht 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?

Autor: Falk Brunner (falk)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Aladin Mujovic (djas020)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich meine das hier:
  mov   temp1, temp5       ; Zehntausender Stelle
    rcall transmit
    mov   temp1, temp6       ; Tausender Stelle
    rcall transmit
    mov   temp1, temp7       ; Hunderter Stelle
    rcall transmit
    mov   temp1, temp8       ; Zehner Stelle
    rcall transmit
    mov   temp1, adlow       ; Einer Stelle
    rcall transmit
    ldi   temp1, 13          ; CR
    rcall transmit
    ldi   temp1, 10          ; LF
    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?

Autor: Falk Brunner (falk)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Aladin Mujovic (djas020)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
du verstehst meine frage nicht..

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

32 gibt es insgesamt oder?

Autor: JensG (Gast)
Datum:

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

Autor: Falk Brunner (falk)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Aladin Mujovic (djas020)
Datum:

Bewertung
0 lesenswert
nicht 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..

Autor: Falk Brunner (falk)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Michael Wilhelm (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Michael Wilhelm (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Edit:
nicht 2 Register pro Spannungswert, sondern nur 2 Register.

MW

Autor: Aladin Mujovic (djas020)
Datum:

Bewertung
0 lesenswert
nicht 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?

Autor: Johannes M. (johnny-m)
Datum:

Bewertung
0 lesenswert
nicht 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...

Autor: JensG (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Falk Brunner (falk)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Aladin Mujovic (djas020)
Datum:

Bewertung
0 lesenswert
nicht 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?

Autor: Falk Brunner (falk)
Datum:

Bewertung
0 lesenswert
nicht 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

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.