PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Auswertung/Funktionsweise des A/D Wandlers



robotxy
20.06.2004, 17:16
Hi!
ich möchte den A/D Wandler meines Mega16 benutzen.
Kann mir jemand vielleicht die Auswertung des A/D Wandlers erklären
Nach meinen Informationen unterteilt er die Referenzspannung in 256 Teile, stimmt das?
Man fragt doch den Wandler mit ADc ab oder(unter Bascom)?
Muss ich sonst noch etwas beachten?
Wie schließe ich dann ein Poti/LDR an den A/D Wandler?
MFG
Rasmus

Flite
21.06.2004, 13:22
Hallo!
Es dürfte sich bei dem AD Wandler um einen 10bit ADC handelt, dh. er unterteilt den Spannungsbereich zwischen ARef und AGND in 1024 Teile. Liegt dein ARef jetzt bei 5V hast du damit eine Auflösung 4,88 mV.
Allerdings ist die Größe von ARef auch begrenzt (sie darf imho nicht mehr als 0,2 V über AVCC und nicht unter einem bestimmten Wert liegen -> also im Datasheet nachschauen).

Wie man die ADC Werte in Bascom abfragt weiß ich nicht - da ich nicht mit Bascom arbeite. Der AD Wandler muss auf jeden Fall zuerst initialisiert werden. Anschließend kann man den Wert mit einer einfachen Funktion auslesen.

Wenn du auf die Genauigkeit der Werte wert legst, solltest du die Tipps im Datenblatt berücksichtigen (beim Anschluss von AVCC z.B. die Induktivität mit rein).

Um einen änderbaren Widerstand anzuschließen benötigst du einen Spannungsteiler. Dazu nimmst du einen Festwiderstand bekannter Größe und hängst diesen an VCC und mit der anderen Seite an den Pin des LDR. Der LDR dann noch gegen GND und zwischen LDR und Widerstand deinen AD Port. Evtl. kannst du da dann noch nen Schutzwiderstand in Reihe reinbauen (aber nicht unbedingt notwendig). Hier ist aber vorsicht geboten, da beim Spannungsteiler keine linearen Werte rauskommen. D.h. du musst das ganze Software mäßig linearisieren.
Einfacher ist das beim Poti. Da schließt du das eine Ende an VCC, das andere an GND. Dann kommt der Schleifer an den AD Port.

Bei beiden Fällen kannst du nun Aref auf AVCC legen. Wichítig ist, dass keine Spannungen an den AD Port kommen, die über Aref liegen.

Viele Grüße
Flite

