Forum: Mikrocontroller und Digitale Elektronik ADC lässt sich mit cbi ADEN nicht ausschalten


von Andy11 (Gast)


Angehängte Dateien:

Lesenswert?

ich weis nicht wieso aber, es lässt sich irgendwie nicht machen, dass 
ich per ADEN den ADC ausschalte

die Unterprogramme habe ich der Textdatei beschrieben
1
;**********************************Header**************************************
2
;* Projektname:  Roboter-Linienverfolgung                    *
3
;* Name des Erstellers: Shamoon Andy                      *
4
;* Zuletzt aktualisiert: 7.4.2010                        *
5
;* Beschreibung: Ein ROboter, der einer ca1,5-2cm Linie nachfaährt        *                                      
6
;******************************************************************************
7
8
9
;*****************************Initialisierungen********************************
10
.include "m16def.inc" ;Definitionsdatei des Mega8
11
12
;Stackpointer-init***********
13
rjmp Stack_init
14
Weiter:
15
16
;ADC-init***********
17
rcall ADC_init  ;Externe Refernz, Prescaler = 128, Enable ADC = true, Kanal 0
18
19
;*****************Deklarierete Funktionen und Subroutinen**********************
20
21
;*************************Variablendeklarationen*******************************
22
23
;*****************************Ein-Ausgänge*************************************
24
  ser r16
25
  out DDRB, r16  ;PORTB als ausgabeport
26
27
;******************************************************************************
28
29
30
;*****************************Hauptprogramm************************************
31
    Hauptprogramm:;Do
32
call    EnableADC
33
call    DisableADC
34
call     ADC_Kanal3
35
call      StartADC
36
          in r16, ADCH
37
          com r16
38
          out PORTB, r16
39
call      EndADC
40
rjmp   Hauptprogramm ;Loop
41
42
43
44
;***********************Unterprogramme/Funktionen******************************
45
;################################################################################
46
.include "Division8Bit+Rest.asm"   ;8 Bit division    //call division
47
.include "WaitCA1s.asm"        ;Warte ca 1s ab    //call wait
48
.include "Stack_init.asm"      ;Stackinitialisieung//call Stack_init
49
.include "ADC_init.asm"        ;ADCinitialisieung  //call ADC_init
50
.include "EnableADC.asm"      ;ADC erlauben    //call EnableADC
51
.include "DisableADC.asm"      ;ADC sperren    //call DisableADC
52
.include "StartADC.asm"        ;Starte Messung    //call StartADC
53
.include "EndADC.asm"        ;Stoppe Messung    //call EndADC
54
.include "ADC_Kanal0.asm"      ;Wechsel zu Kanal 0 //call ADC_Kanal0
55
.include "ADC_Kanal1.asm"      ;Wechsel zu Kanal 1 //call ADC_Kanal1
56
.include "ADC_Kanal2.asm"      ;Wechsel zu Kanal 2 //call ADC_Kanal2
57
.include "ADC_Kanal3.asm"      ;Wechsel zu Kanal 3 //call ADC_Kanal3
58
;################################################################################

von Andy11 (Gast)


Angehängte Dateien:

Lesenswert?

sry hier sind die Erklärungen

von Hc Z. (mizch)


Lesenswert?

> .include "m16def.inc" ;Definitionsdatei des Mega8

Da ist entweder der Kommentar oder der Filename falsch.  Die beiden 
genannten Prozessoren sind sich aber tatsächlich sehr ähnlich, so dass 
das noch nicht der gesuchte Fehler sein muss.

Was aber der Fehler ist, hast Du weder genau genug beschrieben noch hast 
Du den nötigen Code geliefert.  Wenn man nach dem sucht, finden sich nur 
ein paar .include-Direktiven.

von AVRuser (Gast)


Lesenswert?

Hallo,

in Inhalt.txt steht:

> DisableADC:
> cbi ADMUX, ADEN
> ret

> EnableADC:
> sbi ADMUX, ADEN
> ret

