ADC a AtMega88 - měření napětí na děliči, interní reference

***Dobry den,
mohl by mi prosim nekdo pomoci, jak mam pomoci ad prevodniku merit napeti? Napeti z baterie privadim pres delic na vstup ADC03. Delic ma dva stejne odpory. Takze se by na vystupu mela byt polovina napeti baterie a hlavne vzdy by mela byt nizsi nez vnitrni reference 2.56V, kterou taktez pouzivam.
Polovina napeti baterie na vystupu delice to presne neni, ani na druhem odporu (R1 jak pravi obecne schema o delicich). Proste baterie ma 3,8V. A na jednom odporu je 1,8V a na druhem taky. Takze jednou z veci co nechapu je, kam se ztrati 0,2V.
A tou dalsi a hlavni veci. Jak mam rozpoznat, treba roznout ledku, kdyz baterie poklesne na uroven pod 3,5V a pak treba jeste pod 3,3V.
Procetl jsem spoustu knih. Udelal podle ruznych for. Ale stale mi to nefunguje.
Zkousim to tak, ze kdyz je pod 3.5 V, tak zhasni ledku. K baterii jsem si dal potenciometr, abych si do zarizeni mohl napeti regulovat.
Jenze jak tak reguluju, tak kdyz zmenim to napeti dolu pomalu, tak led furt sviti, nezhasne se, ani kdyz dojdu az k 2 voltum. Kdyz s tim potenciometrem trhnu rychlej, tak se ledka rozblika.
Mimovse jsem zjistil, ze na vstupu zarizeni je napeti 3,6V kdyz sviti ta ledka, a 3,8V kdyz nesviti. {jsou to hodnoty na vstupu do zarizeni, ne za stabilizatorem}.

Dekuju moc za rady
Jak je v titulku uvedeno pouzivam Atmegu88PA a pro programovani AVR studio

V zaveru pridavam jeste kousek zdrojaku jak to zkousim podle te knihy.***

[code]#include <avr/io.h> // hlavi.ckov�Ly soubor popisuj�L.c�L. mikrokontrol�Ler
#include <avr/interrupt.h> // knihovna pot.rebn�La pro p.reru.sen
#include <util/delay.h>

#define F_CPU 2000000UL

//ZKOUSKOVA LED {CERVENA}*/
#define LED 6
#define LED_ON PORTD &= ~(1<<LED)
#define LED_OFF PORTD |= (1<<LED)

void portInit()
{
DDRD |= (1<<LED);
PORTD|= (1<<LED);
}

volatile int napeti;
int main(void)
{
portInit(); //inicializace led

ADCSRA=0b10001111; //zapnuti ad prevodniku, povoleni preruseni po dokonceni prevodu a nastaveni nejpomalejsiho prevodu
ADMUX =0b00000011; //vyber kanalu 03 

ADCSRA|=0b01000000; //logicky soucet pro registr k spusteni prevodu. Po dokonceni prevodu vyvola vector preruseni



sei() ; //povoli vsechna preruseni


while(1)  //obecna prazdna smycka....
{ 
}

}

ISR( ADC_vect )
{
float realne; //definice real promene
napeti=ADCW; //hodnota po vypoctu ulozena do napeti{napeti je typ int}
realne=(float) 2.56/1023; // vnitrni reference lomeno rozliseni prevodniku 10bitu
realne=(float) realne*napeti; // vynasobeni hodnota napeti
if (realne<3.5)
LED_OFF;

if (realne>=3.5)
	LED_ON;

_delay_ms(20); //kratka prodleva
ADCSRA|=0b01000000; //znovu zpusteni dalsiho prevodu
}[/code]

POZN.: napada me jestli ADCW nenasobit dvema, kdyz tam mam ten delic, ale s tim to taky nefungovalo.
POZN.: Kod je upraveny z kvetakov.net/clanky/avr/55-v … dniku.html**

Moc diky, LukasG.
icq 226166464**

:arrow_right: administrator: přejmenováno z "ADC a AtMega88"

Zdar, píšeš tu o interní referenci 2.54V. Tohle jsi četl? “Internal reference voltages of nominally 1.1V or AVCC are provided On-chip.” :wink: Na kód ještě mrknu…