Florian
21.06.2004, 13:48
Hi Flite!
Das Thema interessiert mich auch! ;-)
Ich bin bisher noch nicht dazu gekommen die AD-W. auszuprobieren! :-(
Programmierst Du in Assembler?
Wenn ja, könntest Du mir dann vielleicht, wenn es möglich wäre, einen mit Kommentaren versehenen einfachen Code posten?
Oder könntest Du mir einen Code basteln, wo der AD-W. abgefragt wird und die 10 Bit an Ausgängen ausgegeben werden?
Wenn möglich auch Kommentiert?
Wäre nett, aber wenn nicht, ist es auch in Ordnung!
Ich weiß selber, wie viel man zu tun hat! ;-) :-(

robotxy
21.06.2004, 14:20
Hi!
Also wäre bei einer Referrenzspannung von 5V, eine Einheit 0.0048828(Ref : 1024)groß, oder?
LDR:

Vcc----R---LDR---GND
............|
..........Port
weiß jemand wie man das ganze dann mit Bascom abfragt?(irgendwie mit "ADc", bin mir aber nicht ganz sicher)
Danke schonmal
MFG
Rasmus

Flite
21.06.2004, 15:10
Hallo!
Ja - eine Einheit des ADC wären dann 4,88mV (=0,00488 V).

der Port muss zwischen R und LDR (aber ich denke, das hast du so gemacht - nur das Forum hat die Leerzeichen eingespart).

ADC in Bascom:

Config Adc = Single , Prescaler = Auto
Start Adc
Dim W As Word, Channel As Byte

Channel = 0 ' Pin Nummer von 0 - 7
W = Getadc(Channel)

Übrigens: ich hab nur bei Google 'bascom adc einlesen' eingegeben und den zweiten Link genommen.

Grüße
Flite

Grüße
Flite

robotxy
21.06.2004, 15:12
Danke!
Ich habe schon verschiedene Möglichkeiten gesehen(gefunden bei Google), aber ich war mir nicht sicher, welches die "Richtige" ist.
MFG
Rasmus

Florian
21.06.2004, 17:41
Hi!
Hat jemand sowas auch für Assembler?

Flite
21.06.2004, 17:53
Hier gibts auch einen für Assembler. Ist für den Mega32, sollte sich jedoch problemlos umschreiben lassen:



;**********************************************
;*
;* 10 bits A/D converter demo
;*
;**********************************************

.include "C:\VMLAB\include\m32def.inc"

; Registers definitions
;
.def temp = r16
; my Def
;**********************************************
;.equ ADTS2 =7
;.equ ADTS1 =6
;.equ ADTS0 =5
;**********************************************
; Reset and interrupt vectors
;
.cseg
;************************************************* ********************
.org $00 ; 1 $000 Reset Go to Reset handler
rjmp start
.org $02
rjmp dummy
.org $04
rjmp dummy
.org $06
rjmp dummy
.org $08
rjmp dummy
.org $10
rjmp dummy
.org $12
rjmp dummy
.org $14
rjmp dummy
.org $16
rjmp dummy
.org $18
rjmp dummy
.org $20
rjmp ad_vector ; ADC complete
.org $22
rjmp dummy
.org $24
rjmp dummy
.org $26
rjmp dummy
.org $28
rjmp dummy


; rjmp ad_vector ; ADC
;***********************************************
dummy:
nop
nop
nop
nop
reti
;***********************************************
;***********************************************
; ADC complete interrupt service
;
ad_vector:

in temp, ADCH
sbi ADCSR,ADSC ; StartConversion
sei
ret

;***********************************************
; Reset handler
;
start:

clr temp ; first clear all registers
out ACSR,temp
out ADMUX,temp
out ADCSR,temp
out SFIOR,temp

ldi temp,high(RAMEND)
out sph,temp
ldi temp,low(RAMEND)
out spl,temp

; ldi temp, $AB ; Power on ADC; select prescaler (/8); free running
; out ADCSR,temp ; and enable end of conversion interrupt


sbi ADCSR,ADEN ; ADC-Enable
sbi ADCSR,ADIE ; ADC-EnableEnable Interrupt
sbi ADCSR,ADPS2 ; SET Prescale to //
cbi ADCSR,ADPS1 ; Divisions Factor //
cbi ADCSR,ADPS0 ; by 16

sbi ACSR,ACIE ; ACIE: Analog Comparator Interrupt Enable
sbi ACSR,ACIS1 ; ACIS1, ACIS0: Analog Comparator //
sbi ACSR,ACIS0 ; Interrupt Mode Select //

sbi ADMUX, ADLAR ; Get 8 most significant bits in ADCL

nop
nop
nop ; Leave some time to stabilize before starting
nop

sbi ADCSR,ADSC ; StartConversion

sei ; A warning must be issued here!!. 8 is not enough
; as prescaler factor to obtain a 50-200 KHz
; recommended ADC clock

forever:
rjmp forever ; Infinite loop, interrupted by ADC conversions



Ich hab den Code jedoch nicht ausprobiert - beim groben überfliegen sieht es jedoch recht gut aus ...

Grüße
Flite

Florian
21.06.2004, 18:27
Hi Flite!
Danke für den Code!
Ich habe ihn jetzt 3 mal durchgelesen!
Leider habe ich nicht verstanden, was der Code überhaupt machen soll!
Was gibt er aus, oder bearbeitet er?

Flite
21.06.2004, 21:19
Hallo Florian,

ich versuch mal das meiste zu erklären ...


.include "C:\VMLAB\include\m32def.inc"
.def temp = r16
.org $00 ; 1 $000 Reset Go to Reset handler
rjmp start
.org $02
rjmp dummy
.org $04
rjmp dummy
.org $06
rjmp dummy
.org $08
rjmp dummy
.org $10
rjmp dummy
.org $12
rjmp dummy
.org $14
rjmp dummy
.org $16
rjmp dummy
.org $18
rjmp dummy
.org $20
rjmp ad_vector ; ADC complete
.org $22
rjmp dummy
.org $24
rjmp dummy
.org $26
rjmp dummy
.org $28
rjmp dummy


Die Interrupt Vektor Table. Je nach ausgeführtem Interrupt springt er hier zu den entsprechenden Unterfunktionen.



dummy:
nop
nop
nop
nop
reti


Wenn ein nicht gewünschter Interrupt ausgeführt wird (also einer, der nichts mit dem ADC zu tun hat und nicht der Reset ist) springt er in diese Funktion. Die verplemtern nur Rechenzeit und sollte überflüssig sein.



ad_vector:

in temp, ADCH
sbi ADCSR,ADSC ; StartConversion
sei
ret


Die Funktion wird über die Interrupt Table aufgerufen, sobal ein Wert gewandelt wurde.

in temp, ADCH liest has High Byte der ADC Wertes ein. Eigentlich müsste man hier noch eine zweite Variable einlesen, in der der Wert ADCL (das Low Byte) eingelesen wird. Fehlt hier völlig (warum, siehe weiter unten).

Anschließend werden hier die Interrupts allgemein angeschaltet (da sie niergends abgeschaltet werden, sollte das eigentlich überflüssig sein).



ldi temp,high(RAMEND)
out sph,temp
ldi temp,low(RAMEND)
out spl,temp


Initialisierung des Stack
Das löschen der Register sollte überflüssig sein.



sbi ADCSR,ADEN ; ADC-Enable
sbi ADCSR,ADIE ; ADC-EnableEnable Interrupt
sbi ADCSR,ADPS2 ; SET Prescale to //
cbi ADCSR,ADPS1 ; Divisions Factor //
cbi ADCSR,ADPS0 ; by 16


Hier wird der ADC angeschaltet, der Interrupt (sobald eine Wandlung fertig ist) angeschaltet, und der Prescaler auf 16 gesetzt.

Beim ADMUX Register sind folgende Werte wichtig:
Die beiden MSB (REFS0/1) sind auf 0 zu setzen um mit ARef als Referenz zu arbeiten.
ADLAR (wird im Bsp. gesetzt) dient dazu, das Ergebnis nicht rechtsbündig (also 8 Bit im unteren Byte und 2 Bit im High byte), sondern linksbündig (also 8 bit im high byte und 2 bis im low byte) auszugeben.
D.h. da oben nur das High Byte ausgelesen wurde, und linksbündig aktiviert ist, werden hier im Beispiel nur 8 bit genutzt (anstatt 10 möglichen).

Die restlichen 5 bit im ADMUX Registen (MUX 4- 0) dienen dazu, einzustellen, welcher der ADC pins eingelesen werden soll. Da alle 5 Bits auf 0 sind wird der ADC0 eingelesen.


sbi ADMUX, ADLAR ; Get 8 most significant bits in ADCL
linksbündig wird aktiviert.



sbi ACSR,ACIE ; ACIE: Analog Comparator Interrupt Enable
sbi ACSR,ACIS1 ; ACIS1, ACIS0: Analog Comparator //
sbi ACSR,ACIS0 ; Interrupt Mode Select //


Hier wird wohl etwas für den Analog Comparator eingestellt. Diese Passage verstehe ich auch nicht und würde sie einfach löschen.

Dann kommen ein paar nop's - benötigt er wohl zur Stabilisierung (würde ich je nach verwendeter Taktfrequenz evtl. noch ein wenig länger machen).


sbi ADCSR,ADSC ; StartConversion

Hier wird das erste Mal eine Wandlung gestartet. Zukünftige Wandlungen werden automatisch nach einer vollendeten Wandlung gestartet (im Interrupt).

Mit sei werden die Interrupts alle aktiviert.

Danach folgt nur noch eine Endlosschleife, die nach jeder vollendeten Wandlung per Interrupt unterbrochen wird.


Das macht das Programm:
Das Programm wandelt die am ADC0 liegende Spannung bezogen auf AREF in einen digitalen 8 bit Wert um, der in der Schleife immer aktuell in der Variable Temp steht. Dieser muss nur ausgelesen werden und beispielsweise über das UART oder ein LCD angezeigt werden.

Falls du noch Fragen hast melde dich!

Ich hoffe dir geholfen zu haben (allerdings gebe ich keine Garantie über die geschribenen Dinge, da ich nebenher Fußball schaue und ich noch nie etwas mit dem ATMega32 gemacht habe).

Viele Grüße
Flite

Florian
22.06.2004, 11:48
Hi Flite!
Erstmal ein ganz dolles "DANKESCHÖN"! ;-)
Danke für die ganze Arbeit, die Du Dir gemacht hast!
Ich werde jetzt den Code einfach mal für den AT90S4433 umschreiben und ihn hier zum kontrollieren posten! :lol:
Eine Frage habe ich allerdings jetzt schon:
Was ist ein Prescaler?