Hast du nicht ins Datenblatt geschaut? Das Bit ADEN ist nicht im ADMUX, 
sondern im ADCSRA-Register zu finden ...

von Andy11 (Gast)


Lesenswert?

>Hast du nicht ins Datenblatt geschaut? Das Bit ADEN ist nicht im ADMUX,
>sondern im ADCSRA-Register zu finden ..

hah danke, natürlich habe ich im Datenblatt nachgeschaut, jedoch merke 
ich mir die Register nie und habe hier wahrscheinlich irrtümlich das 
falsche genommen

lg andy

von Hc Z. (mizch)


Lesenswert?

Ah, den Code hast Du nachgeliefert, das hat sich mit meiner Antwort 
überschnitten.

Und der Fehler äüßert sich nun genau worin?

Übrigens:  StartADC wartet nicht, bis der ADC fertig ist, sondern kehrt 
in diesem Fall sofort zurück.  Das kann vielleicht noch gewünscht sein. 
Aber für den Fall, dass der ADC 'fertig' meldet, läuft es in die Wüste 
(in den hier nicht beschriebenen Code danach).

von spess53 (Gast)


Lesenswert?

Hi

Hat es einen bestimmten Grund, das du dein Programm auf zig, fast leere, 
Dateien verteilst?
Ebenfalls ist es recht sinnfrei, Programmteile, die nur einmal benötigt 
werden, (z.B. Stackinitialisierung) in Unterprogramme zu packen.
Sinnvoller ist es, z.B. die Umschaltung der Kanäle in einem 
Unterprogramm zu machen. Die Kanalnummer wird einfach in einem Register 
übergeben.
Im Datenblatt findest du übrigens ein Codebeispiel aus dem du ersehen 
kannst, wie man eine ADC-Wandlung startet und auf das Ergebnis wartet.

MfG Spess

von Hannes L. (hannes)


Lesenswert?

> Hat es einen bestimmten Grund, das du dein Programm auf zig, fast leere,
> Dateien verteilst?

Ich mach's auch manchmal, weil Blättern zum anderen Editorfenster 
schneller geht als Scrollen und Zurückscrollen im längeren Quältext. Und 
ich muss (dank Alzheimer Light) oft nachschaun, wie ich denn nun meine 
Labels auf Konstanten, Register, RAM-Bereiche und Routinen genannt habe. 
Daher rechnet sich das Aufsplitten des Quältextes gelegentlich. Meist 
kopiere ich die Teile aber später wieder zusammen.

Bei den restlichen Punkten stimme ich Dir zu.

Ich kann mir aber gut vorstellen, dass man versucht, modular zu 
programmieren und wie bei einer Hochsprache alles in "Funktionen" zu 
packen. Das täuscht Übersichtlichkeit vor, verbraucht aber aufgrund 
unnötiger Sprünge und Rücksprünge unnötig Ressourcen. Dieselbe 
Übersichtlichkeit erreicht man auch mit ein paar Kommentaren. ;-)

...

von Peter D. (peda)


Lesenswert?

Anstatt Dich tot zupushen, definier Dir lieber ein paar 
Scratchpadregister, die jede Funktion zerstören darf.

Und nenn die Programme wie es sich gehört *.asm.
*.txt ist für Prosa (Liebesbriefe usw.) reserviert.


Peter

von Peter D. (peda)


Lesenswert?

Hannes Lux schrieb:

> Ich kann mir aber gut vorstellen, dass man versucht, modular zu
> programmieren und wie bei einer Hochsprache alles in "Funktionen" zu
> packen. Das täuscht Übersichtlichkeit vor, verbraucht aber aufgrund
> unnötiger Sprünge und Rücksprünge unnötig Ressourcen.

Das ist einer der Vorteile einer Hochsprache, sie kann beim Optimieren 
alle nur einmal aufgerufene Funktionen inlinen.


Peter

von spess53 (Gast)


Lesenswert?

Hi

>Anstatt Dich tot zupushen, definier Dir lieber ein paar
>Scratchpadregister, die jede Funktion zerstören darf.

Dann lieber push/pop.

MfG Spess

