mal wieder ADC

Hallo Gulliver,

dein im letzten Beitrag angehäntes Programm sieht schon anders aus, als das zuvor gepostete.

Das hier wird Probleme geben:
Code:
ADCISR:
    
          out PORTB, akku

        [COLOR=#800000][B]pop akku ret[/B][/COLOR]
    
    reti

Aus einer ISR muss man mit reti rausgehen.

Du holst "akku" vom Stack, ohne da etwas zuvor abgelegt zu haben. Da sich der Controller auch beim Einsprung in die ISR (Einsprungadresse), die Rücksprungadresse im Hauptprogramm auf dem Stack ablegt, stimmt der Stackpointer nicht mehr und es kommt sofort zum "Absturz" deines Programms.

Eine ISR macht dann Sinn, wenn du das ADC Ergebnis sofort in der ISR verarbeitest. In deinem Fall also dort in das Port-Register kopierst.

Du solltest hier auch nicht "single conversion" verwenden, sondern den "free running mode" verwenden. Die Initialsierung des ADC machst du vor der Hauptschleife einmalig, auch diesen nur einmalig starten. Im hauptprogramm kannst du dann beliebige Sachen erledigen. Die Ausgabe des ADC Ergebnisses am Port erledigt dann die ISR.

Wenn du das ADC Ergebnis im Hauptprogramm verarbeiten möchtest, und dies nicht zeitkritisch ist, dann könntest du die in der ISR das Ergebnis auch in einer Variablen zwischenspeichern. Diese Variable kannst du dann im Hauptprogramm verarbeiten, dann wenn mal Zeit ist. In dieser steckt dann immer das letzte ADC Ergebnis. Alternativ kannst du auch einfach das Interruptanforderungsflag im Verlauf des Hauptprogramm ab und zu mal pollen und dir ADCH "holen".

In der ISR musst du ggf. noch darauf achten, dass das Statusregister SREG gesichert wird, zum Beispiel auf dem Stack (push, pop).


Dirk :ciao:

EDIT:
Interurpts gibst du normalerweise nur einmal global frei (sei), nicht in der Hauptschleife. (Es sein denn du schaltest vorher Interrupts aus bestimmten Gründen aus (cli)).
 
hallo dirk :)


das ret im isr hatte ich noch bemerkt und schnell abgeändert :)

Mich verwirrt etwas ,dass das adc interrupt flag auf 1 gesetzt bleibt und der vektor trotzdem nie angesprungen wird.

hier nochmal der abgeänderte abschnitt:

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, MUX4				; Single Ended Input ADC0 
		cbi ADMUX, MUX3
		cbi ADMUX, MUX2
		cbi ADMUX, MUX1
		cbi ADMUX, MUX0


		


;******


; 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 

		;start free running mode	 ( 1 setzten für erste wandlung)
		sbi ADCSRA, ADSC
		sbi ADCSRA, ADIE 
	   

adc_loop:
	
	adc_wait:
  		sbic ADCSRA, ADSC
  		rjmp adc_wait	

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

	
		reti

pop akku 
ret


nachtrag:


ah das ADCS bits ist nicht gesetzt wenn er in der adcschleife ist..
 
Hi Gulliver,

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.
nein, das hast du so nicht richtig verstanden.

Jetzt muß ich erstmal das Datenblatt ansehen (war glaube ich Mega32 oder?) ...

ADC Control and Status Register A – ADCSRA (siehe Datenblatt)

Du sagst dem Controller mit dem Bit 3 (ADIE: ADC Interrupt Enable) das er am Ende der Wandlung einen Interrupt auslösen soll. (When this bit is written to one and the I-bit in SREG is set, the ADC Conversion Complete Inter-rupt is activated.)

Dann startest du die Wandlung (oder läßt sie dauernd automatisch starten).

Wenn die Wandlung beendet ist, dann setzt der Controller das Bit 4 (ADIF: ADC Interrupt Flag) und löst (wegen Wandlung beendet) einen Interrupt aus und reißt dich damit aus dem aktuell ausgeführten Programmteil. Er springt dann automatisch und selbstständig über die Interruptverarbeitung an die Flash-Speicherstelle $020 (ADC Conversion Complete). Das ist die Interruptvektortabelle. An dieser Stelle steht ein Sprungbefehl auf deine ISR. In der ISR liest du dann das fertige Wandlungsergebnis aus dem ADC Data Register (ADCL and ADCH).

Du löst also NICHT mit dem Lesen des ADCH-Registers einen Interrupt aus sondern das macht der Controller alleine wenn die Wandlung beendet ist.

