Forum: Mikrocontroller und Digitale Elektronik Atmega32 AD-Wandlung


von casio (Gast)


Lesenswert?

Hallo zusammen,
ich hoffe ihr könnt mir helfen. Ich habe ein Problem mit der 
AD-Wandlung. Zunächst einmal: Ich nutze ein Atmega32 mit einem Quarz von 
11MHz. An den Port Pin PA0 (ADC0) habe ich über einen Spannungsteiler 
eine Spannung von 1,8V angelegt. An AVCC liegt über LC-Kombination 5V, 
ebenfalls an AREF angelegt.

Nun zu den Einstellungen der Register. Die Register, so denke ich 
jedenfalls, habe ich richtig eingestellt.
In ADMUX den Analogkanal ADCO ausgewählt, die Spannungsreferenz auf AVCC 
gestellt. Außerdem ADLAR auf eins gesetzt, da mich die unteren Bits der 
ADW zunächst nicht interessieren.
Desweiteren den ADW im ADCSRA enabled, den Vorteiler auf 128 
eingestellt. Somit 11,059MHz/128=86,4kHz für ADW (sollte ja zwischen 
50kHz und 200kHz). Und Auto Trigger disable. (Eigentlich will ich den 
ADW im free running mode betreiben. Müsste dann ADATE=1 und 
SFIOR=000xxxxx sein.)
In einer Endlosschleife starte ich die AD-Wandlung warte auf das 
Ergebnis und gebe schließlich ADCH auf dem PORTC aus. (JTAG habe ich 
deaktiviert (AVR-Studio). Da sonst die JTAG-Pins auf 5V gelegt werden 
wegen Pull-up Widerstand.). Am PortC sollt nun der AD-Wert anliegen. 
Klar dieser Wert wird immer wieder überschrieben und das Ergebnis der 
AD-Wandlung könnte ein wenig variieren. Doch die Tendenz des AD-Wertes 
sollte doch stimmen. Doch dies ist leider überhaupt nicht der Fall. Am 
PortC liegt der Wert 0000|0101 an. AD-Wert somit mind. 10100 (101 + die 
beiden niederwertigsten Bits). Ergibt ein AD-Wert =20. Müsste aber doch 
1,8*1024/5=368 sein.

Was mache ich falsch in meinem Quelltext. Und gibt es noch etwas beim 
Free Running Mode zu beachten?


.include "m32def.inc"
.org 0x000        rjmp main      ; Reset

main:

.def temp = r16

  ldi temp, low(RAMEND)    ;Startadresse Stack
  out SPL, temp
  ldi temp, high(RAMEND)
  out SPH, temp

  ldi temp, 0x00
  out DDRA, temp    ;PORTA (ADC Port) als Eingang

  ldi temp, 0xFF
  out DDRC, temp    ;PortC als Ausgang
  out DDRB, temp    ;PortB als Ausgang

  clr temp
  out PORTC, temp    ;PORTC zurücksetzen
  out PORTB, temp    ;Led an

    ; ADC Multiplexer Selection Register ADMUX
    ; REFS1 REFS0 ADLAR MUX4 MUX3 MUX2 MUX1 MUX0

    ldi temp, 0b01100000      ; REFS1=0 REFS0=1  AVCC with external
                              ; capacitor at AREF pin
    out ADMUX, temp           ; ADLAR=1 ADC conversion result in the ADC
                              ; Data Register is left adjusted
                  ; MUX4 - MUX0: Analog Channel and Gain Selection Bits
                  ; MUX4 - MUX0: 00000 Single Ended Input ADC0

    ; ADC Control and Status Register A ADCSRA
    ; ADEN ADSC ADATE ADIF ADIE ADPS2 ADPS1 ADPS0

    ldi temp, 0b11000111      ; ADEN=1 ADC Enable
    out ADCSRA, temp          ; ADSC=1 Start Conversion
                              ; ADATE ADC Auto Trigger Disable
                              ; ADPS2 - ADPS0 ADC Prescaler Select Bits
                              ; ADPS2 - ADPS0=111 division factor=128
                              ; 11,059MHz/128=86,4kHz

ende:

    sbi ADCSRA, ADSC        ; den ADC starten

  wait_adc:
    sbic ADCSRA, ADSC       ; wenn der ADSC=0, d.h. Umwandlung beendet,
                            ; wird der nächste Befehl übersprungen
    rjmp wait_adc

    ldi r16, ADCH
    out PORTC, r16

jmp   ende

von casio (Gast)


Lesenswert?

ach ja, danke schon mal

von Spess53 (Gast)


Lesenswert?

Hi


>    ldi r16, ADCH
>    out PORTC, r16

mit der ersten Zeile lädst du r16 mit der Adresse von ADCH ($05), nicht 
mit dem Inhalt.

Richtig:  in r16,ADCH

MfG Spess

von casio (Gast)


Lesenswert?

Okak, thx a lot.
Nun aber nochmal eine Frage. In wie weit unterscheiden sich ldi und in?

Muss ich immer den "in" Befehl nutzen, wenn ich ein Registerwert nutzen 
möchte?
So z.B.

    in temp, SFIOR
    andi temp, 0b00011111
    out SFIOR, temp

                anstatt

    ldi temp, SFIOR
    andi temp, 0b00011111
    out SFIOR, temp

Vielen Dank
casio

von Karl H. (kbuchegg)


Lesenswert?

casio wrote:
> Okak, thx a lot.
> Nun aber nochmal eine Frage. In wie weit unterscheiden sich ldi und in?
>

? Das solltest du als Assemblerprogrammierer aber schon wissen.

ldi = load immediate

  ldi  rxx, yy

lädt das Register rxx mit dem direkt angegebenen Wert yy. Daher
auch das immediate, weil der zu ladende Wert direkt angegeben wird.

in = in

  in  rxx, yy

Holt vom Port yy den momentan anliegenden Wert und speichert ihn
im Register rxx

von Hannes L. (hannes)


Lesenswert?

LDI lädt ein Register mit einer Konstanten
IN lädt ein Register mit dem Inhalt eines I/O-Registers
LDS lädt ein Register mit dem Inhalt einer SRAM-Zelle
LPM lädt ein Register mit dem Inhalt einer Flash-Zelle über Z-Pointer
MOV lädt ein Register mit dem Inhalt eines anderen Registers
LD lädt ein Register mit dem Inhalt einer SRAM-Zelle über Pointer
LDD lädt ein Register mit dem Inhalt einer SRAM-Zelle über Pointer mit 
Offset

Mehr fällt mir auf die Schnelle nicht ein. Aber bei ATMEL gibt es ein 
PDF dazu (AVR-Instruction_Set) und im Datenblatt sind auch alle Befehle 
aufgelistet.

...

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.