mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik mC mit schneller Ad-Wandlung


Autor: Lars E (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Seit knapp einen Jahr arbeite ich als Werksstudent an einer Anwendung 
mit einem Atmega8.

Laut Datenblatt soll hier die "Conversion-Time" der AD-Wandlung 13-250 
microSec dauern.

Beobachtet habe ich eine Reaktionszeit, die eher bei einer 1/10 Sekunde 
liegt.
Die Ursache könnte natürlich auch nicht an der AD-Wandlung liegen.

Ist der Atmega8 wirklich so langsam?
Gibt es eine schnelle alternative, die möglichst kompatibel ist?

Autor: Peter (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Lars E schrieb:
> Die Ursache könnte natürlich auch nicht an der AD-Wandlung liegen.

das denke ich auch, wird wohl an der Software liegen.

Autor: Floh (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Lars E schrieb:
> Beobachtet habe ich eine Reaktionszeit, die eher bei einer 1/10 Sekunde
> liegt.
> Die Ursache könnte natürlich auch nicht an der AD-Wandlung liegen.

Wie hast du das beobachtet? mit den Augen?

Mann kann mit AVRs locker 200kSps erreichen, wenn man nicht allzu genaue 
Werte braucht (also 8bit reichen).

Autor: Falk Brunner (falk)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@  Lars E (Gast)

>Laut Datenblatt soll hier die "Conversion-Time" der AD-Wandlung 13-250
>microSec dauern.

Das ist auch so.

>Beobachtet habe ich eine Reaktionszeit, die eher bei einer 1/10 Sekunde
>liegt.

Beobachtet? Wie?

>Die Ursache könnte natürlich auch nicht an der AD-Wandlung liegen.

das ist zu 100% der Fall.

>Ist der Atmega8 wirklich so langsam?

Nein.

>Gibt es eine schnelle alternative, die möglichst kompatibel ist?

Programmier richtig, dann klappts auch mit dem ADC.

http://www.mikrocontroller.net/articles/AVR-GCC-Tu...

Multitasking

MfG
Falk

Autor: Lars E (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
ich hatte vor der Messung einen Ausgang eingeschaltet und nach der 
Messung wieder abgeschaltet und den Ausgang aufs Oszi gelegt...

Ich hatte allerdings eine 10 Bit Messung gemacht und die 2 lsb wegfallen 
lassen.

gut- dann geht meine Ursachen-Forschung Richtung Software...

Autor: Peter (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Lars E schrieb:
> ch hatte vor der Messung einen Ausgang eingeschaltet und nach der
> Messung wieder abgeschaltet und den Ausgang aufs Oszi gelegt.

gehört auch zufällig eine float/double berechnung zu der Messung?

Autor: Weingut Pfalz (weinbauer)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
8-bit geht auch anders,den ADC konfigurieren für Daten linksbündig und
dann nur noch das highbyte auslesen ... bring mächtig Speed.

Autor: Jens G. (jensig)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>8-bit geht auch anders,den ADC konfigurieren für Daten linksbündig und
>dann nur noch das highbyte auslesen ... bring mächtig Speed.

Begründet aber nicht, daß der µC 0,1s braucht ...

Autor: Lars E (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
ok, mal die entsprechenden Unterprogramme:
getOberw:    cbi     PORTB, 3
             ldi     EK, 0b00000010  ;ADC initialisieren  
             rcall   AD_Wandlung
             reti
AD_Wandlung: out     ADMUX, EK
             sbi     ADCSRA, ADSC    ; den ADC starten 
wait_adc:    sbic    ADCSRA, ADSC    ; warten auf AD-Wandlung
             rjmp    wait_adc
             reti

Konfiguriert habe ich es  ADCSRA 10011101


Ggf. verlängern massig Interupts die Messung.

Autor: spess53 (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi

1. Unterprogramme beendet man nicht mit 'reti', sondern mit 'ret'
2. Warum setzt du ADIE, wenn du den ADC pollst?

MfG Spess

Autor: Tom R. (rengi)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wann wird denn der Port wieder gesetzt?
Mit welchem Tackt arbeitet der Mega8?

Autor: Lars E (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Dann versuche ich es so gut es geht zu beantworten ;)


> 1. Unterprogramme beendet man nicht mit 'reti', sondern mit 'ret'

habe ich ehrlich gesagt immer gemacht- funktioniert auch- hat das 
irgendworauf einen Einfluß? Ich werde es ändern...


> 2. Warum setzt du ADIE, wenn du den ADC pollst?

genauso gute Frage- änder ich auch.


> Wann wird denn der Port wieder gesetzt?

Ich arbeite mit einer automatensteuerung- sprich ich befinde mich in 
einer schleife- rufe getOberw auf, prüfe ob der wert den Sollwert 
erreicht hat und wiederhole die Schleife bis er den Wert erreicht hat.


> Mit welchem Tackt arbeitet der Mega8?

er arbeitet mit 3.68864 Mhz



Danke schon mal für die ganzen Antworten,

Grüße,

Lars

Autor: spess53 (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi

>habe ich ehrlich gesagt immer gemacht- funktioniert auch- hat das
>irgendworauf einen Einfluß?

Ja. Das wirkt zusätzlich wie 'sei'. Kann also ein vorheriges 'cli' 
unwirksam machen.

MfG Spess

Autor: Christian H. (netzwanze) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Lars E schrieb:
> habe ich ehrlich gesagt immer gemacht- funktioniert auch- hat das
> irgendworauf einen Einfluß? Ich werde es ändern...

Im Prinzip machen beide Befehle das gleiche, nur dass bei reti 
zusätzlich Interrupts wieder freigegeben werden. Also ein atomares "sei 
+ ret".

Autor: Tim (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Konfiguriert habe ich es  ADCSRA 10011101
> er arbeitet mit 3.68864 Mhz

Macht also 3688640/32/13 = 8866,9 Wandlungen / Sec
Ergo 112,7 µSec für eine.
Also bist du mit deinen 0,1 Sec ca Faktor 1000 daneben.

Poste mal mehr code....

Autor: Lars E (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
OK, da ich befürchte, dass 700 Zeilen Code auch nichts nützen mal die 
weiteren relevanten Stellen:


Aufgeführt wegen der Interrupts
begin:    
rjmp  main      ; RESET External Pin, Power-on Reset, Brown-out Reset and Watchdog Reset
reti            ;  INT0 External Interrupt Request 0
reti            ;  INT1 External Interrupt Request 1
reti            ;  TIMER2 COMP Timer/Counter2 Compare Match
reti            ;  TIMER2 OVF Timer/Counter2 Overflow
reti            ;  TIMER1 CAPT Timer/Counter1 Capture Event 
reti            ;  TIMER1 COMPA Timer/Counter1 Compare Match A
reti            ;  TIMER1 COMPB Timer/Counter1 Compare Match B
reti            ;  TIMER1 OVF Timer/Counter1 Overflow
rjmp    timer0_overflow  ;  TIMER0 OVF Timer/Counter0 Overflow
reti            ;  SPI, STC Serial Transfer Complete
reti            ;  USART, RXC USART, Rx Complete
reti            ;  USART, UDRE USART Data Register Empty
reti            ;  USART, TXC USART, Tx Complete
rjmp   on       ;  ADC ADC Conversion Complete
reti            ;  EE_RDY EEPROM Ready
reti            ;  ANA_COMP Analog Comparator
reti            ;  TWI 2-wire Serial Interface
reti            ;  SPM_RDY Store Program Memory Ready


Initialisieren des Timers und der UART
ldi     temp1, 0b00000001    ; TOIE0: Interrupt bei Timer Overflow
out     TIMSK, temp1
;------------------------------------------------------------------
sbi  UCSRB, 3
ldi  r16, 23
out  UBRRL, r16


Hier der Unterprogramm-Aufruf in der Schleife im Hauptgrogramm:
phase450:  
rcall  getOberw
cpi    Oberw, 110  ;gehe in Phase 500 wenn
BRSH   phase500    ;die Oberw erreicht ist
rjmp   phase450


Interrupt bei neuem AD-Wert, Verarbeitung und Ausgabe per UART
Verarbeitung ist natürlich notwendig- wenn die UART-Ausgabe sehr viel 
Zeit benötigt könnte sie weggelassen werden, ist z.Z. vor allem zur 
Kontrolle für mich
on:      
sbrc  EK, 0    ;wenn Bit 1 von EK auf 1 steht,    
rjmp  onKw     ;dann springe zum verarbeiten des Kniewinkels
sbrc  EK, 1    ;wenn Bit 2 von EK auf 1 steht,    
rjmp  onOberw  ;dann springe zum verarbeiten des Oberschenkelwinkels

onMt: ;habe ich hier im Code mal beode weggelassen, da nicht relevant
onKw  ;es werden hier halt die anderen beiden Eingänge verarbeitet

onOberw:  
push  temp1        
push  temp2  ;rette  die Temps
    
in    temp1, ADCL    
in    temp2, ADCH
;-----------------------
asr   temp2  
mov   Oberw, temp1
ldi   temp1, 160
add   Oberw, temp1
    
putChar2:  
sbis  UCSRA, 5 ;gebe die Daten über den Comp aus
rjmp  putChar2
out   UDR, Oberw 
        
pop   temp2    ;schreibe die Temps zurück
pop   temp1
reti           ;und zurück ins Hauptprogramm


Timer, der ggf, auch ein paar mal reinhackt- nutze ich sowohl zur 
"Zeitmessung" aber vor allem für ein PWM-Signal zur Motorsteuerung.
Ist leider an dieser Stelle auch nötig- aber es läßt sich bestimmt auch 
anders realisieren.
timer0_overflow:       ; Timer 0 Overflow Handler
inc     PWMCount       ; den PWM Zähler von 0 bis
cpi     PWMCount, 101  ; 101 zählen lassen
brne    WorkPWM        ; springe wenn ungleich 101 zu WorkPWN
clr     PWMCount       ; wenn gleich lösche PWNCount
        
WorkPWM:      
push   temp1           ;rette Temp1
cbi    PORTB, 5        ;lösche PortB5
ldi    temp1, 100      ;lade 100 in temp1
sub    temp1, v        ;temp1=100 - v
        
cp     PWMCount, temp1 ;Vergleiche den Grenzwert (temp1=100-v) mit dem Zählwert PWMCount
brlo   zur1            ;wenn er niedrieger ist springe zu zur1
sbi    PORTB, 5        ;setzte PORTB5
 
zur1:   
pop    temp1           ;temp1 zurück schreiben
reti                   ;zrück zum Hauptgrogramm


Dann schon mal vielen Dank an alle die sich die Mühe machten bis hier zu 
lesen,

Grüße,

Lars

Autor: Floh (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
vorher hast du die analogmessung noch gepollt, jetzt ist plötzlich ein 
Interrupt da, in dem du auch noch sehr langwierige Dinge tust (serielle 
Übertragung).

Poste mal deinen GESAMTEN Code als Anhang, diese Häppchentaktik bringt 
uns und damit dir nichts.

Autor: Tim (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wenn ich das jetzt richtige zusammen gesammelt habe hast du folgenden 
Ablauf Programmiert:

phase450:
rcall  getOberw
 ldi EK,.... für die Mux
AD_Wandlung:
 adc start und warten bis fertig.
IRQ ADC fertig
 Verarbeitung ja nach EK und Ausgabe via UART

Von wo bis wo hat du die 0,1 sek gemessen?

Und dann noch ein parr Fragen zum Code:

Wo und wie sicherst du das SREG in den ISR? Wiederherstellung?
Warum fragst du in on: nicht das ADMUX register ab?
EK ist was du messen wolltest, ADMUX das was du gemessen hast.

Was wolltest du hier rechnen:
in    temp1, ADCL    
in    temp2, ADCH
;-----------------------
asr   temp2  
mov   Oberw, temp1
ldi   temp1, 160
add   Oberw, temp1
Oberw = ADCL + 160? Überlauf? ADCH egal?
Also ist Oberw von 0..Vref 4x hintereinander 160..255..0..159
Warum verwendest du keine Hardware PWM mit Timer 1/2?

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.