Danke nochmals!

Gottfreak
22.06.2004, 13:58
Ein Prescaler ist ein Vorteiler. Der dafür angegebene Wert gibt an, um welchen Faktor ein Timer langsamer läuft als der Systemtakt.
8MHZ und ein Prescaler von 64 hieße z.B., dass mit einer Frequenz von 8MHZ/64 = 125kHz hochgezählt wird.

Florian
22.06.2004, 14:11
Hi Gottfreak!
Das ist dann also sowas wie bei den Timern!
Dann hab ich das jetzt verstanden! ;-)
Danke nochmnal!

Florian
22.06.2004, 18:45
Hi!
Ich habe noch eine Frage!


;**********************************************
;.equ ADTS2 =7
;.equ ADTS1 =6
;.equ ADTS0 =5
;**********************************************


Warum sind die .equ's als Kommentar eingefügt?
Dann funktionieren die doch garnicht! Die werden doch dann übersprungen! Oder doch nicht?

Florian
22.06.2004, 19:05
Hi!


; rjmp ad_vector ; ADC
;***********************************************
dummy:

Das rjmp ... ist auch als Kommentar gemacht! Soll das sein?

Edit:
Mir fällt auf, dass auch andere Elemente als Kommentar geschrieben sind! :-(

Flite
22.06.2004, 19:29
Also wenn ich das auf die Schnelle wichtig überblicke waren die hinter den Kommentaren stehenden Anweisungen nur für frühere Tests etc. zuständig.

Die equs werden niergends im Programm mehr verwendet (also war das wahrscheinlich auch zu testzwecken drin). Außerdem sollten die Definitionen eigentlich auch in der m32def.inc stehen.

Versuch das ganze Mal auf den 4433 umzuschreiben (und lass die kommentierten Befehle einfach weg) und stell den Code mal hier rein.
Ich les mir das dann mal durch - ist eigentlich nicht schwierig.

Allerdings:
der 4433 verfügt imho nicht über die Möglichkeit das Ergebnis linksseitig anzugeben.

Viele Grüße
Flite

Flite
22.06.2004, 19:40
Die ADTS 0 - 2 Bits sind die MSBs im SFIOR Register (Special Function I/O Register). Damit lässt sich eine Triggerfunktion des ADC steuern.

In obigem Beispiel war der Trigger wohl auf den Analog Comparator (001) geschaltet - daher auch die Reste des Analog Comparator im Quelltext.

Ganz oben bei der Initialisierung wird das SFIOR auf 0x00 gesetzt -> daher sind auch die ADTS auf 0 und der Trigger läuft auf Free Running.

Grüße
Flite

Florian
22.06.2004, 21:40
Hi Flite!


Allerdings:
der 4433 verfügt imho nicht über die Möglichkeit das Ergebnis linksseitig anzugeben.

Was muss ich dann machen, um trotzdem eine 8 Bit Zahl ausgeben bzw. in temp packen zu können?

Muss ich das so machen:?

ad_vector:

in temp , ADCL
sbi ADCSR , ADSC
sei
ret

Flite
22.06.2004, 21:54
Hallo Florian,

nein - das wird nicht funkitonieren.
Lies das ADCL in das Low Byte eines pseudo 16 Bit Registers ein (z.b. ZL)
dann das ADCH in das entsprechene High Byte (z.B. ZH).

Anschließend rotierst du das 16bit Register 2 mal nach rechts (wobei die zwei Bit aus dem High Byte ins Low Byte runterrutschen und die beiden LSB des Low Bytes verlohren gehen).



ad_vector:
in ZL, ADCL
in ZH, ADCH
ror Z
ror Z
mov temp, ZL

sbi ADCSR, ADSC
(sei)
ret


Viele Grüße
Flite

Florian
23.06.2004, 15:14
Hi Flite!
Das habe ich mir schon fast gedacht, dass das nicht geht! ;-)
Naja, danke für Deine Erklärung, wie ich das dann machen kann! :-)
Wenn ich demnächst mal Zeit haben sollte, dann werde den Code für den 4433 machen!
Ich denke mal, dass ich das heute oder morgen schaffen werde, jetzt ist ja endlich der Arbeiten-Streß vorbei, denn bald (7.7.) gibt es Zeugnisse!
\:D/ \:D/ \:D/ \:D/ \:D/ \:D/ \:D/ \:D/ \:D/ \:D/ \:D/ \:D/ \:D/ \:D/ \:D/ \:D/ \:D/ \:D/

