Forum: Mikrocontroller und Digitale Elektronik Atmega8 ADC Frustration (Assembler)


von Arood (Gast)


Angehängte Dateien:

Lesenswert?

Guten Abend,

ich versuch nun schon seit einigen Stunden eine Spannung mit hilfe des
ADC's des Atmega8 einzulesen, aber leider ohne Erfolg.
Das Internet hab ich auch schon wundgesucht, aber nichts passendes 
gefunden.
Ich will eine kleine LED, welche an Pin0 von Port C angeschlossen ist, 
in verschiedenen Frequenzen blinken lassen.
Dazu wollte ich die 8 höherwertigen Bits auslesen und damit eine 
Zeitschleife "steuern" (0-255 Durchläufe * ca.10ms ).
Das Speichern des "Spannungswertes" erfolgt in der Interruptroutine des 
ADC

Erstmal der Ausschnitt des Codes:
1
       .include "m8def.inc"      ;Definitionsdatei fuer den ATmega8 dazuladen
2
  
3
      .dseg
4
5
COUNT:  .BYTE  1
6
        .cseg                     ;Beginn eines Code-Segmentes
7
   
8
       .org 0x00                   ;Startadresse=0x0000 (Anfang des Flash)
9
10
        rjmp start
11
12
.org   OVF1addr
13
        rjmp  OVF1      
14
.org   ADCCaddr               ; ADC Interrupt Vector Address
15
        rjmp  ADCRUPT
16
17
18
start:  ldi    r16, 0b11111111    
19
        out   ddrd,r16
20
        out    ddrb,r16
21
        out    ddrc,r16      ;Alle Ports auf output
22
23
        ldi   r16,high(RAMEND)  ; 
24
        out   SPH,r16       ; Set Stack Pointer to top of RAM
25
        ldi   r16,low(RAMEND)
26
        out   SPL,r16
27
28
        LDI    r16, 91
29
        sts    COUNT, r16      ;COUNT Variable auf 1s initialisieren
30
31
  
32
    
33
    rcall  ADCINI        ;ADC initialisieren
34
    sei              ;Interrupts zulassen
35
main:    
36
    
37
    
38
    
39
40
    SBI     portc, 1  
41
    rcall   wait
42
    CBI     portc, 1
43
    rcall   wait  
44
  
45
    
46
    ldi   r18, 0b11001111      
47
    out   ADCSRA, r18        ;ADC conversion start  
48
  
49
50
  
51
    rjmp    main            ;Schleife neu beginnen 
52
 
53
54
55
56
TMR1:  ldi   r18, 0b00000100
57
       out   TIMSK, r18        ;Interrupt enable
58
       ldi   r16,0x01      
59
       out   TCCR1B,r16        ;Timer Start(kein prescaler) 
60
       ret
61
62
OVF1:   inc   r19
63
        reti
64
65
66
67
wait11ms: clr   r19          ;Warteschleife 11ms    
68
          rcall   TMR1        
69
loop1:    ldi   r20, 0x02    
70
          SUB   r20, r19
71
          BRNE  loop1
72
          ret
73
74
75
wait:    lds   r21, COUNT      ;Variable COUNT laden
76
loop2:   rcall  wait11ms      ;11ms warten
77
         dec    r21          ;COUNT bis 0 dekrementieren
78
         BRNE  loop2        
79
         ret
80
81
;***********ADC Initialisierung****
82
ADCINI:    ldi r16, 0b01100000
83
           out ADMUX, r16        ;Pin PortC0, left adjust,AVCC + AREF Capacitor
84
           ldi r16, 0b10001111
85
           out ADCSRA, r16        ;ADC enable,Interrupt enable, Prescaler 128
86
           ret
87
88
;***********ADC Interrupt**********
89
ADCRUPT:  in r0, ADCH          ;"Spannungswert" aus ADCH Register lesen
90
      sts COUNT, r0            ;und in Variable COUNT schreiben
91
92
      reti

In der Simulation läuft das alles Einwandfrei. Die Zeitschleife 
funktioniert auch wenn ich die Werte für COUNT manuell im Code zuweise. 
Wenn ich das Programm nun übertrage und im Schaltungsaufbau teste, dann 
scheint es so, als würde der Wert von COUNT ständig bei 255 liegen, egal 
wie ich das Poti drehe.

Bin schon am Verzweifeln, ich hoffe hier kann mir jemand helfen :-)
Den Schaltplan hab ich acuh noch angehängt.


Gruß, Arood

von R. F. (rfr)


Lesenswert?

Warum ist das Poti nicht an AREF angeklemmt?
Ist die Stellspannung einstellbar?
Gruss
Robert

von tobi (Gast)


Lesenswert?