Edit: V programu nevidím aktivaci interní reference (defalut je externí na AREF).
ADMUX |= (1<<REFS1) | (1<<REFS1);

Dle nastavení děličky a F_CPU máš ADCLOCK=15.625kHz, DS doporučuje 50-200kHz. Pokud chceš provádět měření pomalu, nastav vyšší ADCLOCK, ale spouštěj převod třeba timerem.

Nejsou ty FLOAT výpočty zbytečné? :wink:

Aby ses vešel do interní reference, budeš potřebovat dělič zhruba 1/4. Potom bude prahová úroveň pro 3.5V následující: 1023 * 3.5/4/1.1 = 814.

if(ADCW < 814) { LED_OFF; } else { LED_ON; }

To má určitou nepříjemnost. Malá baterie je poměrně měkký zdroj a její napětí se zátěží kolísá. Když tedy klesne pod 3.5V, ty vypneš diodu a odlehčíš tak baterii. Její napětí trochu vzroste. Tím zas diodu rozsvítíš a stále dokola až do doby, než se vybije natolik, že ani po snížení odběru o proud LED nepětí nepřesáhne ony 3.5V

JO, uz to vidim v tom datasheetu. Proc jsem si myslel ze je 2.56?
Vsude se psalo ze je 2.56.

Takze tedka tech 1.1V je rozdeleno do 1024 urovni? A delicem se musim dostat pod uroven 1.1V i pri plne nabite baterii. A to co jsi napsal>

mas pravdu. Proto jsem prohodil ty to roznuti a zhasnuti, ale delalo mi to stejne.

Jeste co mi delal problem je stabilizator Max604. Ma mit na vystupu 3.3V, v rozmezi vstupniho napeti 2.7V az 11.5V No ale kdyz mam na vstupu do zarizeni 3.2V, tak to na 3.3 nestabilizuje a je tam 3.1V. {a ta led je zhasla}

Tak jsem prohodil ty rezistory. Ale stejne to nejde. Je tam ted pomer 1 ku 4,7.

Pri 636

if(ADCW > 636) { LED_OFF; } else { LED_ON; }
je led zhasla. napeti na baterii je 3,81 V. Pritom ale podle toho tveho vzorce kde za 4 dosadim mych 4,7 a napeti 3.5 V vyjde 692.
Ale pri

if(ADCW > 637) { LED_OFF; } else { LED_ON; }
je led rozla a napeti na bat je 3,78 V.

Prikladam schema jeste. Jestli v nem neuvidis chybku. Dekuju moc za predesle rady. Tu inicializaci jsem si snad opravil

[code]ADCSRA=0b10001100; //zapnuti ad prevodniku, povoleni preruseni po dokonceni prevodu a nastaveni rychlosti prevodu
ADMUX |= (1<<REFS0) | (1<<REFS1) | (1<<MUX1) | (1<<MUX0);
ADCSRA|=0b01000000; //logicky soucet pro registr k spusteni prevodu. Po dokonceni prevodu vyvola vector preruseni

sei() ; //povoli vsechna preruseni

while(1) //obecna prazdna smycka…
{
}[/code]

Proč 2.56 metušim, ale běžně se používá reference 2.54V a bývá i v procesorech, tady to ovšem nevyšlo :slight_smile:

Ten stabilizátor je běžný LDO, žádný spínaný nebo něco podobného. Aby mohl tedy stabilizovat určité napětí, potřebuje na vstupu o něco více než je výstup a to o “Drop Out Voltage”. Jeho rozsah vstupních napětí je sice 2.7-11.5, ale to neznamená, že na výstupu bude schopen vyrobit všechno co tě napadne :wink:. Že má úbytek jen 0.1V je nádherná hodnota.

Zkus udělat ten dělič tvrdší (menší odpory). S tím děličem jsi totiž na srovnatelné hodnotě proudu s unikajícím proudem pouzdra a výstupního tranzistoru v mcu. Pokud bys chtěl aby ti pak ten silnější dělič nevyžíral baterku neustále, můžeš mu připojit spodní konec na I/O nožku a připínat ho na zem jen v době měření. Na výstupním tranzistoru procesoru bude sice malý úbytek, ale to při proudech pod 1mA nestojí za řeč. Ostatně si to můžeš změřit.

