Forum: Mikrocontroller und Digitale Elektronik ADC bei ATmega32 ?


von Peter (Gast)


Lesenswert?

Hallo zusammen,
ich komm nicht mehr weiter bei der ADC Schnittstelle.
Ich bin gerade dabei mich in die ADC Schnittstelle des ATmega32
einzuarbeiten. Leider sind da einige Fragen noch offen.
Ich kapier einfach nicht wie das vorgehen ist bei der sog. Single
Conversation und dem Free Running Mode bzw. der Interrupthandhabung.
Single Conversation starten kommt Messwert -> Interrupt wird ausgelöst
O.K soweit verstanden aber bei Free Running Mode wird dauernd gelesen
was heißt das wird da immer ein Interrupt ausgelöst.
D.h Prozzessor wär nur mit ADC beschäftigt wenn z.B ein Analog Wert
anliegt.?? Bei Free Running ist da ADSC Bit dann dauern auf 1 ? Oder
wird zwischendrin wie bei Single Conversation nach Umwandlung des
Empfangswertes dieses Bit (ADSC) auf 0 gesetzt?
Wer kann mir in dieser Problematik weiterhelfen, lese schon dauern die
Spec werd aber in diesen und vielen anderen Punkten nicht schlau...

Vielen Dank im Voraus

Peter

von Peter (Gast)


Lesenswert?

Weiß jemand einen Source Code in Assembler indem man die grundlegende
Handhabung des ADC (evtl mit single und free Running mode , Interrupt)
nachvollziehen kann . Oder in irgend einem Tutorial ?

Vielen Dank

von ERDI - Soft (Gast)


Lesenswert?

Wenn du mal guckst, was die maximale Samplezahl pro Sekunde ist
(15kSps), wirst du feststellen, dass dir genug Zeit bleibt, um zwischen
den einzelnen Interrupts selbst bei 1MHz noch komplexere Aufgaben zu
erledigen. (Bei voller A/DC Frequenz bei 8MHz bleiben etwa 500
Taktzyklen, um den AD-Wert zu verarbeitn und anderes zu machen. Aber
ich denke mal, dass du den A/D-Wandler nicht mit voller Frequenz
betreiben mußt, oder?)
Wie das mit dem Bit ist, weiß ich nicht, aber das steht alles im
Datenblatt. (Ich weiß: "...lese schon dauern die
Spec werd aber in diesen und vielen anderen Punkten nicht schlau...".
Trotzdem, lesen bildet!)

von Thomas Burkhardt (Gast)


Lesenswert?

Hallo,

ich habe bisher nur am Mega8 mit dem ADC gearbeitet, denke aber, dass
es prinzipiell gleich ist.

Während beim Single-Conversion das ADSC wieder auf Null gesetzt wird,
bleibt es im Free-Running mode auf Eins, d.h. es wird nur einmal am
Beginn vom Programm gesetzt.

Wenn der Interrupt aktiviert ist, dann wird er immer am Ende einer
Wandlung ausgelöst, sei es jetzt Single-Conv. oder Free-Running. Der µC
wird also in diesem Sinne nur beschäftigt, wenn ein Wert fertig ist. Es
ist allerdings zu beachten, dass im Free-Running auch weiter gewandelt
wird, wenn das Interrupt-Flag nicht gelöscht wird. Wenn also dein
Programm nicht jeden Interrupt vom ADC auswertet (oder auswerten kann)
dann würden Werte verloren gehen.


Viele Grüße

von Thomas Burkhardt (Gast)


Lesenswert?

Hallo Peter,

Source Code kann ich dir heute abend suchen - aber wahrscheinlich hat
bis dahin schon jemand anderes welchen geschickt ;-)
Ansonsten würde ich empfehlen nochmal bei www.avrfreaks.net
nachschauen, da gibt's einen Haufen Tutorials.

Viele Grüße

von Thomas Burkhardt (Gast)


Lesenswert?

