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

PIC, AVR, Arduino, Raspberry Pi, Basic Stamp, PLC mm.
Användarvisningsbild
Icecap
Inlägg: 26658
Blev medlem: 10 januari 2005, 14:52:15
Ort: Starup (Haderslev), Danmark

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

Inlägg av Icecap »

Helt rätt, är det fasta värden man ska skala et värde med kan det definitivt löna sig att kolla lite på det hela men likaväl är det fel till att börja med att använda en 8-bit variabel till att lägga ett 10-bit värde i...
Användarvisningsbild
jesse
Inlägg: 9240
Blev medlem: 10 september 2007, 12:03:55
Ort: Alingsås

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

Inlägg av jesse »

Om du får ett värde på t.ex. 1023 och multiplicerar med 100 så blir det 102300. Men ett uint16_t rymmer bara tal upp till 65535. Men när du sedan delar det stora talet med 1024 så får det plats i en uint8_t (som rymmer tal mellan 0 och 255) : 102300/1024 = 99.

Du kan alltså klara dig med en 8-bitars variabel för att lagra resultatet i form av procent.

För att kunna utföra beräkningen krävs däremot att ett mellanresultat (102300) lagras som 32-bitars. Då gör du så här:

Kod: Markera allt

uint16_t adc_value; // 0-1023
uint8_t procent  // 0-99
...
procent = (uint8_t)( ((uint32_t)adc_value*100)/1024);
detta betyder: Du omvandlar "adc_value" till 32-bitars och multiplicerar med 100. Sedan divideras detta 32-bitars värde med 1024. Svaret omvandlas till 8-bitars och stoppas in i "procent".

Kondensatorn är bara bra - den fungerar som lågpassfilter - dvs tar bort brus i signalen - den försämrar inte noggrannheten om man inte ska mäta snabba signaler. Angående den "inbyggda" kapacitansen i en ADC: Den ligger ofta på några få pF, och laddas upp med insignalen vid varje omvandling och kan laddas ur däremellan. Dessa upprepade i- och ur-laddningar kan påverka inspänningen om resistansen på ingången är för hög. En extern kondensator påverkar inte detta.
Användarvisningsbild
toffie
Inlägg: 1888
Blev medlem: 22 juli 2004, 21:38:07
Ort: Töreboda / Stockholm
Kontakt:

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

Inlägg av toffie »

makan1975 skrev:Ä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%..
Jodå, det stämmer och det skrev jag att jag förstod i mitt förra inlägg. Det jag blev konfunderad över är att pot 1 och 2
gick från 3-96 medan pot 3 gick från 3-94.. Min undran var varför tredje inte fick samma värden när alla var inkopplade likadant.

Nu när jag tagit bort motstånden så fungerar det givetvis helt perfekt, 0-100 (på mindre än 1 sekund, det ni ;))

PHermansson
Intressant projekt, har inte du skrivit någon tråd om detta? Känner igen det, men kanske någon annan som skrivit om liknande.. :humm:

Icecap skrev: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.
Icecap, nu ger jag dig rätt för det där fungerar precis som min kod gjorde inatt innan jag gick och la mig.

Följande kod

Kod: Markera allt

uint8_t ADCvalue;
...
static uint32_t readADC(uint8_t channel)
{
    ...
}
...
ADCvalue = ((readADC(0)*100)/1023);
Ger exakt som denna, enligt mina tester..

Kod: Markera allt

unsigned long ADCvalue;
...
static uint16_t readADC(uint8_t channel)
{
    ...
}
...
ADCvalue = readADC(0);
ADCvalue *= 100;
ADCvalue /= 1023;
Nerre
Ok, då ska jag lägga det på minnet (skriva ner det) så jag designar det så i fortsättningen. Tackar! :)

Icecap skrev:Kom ihåg att ha en kondensator mellan AD-ingången och GND, en 10nF-100nF keramisk är synnerligt bra.
Jodå det har jag redan, som jag skrev i min första post, däremot så fanns inte det med på bilden jag la in senare, men
det är inte jag som gjort den utan hittade bara en på Google som liknande alla de som jag sett..
Men en konding mellan referens och GND har jag :) Dock inte precis vid uC som de bör sitta, men nu är det bara utveckling / test ;)

bearing
Tack för den informationen! Det där är verkligen något jag inte skulle kunna komma på själv :P
Finns det någon speciell anledning att räkna ut det på detta sätt? Finns det någon gång då man inte kan eller får använda en uint32?

jesse
Tackar! Ska ta och prova den varianten också, se vad som tar "minst" plats i programminnet :D


Jag måste säga att jag verkligen uppskattar all hjälp jag fått i denna tråd, ni ska ha jättetack! :)
Nerre
Inlägg: 27257
Blev medlem: 19 maj 2008, 07:51:04
Ort: Upplands väsby

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

