Sida 1 av 2

AVR ADC, typ av värde på input från potentiometer

Postat: 19 oktober 2010, 21:53:56
av toffie
Hej på er,
Har klurat på detta i ett par dagar, men kommer inte fram till någon "lösning" eller svar på mina funderingar..

Sitter och klurar på vad det egentligen är jag får in på ADC pinnen på min AVR från en potentiometer.
Hårdvarumässigt så är det ju en spänning som går in, sen gör ju ADC delen om detta till ett digitalt värde,
men vad är det egentligen detta digitala värde står för?

Jag har kopplat 5V på ena delen av potten, GND på andra och i mitten finns ju såklart referenspinnen.
Mellan referenspinnen och jord har jag satt en 100nF kondensator, över 5V och GND har jag vardera satt ett
330 ohm motstånd för att se till så ingen av ändpunkterna på potentiometern gör kortslutning..

När jag sedan läser in värdena, har tre potentiometrar kopplade på detta sätt till ADC0, ADC1 samt ADC2,
så får jag in ett värde på mellan ~32 och ~990. Skulle jag inte haft motstånden skulle det väl varit något
annorlunda värden, men frågan är vad står egentligen dessa värden för?

Är det rakt upp och ner ett Volt referensvärde? Som med viss matte kan göras om till det riktiga Volt värdet?
Eller är det kanske ett värde mellan 0 och 1000 baserat på det riktiga Volt värdet eller är det för vad ADC "utrymmet" klarar?

Slutligen undrar jag vad som är bäst att använda? Det värdet mellan ~32 och ~990 eller göra om det till mer
"användarvänligt" 0-100, med andra ord procent.

Jag har två användarområden som jag behöver täcka, dock inte i samma projekt.
Det ena är just 0-100, för volymkontroll och liknande kontroller där 0-100 skulle passa rätt bra.
Det andra är att kontrollera ett servo i slutändan, ADC sitter på en sändare och tar emot värdena från pot och
sedan skickas det till en mottagare trådlöst som i sin tur gör verklighet av värdet och kontrollerar ett servo.
Kanske man kan göra om det till 0-254 också?

Vilket tycker ni skulle vara bäst?
Och framförallt, hur skulle man kunna omvandla (med matte? / direkt i ADC avläsningen?) till antingen 0-100 eller 0-254?
Eller skulle ni helt enkelt använda 32-990, det är väl "större" upplösning i det värdet än i exempelvis 0-100?

Jag har klippt ut den aktuella koden för att läsa av ADC och för att presentera på en LCD. Det ända som egentligen skiljer
är att den kod som ligger i processorn är interrupt-baserad istället för loop-baserad som följande kod är, men det ändrar ju
inte själva värdet från ADCn ;)

Kod: Markera allt

int main(void)
{
    ADMUX = (1 << REFS0);  // External Aref (5V)
    ADCSRA |= (1 << ADPS2) | (1 << ADPS1) | (1 << ADPS0) | (1 << ADIE); // ADC prescaler
    ADCSRA |= (1 << ADEN); // Enable ADC
    
    while(1)
    {
        potvalue = readADC(0); // Read value from ADC, specify channel
        LCD_W(potvalue); // Write to LCD
        _delay_ms(100);
    }
}

static uint16_t readADC(uint8_t channel)
{
    ADMUX &= ~0x1F;   // Clear channel selection
    ADMUX |= channel; // Specify channel

    ADCSRA |= (1 << ADSC); // Start conversion
    while (bit_is_set(ADCSRA, ADSC)); // Wait for conversion complete

    return ADC; // Return ADC value
}

Re: AVR ADC, typ av värde på input från potentiometer

