PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : AD-Wandler problem



Superhirn
26.12.2006, 12:06
Hallo,

Mein code funktioniert einfach nicht. er ist aus den avr-gcctutorial von mikrocontroller.net abgewandelt.
Der wert der herauskommt ist vermutlich nicht null, nicht größer null und nicht kleiner null :(
Der Code ist in 3 dateien zerlegt. Programieren tu ich mit Kontrollerlab, hab den aktuellen avr-gcc, mein avr ist ein Mega 16 mit 14,.... mhz. F_CPU wird von Kontrollerlab definiert und muss nomit nicht im programm stehen.

pinbelegung.h:

#include <avr/io.h>

void initavr(void) {

DDRD = 0xF0;
DDRB = 0xE3;

}

adc.c:

#include <avr/io.h>
#include <util/delay.h> // definiert _delay_ms()

void adcstart(void);
void adcstop(void);

void adcstart(void) {
ADCSRA |= ((1<<ADPS0) | (1<<ADPS1) | (1<<ADPS2) | (1<<ADEN));//ADPS0-2(Vorteiler 128), ADEN (Enable)
uint8_t kanal = 0;
ADMUX = kanal;
ADMUX |= (1<<REFS1) | (1<<REFS0);

ADCSRA |= (1<<ADSC); // eine ADC-Wandlung als Dummy zum warmlaufen
while ( ADCSRA & (1<<ADSC) ) {
; // auf Abschluss der Konvertierung warten
}
}

void adcstop(void) {
ADCSRA &= ~(1<<ADEN);
}

uint16_t adcget(uint8_t kanal) {
uint8_t i;
uint16_t ergebnis = 0;

ADMUX = kanal; // Kanal waehlen
ADMUX |= (1<<REFS1) | (1<<REFS0); // interne Referenzspannung nutzen

ADCSRA |= (1<<ADSC); // eine Wandlung "single conversion"
while ( ADCSRA & (1<<ADSC) ) {
; // auf Abschluss der Konvertierung warten
}

ergebnis=ADC;
return ergebnis;
}



adc_test.c (Mit main schleife):

#include <avr/io.h>
#include <util/delay.h> // definiert _delay_ms()
#include "pinbelegung.h"

uint16_t adcwert = 0;

int main(void)
{
initavr();

adcstart();
PORTB |= (1<<PB7) | (1<<PB5) | (1<<PB6);

for(;;) {
adcwert = adcget(0); // MUX-Bits auf 0b0000 -> Channel 0
//adcwert = adcget(2); // MUX-Bits auf 0b0010 -> Channel 2

if (adcwert==0) {
PORTB |= (1<<PB7);
}

else if (adcwert<0) {
PORTB |= (1<<PB5);
}
else if (adcwert>800) {
PORTB |= (1<<PB6);
}
else {
PORTB &= ~((1<<PB5) | (1<<PB6) | (1<<PB7));
}
_delay_ms(100);
}
return(0);
adcstop();
}


Frohe Weihnachten
Thomas

linux_80
26.12.2006, 12:57
Hallo,

bei Mega16 sind die ADC-Eingänge doch an PortA, ich kann da im Programm nirgends dazu etwas finden, Stichwort DDRA !

Evtl. schreibst Du auch beim auslesen des Wertes auch gleich so:
ergebnis = ADC;
denn das mit der Reihenfolge des auslesens der 16-Bit-Register ist immer so eine Sache.

Superhirn
26.12.2006, 14:06
Ich lese jetzt den wert mit ergebnis = ADC; aus. doch noch kein ergebnis.

DDRA brauch ich ja nicht als eingang zu definieren, oder? Der kanal wird ja von den mux bits festgelegt.

wenn ich bei den if schleifen abfrage, ob adcwert=0 dann leuchtet keine der leds an pb5-7, jedoch wenn ich frage adcwert >= 9 leuchtet pb7, hedoch an adcwert>0 leuchtet nichts. also müsste der wert zw. 0 und 1 liegen. soll jedoch zw. 1 und 1024 sein.

Grüße
Thomas

linux_80
26.12.2006, 15:06
Doch, Du musst auf Eingang stellen, sonst kommt nix rein an den ADC, und Du misst nur 0 oder 1, evtl. noch wenn der Pullup aktiviert ist 1023.

Superhirn
26.12.2006, 15:27
Alos jetzt hab ich DDRA = 0x00; in die initavr am anfang geschrieben. doch es hat nichts gebracht.

normalerweise ist das ja shcon auf eingang, oder? alles ist auf 0 wenns nit anders programmiert wird.

linux_80
26.12.2006, 19:35
Ja, stimmt auch wieder,
wie schaut denn deine externe Beschaltung aus ?
Wenn Du interne REF-Spannung(2,56V) hast, sollte da ein Kondensator aussen dran sein.

Evtl. liegt es aber auch an deiner If-Abfrage, Du setzt anfangs alle Ausgänge auf 1, kleiner 0 kann der Wert eigentlich nicht werden, dann sollten die Ausgänge auf 0 gehen, wenn der Wert zwischen 0 und 800 liegt :-k
Mach evtl. mal die Pause am Ende etwas länger, damit man etwas mehr Zeit hat zu sehen was da genau passiert, sonst kanns sein das es nur so ausschaut als wenn die immer an oder aus sind :-k

Aber zeig erstmal Deine Schaltung, dann schau'ma weiter.

Superhirn
26.12.2006, 20:28
Hallo,

auf http://embedit.de/content/view/47/26/ ist eine pdf mit der beschreibung.
ein kondensator ist dran.

Die zeile wo pb5-7eingeschalten werden (PORTB |= (1<<PB7) | (1<<PB5) | (1<<PB6); ) hab ich shcon rauskommentiert. das ist nicht schuld.

Spielt die reihenflger wie ich die Register setze eine rolle? wie kann ich es wenns eine rolle spielt den code so schnell wie möglich durchführen lassen (also so wenig wie möglich register setzen zu müssen pro durchlauf).

Ihrkönnt mir auch helfen wenn ihr mir funktionierenden singleconversation c code von euch wo rauskopiert den ich dann vergleichen kann.

ich habe die avr.c etwas verändert, jedoch soll dies nicht die entgültige lösung sein:

#include <avr/io.h>
#include <util/delay.h> // definiert _delay_ms()

void adcstart(void);
void adcstop(void);

void adcstart(void) {
// ADCSRA |= ((1<<ADEN) | (1<<ADPS0) | (1<<ADPS1) | (1<<ADPS2));//ADPS0-2(Vorteiler 128), ADEN (Enable)
//
// ADMUX = 0;
// ADMUX |= (1<<REFS1) | (1<<REFS0);
//
// ADCSRA |= (1<<ADSC); // eine ADC-Wandlung als Dummy zum warmlaufen
// while ( ADCSRA & (1<<ADSC) ) {
// ; // auf Abschluss der Konvertierung warten
// }
}

void adcstop(void) {
ADCSRA &= ~(1<<ADEN);
}

uint16_t adcget(uint8_t kanal) {


ADMUX = 0xC0; //0b1100 0000
ADCSRA = 0xC7; //0b1100 0111


uint16_t ergebnis = 0;

// ADMUX = kanal; // Kanal waehlen
// ADMUX |= (1<<REFS1) | (1<<REFS0); // interne Referenzspannung nutzen
// // ADCSRA |= (1<<ADEN);
// ADCSRA |= (1<<ADSC); // eine Wandlung "single conversion"
while ( ADCSRA & (1<<ADSC) ); // auf Abschluss der Konvertierung warten

ergebnis=ADC;
adcstop();
return ergebnis;
}

Was da passiert, außer dass es nicht funktioniert kann ich leider nicht mehr sagen da mein akku leer wurde.

mfg
Thomas

linux_80
26.12.2006, 21:07
Hast Du schon die Wiki Seite angeschaut:
https://www.roboternetz.de/wissen/index.php/ADC_%28Avr%29
Da ist doch ein schönes C-Beispiel drin, evtl. kann man das mit dem aktivieren des ADC und das beenden weglassen, so wie das bei Deinem Beispiel schon ist.
Den Prescaler noch richtig einstellen, schaut bei Dir auch schon gut aus mit den 128 bei 14,7456MHz.

Wie hast Du das zu messende an den AVR angeschlossen, evtl. läuft da der Strom nicht so wie Du meinst ?

Hubert.G
26.12.2006, 21:54
Habe das Programm mal gecheckt. Du musst dir das Prog wieder teilen, ich habe es zusammengefasst, die Pin verändert da bei mit dort LEDs drauf hängen und die if-Schleife geändert. Dann das mit einem Poti probiert, die drei LED laufen je nach Eingangsspannung hin und her. Ich hoffe es ist so wie du es dir vorgestellt hast.

Hubert

Superhirn
27.12.2006, 15:51
Danke an alle. Besonders Hubert. Deine Datei ging sofort.

Grüße
Thomas