mal wieder ADC

Gulliver

Neues Mitglied
20. Nov. 2012
21
0
0
Sprachen
hallo allerseits,

das ganze ding lief schon.. dann hab ich etwas dran rumgespielt und jetzt ergibt sich mir der fehler in der inneren programmlogik nicht. kann da vll. mal jemand ein blick drauf werfen der was davon versteht im gegensatz zu mir und sagen was darin kein sinn ergibt? ^^




Code:
ADCInit:


push 	 akku





		ldi akku, 0xFF				;PORT B auf Ausgang
		out DDRB, akku

		ldi akku, 0b11111110		;Port A Pin 0 auf Eingang, 1-7 Ausgang
		out DDRA, akku

		ldi akku, 0xFF   			;LEDS ausschalten Port B
		out PORTB, akku


		cbi ADMUX, REFS1			; AVCC as Voltage Reference 
		sbi ADMUX, REFS0

		sbi ADMUX, ADLAR

		cbi ADMUX, MUX4				; Single Ended Input ADC0 
		cbi ADMUX, MUX3
		cbi ADMUX, MUX2
		cbi ADMUX, MUX1
		cbi ADMUX, MUX0


		sbi ADCSRA, ADEN			; ADC enable
		sbi ADCSRA, 2				; Abtast Frequenz Teiler 20 
		cbi ADCSRA, 1
		sbi ADCSRA, 0
		cbi ADCSRA, 5
		cbi ADCSRA, 4			;no Free Run
		cbi ADCSRA, 3

messen:

		ldi  akku, (1<<ADEN) | (1<<ADSC) | (1<<ADIE)
		out  ADCSR,akku



	
		in akku, ADCH			;Digitalisierter Wert einlesen High Byte
	
		ldi akku, PORTB 	;PORTB Led an
		out PORTB, akku
		rjmp messen





pop		 akku
ret
 
Hallo Gulliver,

ich sehe zwei Probleme:

(1) Du hast den ADC-Interrupt aktiviert, aber wahrscheinlich kein Sprung zu einer Interruptserviceroutine vorgesehen. Falls du Interrupts nutzt und global freigibst, wird dir dein Programm "abstürzen". Wahrscheinlich nutzt du keine Interurpts und gibst diese nicht global frei (sei), dann macht der Punkt 1 nichts aus.

(2) nachdem du die Wandlung startest, liest du sofort das Ergebnis aus ADCH. Du musst zuerst warten, bis die Wandlung fertig ist. Das Bit ADSC im Status-Register ADCSR wird zurückgesetzt, wenn die Wandlung fertig ist. Also polle dieses Bit in einer kleinen Schleife.




Noch eine Bemerkung. Du setzt und löscht einzelne Bits in ADMUX und ADCSR. Danach kopierst du noch einmal vom akku in ADCSR, nutz diese letztere Schreibweise.

ldi akku, (1<<ADEN) | (1<<ADSC) | (1<<ADIE)
out ADCSR,akku

Diese ist kürzer und verständlicher, wenn du mehrere Bits veränderst.

Dirk :ciao:
 
hallo dirk :)

ja an der programmübersicht lohnt es sich von anfang an zu arbeiten.^^

hab den interrupt nun aus und das einlesen der wandlung etwas verzögert.

aber daran lag es nicht. hab ich irgend etwas vergessen ?
oder lässt sich kein direkter fehler, ohne das ganzes prog. zu posten und mein explizites vorhaben zu erläutern, mehr finden??
 
Hallo Gulliver,

ein Delay ist wichtig. Das Ergebnis in ADCH ist erst gütlig, wenn die Wandlung erledigt ist. Hier am besten das Bit ADSC üperbrüfen:

warte_adc:
sbic ADCSR, ADSC
rjmp warte_adc


Du verwendest einmal ADCSRA und dann ADCSR ... Auf welchem Mikrocontroller läuft das Programm?

Noch einen Hinweis nebenbei: Die erste Wandlung nachdem der ADC aktiviert wurde, würde ich verwerfen, da die Messung ggf. "bisschen daneben" ist.

Dirk :ciao:
 
soll auf einen Atmega32...

Den delay hab ich so eingefügt.