Flite
25.06.2004, 11:24
Hallo Florian!

Wie in der PM besprochen hab ich das ganze mal für den 4433 umgeschrieben.

Auf Richtigkeit kann ich leider keine Garantie geben, da ich schon lang nix mehr in Assembler programmiert habe und ich es auch nicht getestet habe. Ich werd aber gleich mal das Programm im AVR Studio ausprobieren und schauen, ob es funktioniert oder nicht ... =P~

So, der Code:


.include "4433def.inc"
.def temp = r16
.def ad_value = r17

.org 0x000
rjmp init ; Initialisierung / RESET
reti ; IRQ0
reti ; IRQ1
reti ; Timer1 Capture
reti ; Timer1 Compare
reti ; Timer1 Overflow
reti ; Timer0 Overflow
reti ; SPI Complete
reti ; UART Rx
reti ; UART Data empty
reti ; UART Tx
rjmp adc_int ; ADC Conversion Complete
reti ; EEPROM ready
reti ; Analog Comparator


; ################################
; Initialisierung
; ################################

init:
; ################################
; Ports initialisieren (alle PINS INPUT - interne Pullups aktiviert)
; ################################

ldi temp, 0x00
out DDRB, temp

ldi temp, 0xFF
out PORTB, temp

ldi temp, 0x00
out DDRC, temp