Postat: 19 oktober 2010, 22:20:49
av PHermansson
Förstår inte poängen med motstånden, de brukar man inte ha?
Troligen har du en 10-bitars Adc. 10 binära bitar motsvarar 1024 decimala värden. Adc'n har alltså en upplösning på 1024 bitar, du kan som bäst få en noggrannhet på 1/1024-del av referensspänningen. Denna spänning, Vref, anges vid konfigureringen och kan vara matningsspänningen eller en egendefinierad spänning.
Om du har Vcc=Vref och Vcc=5 volt så är varje Adc-bit värd 5/1024 = 0,0049 volt (avrundat). Läser du tex av värdet 32 är spänningen på Adc'n 32*0,0049= 0,1568 volt.

Re: AVR ADC, typ av värde på input från potentiometer

Postat: 19 oktober 2010, 22:32:55
av toffie
Glömde skriva vilken AVR jag använde, men ja det stämmer 10-bit ADC på min Atmega32 :)
Referensspänningen är matningsspänningen på 5V på min STK500.

Anledningen till motstånden är att jag sett väldigt många exempel på en just sådan koppling;
Bild
Har väl visserligen sett lika många exempel helt utan motstånd, men har för mig att jag läst både här på forumet och andra
sajter om att man kan/bör ha motstånd för att inte kortsluta mellan 5V och GND på något sätt vid ändlägena.

Okej så det är alltså så man räknar ut ADC värdet till volt, mycket informativt!
Många tack för den infon! :)

Har du för övrigt några tankar på omvandlingen till 0-100 / 0-254 eller så för vidare användning?
Och inte göra det till en voltmeter alltså ;)


En annan fråga jag kom på, värdena är ofattbart stabila, långt mycket bättre än innan jag satte 100nF mellan referenspinnen
och GND på potentiometern.. Dock så får jag "lite" ostabilitet vid vissa positioner.. det pendlar bara mellan 1 värde upp/ner
så det är inte helt världen.. men hur skulle man kunna stabilisera det ännu mer? Går det ens?

Det är ju som sagt min STK500 som jag kör på, så det finns ju inga filter alls vid MCUn som induktanser eller kondensatorer..
Så bara genom att sätta någon induktans och fler kondensatorer direkt vid MCUn på ett labbkort borde väl göra det hela mer
eller mindre perfekt?

Re: AVR ADC, typ av värde på input från potentiometer

Postat: 19 oktober 2010, 22:54:03
av Borre
Potentiometern kortsluter aldrig 5V och jord i detta fall, den har ju 10K ohm mellan de yttre pinnarna oavsett läge på potentiometern. Att 5V eller jord ansluts direkt till ADCn, i ändlägena på potentiometern, gör inget.

Re: AVR ADC, typ av värde på input från potentiometer

Postat: 19 oktober 2010, 23:06:27
av Icecap
Att omvandla värden mellan 0 och 1023 till ett tal mellan 0 och 100 är faktisk synnerligt enkelt:

Ta råvärdet, multiplicera med 100 och dela med 1023.

Effekten av detta blir en delning med 10,23.

Re: AVR ADC, typ av värde på input från potentiometer

Postat: 19 oktober 2010, 23:28:58
av toffie
Borre
Ok, måste vara att jag tänkt fel någonstans ;)

Icecap
Okej det låter ju lätt, har ju inte direkt gått matte E ;) hehe.. Jag vet, det är enkel matte, men kom bara inte på det ;)
Så, jag provade att göra så som du sa;

Kod: Markera allt

((readADC(0)*100)/1023);
Värdet börjar fortfarande på 3, men det gör ju inte så mycket till en början.. Men däremot så när man skruvar på potten
så går det först upp till 65, sen till 000 igen och sedan upp till 33..

Läser jag värdet fel eller är uträkningen fel?

Edit
Oh såg nu, provade att dra ner till uint8 men det blev ju knasigare, så provade uint32 bara för skojs skull..
Nu får jag 3-99 vilket är mer eller mindre någorlunda lagom perfekt.. :D

Däremot, är verkligen en uint32 bra för detta? Den tar väl lite väl stor plats, eller?
Enligt kompilatorn blev det 126 bytes mer.. hmmm..