Bit 4 – ADIF: ADC Interrupt Flag
This bit is set when an ADC conversion completes and the Data Registers are updated. The ADC Conversion Complete Interrupt is executed if the ADIE bit and the I-bit in SREG are set. ADIF is cleared by hardware when executing the corresponding interrupt handling vector. Alter-natively, ADIF is cleared by writing a logical one to the flag. Beware that if doing a Read-Modify-Write on ADCSRA, a pending interrupt can be disabled. This also applies if the SBI and CBI instructions are used.

Gruß
Dino
 
ok.. dann hab ich es jetzt verstanden ^^

er reißt aber in meiner konfiguration leider überhaupt nicht aus dem hauptprogramm.. der interruptvektor bleibt unberührt.. und wie gesagt das interrupt flag bleibt gesetzt. das verwirrt mich irgendwie..
 
ok.. dann hab ich es jetzt verstanden ^^

er reißt aber in meiner konfiguration leider überhaupt nicht aus dem hauptprogramm.. der interruptvektor bleibt unberührt.. und wie gesagt das interrupt flag bleibt gesetzt. das verwirrt mich irgendwie..
Der Interruptvektor ist lediglich eine Tabelle mit Sprungbefehlen um in die eigentliche ISR zu kommen. Wenn da nichts passiert, dann dürftest du nie in deine ISR kommen :confused:

Gruß
Dino
 
ja genau das is das problem ^^

ich komm nicht in die isr so wie ich es versuche / will .. woran kann das liegen ? ich merke eben nur wie schon gesagt dass das flag gesetzt bleibt in der adc hauptschleife (also beim debuggen mit nem dragon). da kann schon irgendwas nicht stimmen..




nachtrag:


ok ich hab mir das sreg nochmal genauer angesehene und bemerkt dass das global interrupt bit nicht gesetzt wurde. "sei" stand an einer stelle an ddie das programm nie gekommen ist.
 
ich komm nicht in die isr so wie ich es versuche / will .. woran kann das liegen ? ich merke eben nur wie schon gesagt dass das flag gesetzt bleibt in der adc hauptschleife (also beim debuggen mit nem dragon). da kann schon irgendwas nicht stimmen..

nachtrag:
ok ich hab mir das sreg nochmal genauer angesehene und bemerkt dass das global interrupt bit nicht gesetzt wurde. "sei" stand an einer stelle an die das programm nie gekommen ist.
das wird dann wohl das Problem sein.

1. der Interrupt für die entsprechende Funktion muß aktiviert sein (bei dir ADC)
2. global müssen Interrupts aktiviert sein (SEI-Befehl)
3. der Interrupt muß auch wirklich hardwaretechnisch ausgelöst werden

dann sollte es auch gehen.

Gruß
Dino
 
ja so geht es..

damit kann ich erstmal gut weiterarbeiten.

danke euch nochmals.. Habt mir nun schon oft entscheidene tips und hilfen gegeben..

hoffe ich kann euch demnächst mit etwas qualifizierteren fragen nerven :p
 
eine kurze frage ergibt sich mir da doch noch..

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 

		;start free running mode	 ( einmal setzten für erste wandlung)

		sbi ADCSRA, ADIE 
	        sbi ADCSRA, ADSC

        
		
ADCISR:
		
		push temp              ; Das SREG in temp sichern. Vorher
                in   temp, SREG       ; muss natürlich temp gesichert werden
		
		in akku, ADCH
		
  		out PORTB, akku

	        out SREG, temp        ; Die Register SREG und temp wieder
        pop temp                         ; herstellen
	
		reti




ich hab im hauptprog eine endlosschleife da ja der adc frei laufen soll..
das tut er auch allerdings nur einmal(auslösen des interrupts). Danach bleibt er in der schleife hängen.
Das ADSC bit ändert sich auch nicht mehr.

ich nehme an der "free run mode" ist nicht richtig eingestellt.

das datenblatt sagt mir, dass einmalige starten nach dem enable setzt den free run in gang.
solange eine wandlung im gange ist bleibt das ADSC bit 1.

nach der ersten wandlung bleibt es null, es startet also keine erneute wandlung.. was hab ich da falsch gemacht ?
 
ich nehme an der "free run mode" ist nicht richtig eingestellt.

Hallo Gulliver,

im ADCSRA Register das Bit ADATE (ADC Auto Trigger Enable) setzen.

Danach einfach einmal starten, wie bisher.

Noch eine Bemerkung:
Die Triggerquelle wählt man im Register SFIOR durch die Bits ADTS2..0. Sind alle Bits 0 (ist nach Reset so), dann ist FreeRunningMode eingestellt, dass heißt, der ADC triggert sich selber. Du musst hier also nichts einstellen, wenn du den ADC im FreeRunningMode betreiben möchtest.

Dirk :ciao:
 

Ü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)