ldi temp, 0xFF
out PORTC, temp

ldi temp, 0x00
out DDRD, temp

ldi temp, 0xFF
out PORTD, temp

; ################################
; Stack initialisieren
; ################################

ldi temp, RAMEND
out SP, temp

; ################################
; ADC initialisieren
; ################################

; Multiplexer setzen - PC0 ist analoger Eingang
cbi ADMUX, MUX0
cbi ADMUX, MUX1
cbi ADMUX, MUX2

; ADC Interrupt anschalten
sbi ADCSR, ADIE

; Prescaler auf 16 setzen
cbi ADCSR, ADPS0
cbi ADCSR, ADPS1
sbi ADCSR, ADPS2

; AD Converter anschalten
sbi ADCSR, ADEN

; Erste Wandlung auslösen
sbi ADCSR, ADSC

; ################################
; Hauptprogramm
; ################################

main:
; Hier könnte nun der ad_value umgerechnet werden und über
; UART oder LCD ausgegeben werden
rjmp main


; ################################
; ADC Interrupt
; ################################

adc_int:

; gewandelte Werte einlesen
in ZL, ADCL
in ZH, ADCH

; zweimal nach rechts rotieren (um die beiden LSB
; in das Low Register zu kriegen) -> 8 bit Wandlung
ror Z
ror Z

; 8 bit Wert in ad_value schreiben
mov ad_value, ZL

; neue Wandlung starten
sbi ADCSR, ADSC

reti


Viele Grüße
Flite
EDIT: Ach ja, wenn du irgendwleche Fragen hast: nur zu !!

Florian
25.06.2004, 12:32
Hi Flite!
Ich werde nachher noch das Programm ausprobieren, oder auch morgen oder so!
Mal gucken obs funktioniert!
Dann werd ich das progrmm mal durcharbeiten und dann fragen dazu stelklen! :-)

Danke nochmal! :-)

Flite
25.06.2004, 12:40
Hallo Florian,

ich habe das Programm gerade simuliert.

Es waren noch zwei Fehler drin.
Erstens kann man das Z Register wohl nicht rotieren (also hab ich es mit zwei einzelnen gemacht).
Zweitens hab ich vergessen mit 'sei' die Interrupts global anzuschalten. :-b

Hier noch mal der Code, der so jetzt auch funktionieren sollte ...



.include "4433def.inc"
.def temp = r16
.def ad_value = r17

.org 0x000
rjmp init ; Initialisierung / RESET
reti ; IRQ0
reti ; IRQ1
reti ; Timer1 Capture
reti ; Timer1 Compare
reti ; Timer1 Overflow
reti ; Timer0 Overflow
reti ; SPI Complete
reti ; UART Rx
reti ; UART Data empty
reti ; UART Tx
rjmp adc_int ; ADC Conversion Complete
reti ; EEPROM ready
reti ; Analog Comparator


; ################################
; Initialisierung
; ################################

init:
; ################################
; Ports initialisieren (alle PINS INPUT - interne Pullups aktiviert)
; ################################

ldi temp, 0x00
out DDRB, temp

ldi temp, 0xFF
out PORTB, temp

ldi temp, 0x00
out DDRC, temp

ldi temp, 0xFF
out PORTC, temp

ldi temp, 0x00
out DDRD, temp

ldi temp, 0xFF
out PORTD, temp

; ################################
; Stack initialisieren
; ################################

ldi temp, RAMEND
out SP, temp

; ################################
; ADC initialisieren
; ################################

; Multiplexer setzen - PC0 ist analoger Eingang
cbi ADMUX, MUX0
cbi ADMUX, MUX1
cbi ADMUX, MUX2

; ADC Interrupt anschalten
sbi ADCSR, ADIE

; Prescaler auf 16 setzen
cbi ADCSR, ADPS0
cbi ADCSR, ADPS1
sbi ADCSR, ADPS2

; AD Converter anschalten
sbi ADCSR, ADEN

; global Interrupts aktivieren
sei

; Erste Wandlung auslösen
sbi ADCSR, ADSC

; ################################
; Hauptprogramm
; ################################

main:
; Hier könnte nun der ad_value umgerechnet werden und über
; UART oder LCD ausgegeben werden
rjmp main


; ################################
; ADC Interrupt
; ################################