Hallo Peter,

und nochmal ;-)
Ganz vergessen hatte ich die App. Notes direkt von www.atmel.com
Dort werden viele Einzelproblematiken gut beschrieben. Kann sein, dass
da was über ADC bei ist.


Viele Grüße

von Peter (Gast)


Lesenswert?

Danke Thomas für Deine Hilfe,
leider bin ich noch kein bisschen vorangekommen.

Kann jemand mal über den Sourcecode schauen was faul ist ?
ich will an ADC0 eine Spannung anlegen die dann gewandelt am Port A
(Low Byte) auch ausgegeben werden soll (Ich weiß 1 Bit fehlt wegen des
Eingangspins)

Leider tut sich nichts an den LEDs ; Bei Single Step springt Programm
immer auf TIM0_OVERFLOW dann auf ADR 0 -> Srung auf main ????


Vielen Dank

Peter

rjmp main ; Reset Handler
 reti ; EXT_INT0 ; IRQ0 Handler
 reti ;EXT_INT1 ; IRQ1 Handler
 reti ;EXT_INT2 ; IRQ2 Handler
 reti ;TIM2_COMP ; Timer2 Compare Handler
 reti ;TIM2_OVF ; Timer2 Overflow Handler
 reti ;TIM1_CAPT ; Timer1 Capture Handler
 reti ;TIM1_COMPA ; Timer1 CompareA Handler
 reti ;TIM1_COMPB ; Timer1 CompareB Handler
 reti ;TIM1_OVF ; Timer1 Overflow Handler
 reti ;TIM0_COMP ; Timer0 Compare Handler
 reti ;TIM0_OVF ; Timer0 Overflow Handler
 reti ;SPI_STC ; SPI Transfer Complete Handler
 reti ;USART_RXC ; USART RX Complete Handler
 reti ;USART_UDRE ; UDR Empty Handler
 reti ;USART_TXC ; USART TX Complete Handler
 rjmp ADC ; ADC Conversion Complete Handler
 reti ;EE_RDY ; EEPROM Ready Handler
 reti ;ANA_COMP ; Analog Comparator Handler
 reti ;TWI ; Two-wire Serial Interface Handler
 reti ;SPM_RDY ; Store Program Memory Ready Handler

main:

    ;Initialisierung des Stack Pointers ->notwendig bei Interrupt
Sprüngen
       ldi   stack,LOW(RAMEND);Initiate Stackpointer
       out   SPL,stack ; wegen Interrupts und Unterprogr.
       ldi   stack,HIGH(RAMEND)
       out   SPH,stack
       ;Stackpointerinitialisierung ende


    ldi ll,0x00
    out ADMUX,ll

    ldi ll,0xFB
    out ADCSR,ll ;Reg ADCSRA beschrieben


    ldi port_direction, 0xfe
    out DDRA, port_direction ;PortB auf Ausgang schalten


    sei ;Set Global Interrupt Enable this means bit7 in Status Register
is set to 1.


loop:    ;ldi kk,0xDB
       ;out ADCSR,kk ;Reg ADCSRA beschrieben-> Neue Konversation
eingeleitet

    rjmp loop




ADC:
    in mp,ADCL
    in tr,ADCH

    out PORTA,mp
    ;out PORTA,tr

    reti

von Christoph (Gast)


Angehängte Dateien:

Lesenswert?

Hi,
warum setzt du das ADIF Bit?

Im Anhang is nen kleines ADC Programm, momentan als Free runnning, der
Programmteil für Single Conversion ist auch dabei

Bis denn

von Peter (Gast)


Lesenswert?

Hallo Christoph,
danke für dein Programm, aber auch mit deinem Programm rührt sich
nichts, was kann ich noch alles probieren. Kann es daran liegen das ich
Eingang und Ausgang den Port A benutze? Aber ich schalte doch um, bzw.
hab einen Pin als Eingang definiert.
Dein Programm indem ich in der ISR den PortA setze...