Inlägg av Nerre »

Att det skiljde mellan kanalerna beror väl på att motstånden inte är exakta. De har väl antagligen en tolerans på +/- 10%.(Även potarna skiljer sig antagligen åt, men det märks ju inte lika mycket.)
bearing
Inlägg: 11676
Blev medlem: 2 mars 2006, 01:01:45
Ort: Ängelholm

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

Inlägg av bearing »

toffie skrev: bearing
Tack för den informationen! Det där är verkligen något jag inte skulle kunna komma på själv :P
Finns det någon speciell anledning att räkna ut det på detta sätt? Finns det någon gång då man inte kan eller får använda en uint32?
Ifall man gör ett program som ska kunna göra många beräkningar på kort tid, eller har ont om minne, kan man behöva skriva om beräkningar (och annan kod för den delen) så att de görs på kort tid/med få instruktioner.

Eftersom att microcontrollern jobbar med 8-bitars tal kommer hantering av 16-bitarstal ta ungefär dubbelt så lång tid och dubbelt så mycket plats i både RAM- och FLASH-minnen (minst). 32-bitarstal tar således ungefär fyra gånger så mycket resurser (minst).

Division är något som tar väldigt lång tid för en sån här microcontroller, vilket beror på att den inte har någon instruktion för division. Programmet använder därför en algoritm som liknar "liggande stolen" för att dividera. Addition av två 8-bitars tal tar bara 1 instruktion och 1 klockcykel att utföra. Division av två 8-bitarstal tar nog runt 20 instruktioner och kanske 50 klockcykler. Det blir värre med 32-bitars tal. Addition tar ca 4 instruktioner. Division av två 32-bitarstal tar flera hundra, kanske närmare tusen klockcykler. Shiftning tar dock bara en, eller några få instruktioner och klockcykler. Därför är det bra att skriva algoritmer som dividerar med jämna multiplar av 2 (tal som: 4, 8, 64, 512 o.dyl.) vilket översätts av kompilatorn till skiftningar, och inte anrop till divisionsfunktioner.
Användarvisningsbild
jesse
Inlägg: 9240
Blev medlem: 10 september 2007, 12:03:55
Ort: Alingsås

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

Inlägg av jesse »

Det är värt att tänka på det där med division. Särskilt om man måste utföra det i 32-bitar. Det tar mycket programminne.
När jag gör en sån här sak så frågar jag mig: vad är viktigt för att kunna använda resultatet? Om man ska presentera det på en display som ett värde mellan 0 och 99 så är den metoden bra (dvs *100/1024), men annars kan det vara smartare att tex använda ett värde mellan 0 och 255 istället - då behöver man bara shifta det inlästa värdet två bitar åt höger : det går supersnabbt!

Kod: Markera allt

uint8_t  ADCvalue;

ADCvalue = (readADC(0) >> 2);
Användarvisningsbild
toffie
Inlägg: 1888
Blev medlem: 22 juli 2004, 21:38:07
Ort: Töreboda / Stockholm
Kontakt:

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

Inlägg av toffie »

Det är ju klart som ni båda säger, ska man göra många beräkningar och även snabbt så kan ju större integers och jobbiga
uträkningar göra så man tappar prestanda..

bearing
Visste inte heller att det tog mycket kraft för divisioner, det är ju lite synd att division inte finns inbyggd med
en riktigt optimerad teknik, som det verkar vara för multiplikation osv?

jesse
Genom att göra om till uint8_t igen och göra en högerskiftning så minskade jag själva programmet med 250 bytes!?! :happy:
Kanske inte så mycket när hela programmet än så länge ligger på 966 bytes efter bytet och man har 32K att tillgå..
Men förhoppningsvis kan man ju nu tänka sig att jag lyckats lära mig något väldigt bra, tack vare er :D

Denna är till er :tårta: ;)

En annan fråga, går det att se i AVRStudio tillsammans med STK500 hur många cykler som jag faktiskt använder?
Typ som en aktivitetshanterare som kan visa i procent hur mycket processorn arbetar.. Eller är det sådant man behöver
JTAG och debugverktyg för?
Nerre
Inlägg: 27257
Blev medlem: 19 maj 2008, 07:51:04
Ort: Upplands väsby

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

Inlägg av Nerre »

Multiplikation är ju mycket enklare än division även om man gör det manuellt.

Division måste väl mer eller mindre göras med nån form av iteration.
Användarvisningsbild
PHermansson
EF Sponsor
Inlägg: 4340
Blev medlem: 22 december 2004, 00:46:38
Ort: Särestad Grästorp
Kontakt:

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

Inlägg av PHermansson »

Jo det finns en tråd om fläktstyrningen nånstans tror jag. Den använder dock en PIC12F675 och mikroC. ( :wacko: tycker vissa om den kombinationen :) ).
Men här är koden iaf, inte särskilt avancerad :)