adc_int:

; gewandelte Werte einlesen
in ad_value, ADCL
in temp, ADCH

; zweimal nach rechts rotieren (um die beiden LSB
; in das Low Register zu kriegen) -> 8 bit Wandlung
ror temp
ror ad_value
ror temp
ror ad_value

; neue Wandlung starten
sbi ADCSR, ADSC

reti


Sollte funktionieren. Du musst natürlich noch eine Ausgabe dazu programmieren. Im einfachsten Fall wären das 8 Leds an einen Port und an den Port dann das Ergebnis ausgeben ...

Grüße
Flite

Florian
25.06.2004, 13:35
Hi Flite!
Danke, dass Du Dir so viel Mühe mit mir gibst! :-) *merci beaucoup* *thanks* *Danke sehr*
Ich werde erstaml irgendwann demnächst das Programm ausprobiern!
Ich werde dazu dann die 8 LED's an den µC dranhängen!
Ich habe mal was gehört, dass die erste Messung des ADC immer falsach ist, stimmt das?
Wenn ich noch Fehler finde, oder Fragen habe, werde ich mich noch bei Dir melden! :-)

Florian
27.06.2004, 19:00
Hi Flite!
Ich habe eine Frage!
Irgendwie scheint mein AVR zu spinnen!
Ich habe jetzt bei main: (Hauptprogramm) folgendes eingefügt:

out PORTD, ad_value
Wenn ich nun das programm in den AVR lade, leuchtet keine der 8 LED's! Bis dahin erstmal alles super!
Ich habe Stiftleisten als Ausgänge des AVR's auf meiner Platine.
Wenn ich nun einen Finger an den PC0 halte, zeigt mir die LED-Anzeige 2-3 leuchtende LED's an! Also PD0-2!
Kann das sein, oder ist mein AVR kaputt? Alles andere scheint aber noch zu funktionieren und es sind auch keine Lötbrücken auf der Platine!

Danke für Deine (Eure) Hilfe!

Flite
27.06.2004, 21:07
Hallo Florian,

Also du musst natürlich zuerst in der Initialisierung den PORT B aus Ausgang stellen. Da jedoch ein paar LEDs leuchten geh ich mal davon aus, dass du das gemacht hast.

Nun ja - mit einem Finger an den AVR langen ist eigentlich ja keine so tolle Lösung *g* Wenn du statisch ausgeladen bist kannst du dabei (zumindest theoretisch) den AVR zerschießen. Mir ist das allerding noch nie passiert.

Aber das ein paar LEDs anfangen zu leuchten ist schon richtig ... Der AVR misst an deinem Finger eine Spannung und gibt diese aus ...

Du musst den PC0 von ausßen beschalten. Zum test kannst du folgendes machen: du kann mit einem Kabel entweder GND auf den Pin halten (dann sollten alle LEDs aus sein) oder mal an VCC hängen. Dann sollten alle LEDs an sein.

Wenns das nicht funktioniert müssen wir mal schauen ob wo anders noch ein Problem ist.

Viele Grüße
Flite

PS: einmal hab ich doch einen AVR kaputt gekriegt - da ging auch der AD Wandler nicht mehr ...

Florian
28.06.2004, 12:17
Hi Flite!
Ich habe jetzt das gemacht, was Du gesagt hast!
Irgendwie ist es bei mir genau andersrum!
Wenn ich GND an den PC0 halte, dann leuchten alle LED's und wenn ich die VCC (5V) dranhänge, dann leuchtet gar keine! :-(
Wie kann das sein?

Flite
28.06.2004, 16:30
Ach verzeihung!

Is klar - du hast deine LEDs sicherlich gegen VCC geschaltet. Also wenn du GND (0V) anlegst wird der PORT auf 0b00000000 geschalten, was bei deiner Schaltung alle LED's leuchten lässt.

Stimmt also alles! Funktioniert!

Grüße
Flite

Florian
28.06.2004, 18:10
Hi Flite!
Du bist ein Schatz! :lol: O:)
Danke! Vielen vielen Dank!
Ich bin ja so ein dusseln! ;-)
Das ich da nicht selbst drauf gekommen bin! ;-) ](*,)
Kennst Du einen Befehl, mit dem man das invertieren kann?
Danke nochmal! =D>

*!!! Juuuuuhhhhhhhhhhuuuuuuuuuuuuuuuu !!!*

Flite
28.06.2004, 20:30
Hallo Florian,

freut mich, dass alles klappt!

Klar:

einfach com ad_value
unter den 4 rors einfügen ....

Dann klappt das auch ...
Darf man fragen, was du damit vor hast?

Viele Grüße
Flite

