 |
www.elektronik.si Forum o elektrotehniki in računalništvu
|
| Poglej prejšnjo temo :: Poglej naslednjo temo |
| Avtor |
Sporočilo |
grecko453 Član

Pridružen-a: Pet 24 Sep 2010 13:02 Prispevkov: 86 Aktiv.: 0.45 Kraj: Ljubljana
|
Objavljeno: Pon Jan 31, 2011 10:24 am Naslov sporočila: ADC library |
|
|
Za programiranje uporabljam mikropascal, vendar sem pri uporabi ADC knjižnice naletel na omejitev.
V help fajlu je za ADC knjižnico naslednje opozorilo:
Note : This function doesn't work with the external voltage reference source, only with the internal voltage reference.
Torej v prevodu;
ne morem uporabiti obstoječe knjižnice, če želim določiti, da Vref ne bo Vcc, ampak napetost na nekem od AN pinov.
Sicer sem pregledal datasheet za PIC16F886, kjer z bitom VCFG0 (ADCON1 register) določaš z 0 = Vdd, z 1 = Vref+ pin. Vendar mi to nič ne koristi, ker pascalova knjižnjica ne omogoča izbire Vref pina.
Če je kdo tako prijazen bi prosil za pomoč. |
|
| Nazaj na vrh |
|
 |
grecko453 Član

Pridružen-a: Pet 24 Sep 2010 13:02 Prispevkov: 86 Aktiv.: 0.45 Kraj: Ljubljana
|
Objavljeno: Pon Jan 31, 2011 11:04 am Naslov sporočila: |
|
|
Našel sem en podoben primer za dsPIC30F6014. Vendar preveč zame, da bi priredil za 16F886.
| Koda: |
function My_Adc_Read(ch: byte): word;
// Will use external Vref+ on pin RA10 instead of internal Vdd Vref
// as done by ADC_Read. Tested on dsPICPRO with dsPIC30F6014 mikroPascal 4.0.0.0
// library ADC_Read destroys ADCON2 before converting thus making impossibile
// to use external VREF+
begin
ch := ch and $000F; // ch must be in range 00..15 (Dec)
SetBit(TRISB,ch); // Configures pin on PORTB as input
ADPCFG := 0;
ClearBit(ADPCFG,ch); // Chth channel will be sampled and converted
ADCON1 := $00E0; // ADC=off, Output_format=INTEGER,
// automatic start of conversion after end of sampling,
// manual start of sampling
ADCHS := ch; // Connect RBch on ANch as DAC +input (-input at Vref-)
ADCSSL := 0; // No scan
ADCON3 := $1F1B; // ADCS=27 (27*Tcy = 337 ns > 333 required)
// Value is right for FOsc = 80 MHz.
ADCON2 := $2000; // Interrupt on completation of 1 sample
// External VRef+
ADCON1.15 := 1; // ADC on
ADCON1.1 := 1; // SAMP=1, start sampling
while ADCON1.0 = 0 do nop; // Wait for DONE bit in ADCON1
result := ADCBUF0; // Returns the result
end; |
|
|
| Nazaj na vrh |
|
 |
gumby Član


Pridružen-a: Sob 28 Apr 2007 12:32 Prispevkov: 4066 Aktiv.: 17.60
|
Objavljeno: Pon Jan 31, 2011 11:50 am Naslov sporočila: Re: ADC library |
|
|
| grecko453 je napisal/a: |
| Note : This function doesn't work with the external voltage reference source, only with the internal voltage reference. |
Tole je dovolj dober razlog, da nehaš uporabljat debilne knjižnice in napišeš svoje rutine za AD pretvorbo...
Nastaviti moraš naslednje registre:
TRISx (vse analogne pine nastavi na vhod)
ANSEL, ANSELH (analogni vhodi)
ADCON0 (hitrost pretvorbe, izbira vhoda, vklop AD)
ADCON1 (poravnava, +/- referenca)
INTCON, PIE1, PIR1 (če uporabljaš prekinitev za AD)
Pretvorbo štartaš z postavitvijo bita GO/DONE v ADCON0.
Rezultat pretvorbe bo v ADRESH/ADRESL...
Sicer pa poglej datasheet (poglavje 9.2), je vse lepo napisano  _________________ Tule nisem več aktiven. |
|
| Nazaj na vrh |
|
 |
grecko453 Član