Bin jetzt zu faul ins Datenblat zu schauen, aber

 ldi    r16, 0b11111111
     out   ddrd,r16
        out    ddrb,r16
        out    ddrc,r16      ;Alle Ports auf output

port C ist ausgang. so dass Du dein hier den Port samplest?

Wie gesagt, zu faul, aber wenn man man ADCH ausliest, muss man nicht 
auch ADCL auslesen?

von tobi (Gast)


Lesenswert?

PS: ist AGND mit GND verbunden?

von eProfi (Gast)


Lesenswert?

Versuche, eine Debug-Ausgabe zu realisieren, entweder eine Serielle zum 
PC oder zumindest die ADC-Daten am PortD auszugeben, damit Du siehst, an 
welcher Stelle es hakt.


Im DDRC ist alles auf Ausgang, PortC0 ist Dein ADC-Eingang.

von Arood (Gast)


Lesenswert?

@Robert:
Für diese simple Schaltung ist es doch nicht essentiell, das Poti an 
AREF anzuschließen, oder?
Was meinst du mit Stellspannung?

@Tobi

Ob input oder output dürfte egal sein wenn  der ADC aktiviert ist, hab 
acuh beides ausprobiert, so isses net :-)
Das Datenblatt sagt, ADCH auszulesen reicht wenn es links ausgerichtet 
ist.
GND und AGND sind verbunden, ja

von R. F. (rfr)


Lesenswert?

Wenn der eingelesene Wert nicht verändert werden kann, kann es sein, 
dass das Poti keine veränderlichen Werte liefert. Ein Nachmessen mit dem 
Multimeter ist daher sinnvoll.

von Stefan B. (stefan) Benutzerseite


Lesenswert?

Die Frage von tobi ist IMHO noch nicht befriedigend beantwortet.

Laut Schaltplan.png hat AGND keine Verbindung zu GND und bambelt in der 
Luft, wenn der ISP-Programmieradapter nicht eingesteckt ist.

Versuchsweise würde ich den Test mit einer zusätzlichen Brücke von GND 
nach AGND wiederholen.

NB: Welchen Zweck hat R2?
AVcc o-----###-----o Vcc
          R2 47R

von Arood (Gast)


Lesenswert?

Das Poti liefert veränderliche Werte, das hab ich schon gemessen.
GND und AGND sind verbunden, da ist im Schaltplan nur irgendwie die 
Junction verschwunden (oberhalb rechts von C6)

R2 hatte ich ursprünglich nicht drin, den hab ich auf ner Beschaltung 
hier in den Infos gesehen, statt einer Spule. Dann hab ich ihn halt mal 
reingelötet

von Hannes L. (hannes)


Lesenswert?

Arood schrieb:
>
> R2 hatte ich ursprünglich nicht drin, den hab ich auf ner Beschaltung
> hier in den Infos gesehen, statt einer Spule. Dann hab ich ihn halt mal
> reingelötet

Du hast 47 Ohm in der Stromversorgung von PortC und ADC und wunderst 
Dich, dass der ADC nicht funktioniert?

...

von tobi (Gast)


Lesenswert?

Nö, wenn der Port Ausgang ist, is er Ausgang.
Wär mir neu, dass die ADC-Unit da von sich aus umschaltet. Kannst mich 
natürlich mit Datenblatt-Seiten-Angabe geren überzeugen ;-)

Du startest die Conversion, wartest aber nicht bis die fertig ist. Hier 
ist in dem Code eine Race-Condition.
(Kann es sein, dass der ADC eine Conversion abbricht und neu startet, 
wenn man bei einer laufenden Conversion nochmal SC schreibt?)

Aber bring mal erstmal deine Schaltung in Ordnung:
- AGND muss angeschlossen sein (verbinde es einfach mit GND, das passt 
schon)
- Hinweis: Der C am VREF muss streng genommen auch mit AGND verbunden 
werden, nicht mit GND -- wenn man es exakt machen möchte
- die 47Ohm werden zwar nix machen (da in AVCC nicht viel Strom reingeht 
und der nicht getaktet ist) jedoch ist hier 0Ohm besser (normalerweise 
werden in ner Schaltung die Analogen versorgunen und massen extra 
geroutet und dann an einem Sternpunkt zusammengeschlossens.)
Atmel empfiehlt eine Spule + C um Störungen zu filtern. Steht in jeden 
Datenblatt und auch in ein paar ANs, braucht man aber meistens nicht.

PS: Sample mal Kanal 0b1110 (VBG). Dann kannst Du das Problem eingrenzen 
ob SW oder HW. (nat. muss auch hier AREF,AVCC,ABGND richtig sein....)

PPS: Dein Schaltplan ist recht unübesichtlich und schwer zu lesen... 
Arbeite mehr mit Netznamen und Symbolen (z.B für +5V, GND, ...)
z.B wie hier: Beitrag "Re: DTMF AVR314 nach  mega8"

