PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : AD-Wandler in C mit mega32



eXe`
09.03.2005, 15:55
hi,

also gleich zu meinem problem, ich arbeite auf dem RN-Control 1.4 mit dem ATMELmega32 Chip und 2x SHARP GP2D12 Abstandmessungs Sensoren, welche ich an PORTA PA0 und PA1 angeschlossen habe. Nun sollte der AD-Wandler mir die eingehende Spannungen (zwischen) 0.4 und 2.6V in 2 Variablen (eine pro Sensor) speichern. Timer und so ist schon alles aufgesetzt, sollte also, kein problem darstellen, initialisiert hab ich ihn auch, nur weiß ich einfach nicht, wie ich den ADC ansprechen soll, da mir dazu einfach die kenntnisse fehlen, sollte jemand dort ein programmschnipsel haben, wäre ich sehr dankbar.

greez eXe`

muraad
09.03.2005, 16:22
Also hier bisschen Code mit vielen Kommentaren.
Wobei die Defines nicht die eleganteste Lösung sind. Es ist besser du
machst dir ne eigene adc_init() Funktion und setzt dort nur die Bits die du in deinem Fall brauchst.


#include <avr/io.h>

/* Analog/Digiatl konverting */
#define ADCchannel_init DDRA=0x00 // ADC Port als Eingang deklarieren
#define ADCinit ADCSRA|=(1<<ADEN) // Teilt dem Board mit das der jeweilige Port für ADC verwendet wird
#define ADCdisable ADCSRA &=~(1<<ADEN) // machs das vorherige wieder rückgänig
#define ADCstart ADCSRA|=(1<<ADSC) // startet eine konvertierung auf dem gewünschten Kannal/Pin
#define ADCfree ADCSRA|=(1<<ADATE) // schaltet den freilaufenden Modus ein
#define ADCvintern ADMUX=(1<<REFS1) | (1<<REFS0) // interne Spannungsversorgung
#define ADCinterrupt_on ADCSRA|=(1<<ADIE) // ADC interrupt wird freigeschalten
#define ADCprescaler_2 ADCSRA |=(1<<ADPS0) // gewünschter Teilungsfaktor/Prescaler
#define ADCprescaler_4 ADCSRA|=(1<<ADPS1)
#define ADCprescaler_8 ADCSRA=(1<<ADPS1) | (1<<ADPS0)
#define ADCprescaler_16 ADCSRA|=(1<<ADPS2)
#define ADCprescaler_32 ADCSRA=(1<<ADPS2) | (1<<ADPS0)
#define ADCprescaler_64 ADCSRA=(1<<ADPS2) | (1<<ADPS1)
#define ADCprescaler_128 ADCSRA=(1<<ADPS2) | (1<<ADPS1) | (1<<ADPS0)
#define ADCprescaler_reset ADCSRA = ~_BV(ADPS2) & ~_BV(ADPS1) & ~_BV(ADPS0) // setzt Prescalerbits zurück
#define ADCchannel_1 //gewünschter Kannal z.B bei ATmega32 PINA0 - PINA7
#define ADCchannel_2 ADMUX|=(1<<MUX0) // bei nicht freilaufen muss ADCchannel_x vor
#define ADCchannel_3 ADMUX|=(1<<MUX1) // ADCstart kommen dann kann man mit getadc() der
#define ADCchannel_4 ADMUX= (1<<MUX1) | (1<<MUX0) // Adcwert des gewählten Kannals auslesen
#define ADCchannel_5 ADMUX|=(1<<MUX2)
#define ADCchannel_6 ADMUX= (1<<MUX2) | (1<<MUX0)
#define ADCchannel_7 ADMUX= (1<<MUX2) | (1<<MUX1)
#define ADCchannel_8 ADMUX= (1<<MUX2) | (1<<MUX1) | (1<<MUX0)
#define ADCchannel_reset ADMUX= ~(1<<MUX2) & ~(1<<MUX1) & ~(1<<MUX0)
inline unsigned int getadc(void)
{
while (ADCSRA & (1<<ADSC)) {} // Warten bis Messung fertig
return ADC;
}

void main(void)
{
unsigned int adc_wert;
ADCchannel_init;
ADCinit; // A/D Converter aktivieren
ADCvintern;
ADCprescaler_128;
ADCchannel_1;
ADCstart; // Startet Messung an A/D Pin1 d.h. PINA0
adc_wert=getadc();
ADCchannel_reset;
ADCchannel_2; // Startet Messung an A/D Pin2
ADCstart;
adc_wert=getadc();
ADCdisable;
}