Pridružen-a: Pet 24 Sep 2010 13:02 Prispevkov: 86 Aktiv.: 0.45 Kraj: Ljubljana
|
Objavljeno: Tor Feb 01, 2011 7:09 pm Naslov sporočila: |
|
|
koda gre takole:
| Koda: |
program vaja;
procedure ad();
begin
ADCON0.7-6:=01; //fosc/8
ADCON0.0:=1; //enable ADc
ADCON1:=%00010000; //adfm=0, Vref- = Vss, Vref+ = pin
delay_us(5); //required acquisition time
ADCON0.1:=1; //start conversion
repeat
until ADCON0.1=0; //wait for ADC conversion to complete
end;
var adc:integer;
txt:string[16];
begin
TRISA:= %11111111; //RA0-7 as input
ANSEL:= %11111111; //AN0-7 are enabled
ANSELH:=%00000000; //AN8-13 are disabled
LCD_Config(PORTB,3,2,1,0,PORTB,4,7,5); //configure LCD on portA
LCD_Cmd(LCD_CLEAR); // clear display
LCD_Cmd(LCD_CURSOR_OFF); // turn cursor off
while true do
begin
ADCON0.3-0:=%0010; //read from AN2 pin
ad();
adc:=ADRESH*4; //read upper 8 bits of 10bit conversion and multiply by 4 (ADRESH register)
intToStr(adc,txt);
LCD_Out(1,11,txt);
end;
end. |
nekaj nejasnosti kljub prebranemu poglavju 9.2 še vedno imam.
1. v datasheetu je neka formula za minimalni čas potreben med nastavitvijo ADCON1 registra in trenutkom ko poženeš konverzijo. Zanima me ali je 5us? V formulo se nisem poglabljal je pa v formuli uporabljena napetost Vapplied in Vchold
2. druga stvar, ali rabim kakšen kondenzator na vhodu AN pinov? Zato ker v datasheetu je nek graf med kapativnostjo in časom in omenjo je nekaj glede puščanja pin (pin leakage).
3. nekaj težav imam pri branju iz registra ADRESH in ADRESL. nastavil sem levo poravnavo kar pomeni da imam v registru ADRESH zgornjih 8bitov in številka gre 0d 0 do 255 (logično glede na to da je 2^8, 255), nejasno pa mi je zakaj če berem samo ADRESL register mi da vrednost med 0 in 192, čeprav bi morala biti tu samo dva spodnja bita, torej od 0 do 4.
Formulo za branje ADC vrednosti sem si zamislil takole: adc:=ADRESH*4+ADRESL, vendar kot rečeno ADRESL gre vse do 192. |
|
| Nazaj na vrh |
|
 |
gumby Član


Pridružen-a: Sob 28 Apr 2007 12:32 Prispevkov: 4066 Aktiv.: 17.60
|
Objavljeno: Tor Feb 01, 2011 7:50 pm Naslov sporočila: |
|
|
1: kondenzator rabi par us, da se napolni na vrednost, ki je na vhodu... zato po izbiri analognega vhoda (CHSx biti v ANSEL) počakaj par us, preden zaženeš pretvorbo (če ne spreminjaš vhodnega pina, potem ni treba čakat)
2: prikazan je model analognega vhoda, tistih 500nA predstavlja izgube... tu je najbolj pomembno, da imaš nizko impedanco na vhodu, kondenzator načeloma ni potreben
3: poglej, kje sta tista dva bita v registru ADRESL, ko imaš levo poravnavo
Če misliš uporabit vseh 10 bitov je bolj praktično imet desno poravnavo, takrat samo ADRESH pomnožiš z 256 (shift levo za 8 bitov) in prišteješ ADRESL. Za 8 bitov je pa bolj praktična leva poravnava, takrat je rezultat kar ADRESH (spodnja dva bita ignoriraš). _________________ Tule nisem več aktiven. |
|
| Nazaj na vrh |
|
 |
gumby Član


Pridružen-a: Sob 28 Apr 2007 12:32 Prispevkov: 4066 Aktiv.: 17.60
|
Objavljeno: Tor Feb 01, 2011 8:01 pm Naslov sporočila: |
|
|
Še nekaj glede programa: načeloma se nastavitev parametrov za AD pretvornik izvede samo enkrat. Nato v zanki določiš vhodni kanal in štartaš pretvorbo (ter odčitaš rezultat). Če vedno bereš isti kanal, potem niti kanala ni treba vedno znova nastavljat v zanki, ampak to storiš samo 1x med nastavitvijo ostalih parametrov. _________________ Tule nisem več aktiven. |
|
| Nazaj na vrh |
|
 |
grecko453 Član