@Arood: Nein, AREF darf nicht belastet werden. An AREF hat ein C und 
sonst nix was verloren.

von Entwickler (Gast)


Lesenswert?

>OVF1:   inc   r19
>        reti

Ohne aufs Ganze zu kucken, mit diesem Programmierstil kommt man nicht 
weit. INC beeinflußt (hier: zerschießt) das Statusregister.

von eProfi (Gast)


Lesenswert?

Ich habe die Schaltung kurz aufgebaut (leicht verändert, da M32 statt 
M8) und es funktioniert einigermaßen.
Das Problem liegt an der Warteschleife, da sie sowohl bei 0 als auch bei 
FF lange wartet.
Von 0,00 bis 0,027V blinkt die LED langsam, bei 0,03V so schnell, dass 
man es nicht mehr sieht (halbe Helligkeit). Ab 0,06V merkt man, dass sie 
sehr schnell blinkt.

Vielleicht willst Du nicht die Periodendauer, sondern die Frequenz 
proportional zur Eingangsspannung machen?

Manchmal "blinzelt / verschluckt" sie einmal kurz. Liegt daran, was 
"Entwickler" gerade schrieb.

Das Blinken würde ich direkt in der Timer-ISR machen.
Das Konstrukt mit wait11ms ... ist alles verworren.


47 Ohm als RC-Filter statt einer L in Verbindung mit einem C sollte in 
Ordnung sein, es können auch weniger Ohm (oder mehrere 47er parallel) 
sein, falls vorhanden. Allerdings sollten dann keine 
PullDown-Verbraucher dranhängen. Du hast nicht geschrieben, ob Deine LED 
an +5V oder Gnd geht.

von Arood (Gast)


Lesenswert?

sooo, nabend!

Danke erstmal für die zahlreichen Antworten :-)
Im Anhang hab ich mal den aktuellen Schaltplan.

Ich versuch jetzt mal den Code zu überarbeiten, dann meld ich mich 
wieder :-)

>Von 0,00 bis 0,027V blinkt die LED langsam, bei 0,03V so schnell, dass
>man es nicht mehr sieht (halbe Helligkeit). Ab 0,06V merkt man, dass sie
>sehr schnell blinkt.

Das versteh ich jetzt absolut nicht, warum sind hier die änderungen nur 
bei <0,06V zu sehen?
Ich warte doch in der Zeitschleife länger, wenn die Spannung sich 
erhöht.
Ob nun die Frequenz oder die Periodendauer proportional zur Spannung 
ist, das ist mir eigentlich egal, programmiert ist es aber auf die 
Periodendauer.

...aber naja, wie gesagt, ich versuch mich erstmal an nem sauberen Code

Gruß

von Arood (Gast)


Angehängte Dateien:

Lesenswert?

Anhang vergessen

von Arood (Gast)


Lesenswert?

soo, hab jetz mal was neues geschrieben. Ich hab die Interrupts jetz 
komplett weggelassen und arbeite mit dem overflow-flag vom Timer1 und 
dem SC Bit vom ADC.
Mit dem SREG Register sollte es jetzt auch keine Probleme geben 
eigentlich.