Florian
28.06.2004, 20:40
Hi Flite!
Cooooooooooooooooooool!
Juuuuuuuuuuhuuuuuuuuuu! ;-)
*supermegafreu* :lol:

Ich will mit meinem AVR den GP2D12 und den ADXL 202JE auswerten! :-)
Damit möchte ich mein JuFo-Projekt machen! :-)

Flite
28.06.2004, 20:48
wow - genial!

ich hab grade versucht dich per icq zu kontaktieren. Aber der Server von denen ist wohl grade down.

Meine Nummer ist: 98927688

Vielleicht klappts bei dir ja :-)

Viele Grüße
Flite

Florian
29.06.2004, 13:06
So!
Jetzt funktionierts!
Danke an Flite nochmal! :-)
Wens interessiert, ein Video:
http://www.cer-online.de/video/video.avi

Florian
06.07.2004, 15:02
Hi @ all!
Ich habe nochmal zwei kleine Fragen!
Wie kann ich den ADC Port z.B. von PC0 auf PC2 verlegen?
Wie kann ich zwei oder mehr Ports "gleichzeitig" auswerten?

Danke im Voraus!

Flite
06.07.2004, 17:52
Hallo Florian,

hier wird der Eingang bestimmt:



cbi ADMUX, MUX0
cbi ADMUX, MUX1
cbi ADMUX, MUX2


mit cbi schreibst du einen Null, mit sbi eine Eins. Da du 2 ^ 3 Kombinationen hast, kannst du jeden der 8 Analogeingänge einlesen.

Wenn du mehrere einlesen willst, musst du nach dem ersten die Einstellungen des AD Mux ändern, dann wieder lesen, dann wieder ändern, ...

Da es nur einen AD wandler gibt, der mit einem Analog Multiplexer ausgestattet ist, kannst du nicht alle Werte auf einmal einlesen ...

Grüße
Flite

Florian
06.07.2004, 18:46
Hi Flite!
Danke für Deine Hilfe!
Ich dachte bisher immer, dass nur die C-Control einen gemultiplexten AD-Wandler hätte und deshalb so langsam wäre.
Warum ist das beim AVR auch so, warum ist der aber nicht so langsam?
Naja, danke nochmals!
Ich hoffe, ich habe bald mein erstes Projekt mit den AD's fertig! :-) *freu*

Florian
07.07.2004, 14:31
Hi @ all!
Ich habe da ein kleines Problem! :-(
Ich habe schon einiges jetzt ausprobiert und es hat auch alles funktioniert, aber ich weiß nicht, wie man mehrere Werte nacheinander einlesen kann!
Ich verstehe leider die Erklärung von Flite nicht! :

Wenn du mehrere einlesen willst, musst du nach dem ersten die Einstellungen des AD Mux ändern, dann wieder lesen, dann wieder ändern, ...

Kann mir das jemand (natürlich auch Flite) nochmal erklären, vielleicht an dem praktischen Beispiel das hier die ganze Zeit verwendet wird?

Danke nochmals! :-)

Flite
10.07.2004, 11:45
Hallo Florian,

hier ein (hoffentlich) funktionierender Code für den Adwandler.

Er liest die AD Ports 0 - 2 ein und schreibt die Werte je in ein eigenes Register. Der Code ist nicht optimiert (Speicherplatz / RAM) damit er übersichtlicher bleibt ...

Hier der Code:



.include "4433def.inc"
.def temp = r16
.def ad_value = r17
.def ad_value0 = r18
.def ad_value1 = r19
.def ad_value2 = r20
.def count = r21

.org 0x000
rjmp init ; Initialisierung / RESET
reti ; IRQ0
reti ; IRQ1
reti ; Timer1 Capture
reti ; Timer1 Compare
reti ; Timer1 Overflow
reti ; Timer0 Overflow
reti ; SPI Complete
reti ; UART Rx
reti ; UART Data empty
reti ; UART Tx
rjmp adc_int ; ADC Conversion Complete
reti ; EEPROM ready
reti ; Analog Comparator


; ################################
; Initialisierung
; ################################

init:
; ################################
; Ports initialisieren (alle PINS INPUT - interne Pullups aktiviert)
; ################################

ldi temp, 0x00
out DDRB, temp

ldi temp, 0xFF
out PORTB, temp

ldi temp, 0x00
out DDRC, temp

ldi temp, 0xFF
out PORTC, temp

ldi temp, 0x00
out DDRD, temp

ldi temp, 0xFF
out PORTD, temp

; ################################
; Stack initialisieren
; ################################

ldi temp, RAMEND
out SP, temp

; ################################
; ADC initialisieren
; ################################

; Multiplexer setzen - PC0 ist analoger Eingang
cbi ADMUX, MUX0
cbi ADMUX, MUX1
cbi ADMUX, MUX2