von Peter D. (peda)


Lesenswert?

spess53 schrieb:
> Hi
>
>>Anstatt Dich tot zupushen, definier Dir lieber ein paar
>>Scratchpadregister, die jede Funktion zerstören darf.
>
> Dann lieber push/pop.

Wenn man unbedingt deutlich größeren und langsameren Code als jeder 
C-Compiler produzieren will.


Peter

von spess53 (Gast)


Lesenswert?

Hi

>Wenn man unbedingt deutlich größeren und langsameren Code als jeder
>C-Compiler produzieren will.

Das gleicht der Compiler mit seinen Registerkonventionen wieder aus.

MfG Spess

von Karl H. (kbuchegg)


Lesenswert?

Na ja
Bei sowas
1
ADC_Kanal1:
2
  push r16
3
    ldi r16, 0x21
4
    out ADMUX, r16
5
  pop r16
6
ret

hat der Programmierer schon ein wenig  übertrieben. Das ist zwar (aus 
Registersicht) alles abgesichert, jedoch stehen die Chancen, dass dieser 
Code in einer tief verschatelten Aufrufhierarchie aufgerufen wird, nicht 
besonders gut. Benutzt man, wie Peter meint, ein paar Scratchpad 
Register, die jeder nach Gutdünken verändern darf (in dem Fall r16), 
dann ist man ds 'Problem' erst mal los.

Der Programmierer wollte eben Universalroutinen haben, die er überall 
einsetzen kann ohne sich grossartig Gedanken zu machen. Dagegen ist 
erstmal nicht viel zu sagen, ausser: Machs dann wenigstens richtig! Wenn 
die Funktion nur einen bestimmten Kanal einstellen soll, dann soll sie 
auch nur das tun! D.h. die restlichen Bits in ADMUX sind für die 
Funktion tabu und dürfen nicht verändert werden.

So wie sie jetzt ist, ist diese Funktion nicht Fisch und nicht Fleisch.

von Andy11 (Gast)


Lesenswert?

>Übrigens:  StartADC wartet nicht, bis der ADC fertig ist, sondern kehrt
>in diesem Fall sofort zurück.
wie lässt es sich denn anders schreiben?


>So wie sie jetzt ist, ist diese Funktion nicht Fisch und nicht Fleisch.
1
ADC_Kanal0:
2
  push r16
3
    in r16, ADMUX  
4
    cbr r16, 15    ;rechten 4 bits löschen
5
    sbr r16, 0    ;Kanal 0
6
    out ADMUX, r16  ;ausgabe 
7
  pop r16
8
ret

ist es so besser?

von spess53 (Gast)


Lesenswert?

Hi

Der ATMega16 hat 5 Mux-Bits

->cbr r16, $1F

>    sbr r16, 0    ;Kanal 0   unnötig.

Warum machst du zum Mux-Setzen nicht ein Unterprogramm.

MfG Spess

von Andy11 (Gast)


Lesenswert?

>->cbr r16, $1F
was ist das Dollar?

von spess53 (Gast)


Lesenswert?

Hi

>was ist das Dollar?

Hexadezimal.

MfG Spess

von Andy11 (Gast)


Lesenswert?

>Hexadezimal.
hab dacht das schreibt man mit 0h

von Ziegenpeter (Gast)


Lesenswert?

Soweit ich weiss gibt man bei sbr  cbr genauso wie bei sbi  cbi als 
zweiten Operanden die Bitnummer an.
D.h.:

cbr r16, 3

entspricht:

ori r16, 1<<3



Also wäre "sbr r16, 0" => "ori r16, 1". Damit würde man Kanal 1 setzen 
nicht 0.

von spess53 (Gast)


Lesenswert?

Hi

>Soweit ich weiss gibt man bei sbr  cbr genauso wie bei sbi  cbi als
>zweiten Operanden die Bitnummer an.

Soweit das Instruction Set richtig ist, kann der 2.Operant einen Wert 
von 0..$FF annehmen.
Entspricht einem ANDI mir dem Komplement des Operanten.