Nastavení AD by mělo být vpořádku, jen bych v registru DIDR0 vypnul vstupní logiku pinu, na kterém je ADC3.

V programu máš LED obsluhovanou na PD6. Tam ovšem žádnou nevidím :wink:

Co je to na tom USB konektoru!? Zkratované datové vodiče a ještě připojené na napájení, to je síla :open_mouth: .

Ak mas na baterke 3,8V a na kazdom z odporov v delici 1,8V co je spolu 3,6V nejaky odpor/impedanciu/ubytok tvoriaci element si nam zatajil. Ak to nie je vyrobne tajomstvo tak von s tym.

Ak si meral baterku pri vypnutom vypinaci a napatia na odporoch pri zapnutom vypinaci, bud tak laskyplny a zmeraj napatia pri ROVNAKYCH pracovnych podmienkach :wink:

ATmega8 mala standartnu referenciu cez 2.5V. Sila zvyku, asi by som urobil na zaciatku zo zotrvacnosti rovnaku chybu :slight_smile:

Dekuji vam…

Uz jsem to nejak rozchodil. Asi jsem blbe pocital. Ale nejaky skluz v tom je. Tak o 20-40 ta hodnota Adwc. Nepotrebuju to zas tak presne, tak jsem to nejak trosku pokoumal.

if(ADCW > 617) //kontrola napeti nad 3.75V { LED_OFF; } else if(ADCW > 555) //kontrola napeti cca 3.4V { LED_OFF; } else if(ADCW > 525) //kontrola napeti cca 3.15V { LED_OFF; } else LED_ON;
Doufam. Odpory jsem zatim nechal ty velike. Ale mozna to zkusim jeste s tim pripojenim na sem pres ten procesor.

Jo, ve schematu ledka neni. to schema je mozna druhe jednotky. Ale principove je to stejne.

Co se tyce toho souctu ubytku != napeti baterky. To fakt nechapu. Proste to tak je. Zatim je zapojene vse ostatni co je na schematu a je to vsechno zaple.

Ja jsem jeste Amater:] To vite. Je to moje prvni hracka co si delam:D. Ale zacit se musi.

Jo a to USB. No to je vytvor jak svina… Proste jen na nabijeni konektor. Stred vede napeti obal mikrousb je zem.

Ted k tomu jeste rozchodit akcelerometr. (s tim nemate zkusenosti?). Je tam freescale7260. Pajel se pekne blbe… ale tak nakones se snad povedlo. Neexistuje nejaky demo program zakladni. Chci proste aby zaznamenal jakekoli pohnuti s celou krabici {jednotkou}
Jak je zapojen je v priloze.

Jeste jednou moc diky vam obema. Kdyz jeste poradite s tim otresovym cidlem. Budu jen rad
Výstřižek2.JPG

Tak zmeraj napatie medzi baterkou a pinom odporu a medzi oboma odpormi a medzi koncom druheho odporu a gnd. Prave taketo nevyjasnene “drobnosti” zavanaju v buducnosti prusermi. Zvykni si tymto nezrovnalostiam prist na kobylku. Je to uzitocne

Ja robim s elektronikou od deviatich rokov a stale sa povazujem za amatera. Mozno trochu oplieskanejsieho elektronikou , ale za amatera. Takze vitaj v klube :slight_smile:

No, takze akcelerometr se mi podarilo spustit. Opet jsem se vice zameril na datasheet. Sleep mode jsem dal na log 1. Tim se otevreli vystupy. Je na nic napeti cca od toho 1V do 2.5V. Takze budu potrebovat na toto asi delic abych to dostal pod 1.1V, ze?

A nebo stacilo by, ze bych na AREF pin privedl napajeci napeti jako vnejsi referenci? A to tety tech 3.3V pres RC?

Jak mam tu. Ale nebude se to byt s tim mereni materie a s vnitrni referenci?
No to bude zase neco na muj mozek to vymyslet.
MMA7260QT.pdf (196 KB)
Výstřižek3.JPG

AREF jako na obrázku zapojit můžeš, ale nesmíš potom zapnout interní referenci, ta je totiž na AREF přímo připojená a těžko říct, jak by se s tim poprala.