Übrigens das Interrupt Flag hab ich nur aus sicherheitsgründen
gelöscht, damit ich weiß daß auf jeden Fall kein Interrupthandling
während dieses Abschnittes vorkommt.

Danke

Peter


 rjmp main ; Reset Handler
 reti ; EXT_INT0 ; IRQ0 Handler
 reti ;EXT_INT1 ; IRQ1 Handler
 reti ;EXT_INT2 ; IRQ2 Handler
 reti ;TIM2_COMP ; Timer2 Compare Handler
 reti ;TIM2_OVF ; Timer2 Overflow Handler
 reti ;TIM1_CAPT ; Timer1 Capture Handler
 reti ;TIM1_COMPA ; Timer1 CompareA Handler
 reti ;TIM1_COMPB ; Timer1 CompareB Handler
 reti ;TIM1_OVF ; Timer1 Overflow Handler
 reti ;TIM0_COMP ; Timer0 Compare Handler
 reti ;TIM0_OVF ; Timer0 Overflow Handler
 reti ;SPI_STC ; SPI Transfer Complete Handler
 reti ;USART_RXC ; USART RX Complete Handler
 reti ;USART_UDRE ; UDR Empty Handler
 reti ;USART_TXC ; USART TX Complete Handler
 rjmp ADC ; ADC Conversion Complete Handler
 reti ;EE_RDY ; EEPROM Ready Handler
 reti ;ANA_COMP ; Analog Comparator Handler
 reti ;TWI ; Two-wire Serial Interface Handler
 reti ;SPM_RDY ; Store Program Memory Ready Handler

main:

    ;Initialisierung des Stack Pointers ->notwendig bei Interrupt
Sprüngen
       ldi   stack,LOW(RAMEND);Initiate Stackpointer
       out   SPL,stack ; wegen Interrupts und Unterprogr.
       ldi   stack,HIGH(RAMEND)
       out   SPH,stack
       ;Stackpointerinitialisierung ende


    ldi ll,0xb00100000
    out ADMUX,ll

    ldi ll,0x0b11101101
    out ADCSR,ll ;Reg ADCSRA beschrieben


    ldi port_direction, 0xfe
    out DDRA, port_direction ;PortB auf Ausgang schalten


    sei ;Set Global Interrupt Enable this means bit7 in Status Register
is set to 1.


loop:    ;ldi kk,0xDB
       ;out ADCSR,kk ;Reg ADCSRA beschrieben-> Neue Konversation
eingeleitet

    jmp loop




ADC:
    in mp,ADCL
    in tr,ADCH

    out PORTA,tr
    ;out PORTA,tr

    ldi port_direction, 0xfe
    out DDRA, port_direction ;PortB auf Ausgang schalten

    reti

von DerInder (Gast)


Lesenswert?