; ADC Interrupt anschalten
sbi ADCSR, ADIE

; Prescaler auf 16 setzen
cbi ADCSR, ADPS0
cbi ADCSR, ADPS1
sbi ADCSR, ADPS2

; AD Converter anschalten
sbi ADCSR, ADEN

; global Interrupts aktivieren
sei

; Erste Wandlung auslösen
sbi ADCSR, ADSC

; ################################
; Hauptprogramm
; ################################

ldi count, 0x00

main:
; Hier könnte nun der ad_value umgerechnet werden und über
; UART oder LCD ausgegeben werden
rjmp main


; ################################
; ADC Interrupt
; ################################

adc_int:

; gewandelte Werte einlesen
in ad_value, ADCL
in temp, ADCH

; zweimal nach rechts rotieren (um die beiden LSB
; in das Low Register zu kriegen) -> 8 bit Wandlung
ror temp
ror ad_value
ror temp
ror ad_value

; Count abfragen
cpi count, 0x00
breq count_0
cpi count, 0x01
breq count_1
cpi count, 0x02
breq count_2


count_0:
; wenn Count = 0: count auf 1 setzen; ad_value in ad_value0 schreiben; mux auf 001 einstellen
ldi count, 0x01
mov ad_value0, ad_value
sbi ADMUX, MUX0
cbi ADMUX, MUX1
cbi ADMUX, MUX2
rjmp end

count_1:
; wenn Count = 1: count auf 2 setzen; ad_value in ad_value1 schreiben; mux auf 010 einstellen
ldi count, 0x02
mov ad_value1, ad_value
cbi ADMUX, MUX0
sbi ADMUX, MUX1
cbi ADMUX, MUX2
rjmp end

count_2:
; wenn Count = 2; count auf 0 setzen; ad_value in ad_value2 schreiben; mux auf 000 einstellen
ldi count, 0x00
mov ad_value2, ad_value
cbi ADMUX, MUX0
cbi ADMUX, MUX1
cbi ADMUX, MUX2
rjmp end

end:
; neue Wandlung starten
sbi ADCSR, ADSC

reti


Hoffe ich konnte helfen.

Viele Grüße
Flite

Florian
16.07.2004, 19:07
Hi Flite!
Also, ich habe die neuen GP2D12 endlich bekommen, sie sind angekommen! *juhuuuuuuuuuuu*
Ich habe sie jetzt nach dem Datenblatt angeschlossen, an Pin 3 Vcc, 5 V und an Pin 2 GND, GND!
Dann habe ich Pin 1 Vo an den ADC PC0 angeschlossen und mit bewährtem Code ausgewertet.
Diese Sensoren werden 100%ig funktionieren (denke ich zumindest), aber irgendwie bekomme ich kein vernünftiges Signal! :-(
Die LED-Anzeige zeigt keine/kaum Veränderung!
Sie steht bei 01101011!
Wenn ich meine Hand bei etwa 10 cm halte leuchtet die Anzeige so auf, 11101011! Nur Bit 0 leuchtet heller! :-(
Aber auch nur bei 10cm!
Sonst ändert sich nichts!
Woran kann das liegen?
Der Code funktioniert ansonsten perfekt! :-(

Kannst Du, oder wer anderes helfen?
Normalerweise soll der Sensor zwischen 0,4 und 2,8 V ausgeben!
Wenn ich jetzt Vo an mein Multimeter anschliße und dessen 2. Stecker an GND, dann stimmen die Werte!
Kann es sein, dass der Messbereich 5 V à 8bit zu groß bzw. zu klein ist?
Ich habe mal was von einem eingebauten Vref von 2,56 V gehört!
Wie kann ich den einschalten???

Ich bin jetzt eine Woche im Urlaub (ich nehme meinen Bot und die Sharps mit), aber ich werde versuchen alle paar Tage mich an den PC im Computerraum zu setzen und online zu kommen! :-)

Danke für Deine/Eure Hilfe!

Blackice2999
08.11.2004, 13:11
Hi @all,

bei einigen µC kann man auch das Bit "ADLAR" setzen welches dann das Ergebnis "Links" ausrichtet.

Vorteil man spart das 2x nach Rechtsgeschiebe
einfach nur ADCH auslesen statt ADCL & ADCH

bsp alt. (ohne ADLAR):

in xl, ADCL
in xh, ADCH

ror xh
ror xl
ror xh
ror xl

mov r16, xl

bsp neu (mit ADLAR):

in r16, ADCH

Gruß Dennis

P.S: Was ich leider auch noch nicht so richtig weis,
wie rechnet man dann mit den ganzen ergebnissen vernünftig...