Dag Hobbyisten,
Ik kom er niet uit hoe ik in een Atmega32 moet instellen zodat ik een externe spanning kan gebruiken als referentie van de ADC. In de datasheet hebben ze het over een externe condensator op de AREF pin maar niet over een externe spanning op de AREF pin. Weten jullie hoe dit zit?
Datasheet:
VREF can be selected as either AVCC, internal 2.56V reference, or external AREF pin.
REFS1 REFS0 Voltage Reference Selection
0 0 AREF, Internal Vref turned off
0 1 AVCC with external capacitor at AREF pin
1 0 Reserved
1 1 Internal 2.56V Voltage Reference with external capacitor at AREF pin
Dan heb ik nog een ander probleem. Ik zet de 10bits waarde van de ADC op een LCD scherm als getal van 0 tot 1024. Alleen stapt de waarde niet per bit maar met meerdere bits tegelijk ook als ik de spanning heel langzaam hoger maak. 7,14,15,17,24,28, 31
Hoe kan dit?
Bedankt!
Als je het ADMUX register instelt als 0x00 maak je gebruik van de AREF pin.
de eerste twee bits zijn voor deze instelling. De bits die erna komen zijn om met de multiplexer de gewenste adc ingang op je poort te kiezen en deze naar de ADC te verbinden.
Daarna zou ik nog eens proberen hoe het zit met het stappen van je ADC, er zit ergens een instelling voor left of right adjusten van de bits, misschien moet je hier eens naar kijken. Lees je ADCH en ADCL ook op de juiste volgorde uit?
rew
four NANDS do make a NOR . Kijk ook eens in onze shop: http://www.bitwizard.nl/shop/
Ja, die stappen doet hij hier ook. Hij heeft echt een behoorlijke neiging om de onderste drie bits (ongeveer) hetzelfde te maken.... Minder ruis. schijnt te helpen. Dus: AGND en DGND scheiden. AVCC netjes ontkoppelen, en ook je analoge signaal netjes stabiel houden tijdens de AD conversie. Eventueel de rest van de CPU stoppen tijdens de conversie.
Op 28 mei 2008 15:36:38 schreef marcel c:
Lees je ADCH en ADCL ook op de juiste volgorde uit?
Het probleem zit hem niet in de volgorde van uitlezen van ADCH en ADCL. Ik pak nu de waarde rechtstreeks uit ADCL ( de 8 LSB bits). Ook dan is de stapgrootte meerdere bits tegelijk. Ik snap niet hoe dat kan.
Op 28 mei 2008 17:53:43 schreef rew:
Minder ruis. schijnt te helpen. Dus: AGND en DGND scheiden. AVCC netjes ontkoppelen, en ook je analoge signaal netjes stabiel houden tijdens de AD conversie.
Mijn voeding is heel stabiel en alles is ontkoppeld. Ik heb het ook in mijn STK500 getest maar ook daar is de stapgrootte meerdere bits tegelijk.
Hoe moet ik de AGND en de DGND scheiden? Ik heb alleen maar een LCD, Atmega32 en een potmeter aangesloten. De controller zelf houd theoretisch het analoge signaal stabiel tijdens een conversie dacht ik maar hoe kan ik dat zelf doen?
Ik snap echt niet waarom die stapgrootte van de ADC meerdere bits tegelijk is. Of is de kwaliteit van een ADC in een controller gewoon slecht?
Dag mensen,
Ik zit kan er maar niet achter komen waarom de ADC van mijn Atmega32 niet per stapje op/afloopt. Hij slaat soms gewoon 5 bits over.
Ik heb een code in C geschreven en in Assembler maar beide met het zelfde resultaat. Ik heb het ook met de ADC van de Atmega8 geprobeerd maar ook dan wekt de ADC niet zoals die zou moeten.
Heeft iemand hier ervaring mee? Wat gaat er verkeerd?
het wordt duidelijker als je een vraag tegelijk aanpakt.
Ik heb hiervoor een overzicht tabel gemaakt van de registers en wat de bits doen.
dan heb ik de taken benoemd die uitgevoerd moeten worden.
het weergeven op 8 bits led.
Arco
Special Member
Arco - "Simplicity is a prerequisite for reliability" - hard-, firm-, en software ontwikkeling: www.arcovox.com
Gebruik je nu wel een stabiele gescheiden spanning voor de analoge voeding? Op de digitale voeding kan makkelijk 10...20mV storing zitten wat bij 5 volt vol bereik al een +/- verschilwaarde van 2...5 geeft...
Beste een ook RF kraaltje tussen analoge voeding zetten...
[Bericht gewijzigd door Arco op (13%)]
pros
Prosper, yop la boum, c'est le roi du macadam (aldus Maurice Chevalier)
@gijsbert: als de ADC van je ATmega32 stapjes overslaat, kan je je afvragen of de ingangsspanning niet met sprongen verloopt. Hier enkele meetwaarden:
U in mV ADC
13 1
17 2
22 3
26 4
31 5
36 6
42 7
45 8
52 9
57 10
1000 202
1006 203
1009 204
1014 205
1020 206
2000 407
2007 408
2012 409
Dat is "met de gauwte" gedaan. Eigenlijk zou je voor elke ADC-stap zowel de onderste spanningsdrempel als de bovenste moeten bepalen, en daarvan het gemiddelde berekenen. Dan zal de gelijkloop veel beter zijn.
Maar mijn doel was enkel, aan te tonen dat de ADC wel degelijk stap-per-stap verhoogt bij een stijgende ingangsspanning.
Scheef_schaap
't schaap is de preut af, meestal vooralleer het spel hespe is! (of in het AN: Meestal zal het eerst mislukken voor alleer het lukt..)
Jeroen Boere
IF you can't convince them, then confuse them!
Op 31 mei 2008 11:09:01 schreef Scheef_schaap:
Der was ne keer ne vis en die ging naar den dokter.
Zijn diagnose? Uit de kom!
?
Ik krijg het nog steeds niet voor elkaar om de ADC stap voor stap te laten tellen. Als voeding gebruik ik nu batterijen.
Op 31 mei 2008 10:40:03 schreef pros:
Maar mijn doel was enkel, aan te tonen dat de ADC wel degelijk stap-per-stap verhoogt bij een stijgende ingangsspanning.
Dat probeer ik ook steeds maar het lukt me niet. Welke code gebruik jij? Ik deze.
/*
27 mei 2008 Atmega32 8MHz extern
Accelerometer project
PORTC = leds
ADC0 = potmeter
*/
#include <avr/io.h>
void Init(void)
{
DDRA = 0x00; //input
DDRB = 0xFF; //output
DDRC = 0xFF; //output
DDRD = 0xFF; //output
ADMUX = (1<<REFS0)|(0<<ADLAR)|(0<<MUX0); //IntRefVCC-Links-ADC0
ADCSRA = (1<<ADEN)|(1<<ADSC)|(1<<ADATE); //ADC Aan, start, auto conversie
}
void ms(int q)
{
int j, i;
for (i = 0; i < q; i++) {
for( j=0; j<5260; j++);//0.01ms 1Mhz//526
}
}
//***************************** main *********************
int main(void)
{
Init();
for(;;)
{
int i,x;
int a = 10;
ms(a);
x = ADCL;
i = ADCH;
PORTC = x;
}
}Of zit er een fout in mijn code?
pros
Prosper, yop la boum, c'est le roi du macadam (aldus Maurice Chevalier)
Wat is de bedoeling van
ADMUX = (1<<REFS0)|(0<<ADLAR)|(0<<MUX0); //IntRefVCC-Links-ADC0
"(0<<ADLAR)" en " (0<<MUX0)" geven beiden 0 als resultaat. Dat wordt dus vertaald naar
ADMUX = (1<<REFS0);
Dat is niet echt een fout --je leest ADC0 uit met Vcc als referentiespanning-- maar het is misschien niet wat je verwacht.
Verder zou ik --zeker bij een systeemklok van 8MHz-- zeker de prescaler inschakelen. Anders ga je nooit een betrouwbare conversie bekomen.
Zo, bv:
ADCSRA = (1<<ADEN) | (1<<ADSC) | (1<<ADATE) | (1<<ADPS0) | (1<<ADPS1) | (1<<ADPS2);
Dan die potmeter. Bedenk wel, dat 1 ADC-stap ongeveer overeenkomt met 5mV (5000 / 1024). Met een voorzichtige hand en een 10-slags potmeter valt dat wel in te stellen, maar met een doorsnee-potmeter zal de minste beweging van de as een spanningsvariatie opleveren die een veelvoud van 5mV is.
Ik heb er mijn labvoeding voor gebruikt. Met een stel toetsen kan ik de uitgangsspanning daarvan met stapjes van 1mV omhoog of omlaag laten gaan.
Misschien nog even de code posten, die ik gebruikt heb:
#define F_CPU 14745600UL
#include <avr/io.h>
#include <util/delay.h>
#define uart_sendchar(x) loop_until_bit_is_set(UCSRA, UDRE);\
UDR = x
void delay_ms(unsigned int ms)
{
for (; ms > 0; ms--) {
_delay_ms(0.998);
}
}
// Verstuur een unsigned int als ascii-string over de RS232-lijn
void dec2RS232(unsigned int getal)
{
unsigned int tmp, deeltal = 10000;
char cnt;
for (cnt = 5; cnt > 0; cnt--) {
tmp = 0;
while (deeltal <= getal) {
tmp++;
getal -= deeltal; // decade berekenen
}
uart_sendchar(tmp + '0'); // ascii-teken verzenden
deeltal /= 10; // deeltal aanpassen voor volgende decade
}
}
int main(void)
{
// Initialiseer ADC
ADCSRA = _BV(ADEN) | _BV(ADPS2) | _BV(ADPS1) | _BV(ADPS0);
ADMUX = _BV(REFS0) | 1; // ADC0 ref=Vcc
ADCSRA |= _BV(ADSC); // start dummy conversion
// Initialiseer UART
UCSRA = 0x00;
UCSRB = _BV(TXEN); // enable tx
UCSRC = _BV(URSEL) | _BV(USBS) | _BV(UCSZ1) | _BV(UCSZ0); // Frame format: 8N1
UBRRH = 0;
UBRRL = (F_CPU / (16 * 38400UL)) - 1; // set baudrate - 38400bd
delay_ms(2000);
while (1) {
ADCSRA |= _BV(ADSC); // start conversion
while (bit_is_set(ADCSRA, ADSC)) { // Effe wachten
}
dec2RS232(ADC);
uart_sendchar('\n');
delay_ms(1000);
}
}
Deze doet elke seconde een meting, en stuurt het resultaat via de UART (en een MAX232) naar de PC.
Op 2 juni 2008 10:10:18 schreef pros:
ADMUX = (1<<REFS0);
Dat bedoel ik maar ik zet die andere bits erbij dat is makkelijker met experimenteren.
Op 2 juni 2008 10:10:18 schreef pros:
Verder zou ik --zeker bij een systeemklok van 8MHz-- zeker de prescaler inschakelen. Anders ga je nooit een betrouwbare conversie bekomen.
Zo, bv:ADCSRA = (1<<ADEN) | (1<<ADSC) | (1<<ADATE) | (1<<ADPS0) | (1<<ADPS1) | (1<<ADPS2);
Dat werkt inderdaad veel beter! Bedankt zeg. Het getal schommelt nog wel een beetje maar wel met stapjes van een bit. Zou je ook kunnen uitleggen waarom het resultaat zoveel beter is met die prescaler?
pros
Prosper, yop la boum, c'est le roi du macadam (aldus Maurice Chevalier)
De ADC werkt maar goed met een clk-frequentie tussen 50kHz en 200kHz. Dat staat vermeld in de datasheet. Maar ik moet meteen toegeven, dat ik die nog steeds niet volledig heb uitgelezen... 