eXe`
10.03.2005, 19:45
also dann bedanke ich mich erstmals, und werd nachsehen ob ichs nun auf die reihe bekomme.

Frostie
17.04.2006, 11:20
Hallo,

ich habe den Mega8 und hab den Codschnippsel mal getestet,

aber leider kennt er den Bezeichner DDRA nicht.

Wo liegt da der Fehler?

Danke

Gruß
Matthias

linux_80
17.04.2006, 12:43
Hallo,
beim Mega 8 gibts nur Port B, C und D,
deswegen gibts auch kein DDRA !
Du musst Dir einen anderen Port aussuchen,

Die ADCs sind beim M8 auf Port C.

Frostie
17.04.2006, 15:49
Ok,

auf das bin ich dann auch noch gekommen, aber reicht es einfach diese Zeile:

#define ADCchannel_init DDRA=0x00
in
#define ADCchannel_init DDRC=0x00

zu ändern oder muß ich noch mehr ändern?

Danke

Gruß
Frostie

Kaiser-F
17.04.2006, 17:36
Hier noch zwei Funktionen...

Gehd bei ATMEGA8535, 32, 128.... und andere wo die Register passen.

Macht X Dummy-Messungen, dann aus x Messungen den Mittelwert


void ADC_init(void) {
ADCSRA = (1<<ADEN) | (1<<ADPS2) | (1<<ADPS1);
}

uint16_t ADC_wert(uint8_t mux) {
uint8_t i;
uint8_t ii;
uint16_t result;
uint16_t ergebnis;
ergebnis = 0;
// +------------ Dummy-Check ------------+
i = 5; // i x Dummy-Check
while(i){
ADMUX = mux; // Kanal waehlen
ADCSRA |= (1<<ADSC); // eine Wandlung "single conversion"
while(!(ADCSRA & (1<<ADIF))); // auf Abschluss der Konvertierung warten (ADIF-bit)
result = ADCL + (ADCH << 8); // Wandlungsergebnisse erfassen
result = 0; // Zurücksetzen
i--;
}
// +------------- Ermittlung ------------+
i = 8;
ii = i; // Schnitt aus i Ergebnissen
while(i){
ADMUX = mux; // Kanal waehlen
ADCSRA |= (1<<ADSC); // eine Wandlung "single conversion"
while(!(ADCSRA & (1<<ADIF))); // auf Abschluss der Konvertierung warten (ADIF-bit)
result = ADCL + (ADCH << 8); // Wandlungsergebnisse erfassen
ergebnis = ergebnis + result; // Aufaddieren
i--;
}
// +-------- Umrechnung & Ausgabe -------+
ergebnis = ergebnis / ii ;
return ergebnis;
}

Frostie
17.04.2006, 17:43
Hm,

ich kriegs einfach ned zum laufen. :-(

Wie kann ich herausfinden, was da für ein Wert rauskommt?

Ich hatte immer abfragen wie:

if(result > 128) ....


Probiert, aber das klappt einfach nicht.

Wenn ich ein Analoges Eingangssignal zwischen 0,5-3,0V habe, mit welchem Wert muß ich dann rechnen?

Danke
Gruß
Frostie

Kaiser-F
17.04.2006, 19:41
Hi,

Hast du den Controller min. so angeschlossen:

http://www.sir-kaiser.de/upload/ADC-connection.JPG

Der ADC muss extra mit spannung versorgt werden.


EDIT:

Der ADC liefert werte zwischen 0 und 1023.
Kommt darauf an was du an AREF angeschlossen hast.

wenn 5V, dann entspricht 5V 1023, 0V 0.

EDIT2:
bei 5V AREF:

0,5V ca. 102
3,0V ca. 614

linux_80
17.04.2006, 21:31
@Kaiser-F
das ist aber ein SMD M32, nicht das da einer mit den Pins durcheinander kommt !

der Frostie wollte doch einen M8 verwenden, aber die Pins heissen zumindest genauso.

SprinterSB
17.04.2006, 22:05
result = ADCL + (ADCH << 8);
Das sollte auf jeden Fall ersetzt werden durch

result = ADC; !!!

Frostie
17.04.2006, 22:29
Was ich nicht ganz verstehe ist,

das der ADC extra mit Spannung versorgt werden soll, was heißt das??

Ich habe den einen Sensor an PC0 angeschlossen, da kommen auch die 0,5 bis 3,0 V an.

Welchen Port, oder Anschuß soll ich jetzt noch mit Spannung beschalten??

Danke
Frostie

SprinterSB
17.04.2006, 22:48
AVRs haben extra Spannungsversoge für den ADC, idR heissen die AVCC. Sinn und Zweck davon ist, diese Spannung gegen VCC zu entkoppeln und so die Messgenauigkeit zu erhöhen, weil auf VCC oft ein Ripple liegt.