MfG Spess

von Hannes L. (hannes)


Lesenswert?

Karl heinz Buchegger schrieb im Beitrag #1665879

> ...

> Wenn
> die Funktion nur einen bestimmten Kanal einstellen soll, dann soll sie
> auch nur das tun! D.h. die restlichen Bits in ADMUX sind für die
> Funktion tabu und dürfen nicht verändert werden.

Das ist generell erstmal richtig und wird von mir nicht angezweifelt.

Bei ADMUX sehe ich das aber anders. Da gehören die Bits einfach 
zusammen. Zu jedem ADC-Kanal gehört auch die Referenzeinstellung und 
auch (sofern es auch in ADMUX liegt) die Formatierung (links/rechts) des 
Ergebnisses (ADLAR). Hier sehe ich Referenz und Resultatformat als 
Bestandteil (Zusatzparameter) des Kanals. Somit ziehe ich das direkte 
Zuweisen des ganzen Bytes vor. Ich bevorzuge dabei ein temporäres 
Register, das nicht gesichert werden muss und undeutsch 
"Scratchregister" genannt werden könnte.

Ich generiere dafür aber keine extra "Funktion". Ist nur ein Kanal 
abzufragen, so wird das im Ini-Bereich eingestellt, sind mehrere Kanäle 
abzufragen, so wird das Setzen von ADMUX Bestandteil der zyklisch 
aufgerufenen Ausleseroutine (ADC-Interrupt oder durch Timer 
synchronisiertes Auslesen).
Dieser zyklisch aufgerufene Job legt das geholte ADC-Ergebnis in ein 
Array (mit oder ohne Mittelwertbildung), zählt den Index hoch (oder 
runter) und begrenzt ihn, holt aus einem weiteren Array (mit demselben 
Index, in ASM durch Zugriff über LDD) den ADMUX-Wert für die nächste 
Wandlung und startet den ADC wieder. Somit erfolgt im Hintergrund reihum 
die Wandlung aller Kanäle mit den zugehörigen Parametern (Referenz, 
Format), ohne dass man sich weiter darum kümmern muss.
Die Mainloop holt sich die Werte dann aus dem Array, da liegt dann immer 
der letzte Wert bzw. der Mittelwert der letzten Messungen. Und das zu 
jeder Zeit für jeden Kanal.

...

von Andy11 (Gast)


Lesenswert?

>Soweit ich weiss gibt man bei sbr  cbr genauso wie bei sbi  cbi als
>zweiten Operanden die Bitnummer an.
>D.h.:

>cbr r16, 3

>entspricht:

>ori r16, 1<<3



>Also wäre "sbr r16, 0" => "ori r16, 1". Damit würde man Kanal 1 setzen
>nicht 0.

ich habs schon ausgetestet, was ich stehen habe passt


>Ich generiere dafür aber keine extra "Funktion". Ist nur ein Kanal
>abzufragen, so wird das im Ini-Bereich eingestellt, sind mehrere Kanäle
>abzufragen, so wird das Setzen von ADMUX Bestandteil der zyklisch
>aufgerufenen Ausleseroutine (ADC-Interrupt oder durch Timer
>synchronisiertes Auslesen).
>Dieser zyklisch aufgerufene Job legt das geholte ADC-Ergebnis in ein
>Array (mit oder ohne Mittelwertbildung), zählt den Index hoch (oder
>runter) und begrenzt ihn, holt aus einem weiteren Array (mit demselben
>Index, in ASM durch Zugriff über LDD) den ADMUX-Wert für die nächste
>Wandlung und startet den ADC wieder. Somit erfolgt im Hintergrund reihum
>die Wandlung aller Kanäle mit den zugehörigen Parametern (Referenz,
>Format), ohne dass man sich weiter darum kümmern muss.
>Die Mainloop holt sich die Werte dann aus dem Array, da liegt dann immer
>der letzte Wert bzw. der Mittelwert der letzten Messungen. Und das zu
>jeder Zeit für jeden Kanal.

sry is mir im Moment viel zu hoch

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.