Pridružen-a: Pet 24 Sep 2010 13:02 Prispevkov: 86 Aktiv.: 0.45 Kraj: Ljubljana
|
Objavljeno: Sre Feb 02, 2011 12:37 am Naslov sporočila: |
|
|
Prvo Hvala za vso pomoč!
Drugo a bi bilo takole ok?
ali bi bilo v obliku funkcije boljše? (na mikroE forumu so mi svetovali naj naredim raje v obliku funkcije) =>
Both solutions are acceptable, though a function with result of type word seems more convenient (Lo(result):=ADRESL, Hi(result):=ADRESH). The input number to be used may be set as function parameter
vendar nisem ravno razumel ta "lo" in "hi", ker lo(ADRESL) bi vrnil 0ti in prvi bit vrednosti registra ADRESL, hi(ADRESH) pa 00, v primeru desne poravnave (ali se motim)?
| Koda: |
program vaja;
procedure ad();
begin
delay_ms(10); //alow acquisition time
ADCON0.1:=1; //start conversion
repeat
until ADCON0.1=0; //wait for ADC conversion to complete
end;
var adc1,adc2:integer;
txt:string[16];
begin
TRISA:= %11111111; //RA0-7 as input
TRISC:=$ff;
ANSEL:= %11111111; //AN0-7 are enabled
ANSELH:=%00000000; //AN8-13 are disabled
ADCON0.7-6:=01; //fosc/8
ADCON1:=%10010000; //adfm=1, Vref- = Vss, Vref+ = pin
ADCON0.0:=1; //enable ADC
LCD_Config(PORTB,3,2,1,0,PORTB,4,7,5); //configure LCD on portB
LCD_Cmd(LCD_CLEAR); // clear display
LCD_Cmd(LCD_CURSOR_OFF); // turn cursor off
while true do
begin
ADCON0.3-0:=%0000; //read from AN0 pin
ad();
adc1:=ADRESH*256 + ADRESL; //read ADRESH & ADRESL registers to get 10 bit ADC value
intToStr(adc1,txt);
LCD_Out(1,1,txt);
ADCON0.3-0:=%0010; //read from AN2 pin
ad();
adc2:=ADRESH*256 + ADRESL; //read ADRESH & ADRESL registers to get 10 bit ADC value
intToStr(adc2,txt);
LCD_Out(2,1,txt);
end;
end. |
imam pa še eno praktično vprašanje. Trenutna ploščica, ki je že izdelana ima na ADC priključeno temperaturno tipalo tipa KTY10. Tipalo je vezano v napetostni delilnik z 3.24k pull down uporom. Napetost med merjenim območjem (-10 do 100°C) tako niha med cca 2.5 in 3.5V, torej diferenca je samo 1V.
Zanima pa me slednje.
Zahteva ni natančnost na decimalke, zgolj absolutna in relativna točnost na nekaj stopinj celzija. Torej pri diferenci 1V koristim 20% širine 10 bitnega AD konverterja kar je za moje pojme dovolj, da dobiš točno teperaturo. Formulo za temperaturo sem dobil tako da sem s pomočjo excela, narisal graf odvisnosti upornosti od temperature.
V prvi stolpec sem vnesel vrednosti ADCja od 0 do 1023, v drugem računam upornost senzorja po formuli Rs=R2*1023/ADC-R2 in v tretjem temperaturo po T=25+(sqrt(a*a-4*b+4*b*Rs/R25)-a)/(2*b). vrednosti a, b, R2 in R25 so konstante.
Sedaj sem ta graf razdelil pri temperaturi 55°C na dve linearni funkciji in to sta moji formuli za računanje temperature.
Temperaturo zaokrožam na celo številko, vseeno pa mi zadeva deluje zelo čudno, saj trenutna temperatura niha tudi do 3°C. Kar pomeni da recimo kaže 20, potem 22 in nato 19....
Torej tu nekaj ne štima.
Napetosni delilnik je napajan iz istega izvora (Vcc) kot dobi ADC referenčno napetost, tako da nihanje napetosti ne bi smelo vplivati. Prav tako je upor in temp senzor na stalni temperaturi, tako da tudi ne bi smel nihati.
Zastavlja se mi vprašanje, če bom z nastavljanjem referenčnih napetosti ADCja na Vref+=3.5 in Vref-=2.5V, sploh kaj pridobil. Res je da bom imel na razpolago več vrednosti pretvorbe, vendar če je zahteva natančnost na nekaj stopinj ali je to sploh smiselno, saj imam pri trenutnem 20% izkoristku vrednosti ADCja 2 vrednosti na vsako stopinjo. |
|
| Nazaj na vrh |
|
 |
gumby Član