hab irgendwie den eindruckt das liegt an meinen port directions. die leds leuchten etwas wirr.
0-2 und dann wieder 5-7 (arbeite mit einen stk500).
sie reagieren allerdings nicht auf spannungsänderungen.
 
Ach, schau mal hier. Das hatte ich übersehen:
Code:
        in akku, ADCH            ;Digitalisierter Wert einlesen High Byte
        ldi akku, PORTB     ;PORTB Led an
         out PORTB, akku         rjmp messen

Du überschreibst den Inhalt von Akku mit der Adresse des Registers PORTB. Entferne mal die mittlere Zeile.
 
hmmm.. interessant.

die leds reagieren jetzt. allerdings nur auf spannungsstöße.
Leg ich eine Spannung an und ab also abwechselnd, verändert sich die darstellung der leds. (als würden sie binär etwas darstellen wollen...) bis irgendwann alle leuchten. dann ändert sich nichts mehr.. wird hier das speicher register vollgeschrieben und nicht mehr gelöscht? oder was kann da passieren ? ^^

sinn war, dass von led 0 an, je mehr spannung anliegt desto mehr leds leuchten. die dinger leuchten eher willkurlich -_-
 
Du bleibst in der Routine ADCInit auf jedenfall hängen.

In dieser Schleife:

Code:
messen:

  ldi  akku, (1<<ADEN) | (1<<ADSC)
  out  ADCSR,akku


  ; delay ?
    
  in akku, ADCH            ;Digitalisierter Wert einlesen High Byte
  out PORTB, akku
rjmp messen

Das Bit ADEN würde ich vor der Schleife setzen und in der Schleife dann die Wandlung (Bit ADSC) starten.

Du stellst ja das ADC Ergebnis linksbündig dar, es reicht also ADCH zu lesen. Die LEDs an PORTB zeigen also den 8bit ADC Wert an (Ich vermute das STK500 invertiert die LEDs).

Was nun genau passiert, weiß ich nicht, du müsstest mal deinen aktuellen Code hier reinstellen, dann kann ich vielleicht mehr dazu sagen.
 
Code:
;********************************************************************************************************************


ADCInit:




; PORTB	  OUT	Leds

push 	 akku





		ldi akku, 0xFF				;PORT B auf Ausgang
		out DDRB, akku

		ldi akku, 0b11111110		;Port A Pin 0 auf Eingang, 1-7 Ausgang
		out DDRA, akku

		ldi akku, 0xFF   			;LEDS ausschalten Port B
		out PORTB, akku


		cbi ADMUX, REFS1			; AVCC as Voltage Reference 
		sbi ADMUX, REFS0

		sbi ADMUX, ADLAR

		cbi ADMUX, MUX4				; Single Ended Input ADC0 
		cbi ADMUX, MUX3
		cbi ADMUX, MUX2
		cbi ADMUX, MUX1
		cbi ADMUX, MUX0


		sbi ADCSRA, ADEN			; ADC enable
		cbi ADCSRA, 2				; Abtast Frequenz Teiler 20 
		cbi ADCSRA, 1
		sbi ADCSRA, 0
		cbi ADCSRA, 5
		cbi ADCSRA, 4			;no Free Run
		cbi ADCSRA, 3

messen:

		ldi  akku, (1<<ADEN)|(1<<ADSC)
		out  ADCSR,akku

		
		warte_adc:
		sbic ADCSR, ADSC
		rjmp warte_adc
	
		in akku, ADCH			;Digitalisierter Wert einlesen High Byte
	
	
		out PORTB, akku
		rjmp messen





pop		 akku
ret


mh so siehts aus... entschuldige wenn es noch unübersichtlich wirkt..
 
