AVR ADC, typ av värde på input från potentiometer
Re: AVR ADC, typ av värde på input från potentiometer
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...
Re: AVR ADC, typ av värde på input från potentiometer
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:
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.
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);
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.
Re: AVR ADC, typ av värde på input från potentiometer
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 2makan1975 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%..
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..

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.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.
Följande kod
Kod: Markera allt
uint8_t ADCvalue;
...
static uint32_t readADC(uint8_t channel)
{
...
}
...
ADCvalue = ((readADC(0)*100)/1023);
Kod: Markera allt
unsigned long ADCvalue;
...
static uint16_t readADC(uint8_t channel)
{
...
}
...
ADCvalue = readADC(0);
ADCvalue *= 100;
ADCvalue /= 1023;
Ok, då ska jag lägga det på minnet (skriva ner det) så jag designar det så i fortsättningen. Tackar!

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, menIcecap skrev:Kom ihåg att ha en kondensator mellan AD-ingången och GND, en 10nF-100nF keramisk är synnerligt bra.
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


bearing
Tack för den informationen! Det där är verkligen något jag inte skulle kunna komma på själv

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

Jag måste säga att jag verkligen uppskattar all hjälp jag fått i denna tråd, ni ska ha jättetack!

Re: AVR ADC, typ av värde på input från potentiometer
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.)
Re: AVR ADC, typ av värde på input från potentiometer
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.toffie skrev: bearing
Tack för den informationen! Det där är verkligen något jag inte skulle kunna komma på själv
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?
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.
Re: AVR ADC, typ av värde på input från potentiometer
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!
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);
Re: AVR ADC, typ av värde på input från potentiometer
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 så 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!?!
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
Denna är till er

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?
uträkningar göra så man tappar prestanda..
bearing
Visste inte heller att det tog så 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!?!

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

Denna är till er


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?
Re: AVR ADC, typ av värde på input från potentiometer
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.
Division måste väl mer eller mindre göras med nån form av iteration.
- 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
Jo det finns en tråd om fläktstyrningen nånstans tror jag. Den använder dock en PIC12F675 och mikroC. (
tycker vissa om den kombinationen
).
Men här är koden iaf, inte särskilt avancerad


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);
}
Re: AVR ADC, typ av värde på input från potentiometer
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.
Re: AVR ADC, typ av värde på input från potentiometer
De flesta (alla?) ATmega har hårdvarumultiplikator. 8bit multiplikation är en instruktion som tar 2 klockcykler. Inte många (ingen?) Attiny har hårdvarumultiplikator.toffie skrev:bearing
Visste inte heller att det tog så 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?
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.
Re: AVR ADC, typ av värde på input från potentiometer
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.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?