PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : ADC mit ATMEGA16



surfer
15.04.2005, 11:29
Hallohallo

Ich habe nun auf den ATMEGA umgestellt. Dort gibt es ja beim ADC ein ADCL und ADCH Register. Wie muss ich die jetzt zusammenknüpfen, dass ich zu meiner 10-bit auflösung komme?

Ausserdem habe ich schon seit meinen ersten ADC Versuchen das Problem, dass 1. die Messung um 10-100 mV abweicht und 2. Starke Störschwankungen und Spannungssprünge gemessen werden (z.B. im ersten Moment wird 3.3V angezeigt, im nächsten 2.1V ???)...
Ich habe den höchsten Prescaler gewählt und arbeite mit der Vref=Vcc...

Ich hoffe ihr könnt mir helfen

PicNick
15.04.2005, 12:06
drei sachen fallen mir zum ADC ein:
1 du mußt adcl u. adch in der richtigen reihenfolge lesen
2 das Timing muß stimmen (auf Flag warten)
3 du braucht einen gewissen mindest-strom zum Messen

all das is im Datenblatt

surfer
15.04.2005, 12:44
Hallo PicNick

Das mit der Reihenfolge ist klar, nur weiss ich nicht, wie ich die beiden Register zusammen in ein Int oder Float reinstecken kann....???

Flag muss ich mal anschauen. Mindeststrom sollte ich eigentlich schon haben, da ich das Signal mit einem OP verstärke...

PicNick
15.04.2005, 12:54
Interrrupt oder Flag, daß der ADC fertig ist, weiß ich nicht auswendig.
Int/float Kommt auf deine Sprache an, und ob du rechts-oder linksbündige werte hast.
rechtsbündig:
integer = ADCH * 256 + ADCL
ODER du tust einfach über die beiden ein 16Bit Integer drüberdefinieren/casten)
(auch sprachabhängig)

Pascal
15.04.2005, 12:54
zu der Anordnung der Bits im ADCL/ADCH steht auf jeden Fall was im Datenblatt
soweit ich mich erinnere, kann man da verschiedene Sachen einstellen(ich glaube, es waren zwei Modi), zB, dass die unteren 8 Bit in ADCL stehen und die zwei anderen in ADCH (oder so ähnlich)

PicNick
15.04.2005, 12:56
Rechtsbündig wäre auch das sinnvollere.

surfer
15.04.2005, 13:05
Super!! Keine Störungen, relativ genaues Messergebnis---Danke!!!

Nur noch eine kleine Frage:
Man muss ja, um die Spannung zu bekommen die Formel Vin=(Vref*ADC)/1024 nehmen. Da könnte ja schon ein Messfehler entstehen, wenn man nicht genau weiss, wie gross Vref ist. Wenn man mal misst und dann den Werte einträgt (z.B. 5.16) stimmt es zwar, aber wenn dann mal etwas mit der Spannungsquelle nicht simmt, und Vref um ein paar mV schwankt, stimmt ja alles nicht mehr....
Wäre es da besser, die internen 2.56V zu nehmen?

PicNick
15.04.2005, 13:11
Es ist immer schwer zu messen, wenn man nicht sicher ist, wie lang das Lineal gerade ist. Wenn du vorne auch noch einen OP hast, geht das Problem weiter. Dann solltest du vielleicht den OP und die Vref zusammen hochkonstant versorgen.
Wie auch immer: EIN Bezugspunkt muß genau sein, sonst hast du Kummer

surfer
15.04.2005, 13:37
OK... Am besten 7805 als Vref... Merci

pebisoft
15.04.2005, 18:42
hallo , hier ein beispiel aus dem forum, von mir zusammengewürfelt.


#include <stdio.h>
#include <stdlib.h>
#include <avr/io.h>
#include <stdint.h>
#include <string.h>

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

uint16_t getadc(void)
{
while (ADCSRA & _BV(ADSC)) {}
return ADC;
}

int main(void)
{

uint16_t x;

ADCinit;
ADCprescaler_16;
//Aktivierung des ADC, festlegen eines Prescalers von 16

while (1)
{
ADCchannel_2;
//Aktivierung des Pins , an ihm soll die zu messende Spannung liegen

ADCstart;
//Start einer Konvertierung

x=getadc();

}
}

mfg pebisoft

( Bei längeren Code Schnipseln doch bitte den Code-Tag benutzten, MfG Kjion )

Kaiser-F
05.08.2005, 22:47
Interrrupt oder Flag, daß der ADC fertig ist, weiß ich nicht auswendig.
Int/float Kommt auf deine Sprache an, und ob du rechts-oder linksbündige werte hast.
rechtsbündig:
integer = ADCH * 256 + ADCL
ODER du tust einfach über die beiden ein 16Bit Integer drüberdefinieren/casten)
(auch sprachabhängig)

Kurze Frage,

So dürfte es ja auch gehen:

x = ADC;

anstatt

x = ADCH * 256 + ADCL;

Dann erhält man ja sofort den 10 Bit-Wert wenn ich mich nicht irre?