Co se týká těch chybějících mV - čím to měříš? Kdybys měl nějaký starší ručičkový voltmetr, tak by to mohlo být, protože jeho vnitřní odpor by byl dostatečně malý aby to měření ovlivnil. Kdybys to přeměřil na tvrdším děliči, měl by se rozdíl zmenšit.

U toho USB chápu, že ho máš jako zdroj, nemůžeš ale přeci připojit I/O vodiče natvrdo na napájení nebo zem, když nemáš pod kontrolou, zda jsou vstupní nebo výstupní. Kdyby nebylo USB na druhé straně blbuvzdorné (a netvrdím že je), mohlo by to být jeho poslední alespoň co se komunikace týká. Datové piny nech nezapojené.

Tak jsem si pro ten akcelerometr napsal jen

[code]if(ADCW > 1000)
{
LED_ON;
}
else
LED_OFF; //zhasne led pri pohybu

_delay_ms(1000); //PRODLEVA ABYCH SI TOHO VSIMNUL.
ADCSRA|=0b01000000; //znovu zpusteni dalsiho prevodu[/code]
a ctu osu X. A ono to fakt funguje. Ale to napeti je tam ve skutecnosti od toho jednoho voltu az k tem dvoum

jinak mam jakysi pujceny digital Alfex DT830D

*A takze k tam tomu
Kdyz zmerim pres ten delic pres odpor R1 a R2 tak je tam napeti 3,72
kdyz jen pres R1 tak 2.83V
a kdyz jen na R2 tak 0.61V coz je dohromady 3.44V *

No fakt to nechapu:D

Pro ten akcelerometr bych dal děliče 1/3 a měřil to taky při referenci 1.1V.

a myslis ze k tomu mohu vyuzit uz ty odpory co tam mam? Ty 1k jako R1 v delici

Těžko říct, v tom pdfku jsem nenašel nic, z čeho by se dala vykoukat zatížitelnost. Asi nezbyde než to zkusit :wink: Další možnost je pak použití OZ jako mezičlánek kdyby se akcelerometr nechtěl nechat zatížit. Malá nepříjemnost - musel by mít rail-to-rail výstup.

No ja jsem videl mnoho schemat kde ty odpory 1k vubec nebyly. Ale problem je, ze nemam z ceho seskladat 330 odpor. Mam jen 100 ohmove, muzu dat tak dva do serie. Vic se mi tam kvuli mistu nevejde:(.
Ale aby ten pomer 1/5 uz nebyl moc no

Aby jsi měl poměr 1/3 a R1=1k => R2=500 :wink:
Když skrouhneš výstup na nižší napětí, tak jen nevyužiješ celou bitovou šířku převodníku, nic jinýho se nestane.

K Uref.


Preco si nenastavis ako zdroj referencneho napatia Ucc? Skus si dobre pozriet moznosti AD prevodnika ATmega88.
Ak tam chces dat presnejsiu referenciu vacsiu ako 1,1V, na Uref pripoj napriklad TL431.


k meraniu na odporovom delici.

kontrolnymi meraniami vychadza, ze vnutorny odpor tvojho multimetra je nieco okolo 1Mohm. Ak si prekreslis odporovy delic najprv tak, ze vnutorny odpor meraku je paralelne pripojeny k odporu 470k a potom k odporu 100k a prepocitas si napatovo prudove pomery vyjde ti:

ze vnutorny odpor meraku paralelne pripojeny k 470k (0% odchylka :slight_smile:, pre priblizny vypocet je predpoklad dostacujuci) je 983Mohm pri tebou nameranych napatovych pomeroch.

ze vnutorny odpor meraku paralelne pripojeny k 100k (0% odchylka :slight_smile:, pre priblizny vypocet je predpoklad dostacujuci) je 1179Mohm pri tebou nameranych napatovych pomeroch.

Ak by som vedel PRESNE hodnoty tych dvoch odporov v delici a nepocital s ich idealnymi hodnotami, oba vysledky by sa viac k sebe priblizovali. Ale i rozptyl 983Mohm a 1179Mohm je pre posudenie vnutorneho odporu multimetra dostatocny.

Z toho vyplyva, ze vnutorny odpor meraku je cca 1Mohm a preto sa nehodi na merania napati napatovych zdrojov s vnutornym odporom vacsim ako 10kohm. Na nich uz zavadza chybu z titulu svjoho vnutorneho odporu nieco okolo 1%. Pre bezne merania je to chyba pouzitelna.

Preto pisem o napatovych zdrojoch s vnutornym odporom < 10kohm, lebo voltmetrom merias napatie. Napatie dava vzdy nejaky napatovy zdroj. Tym zdrojom nemusi byt len baterka, alebo stabilizator, ale i vystup z napatoveho delica. Takze napatie na baterke si nameral spravne - zdroj s velmi malym vnutornym odporom. Ale hodnota napatia na odporoch odporoveho delica je zatazena velkou chybou, lebo v prvom pripade ma taky napatovy zdroj vnutorny odpor cca 100kohm a v druhom 470kohm. No a na take merania sa uz tvoj merak jednoducho nehodi. Preto aj patri do rodiny merakov low-end. Respektive, ak vies aku chybu ti do merania zavedie, vies si spatne prepoctat skutocne hodnoty neovplyvnene jeho vnuytornym odporom.

Takze ak budes tymto merakom merat napatie na odpore 1Mohm a ten bude pripojeny paralelne k baterke 3V, namerias “presne” 3V. Ale ak das 1Mohm odpor s baterkou do serie a budes merat napatie medzi jednym polom baterie a druhym koncom odporu, namerias 1.5V.
Ak to iste spravis s merakom s vnutornym odporom 100Mohm, v druhom pripade namerias napatie 2.97V.

Merania su z fyzikalnej podstaty uplne v poriadku a neznamena to, ze tvoj merak je nepresnejsi, ako ten druhy so 100Mohm vnutornym odporom. Len treba vediet co a ako merias.

Borci, tak ja vam dekuju za vsechny rady a muzeme jit na pivo.)