Das Problem ist leider nach wie vor, irgendein fester Wert füttert meine 
Warteschleife. Das Poti am ADC zeigt keinerlei Wirkung :-(
1
       .include "m8def.inc"      ;Definitionsdatei fuer den ATmega8 dazuladen
2
  
3
      .dseg
4
5
COUNT:  .BYTE  1
6
        .cseg                     ;Beginn eines Code-Segmentes
7
   
8
       .org 0x00                  ;Startadresse=0x0000 (Anfang des Flash)
9
10
    
11
    
12
13
    ldi   r16, 0b11111111    
14
    out   ddrd,r16
15
    out   ddrb,r16          ;PortB/PortD auf Output
16
    ldi   r16, 0b11111110
17
    out   ddrc,r16          ;PortC Pin0 auf input, Rest output
18
19
    ldi   r16,high(RAMEND)  ; 
20
    out   SPH,r16           ; Set Stack Pointer to top of RAM
21
    ldi   r16,low(RAMEND)
22
    out   SPL,r16
23
24
    LDI   r16, 255
25
    sts   COUNT, r16        ;COUNT Variable auf 0,5s initialisieren
26
27
28
    rcall ADCINI            ;ADC initialisieren
29
    
30
    
31
    
32
                  
33
main:    
34
    
35
      sbi    portd, 4
36
      rcall  wait
37
      cbi    portd, 4
38
      rcall  wait
39
    
40
  
41
42
43
      rjmp    main            ;Schleife neu beginnen 
44
 
45
46
47
48
wait:  
49
    rcall  TIMER1             ;Timer1 aktivieren
50
51
    SBI ADCSRA, ADSC          ;ADC start conversion
52
wait_adc:    
53
    sbic    ADCSRA, ADSC      ;Warten bis ADC fertig ist
54
    rjmp    wait_adc
55
56
    in     r18, ADCL
57
    in    r19, ADCH           ;ADC Wert auslesen
58
    sts    COUNT, r19         ;und in COUNT speichern
59
    tst    r19
60
    breq  null                ;wenn COUNT==0 => keine Warteschleife        
61
loop:  
62
    in    r19, TIFR           ;Timer auf Overflow überprüfen und
63
    sbrs  r19, 2              ;überspringen falls Overflow-flag gesetzt
64
    rjmp  loop                ;sonst weiter warten
65
    ldi    r20, 0b00000100    ;Overflow-flag in r20 schreiben
66
    or    r19, r20        
67
    out   TIFR, r19           ;Overflow-flag rücksetzen
68
    lds    r19, COUNT         ;ADC-Wert aus COUNT laden und
69
    dec                       ;dekrementieren
70
    sts    COUNT, r19         ;und wieder abspeichern
71
    clr    r20                ;r20 auf 0 setzen
72
    CPSE  r19,r20             ;COUNT == 0 ? wenn ja, Schleife verlassen
73
    rjmp   loop               ;nein? nochmal
74
75
    ldi    r19, 0
76
    out    TCCR1B, r19        ;Timer stoppen und
77
    out    TCNT1L, r19        ;auf 0 setzen
78
null:  
79
    ret
80
81
82
83
TIMER1: 
84
    clr   r18
85
    out   TIMSK, r18        
86
    ldi   r16,0x01      
87
    out   TCCR1B,r16          ;Timer Start(kein prescaler) 
88
    ret
89
90
91
ADCINI:    
92
      ldi r16, 0b01100000
93
      out ADMUX, r16          ;Pin PortC0, left adjust,AVCC + AREF Capacitor
94
      ldi r16, 0b10001110
95
      out ADCSRA, r16         ;ADC enable,Interrupt enable, Prescaler 64
96
      ret

von Harald M. (mare_crisium)


Lesenswert?

Arood,

könnte daran liegen, dass Du nur den Wert von TCNT1L setzt (direkt vor 
Label "null"). Guck' doch mal im Datenblatt “Accessing 16-bit Registers” 
on page 77. Meiner Meinung nach musst Du IMMER zuerst TCNT1H und TCNT1L 
setzen, und zwar ZUERST TCNT1H und direkt DANACH TCNT1L sonst funzt's 
nicht.

mare_crisium

von Arood (Gast)


Lesenswert?

Nein, daran liegt es leider nicht. Die Warteschleife funktioniert ja 
soweit wunderbar, sofern ich die Werte für COUNT nicht mit Hilfe des ADC 
festlege sondern "per Hand" direkt im Programm eingebe.

von spess53 (Gast)


Lesenswert?

Hi

>Die Warteschleife funktioniert ja
>soweit wunderbar, sofern ich die Werte für COUNT nicht mit Hilfe des ADC
>festlege sondern "per Hand" direkt im Programm eingebe.

Dein Programm ist zwar nicht sehr schön, aber es funktioniert. 
Kontrolliere mal deine Schaltung. Kannst du am ADC-Eingang (PC0) eine 
von der Poti-Stellung abhängige Spannung messen?

MfG Spess

von spess53 (Gast)


Lesenswert?

Hi

Ergänzung:

Ich schrieb:

>Dein Programm ist zwar nicht sehr schön, aber es funktioniert.

allerdings nur wenn man diese Zeile:

>    lds    r19, COUNT         ;ADC-Wert aus COUNT laden und
>    dec                       ;dekrementieren               <-------
>    sts    COUNT, r19         ;und wieder abspeichern

in   'dec r19' ändert.

MfG Spess

von Arood (Gast)


Lesenswert?

das 'dec r19' ist wohl beim posten kaputt gegangen, da hätte AVR Studio 
ja gemeckert!

aaaaaaaaaber ich hab das Problem gefunden, des kann ich kaum erzählen 
:-)

Als ich die Spannung am PinC0 gemessen hab, hab ich immer an meiner 
eingelöteten Stiftleiste gemessen, nicht direkt am IC.
Kaum mess ich am IC, merk ich, dass da nichts anliegt.
Der Pin vom IC-Sockel ist irgendwie nicht vorhanden, allerdings siehts 
an der Lötseite so aus, als wäre er da....naja...dumm gelaufen.
In Zukunft mess ich wohl lieber immer direkt am IC...

Danke an alle die geholfen haben!

Gruß

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.