Pridružen-a: Sob 28 Apr 2007 12:32 Prispevkov: 4066 Aktiv.: 17.60
|
Objavljeno: Sre Feb 02, 2011 8:35 am Naslov sporočila: |
|
|
Preračunaj, koliko znaša 1 bit v stopinjah. Malo šuma bo namreč nonstop prisotnega, torej bo rezultat pretvorbe skakal gor-dol.
Za zmanjšanje tega se boš moral malo potrudit glede samega analognega dela vezja... ločitev napajanja, filtriraneje motenj, precizne reference za Vref+ in Vref-, itd. Na to temo je že par debat na forumu (in tudi drugje), malo preišči...
Poleg tega lahko AD pretvorbo izvedeš v sleep-u, kjer se procesor v bistvu ustavi in se na ta način eliminira večina motenj, ki jih povzroča (poglej datasheet, kako to izvesti).
Na koncu lahko rezultat pretvorbe tudi povprečiš, da še nekoliko zmanjšaš skakanje rezultata... _________________ Tule nisem več aktiven. |
|
| Nazaj na vrh |
|
 |
GJ Član


Pridružen-a: Čet 02 Nov 2006 15:51 Prispevkov: 946 Aktiv.: 3.99 Kraj: Ljubljana
|
Objavljeno: Sre Feb 02, 2011 9:30 pm Naslov sporočila: |
|
|
Ahh…
No ja za hobi temometrček je tole vezje verjetno čisto ok, pač odvisno s čim boš (si) zadovoljen.
Z 10 bitnim ADC-jem se da doseči bistveno boljše meritve kot si jih navedel ti.
Metoda vzorčenja, ki jo uporabljaš ni ravno ustrezna. Vzorčenje z internim MCPU ADC-jem se ponavadi ne vrši v sami aplikaciji temveč v prekinitveni rutini. Recimo, da je frekvenca oscilatorja 16MHz, v tem primeru koristiš recimo prekinitev TMR0, ki jo nastaviš tako, da se izvede vsakih 128us oziroma 512 strojnih ciklov, Pic potrebuje 4 nihaje oscilatorja, da izvede en strojni cikel. V prekinitveni rutini bereš, multipleksiraš in prožiš ADC, rezultate posameznega kanala v sami prekinitveni rutini integriraš (seštevaš) v 24 bitni variabli. Po recimo 1000 pretvorbah pa prekopira prekinitvena rutina ta rezultat v novo variablo in pobriše variablo integratorja, hkrati pa postaviš zastavico aplikaciji, da ve, da je seštevek tisočih zaporednih meritev pripravljen. Aplikacija termometra v ozadju čaka, da se zastavica postavi nakar prebere vrednost in pobriše zastavico, nakar vrednost preko enačb spremeni v temperaturo. Takšna prekinitvena rutina, če je lepo napisana porabi okoli 10% procesorskega časa ostalo pa ostane za aplikacijo termometra. In seveda, čas takšnega prečenja (če izvajaš le eno meritev) je 128us * 1000 torej 0.128s v tem času pa mora tudi aplikacija narediti svoj del naloge.
Če želiš uporabiti KTY10 tako, da boš iztisnil iz njega maksimalno boš potreboval še dva operacijska ojačevalnika (Rail to Rail in/out; recimo: MCP6002), prvi ti mora generirati konstanten tok za napajanje KTY10 senzorja in ta je ponavadi med 0.2 do 1mA, drugi mostiček pa ti pretvori merilno območje v napetostno območje merjenja ADC-ja. In ne potrebuješ nikakršnih hudih napetostnih referenc ali pa ločenih napajanj, za napajanje ADC-ja, skupnih 5V iz LM1117 je povsem dovolj stabilnih, če boš mostičke operacijskih ojačevalcev krmilil z isto napetostjo. Natančnost takšnega termometra v območju od -30 pa do 120oC lahko dosežeš, če ga predhodno dobro programsko umeriš, na 0.2oC. Največji problem je sam KTY10 in njegovo staranje in nelinearnost, če pa uporabiš Pt1000 boš brez problema dosegel natančnost 0.1oC.
LP GJ |
|
| Nazaj na vrh |
|
 |
|
|
Ne, ne moreš dodajati novih tem v tem forumu Ne, ne moreš odgovarjati na teme v tem forumu Ne, ne moreš urejati svojih prispevkov v tem forumu Ne, ne moreš brisati svojih prispevkov v tem forumu Ne ne moreš glasovati v anketi v tem forumu Ne, ne moreš pripeti datotek v tem forumu Ne, ne moreš povleči datotek v tem forumu
|
Uptime: 233 dni
Powered by phpBB © 2001, 2005 phpBB Group
|