Erstmal nur ein paar Tips:
-Du hast Dir ein Macro zum Toggeln eines (beliebigen) Prozessorbeinchens geschrieben. diese Zeilen werden also jedesmal an den entsprechenden Stellen in den Quellcode "hineinkopiert". Du kannst das aber auch einfacher haben, indem Du in das, zu diesem Bein gehörende PIN-Register-Bit eine eins schreibst. (Also entweder mit out und einem Byte das ganze Pin-Register (dann werden alle Beinchen mit'ner 1 getoggelt), oder mit SBI (gezielt auf das eine Bit im Pin-Register))
-Du legst ja mit den .org-Direktiven fest, wo die dann folgenden Instruktionen im Flash landen sollen. Damit willst Du sicherstellen, daß bei IRQs die korrespondierenden ISRs angesprungen werden. Soweit korrekt. Allerdings wäre es einfacher, besser lesbar und portierbar (und auch weniger fehleranfällig), wenn Die die Adressen nicht "festlegen" würdest (hex-Zahlen), sondern entsprechende Konstanten verwenden würdest. Und zwar genau die Konstanten, die genau für diesen Zweck in der Controllerdefinitionsdatei definiert sind. Schau Dir die mal an. Insbesondere den Bereich mit interrupt vectors.
-Dort findest Du zB auch eine Konstante für die Bit-Nr vom Z-Flag - nur daß sie hier SREG_Z heißt...
-Statt BRBC Z, Adresse kannst Du auch BRNE Adresse nehmen (Strenggenommen sind die ganzen SREG-bedingten Branch-Anweiseungen gar keine eigenen Instruktionen, oder BRBC/BRBS ist die "Summe" dieser Instruktionen. Je nachdem, wierum man's sieht. Der Opcode ist:
11110bkkkkkkksss
b=0 -> Sprung wenn Bit gesetzt, b=1 -> Sprung wenn bit gelöscht
kkkkkkk relative Sprungweite (vorzeichenbehaftet/zweierkomplement)
sss=zu vergleichendes Bit (0..7))
-Das mit dem setzen/löschen mehreres Bits in einem I/O-Register über ein Rechenregister hat Dirk ja bereits gesagt
-(eher was für Dirk) Der Controller hat kein ADCSR (nur ein ADCSRA), ABER aus kompatibilitätsgründen wurden in der Definitionsdatei beide definiert/gleichgesetzt. Trotzdem sollte man hier ADCSRA verwenden - ist ... ähm ... sauberer
-einen externen Kondensator am Aref-Pin hast Du?
-Wie sieht die externe Beschaltung von ADC0 aus?
-Du hast den ADC-Prescaler auf 2 gesetzt, nicht auf 20 (wäre eh keine Zweierpotenz). ADPS2..ADPS0=001. direkt hinter dem label messen setzt Du sie jetzt auf 000. Das ist zwar auch Vorteiler=2, wr aber bestimmt nicht Deine Absicht...
 
Hallo zusammen,

was mir noch aufgefallen ist, es wird die Definitionsdatei vom ATmega128 genutzt:

.include "m128def.inc"

Das Programm soll aber auf einem ATmega32 laufen, bzw läuft bereits darauf?

Dirk :ciao:
 
Die falsche include Datei hatte ich schon berichtigt. Hab das prog aus ner txt genommen weil noch ein paar Sachen dazu kamen die mit dem Problem nichts zu hatten.

Also Danke erstmal für die vielen Tipps.

Von dem kondensator hab ich gelesen. Ist der nicht nur für die Genauigkeit wichtig? Weil das muss es nicht sein, ist nur für lernzwecke.
Ansonsten hab ich eine 5v Quelle und ein 5k poti zwischen gnd und pina0. Bis jetzt bin ich der meinung das fehlerpotential ist eher im code..

Also ich werd die Tipps mal so gut es geht umsetzen. Vor allem den mit dem prescaler^^. . Vll findet sich damit irgendwie das prob
 
so kondensator hängt dran...

ich verstehs nich... wieso bleiben die leds alle an wenn sie einmal alle durch irgendeine spannung aufleuchten.
selbst wenn gar keine spannung mehr anliegt. erst wenn ich den reset knopf drücke gehts wieder von vorne los -.-

Code:
ADCInit:



; PORTB	  OUT	Leds

push 	 akku





		ldi akku, 0xFF				;PORT B auf Ausgang
		out DDRB, akku

		ldi akku, 0b11111110		;Port A Pin 0 auf Eingang, 1-7 Ausgang
		out DDRA, akku

		ldi akku, 0xFF   			;LEDS ausschalten Port B
		out PORTB, akku


		cbi ADMUX, REFS1			; AVCC as Voltage Reference 
		sbi ADMUX, REFS0

		sbi ADMUX, ADLAR

		cbi ADMUX, MUX4				; Single Ended Input ADC0 
		cbi ADMUX, MUX3
		cbi ADMUX, MUX2
		cbi ADMUX, MUX1
		cbi ADMUX, MUX0


		sbi ADCSRA, ADEN			; ADC enable
	
		cbi ADCSRA, 5
		cbi ADCSRA, 4			;no Free Run
		cbi ADCSRA, 3

messen:

	ldi  akku, (1<<ADPS2) |(0<<ADPS1) |(0<<ADPS0) 
	ldi  akku, (1<<ADEN) | (1<<ADSC) | (0<<ADIE) | (0<<ADIF)
		out  ADCSR,akku


warte_adc:
sbic ADCSR, ADSC
rjmp warte_adc
	
		in akku, ADCH	;Digitalisierter Wert einlesen High Byte
	
		 	
		out PORTB, akku   ;PORTB Led an
		rjmp messen




pop		 akku
ret

so sieht das endresultat aus..
 
Hallo Gulliver,

ich sehe direkt keine Fehlerursache für den von dir beschriebenen Fehler.

Hierdurch sind alle ADPSn Bits 0, da diese durch das zweite ldi überschrieben werden. Der Prescaler ist also 2
Code:
    ldi  akku, (1<<ADPS2) |(0<<ADPS1) |(0<<ADPS0)
    ldi  akku, (1<<ADEN) | (1<<ADSC) | (0<<ADIE) | (0<<ADIF)   
    out  ADCSR,akku


Wichtig ist, dass die eingebundene Definitionsdatei zu dem Mikrocontroller passt. Wenn du die Definitionsdatei des ATmega128 verwendest,
aber den Code auf einem ATmega32 laufen läßt, "knallts" bereits beim Setzen des Stack-Pointers.

Am besten noch einmal den kompletten vollständigen Code posten und läuft dieser auf einem ATmega32?

Vielleicht auch mal am Pin AVCC messen, sind dort 5V?

Hier ein einfacher Beispielcode für deinen Fall.
PORTB muss Ausgang sein, das 8Bit Ergebnis wird an diesem Port ausgegeben.
(Referenzspannung ist AVCC, Kanal: ADC0, Ergebnis ist linksbündig, Prescaler ist 16,
der Code ist nicht getestet)


Code:
; Referenzspannung: AVCC
; Result Left Adjust
; Channel 0 (PA0)

  ldi akku, (1<<REFS0) | (1<<ADLAR)
  out ADMUX, akku

; ADC Enable
; Prescaler 16

  ldi akku, (1<<ADEN) | (1<<ADPS2)
  out ADCSRA, akku 


adc_loop:
; Start single conversion
  sbi ADCSRA, ADSC

adc_wait:
  sbic ADCSRA, ADSC
  rjmp adc_wait

  in akku, ADCH
  out PORTB, akku

rjmp adc_loop
 
Hallo,

habt ihr mal dran gedacht das der Fehler eventuell analoger Natur sein kann?

Der ADC-Eingang ist sehr hochohmig. Kann es sein das er die Spannung speichert?
Ein offener Eingang verliert nicht wirklich viel Spannung.
Die Sample/Hold-Schaltung im Atmel tut wohl ihr übriges dazu bei.
Leg doch einfach mal nen 100k oder 1M-Widerstand vom ADC-Eingang nach GND.

Gruß
Dino
 
das Problem war menschlicher natur... der adc im stk 500 stellt die spannung so wie ich es eingestellt habe tatsächlich binär dar mit den 8 LED`s an bord. ich dachte ja das wandlungsergebnis wäre einfach unfug, da ich davon ausging, je mehr spannung, desto mehr leds leuchten. Dann würden LEDS die zwischen drin an und wieder ausgehen natürlich keinen sinn machen...

aber bin noch nicht ganz zufrieden.^^

Und zwar würde ich gerne wissen wie ich das ganze mit Interrupts lösen könnte.

Habe mich schlau gemacht wie das grundsätzlich funktioniert und eine Tastenabfrage damit realisiert.
Mir ergibt sich der sinn des ADC interrupts allerdings nicht ganz.
Das flag wird ausgelöst wenn die Wandlung beendet ist. ok...

Aber was wird für gewöhnlich mit so einem flag dann angestellt ? ich meine es macht die wandlung ja nicht genauer aber in wie fern effizienter ?
 
Hallo,

Und zwar würde ich gerne wissen wie ich das ganze mit Interrupts lösen könnte.

Habe mich schlau gemacht wie das grundsätzlich funktioniert und eine Tastenabfrage damit realisiert.
Mir ergibt sich der sinn des ADC interrupts allerdings nicht ganz.
Das flag wird ausgelöst wenn die Wandlung beendet ist. ok...

Aber was wird für gewöhnlich mit so einem flag dann angestellt ? ich meine es macht die wandlung ja nicht genauer aber in wie fern effizienter ?
wenn du dauernd abfragen mußt ob der ADC bereits mit der Wandlung fertig ist, dann kostet dich das wertvolle Prozessorzeit für das dauernde Polling (ist er schon fertig?). Es ist doch viel schöner wenn dir der ADC über einen Interrupt mitteilt das er fertig ist. Damit du das auch sicher erkennst, dafür setzt er auch das Flag (nennen wir es mal "Info-Bit") damit du in der InterruptServiceRoutine abfragen kannst warum der ADC überhaupt einen Interrupt ausgelöst hat.

So lange der ADC abeitet kannst du dann gemütlich die restlichen Aufgaben abarbeiten und mußt dich nach dem Start nicht um ihn kümmern. Das ist so als wenn du jemanden zum Einkaufen schickst. Ohne Interrupt müßtest du dauernd nebenherrennen um zu sehen ob er schon fertig ist. Mit Interrupt kommt er einfach an und sagt "fertig". Dumußt nur noch kontrollieren ob er denn alles bekommen hat.

Gruß
Dino
 
das ganze prog. ist etwas gewachsen.. deswegen im Anhang.
könnte ja das sein, dass das prob ganz woanders steckt..


hm also hab ich das so richtig verstanden ?

Dies ISR soll nur aufgerufen werden wenn die wandlung beendet ist. das geschieht mit einlesen des ADCH, oder ?
( dacht ich jedenfalls immer, das flag bleibt nämlich gesetzt bis ein ich das ADSC bit wieder setze) .
Jedefalls war der Plan mit aufrufen des Interrupts in der ISR das ergebnis nur noch auf die LEDs auszugeben.

Auschnitt:
Code:
;Referenzspannung: AVCC
; Result Left Adjust
; Channel 0 (PA0)

	    ldi akku, (1<<REFS0) | (1<<ADLAR) 
  		out ADMUX, akku

; ADC Enable
; Prescaler 16

  		ldi akku, (1<<ADEN) | (1<<ADPS2) 
  		out ADCSRA, akku 

	    adc_loop:
		; Start single conversion	
		
		sbi ADCSRA, ADSC
		sbi ADCSRA, ADIE
	


  		in akku, ADCH
		rjmp adc_loop
		
ADCISR:
	
  		out PORTB, akku

	
	reti


macht das so sinn ? denn das flag wird wie gesgat gesetzt aber der breakpoint beim interruptvektor wird nie ausgelöst...
 

Über uns

  • Makerconnect ist ein Forum, welches wir ausschließlich für einen Gedankenaustausch und als Diskussionsplattform für Interessierte bereitstellen, welche sich privat, durch das Studium oder beruflich mit Mikrocontroller- und Kleinstrechnersystemen beschäftigen wollen oder müssen ;-)
  • Dirk
  • Du bist noch kein Mitglied in unserer freundlichen Community? Werde Teil von uns und registriere dich in unserem Forum.
  •  Registriere dich

User Menu

 Kaffeezeit

  • Wir arbeiten hart daran sicherzustellen, dass unser Forum permanent online und schnell erreichbar ist, unsere Forensoftware auf dem aktuellsten Stand ist und der Server regelmäßig gewartet wird. Auch die Themen Datensicherheit und Datenschutz sind uns wichtig und hier sind wir auch ständig aktiv. Alles in allem, sorgen wir uns darum, dass alles Drumherum stimmt :-)

    Dir gefällt das Forum und unsere Arbeit und du möchtest uns unterstützen? Unterstütze uns durch deine Premium-Mitgliedschaft!
    Wir freuen uns auch über eine Spende für unsere Kaffeekasse :-)
    Vielen Dank! :ciao:


     Spende uns! (Paypal)