www.mikrocontroller.net

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


Autor: Arood (Gast)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht 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:
       .include "m8def.inc"      ;Definitionsdatei fuer den ATmega8 dazuladen
  
      .dseg

COUNT:  .BYTE  1
        .cseg                     ;Beginn eines Code-Segmentes
   
       .org 0x00                   ;Startadresse=0x0000 (Anfang des Flash)

        rjmp start

.org   OVF1addr
        rjmp  OVF1      
.org   ADCCaddr               ; ADC Interrupt Vector Address
        rjmp  ADCRUPT


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

        ldi   r16,high(RAMEND)  ; 
        out   SPH,r16       ; Set Stack Pointer to top of RAM
        ldi   r16,low(RAMEND)
        out   SPL,r16

        LDI    r16, 91
        sts    COUNT, r16      ;COUNT Variable auf 1s initialisieren

  
    
    rcall  ADCINI        ;ADC initialisieren
    sei              ;Interrupts zulassen
main:    
    
    
    

    SBI     portc, 1  
    rcall   wait
    CBI     portc, 1
    rcall   wait  
  
    
    ldi   r18, 0b11001111      
    out   ADCSRA, r18        ;ADC conversion start  
  

  
    rjmp    main            ;Schleife neu beginnen 
 



TMR1:  ldi   r18, 0b00000100
       out   TIMSK, r18        ;Interrupt enable
       ldi   r16,0x01      
       out   TCCR1B,r16        ;Timer Start(kein prescaler) 
       ret

OVF1:   inc   r19
        reti



wait11ms: clr   r19          ;Warteschleife 11ms    
          rcall   TMR1        
loop1:    ldi   r20, 0x02    
          SUB   r20, r19
          BRNE  loop1
          ret


wait:    lds   r21, COUNT      ;Variable COUNT laden
loop2:   rcall  wait11ms      ;11ms warten
         dec    r21          ;COUNT bis 0 dekrementieren
         BRNE  loop2        
         ret

;***********ADC Initialisierung****
ADCINI:    ldi r16, 0b01100000
           out ADMUX, r16        ;Pin PortC0, left adjust,AVCC + AREF Capacitor
           ldi r16, 0b10001111
           out ADCSRA, r16        ;ADC enable,Interrupt enable, Prescaler 128
           ret

;***********ADC Interrupt**********
ADCRUPT:  in r0, ADCH          ;"Spannungswert" aus ADCH Register lesen
      sts COUNT, r0            ;und in Variable COUNT schreiben

      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

Autor: R. Freitag (rfr)
Datum:

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

Autor: tobi (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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?

Autor: tobi (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
PS: ist AGND mit GND verbunden?

Autor: eProfi (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Arood (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: R. Freitag (rfr)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Stefan B. (stefan) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Arood (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Hannes Lux (hannes)
Datum:

Bewertung
0 lesenswert
nicht 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?

...

Autor: tobi (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Entwickler (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: eProfi (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Arood (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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ß

Autor: Arood (Gast)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Anhang vergessen

Autor: Arood (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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 :-(
       .include "m8def.inc"      ;Definitionsdatei fuer den ATmega8 dazuladen
  
      .dseg

COUNT:  .BYTE  1
        .cseg                     ;Beginn eines Code-Segmentes
   
       .org 0x00                  ;Startadresse=0x0000 (Anfang des Flash)

    
    

    ldi   r16, 0b11111111    
    out   ddrd,r16
    out   ddrb,r16          ;PortB/PortD auf Output
    ldi   r16, 0b11111110
    out   ddrc,r16          ;PortC Pin0 auf input, Rest output

    ldi   r16,high(RAMEND)  ; 
    out   SPH,r16           ; Set Stack Pointer to top of RAM
    ldi   r16,low(RAMEND)
    out   SPL,r16

    LDI   r16, 255
    sts   COUNT, r16        ;COUNT Variable auf 0,5s initialisieren


    rcall ADCINI            ;ADC initialisieren
    
    
    
                  
main:    
    
      sbi    portd, 4
      rcall  wait
      cbi    portd, 4
      rcall  wait
    
  


      rjmp    main            ;Schleife neu beginnen 
 



wait:  
    rcall  TIMER1             ;Timer1 aktivieren

    SBI ADCSRA, ADSC          ;ADC start conversion
wait_adc:    
    sbic    ADCSRA, ADSC      ;Warten bis ADC fertig ist
    rjmp    wait_adc

    in     r18, ADCL
    in    r19, ADCH           ;ADC Wert auslesen
    sts    COUNT, r19         ;und in COUNT speichern
    tst    r19
    breq  null                ;wenn COUNT==0 => keine Warteschleife        
loop:  
    in    r19, TIFR           ;Timer auf Overflow überprüfen und
    sbrs  r19, 2              ;überspringen falls Overflow-flag gesetzt
    rjmp  loop                ;sonst weiter warten
    ldi    r20, 0b00000100    ;Overflow-flag in r20 schreiben
    or    r19, r20        
    out   TIFR, r19           ;Overflow-flag rücksetzen
    lds    r19, COUNT         ;ADC-Wert aus COUNT laden und
    dec                       ;dekrementieren
    sts    COUNT, r19         ;und wieder abspeichern
    clr    r20                ;r20 auf 0 setzen
    CPSE  r19,r20             ;COUNT == 0 ? wenn ja, Schleife verlassen
    rjmp   loop               ;nein? nochmal

    ldi    r19, 0
    out    TCCR1B, r19        ;Timer stoppen und
    out    TCNT1L, r19        ;auf 0 setzen
null:  
    ret



TIMER1: 
    clr   r18
    out   TIMSK, r18        
    ldi   r16,0x01      
    out   TCCR1B,r16          ;Timer Start(kein prescaler) 
    ret


ADCINI:    
      ldi r16, 0b01100000
      out ADMUX, r16          ;Pin PortC0, left adjust,AVCC + AREF Capacitor
      ldi r16, 0b10001110
      out ADCSRA, r16         ;ADC enable,Interrupt enable, Prescaler 64
      ret


Autor: Harald M. (mare_crisium)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Arood (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: spess53 (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: spess53 (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Arood (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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ß

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.