i akcelerometr se mi povedl. Ted si budu uz jen hrat s implementaci teho mereni bateri a otresu do celeho projektu. S tim vas uz nebudu zatezovat

Poprosim jen admina, aby jeste k nazvu teto dizkuze pripsal “mereni otresu akcelerometrem” aby to bylo jednodusi pro ostatni, jestli to hledaji.

A proto sem pridavam kod programu pro rozpoznani otresu, ktery je velmi trivialni a napsany velmi lajcky. Nektere radky by slo vypustit a vepsat primo do podminek. Ale radeji jsem sel na to pomalu a prehledne… tak jak se ma myslenka v noci stvorila v hlave…

Zmenou citlivosti se da menit citlivost, na kterou bude ACM reagovat, ted to rozpozna treba spadnuti tuzky na stul. Cely akcelerometr (resp. mereni) aktivuju a deaktivuju propojkou… Sleep mode kdyz nemam zasunutou propojku tam napsany nemam. Ale bylo by to jen privedeni nuly na sleep mode ACM v dobe, kdy neni propojka nasazena.

Tu to mate:

[code]#include <avr/io.h> // hlavi.ckov?Ly soubor popisuj?L.c?L. mikrokontrol?Ler
#include <avr/interrupt.h> // knihovna pot.rebn?La pro p.reru.sen
#include <util/delay.h>

#define F_CPU 2000000UL

//ZKOUSKOVA LED {CERVENA}
#define LED 6
#define LED_ON PORTD &= ~(1<<LED) //LED ON
#define LED_OFF PORTD |= (1<<LED) //LED OFF

void portInit() //inicializace jen kontrolni LED na PD5 se zapisuje jedna,
{ // cimz se akcelerometr prevede z rezimu spanku do aktivniho
DDRD |= (1<<LED)|(1<<PD5);
PORTD|= (1<<LED)|(1<<PD5);
}

#define CITLIVOST 20 //definice povoleneho rozkmitu

volatile int prevod=0,kanal=0,mereni=0,predchozi_ADCW_x,predchozi_ADCW_y,predchozi_ADCW_z;

void checkACM()
{
ADCSRA|=0b01000000; //logicky soucet pro registr k spusteni prevodu. Po dokonceni prevodu vyvola vector preruseni
prevod=1; //uvedeni prevodu do jedna, aby se pak neopakovalo volani funkce a tim by se stale zacinal prevod
sei() ; //povoli vsechna preruseni
}