Sen såg jag att ADC2, dvs den tredje potentiometern, ger bara ut 3-96.. Är det en dålig pot måhända eller kan det bli sämre
värden ju fler jag slänger på ADC porten? Borde väl inte kunna bli sämre värden bara för att det är fler pottar att läsa av?

Re: AVR ADC, typ av värde på input från potentiometer

Postat: 20 oktober 2010, 00:11:27
av Icecap
Jag skrev ingenstans att du skulle göra så eller hur?

Jag skrev:
U_INT X;
X = readADC(0) * 100;
X /= 1023;

Jag har taskig erfarenhet med att låta kompilern "rensa" sådana uträkningar, därför tar jag dom alltid i två steg.

Då det är 2 konstanter vill den gärna ändra lite på det hela och då blir det inte rätt.

Re: AVR ADC, typ av värde på input från potentiometer

Postat: 20 oktober 2010, 00:13:17
av sneaky
Har du tagit bort motstånden? De begränsar ju max- och min-värdet.

Re: AVR ADC, typ av värde på input från potentiometer

Postat: 20 oktober 2010, 00:45:04
av toffie
Icecap skrev:Jag skrev ingenstans att du skulle göra så eller hur?

Jag skrev:
U_INT X;
X = readADC(0) * 100;
X /= 1023;
Du skrev faktiskt; ;)
Icecap skrev:Ta råvärdet, multiplicera med 100 och dela med 1023.
Sen att jag inte vet hur kompilator och MCU vill att det ska vara strukturerat är en helt annan sak ;)
Att jag sedan glömde skriva med ovan att det skulle vara till integer ADCvalue är en annan sak.

I min kod använde jag således denna kod, sorry för att jag glömde en liten bit ;)

Kod: Markera allt

ADCvalue = ((readADC(0)*100)/1023);
Hur som helst, jag provade att separera det på tre rader enligt följande;

Kod: Markera allt

ADCvalue = readADC(0) * 100;
ADCvalue /= 1023;
Kodsnutten "uint8_t ADCvalue;" har jag längre upp i min kod, förmodar att det var det du menade med "U_INT X;"?

När jag kör denna kod så får jag istället 000 på displayen och värdet ändras inte vid ändring på potentiometern.

Va sjukt, nu när jag bara provade att skriva det igen efter lite ändringar, allt på en rad..

Kod: Markera allt

ADCvalue = ((readADC(0)*100)/1023);
Nu fungerar det hela vägen från 3 till 96, på samtliga tre potentiometrar som jag har inkopplade..!?!? :humm:
Den går alltså inte längre från 65 till 00 utan vidare upp till 96..

Va förvånad jag blev.. :humm:

Hur som helst, men du rekommenderar inte att göra så Icecap?

sneaky
Nope, inte tagit bort motstånden än, men det gav ju olika topp-värden på potentiometrarna förut, vilket det inte gör nu!?
Helmysko att alla tre ger samma värden nu, men det kanske beror på 1% eller 5% skillnaden vad det nu är som de kan fluktuera i?


För övrigt så är värdena helt solida nu, de fladdrar absolut ingenting och jag har inte ändrat på hårdvaran överhuvudtaget.
Men va glad jag blir dock, det är ju precis som jag vill ha det nu, vilket underbart slut på denna dag, kan man gå och lägga
sig nöjd och sova gott (drömma om allt man ska programmera imorrn :roll: :D)

Edit..
Just ja, hade ju ändrat till uint32_t, därför den gick från 3-96 .. inte för att beräkningen blev annorlunda ;)
Men, ska jag köra med uint32_t eller finns det någon annan lösning på just den biten?

Re: AVR ADC, typ av värde på input från potentiometer

Postat: 20 oktober 2010, 01:23:17
av makan1975
Är det inte motstånden som begränsar spänningen så att du inte får värden mellan 0-100?
0,16V kommer väl att ligga över 330Ohm Cirka 3%..