Hallo Peter,
ich hab zwar noch nicht mit dem ADC beim Mega32 gearbeitet, was mir
aber Aufgefallen ist, ist das deine IRQ-Vectoren ins leere laufen.
Beim Mega32 ist jeder Vector 4 und nicht 2 Byte(wie bei den "alten"
AVR's) gross. Sprich du müsstes 2 reti pro Vector eintragen, oder
besser mit .org-Anweisungen arbeiten.
Kleines Beispiel:

.org  0
rjmp  start        ; Reset Handle
.org  INT0addr
rjmp  Int0Interrupt
.org  INT1addr
rjmp  Int0Interrupt
.org  OVF1addr
reti


Gruß
-=jens=-

von Peter (Gast)


Lesenswert?

Hallo Jens,
danke für deinen Hinweis, Du hast recht!
Ich hab noch nicht mit org gearbeitet
Ist das so richtig

Interrupt kommt->MC springt auf die entsprechende Adr. in der z.B
.org 0x0010 steht ->  was heist das dann genau bzw. der darauffolgende
Befehl mit rjmp Name von ISR Label...
Kannst du mir das bitte noch erklären?

Danke Peter

von DerInder (Gast)


Lesenswert?

Hallo Peter,
erstmal ist es am besten (übersichtlichsten) wenn du bei den .org
Anweisungen mit symbolischen Adressen arbeitest, also für deinen
ADC-Interrupt nicht: .org $20, sondern .org ADCCaddr.
Dies kennzeichnet die Adresse in der Vector-Sprungtabelle, die durch
den ADC-Interrupt Angesprungen wird. Der dort stehende Code wird direkt
ausgeführt, deshalb springt man von dort zur eigentlichen
Interruptroutine. Achtung, wenn dein Programm größer wird gibt es
Probleme mit dem rjmp Befehl, da der nur eine Sprungweite von +-2kB
schaft. In diesem Fall musst du den jmp Befehl verwenden.
Zur Addressierung der Interruptvectoren schau dir mal die m32def.inc
Datei an, dort sind ganz am Ende die Zuweisungen für die
Vectoradressen

Gruß
-=jens=-

von DerInder (Gast)


Lesenswert?

Sorry
der rjmp hat natürlich eine Reichweite von +-8kB

-=jens=-

von Peter (Gast)


Lesenswert?

Hallo Jens,
aber was sagt genau folgendes

-----------------------------
.org ADCCaddr
rjmp ADC_HANDLING


ADC_HANDLING:
               ...
------------------------------

wann wird .org ausgeführt bzw. was macht er dann, und wann wird
rjmp ausgeführt...?

bisher habe ich das nur mit den direkten Interrupteinsprungadressen
gemacht da hab ich gewußt bei Interrupt ... springt er auf Adr. z.B
0x020 in meinem Fall und dort habe ich einen rjmpt gesetzt, die anderen
Interrupteinsprungstellen habe ich mit reti belegt das ist mir klar
aber das mit org .?? Sorry hab noch nicht so viel Erfahrung

Danke Peter

von DerInder (Gast)


Lesenswert?

Hallo Peter,
der .org ist nur ne Compileranweisung die dafür sorgt, das der Code an
eine definierte Adresse kommt. Ansonsten ist dein Vorgehen richtig.
Wie gesag der Unterschied zwischen dem Mega32 und den kleineren AVRs
ist, das die Sprungtabelle jeweils 4 Byte für jeden Vector groß ist
(damit man per jmp den gesammten Adressraum ansprechen kann).

Wenn du jetzt die Tabelle mit .org Anweisungen aufbaust liegen die
Sprungbefehle automatisch auf der richtigen Adresse, unabhängig vom
eingesetzten AVR.

Gruß
-=jens=-

von Peter (Gast)


Lesenswert?

AHHH, Jetzt glaub ich hab ichs,

die Anweisung

.org ADCCaddr
rjmp ADC_HANDLING


setzt den rjmp Befehl auf die Adr. $0020 richtig ?

Ich glaube schon...

Vielen Dank

Peter

PS: Weist du vielleicht ob es eine Besonderheit beim Atmega32 gibt.
Ich hab nämlich ein ganz triviales Programm geschrieben das auf PORTA
nur high pegel ausgeben soll -> es funktioniert > programmier ich aber
das ganze auf den PortC um so leuchten nur 4 der 8 LEDs (4 High Pegel)
-> Weist Du rat ??

Peter

von Peter (Gast)


Lesenswert?

Zu meiner letzten Fragen bzgl. Ausgabe an Port C habe ich jetzt nach
Stundenlanger Suche den Fehler gefunden -> Die JTAG Schnittstelle war
enabeld... damit war eine Anzeige nicht auf allen Ports möglich

So gehen die Stunden ins Land...

Grüße
Peter

von DerInder (Gast)


Lesenswert?

Hallo Peter,
sorry zu deinem PORTC Problem fällt mir z.Zt. nichts ein.

Gruß
-=jens=-

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.