int main(void)
{
portInit(); //inicializace led
ADCSRA=0b10001100; //zapnuti ad prevodniku, povoleni preruseni po dokonceni prevodu a nastaveni rychlosti prevodu
ADMUX |= (1<<REFS0) | (1<<REFS1);

while(1)  //obecna prazdna smycka....
{
	if (bit_is_clear(PIND,2)) // Propojka pro ACM nasazena
	{
		//prevod=0;
		if (prevod==0)
		checkACM(); //testuje akcelerometr, zda se pohl
	}
	if (bit_is_set(PIND,2)) // Propojka pro ACM sundana
	{
		LED_OFF; //konrolni led zhasni
		cli(); //zakaz preruseni - zvazit zdali by nestacilo nastavenim prislusneho registru vypnout AD.
		kanal=0; //kanal do nuly, aby zacinal pak s nultym kanalem - X
		mereni=0; //znuluje mereni abych pak mohl met vychozi jinou polohu
		prevod=0; //nastartovani prevodu
	}

}

}

ISR( ADC_vect )
{
int d_hranice,h_hranice;

int aktualni=ADCW; //zde se nahraje hodnota prevodu-aktualni
		
if (kanal==0 && mereni==0)     //vykonace se jen na zacatku, je to ulozeni vychozi
	predchozi_ADCW_x=aktualni; //hodnoty X se kterou se pak porovnavat bude

if (kanal==0 && mereni==1)	//az v druhem kole, kdy mereni je jedna, 
{							//mereni se nastavi na jedna az po prepnuti zase na nulty kanal
	h_hranice=predchozi_ADCW_x+CITLIVOST;
	d_hranice=predchozi_ADCW_x-CITLIVOST;
	
	if (d_hranice<aktualni && aktualni<h_hranice)
		LED_OFF;
		else
			LED_ON;
}


if (kanal==1 && mereni==0) 	   //vykonace se jen na zacatku, je to ulozeni vychozi 
	predchozi_ADCW_y=aktualni; //hodnoty Y se kterou se pak porovnavat bude
   
if (kanal==1 && mereni==1)	//az v druhem kole, kdy mereni je jedna, 
{							//mereni se nastavi na jedna az po prepnuti zase na nulty kanal
	h_hranice=predchozi_ADCW_y+CITLIVOST;
	d_hranice=predchozi_ADCW_y-CITLIVOST;

	if (d_hranice<aktualni && aktualni<h_hranice)
		LED_OFF;
	 	else
	  		LED_ON;
}


if (kanal==2 && mereni==0) 	   //vykonace se jen na zacatku, je to ulozeni vychozi
	predchozi_ADCW_z=aktualni; //hodnoty Z se kterou se pak porovnavat bude
   
if (kanal==2 && mereni==1)  //az v druhem kole, kdy mereni je jedna, 
{							//mereni se nastavi na jedna az po prepnuti zase na nulty kanal
	h_hranice=predchozi_ADCW_z+CITLIVOST;
	d_hranice=predchozi_ADCW_z-CITLIVOST;

	if (d_hranice<aktualni && aktualni<h_hranice)
		LED_OFF;
	 	else
	  		LED_ON;
}

//_delay_ms(1000); //kratka prodleva abych videl zmen, pak smazat  


kanal++; //k prepnuti na dalsi kanal

if (kanal==1)
	ADMUX=(1<<REFS0)|(1<<REFS1)|(1<<MUX0); // kanal 01 - Y
if (kanal==2)
ADMUX=(1<<REFS0)|(1<<REFS1)|(1<<MUX1)|(0<<MUX0); // kanal 02 - Z
if (kanal==3)
{
	ADMUX=(1<<REFS0)|(1<<REFS1)|(0<<MUX1)|(0<<MUX0); // zpet kanal 00 - X
	kanal=0;
	mereni=1; // mereni do jedna, pac uz byly zjisteny a ulozneny vychozi hodnoty
}

ADCSRA|=0b01000000;//znovu spusteni dalsiho prevodu

}[/code]

Tak jeste jednou dik moc. Hezky den a hodne uspechu vsem, co mi tu poradili.

Lukas G.

Pokud bys chtěl ještě o pár uA snížit spotřebu, můžeš u analogových vstupů vypnout vstupní logiku (v reg. DIDR0).