Re: AVR ADC, typ av värde på input från potentiometer

Postat: 20 oktober 2010, 07:05:30
av PHermansson
toffie skrev: Har du för övrigt några tankar på omvandlingen till 0-100 / 0-254 eller så för vidare användning?
Och inte göra det till en voltmeter alltså ;)
Det beror ju på vad man vill göra. En konstruktion jag byggt har en linjär temperaturgivare på en Ad-ingång, en potentiometer på en annan. Man ställer in gränsvärdet med potentiometern, och när temperaturen går över detta värdet (givarens utgång går över en viss spänning) dras en fläkt igång av en av processorns utgångar. I det fallet omvandlas inte Ad-värdet, det är bara en enkel "if ad-value1 > ad-value2"-funktion. Detta kan förvisso göras enkelt utan processor, men man kan ju göra det mer avancerat med tex en ljussensor som hindrar fläkten från att gå när det är mörkt och även bestämma exakt hur länge fläkten ska gå när den väl har startat.

Re: AVR ADC, typ av värde på input från potentiometer

Postat: 20 oktober 2010, 07:33:01
av Icecap
toffie: hur får du 0-1023 att passa i en byte?

Når du använder u_int8t är det ju en byte eller hur? Där vill du sedan lägga in ett 10 bit värde...

Så nej, det ska vara u_int16 för ADC-råvärde och när du har multiplicerat det med 100 kan det bli upp till 102300 vilket tar 17 bit i anspråk, alltså måste du ta närmsta högre storlek variabel som är unsigned long.

unsigned long X:
X = read_ADC(0); // Nu är det passat in i ett 32 bitars variabel
X *= 100; // Först multiplicera
X /= 1023; // Sedan dela
och DÅ är X det värde du vill ha och kan passas i en byte.

Re: AVR ADC, typ av värde på input från potentiometer

Postat: 20 oktober 2010, 09:43:45
av Nerre
OM du ska ha ett skyddsmotstånd (för att t.ex. skydda om porten råkar bli ställd som utgång) så ska det sitta i serie med potens löpare (mellan poten och A/D-ingången alltså). Eftersom ingången normalt inte drar nån ström att tala om kommer spänningsfallet över det motståndet att bli i princip noll.

Re: AVR ADC, typ av värde på input från potentiometer

Postat: 20 oktober 2010, 10:05:20
av Icecap
Kom ihåg att ha en kondensator mellan AD-ingången och GND, en 10nF-100nF keramisk är synnerligt bra. De flesta AD-omvandlare i µC har en kapacitiv omvandlingsstege vilket ger en kapacitiv belastning på ingången under sample-and-hold fasen vilket kondensatorn hjälper på.

Och ja, jag inser att t.o.m. jag hade fel värde (U_INT16) på första delen jag skrev, man måste alltså ha en 32 bit variabel att räkna i.

Re: AVR ADC, typ av värde på input från potentiometer

Postat: 20 oktober 2010, 10:08:58
av bearing
Ett annat sätt att omvandla till 0-100 är att:
*multiplicera med 25
*addera 128 (för avrundning, dvs att ett värde som motsvarar t.ex. 19,6 blir 20 och inte 19)
*shifta höger 8 steg
Då behövs inte några 32-bitars operationer, och inte någon division, så det borde gå snabbt och inte ta upp så stort kodutrymme.

Kod: Markera allt

u_int16 ADCvalue;
ADCvalue = readADC(0);
ADCvalue *= 25;
ADCvalue += 128;
ADCvalue >>=8;

Man kan också använda ett medelvärde på 25 samplingar:

Kod: Markera allt

u_int16 ADCvalue=0;
u_int8 i;

for (i=0;i<25;i++)
    ADCvalue += readADC(0);
ADCvalue += 128;
ADCvalue >>=8;
EDIT: fixade ett feltänk angående avrundningen