Kod: Markera allt

#define fan GPIO.GP5



int potTemp, potTime, light, temp;

long int delayTime;



void main() {

    //Settings

    OPTION_REG = 0b11010000;  //GPIO pullup and TMR0 setup

    

    //GPIOs

    TRISIO = 0b00010111;

    

    //A/D. Fosc/2, AN<3:0> activated.

    ANSEL = 0b00001111;

    

    //ADCON0. 0 (ADFM), 0 (Vref=VDD),00 (dont care),10 (channel select, chan 02),0 (Go/Done), 1 (AD is on)

    ADCON0 = 0b00001101;



    fan = 1;

    

    do{                         // Loop

        potTime = Adc_Read(0);   //Left pot       AN0, pin7

        potTemp = Adc_Read(1);   //Right pot      AN1, pin6

        //light = Adc_Read(2);   //LDR
, not used
        temp = Adc_Read(3);   //TC1047

        

        /*

        20-30 degrees gives 0.7-0.8 volts in. A/D reads 143-164 for these values.

        */

        

        /*

        The temp potentiometer can have values from 0-5V, ie 0-1023 (10-bit A/D).

        */



        temp = temp - 140;

        temp = temp * 50;

        


        if (temp > potTemp) {

          fan = 1;

        }

        if (temp < potTemp) {

          fan = 0;

        }

        

        //Wait a bit

        delayTime = potTime * 3000;

        Vdelay_ms (delayTime);

        

    } while(1);

}
ie
EF Sponsor
Inlägg: 1378
Blev medlem: 23 oktober 2006, 13:12:57
Ort: Tyresö

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

Inlägg av ie »

Om du bara behöver 8 bitar så har jag för mig att ADC'n kan köras i "8-bitsmod", dvs att du bara läser ut de 8 högsta bitarna. Då behöver du inte 16 bit för att ta emot resultatet.
bearing
Inlägg: 11676
Blev medlem: 2 mars 2006, 01:01:45
Ort: Ängelholm

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

Inlägg av bearing »

toffie skrev:bearing
Visste inte heller att det tog mycket kraft för divisioner, det är ju lite synd att division inte finns inbyggd med
en riktigt optimerad teknik, som det verkar vara för multiplikation osv?
De flesta (alla?) ATmega har hårdvarumultiplikator. 8bit multiplikation är en instruktion som tar 2 klockcykler. Inte många (ingen?) Attiny har hårdvarumultiplikator.

Både multiplikation och division i mjukvara är itererande. Brukar krävas ungefär en iteration per bit, beroende på algoritm.
Här är en Application Note från Atmel om multiplikation och division i mjukvara:
http://www.atmel.com/dyn/resources/prod ... oc0936.pdf

Ser att jag var för optimistisk när jag skrev 20 instruktioner och 50 klockcykler för 8 bits division:

Kod: Markera allt

Table 1-1. Performance Figures Summary                      
Application                                                 Code Size (Words)   Execution Time (Cycles)
8 x 8 = 16 bit unsigned (Code Optimized)                    9                   58
8 x 8 = 16 bit unsigned (Speed Optimized)                   34                  34
8 x 8 = 16 bit signed (Code Optimized)                      10                  73
16 x 16 = 32 bit unsigned (Code Optimized)                  14                  153
16 x 16 = 32 bit unsigned (Speed Optimized)                 105                 105
16 x 16 = 32 bit signed (Code Optimized)                    16                  218
8 / 8 = 8 + 8 bit unsigned (Code Optimized)                 14                  97
8 / 8 = 8 + 8 bit unsigned (Speed Optimized)                66                  58
8 / 8 = 8 + 8 bit signed (Code Optimized)                   22                  103
16 / 16 = 16 + 16 bit unsigned (Code Optimized)             19                  243
16 / 16 = 16 + 16 bit unsigned (Speed Optimized)            196                 173
16 / 16 = 16 + 16 bit signed (Code Optimized)               39                  255
Senast redigerad av bearing 20 oktober 2010, 23:44:07, redigerad totalt 1 gång.
Användarvisningsbild
jesse
Inlägg: 9240
Blev medlem: 10 september 2007, 12:03:55
Ort: Alingsås

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

Inlägg av jesse »

En annan fråga, går det att se i AVRStudio tillsammans med STK500 hur många cykler som jag faktiskt använder?
Typ som en aktivitetshanterare som kan visa i procent hur mycket processorn arbetar.. Eller är det sådant man behöver
JTAG och debugverktyg för?
Du behöver varken stk500 eller processor - det räcker med AVRstudio och koden. I AVRstudio har du en simulator som räknar klockcykler. Man kan sätta "breakpoints" på lämpliga ställen i koden så stoppar den på dessa ställen , eller så stegar man manuellt och kollar klockräknaren.
Skriv svar