Prosím mám nasledující dotaz. Měřím napětí AKU přes dělič AD převodníkem na portu PC0. Měření provedu 50x potom to 50-ti vydělím a mám hodnotu to funguje(vše dělám v přerušení od INT0). Problém nastane když sepnu RELE tak naměřená hodnota na PC0 se sníží cca o 3-4 bity. Je to normální?nebo kde muže být chyba? Zkoušel jsem použít i interní referenci,externí referenci s TL 431 a vždy je tam ten pokles při zapnutí rele. Přikládám čast schema zapojení je to moje univerzální zapojení kde si mužu JUMPERAMA připojit PULL UP apod. Momentálně to funguje jako termostat a časovač a kolega tam chtěl dodělat vybijení AKU a narazil jsem na zmíněný problém.
administrator: přejmenováno z “Dotaz na A/D převod ATMEGA 168”
Mas zle navrhnuty plosny spoj/prepojenie.
Zopnutim rele sa nejakym sposobom ubytok napatia na spolocnom vedeni (spoji) odpocita od skutocnej hodnoty a na piny MCU sa dostane skutocne nizsie napatie. Je to bezne spravanie sa systemu s nevhodne rozvrhnutymi GND, pripadne inymi spojmi.
Ak sa vysledna hodnota AD meni IBA v zavislosti od javov vo vnutri zariadenia, kludne mozes pouzit korekcnu metodu: “zopnute rele/ pripocitaj XY bitov”. Bacha vsak na vymenu suciastok za ine , s inymi parametrami. Rele s mensou spotrebou vyvola mensi ubytok.
Osetrit sa to da aj tak, ze tranzistor rele budes ovladat cez darlingtonovy optoclen (napr ILD223, alebo podoby - darlington preto, aby cez opto tiekol co najmensi budiaci prud) a tranzistor s rele das “mimo” cesticky cez ktore preteka AD prud.
Preco AD spustas od INT0 a nie od casovaca? To to ten RTC je o tolko presnejsi? Usetril by si nozicku.
Je velmi velmi dobrym zvykom davat R aj medzi B a E bipolarnych tranzistorov. O FEToch nehovoriach. Pre bipolar tak cca 10-47k a pre FET kludne 220k-1M ak si specialny odvovodneny pripad nevyzaduje nieco ine. Pre male prudy (do 0.1A) sa mi velmi osvedcili MMUN2214/MMUN2114 a im podobne - lisia sa hodnotou odporov. Pripadne obcas pouzijem aj MUN5335. Zabera naozaj velmi malo miesta
No já vlastně každou sekundu vyčítám sekundy z RTC a při 00 sekund vyčtu vše,taky 1x za sekundu změřím teplotu a zobrazím na displeji, přerušení od časovače používám pro snímání tlačítek,jinak děkuji za vysvětlení a doporučení tranzistoru.
Robis plavajuci priemer, alebo hodnotu naozaj spocitas iba 1x za 50 sekund?
Prevod robis od INT0, alebo 1x za sekundu? Ci na INT0 mas impulz 1x za sekundu? Ci ako? Na tlacitka je ich test 1x za 1 sekundu urcite moc pomaly.
Uplne zbytocne vyplytvany pin. Na snimanie tlacitok uplne staci vnutorny citac/casovac ktoreho presnost a stabilita aj keby mal ist z interneho RC oscilatora bohate na tuto ulohu staci. Ale funkcne to urcite bude, nejedna sa o chybu.
rtc pcf 8563 mi udělá externí přerušení 1x za sekundu v tom přerušení 50x změřím AD vstup (měřím napětí vybijené AKU)přepočtu hodnoty pro zobrazení na displej změřím teplotu mám tam 2x DS 18B20 taky převedu teplotu pro zobrazení na displej jdu pryč z přerušení .
Tlačínta řeším vnitřním časovačem TIMER 2 kdy cca 1x za 60mS sejmu stav tlačítek.
Určitě by to šlo řešit vše vnitřním časovačem ale vstupů mám dost a zatím se pořád učím , takže jsem to externí přerušení chtěl vyzkoušet.
Nic proti tomu na delší časy (sekunda) použít externí přerušení od RTC - vyšetří se tím jeden 16ti bitový časovač, který bys na tak dlouhý čas potřeboval (pokud tedy nejedeš na nějakém velmi nízkém kmitočtu).
To ovšem za předpokladu, že RTC používáš primárně k tomu k čemu je určený - tedy jako hodiny a kalendář - minimálně k tomu, any ti na displeji běžel čas, případně datum - nebo pro záznam nějakých událostí. O tom se ale nezmiňuješ.
Pokud to tak není a máš ho jen jako časovač na 1 sec - pak je to ne jeden, ale minimálně tři zbytečně obsazené piny - o zbytečné součástce navíc nemluvě.
už v prvním příspěvku píšu že to používám jako termostat a časovač ,RTC je tam proto že si nastavím čas a datum kdy to má upozornit na nějakou událost.(takových času a datumu nastavuju 6 ),dale se na displeji zobrazuje aktualní čas včetně sekund a datum.
Muj dotaz se týkal problému s AD převodníkem a ne s nedostatkem pinu, nebo použít RTC nebo ne . Psal jsem že se učím a tak jsem si chtěl vyzkoušet I2C komunikaci (RTC pcf 8563 jsem SMD koupil při větším množstvím pod 10 Kč).Jak jsem zjistil problém je asi s těmi GND tady bych potřeboval poradit ?
už v prvním příspěvku píšu že to používám jako termostat a časovač ,RTC je tam proto že si nastavím čas a datum kdy to má upozornit na nějakou událost.(takových času a datumu nastavuju 6 ),dale se na displeji zobrazuje aktualní čas včetně sekund a datum.
Muj dotaz se týkal problému s AD převodníkem a ne s nedostatkem pinu, nebo použít RTC nebo ne . Psal jsem že se učím a tak jsem si chtěl vyzkoušet I2C komunikaci (RTC pcf 8563 jsem SMD koupil při větším množstvím pod 10 Kč).Jak jsem zjistil problém je asi s těmi GND tady bych potřeboval poradit ?
ale ved dobre, ved sa hned necerti
Pinov mas naozaj dost a ucit sa treba to je v absolutnom poriadku.
Len aby si lepsie chapal tie otazky.
Ak po kazdej sekunde spravis 50x AD prevod a ten spriemerujes, mozeme Ti poradit nejake tipy/triky ako na AD. Ale na to musime presne vediet co a ako robis.
Napriklad aby si v prevodoch mohol odfiltrovat vsadepritomnych nabrumenych 50/100Hz i ked v rozsahu +/-1-2LSB 10b prevodnika, je potrebne, aby cas medzi prevodmi bol +/- rovnaky a pokial mozno bol celociselnym nasobkom tych 100Hz. Mne sa osvedcuje hodnota jeden prevod za 1ms. Potom nema zmysel ani priemerovat 50 merani, ale staci 20, a signal mam vyfiltrovany do desiatej harmonickej 50Hz. K tomu ale musim AD prevodnik presne spustat kazdu milisekundu, nestaci spravit bezhlavo dokola 20 prevodov za sebou. No a tu 1ms treba nejako odcasovavat. Preto som sa pytal na ten vzorkovaci kmitocet, viem ze niektore RTC vedia generovat aj 1kHz. Preto som sa na to tak obsirne vypytoval.
Z Tvojich odpovedi som sa doteraz nedozvedel v akych intervaloch robis tie AD prevody a cim su casovane. Takze neviem, ci mas prevod rieseny korektne. Po zopnuti toho rele si mozno niekde k ceste AD privadzas dlhsi kablik a ten moze sposobovat tu indukciu brumu, aj to moze ovplyvnit meranie.
Tak aj preto sa tolko vypytujeme a sme zvedavi a vyjadrujeme svoj nazor. Aby sme Ti mohli pomoct
Ja nejsem naštvaný, ale už nad tím sedím pomalu druhý den.Teď jsem pozkracoval všechny vodiče a a zjistil jsem že GND měréné AKU jsem neměl v jednom bodě s AGND tak jsem to přepojil a už se zdá to funguje dobře (jak na to pořád hledím tak jsem si toho nevšiml).
Ja v tom přerušení zapnu AD převodník počkám 1mS(časová smyčka) a
skočím do podprogramu kde 50x měřím
;* AD převod pro napěťový rozsah *
;*****************************************************************
Je vidět, že opravdu začínáš - věř tomu, že pokud se programování budeš věnovat dál, tak nad některými problémy strávíš třeba i dva týdny.
Pokud jsi opravdu začátečník - pak “klobouk dolu” - to co popisuješ, že jsi “spáchal” navíc v asembleru je podle mně velmi slušná práce, na které se dá samozřejmě spoustu věcí vylepšit.
Já sice nejsem tak zkušený jako místní “guru” Martin, ale pár doporučení můžu předat.
Pokud jsi opravdu na začátku - doporučuju přejít na Cčko - asemblerářů s kterýma bys mohl řešit případné zádrhele v kódu bys tu napočítal na prstech jedné ruky.
nikoliv - v přerušení od časovače nastaveného na 1 ms spustíš AD převod - pak budeš mít za 20 ms 20 převodů - což je patrně účelem eliminace brumu. Při tvé metodě by 20 převodů trvalo 20ms + 20x doba pro samotný převod.
A co se týče počtu vzorků - taky si myslím, že pro tak tvrdý zdroj, jako jsou akumulátory je 20 až až.
Přerušení - snaž se v přerušení se moc dlouho nezdržovat - nastavit příznaky, de/inkrementovat nějakou proměnnou, spustit AD převod - a pryč.
Ty vlastně v přerušení vykonáváš většinu programu včetně těch časově nejnáročnějších částí jako je čtení dallasů, posílání dat do LCD a ani těch 50 převodů není zanedbatelná položka.
Navíc během té doby máš “mrtvá” tlačítka , protože vektor přerušení od INT0 má vyšší prioritu, než od TMR2 - viz tabulka v DS str. 56.
Namítneš sice, že ti to takhle funguje ke tvé spokojenosti - ale to je vedlejší - jde o “návyky” , nebo když použiju formulaci jistého autora “štábní kultůru”, které ti nakonec buď usnadní, nebo naopak zkomplikují práci na složitějších projektech - s takovou mega 128 můžeš dělat velké věci.
presne na to prerusenie je. Vykonaj “nieco” v presnom okamihu a co najrychlejsie. Nesime sa Ti stat ze sa nejake prerusenie nevykona, lebo ho ine vcas nepusti ku slovu.
Vsetky dlhsie kody sa maju spustat napriklad z hlavnej slucky. Info medzi kodom v preruseni a zvyskom kodu v hl.slucke sa moze prenasat napriklad pomocou semaforu (bit alebo cislo, podla potreby).
Priklad: Nejake 8b cislo bude indikovat poradie prevodu. Ak sa do vyhradenej premennej prenesie vysledok najnovsieho prevodu, pocitadlo sa inkrementuje a prec z prerusenia. Ked sa kod v hl. slucke dostane ku slovu, porovna si stav pocitadla so svojou odpamatanou hodnotou. Ak je medzi nimi rozdiel, nie len ze kod v hl. slucke vie ze ma spracovat novu vzorku, ale aj vie ci mu nejaka medzi tym neusla. Novu hodnotu s vysledkom z AD si prenesie do svojej internej premennej a dalej robi uz len s nou. To pre pripad, keby sa novy prevod uskutocnil pod prerusenim prave v case, ked sa spacuva vzorka. Prenos hodnoty sprav pri zakaze prerusenia. Ak potrebujes robit priemer, rutina pod prerusenim moze kludne novu hodnotu pripocitava do 16b cisla a inkrementovat pocitadlo prevodov. To je casovo malo narocne. Delenie (napriklad 20-timi ) rob v hlavnej slucke programu. atd. atd. atd.
Ahoj chcem sa spytat akym sposobom spustat AD prevod v preruseni a priemerovat. Som zaciatocnik programujem v c. Prerusnie som dal pomocou Timeru1 na kazdych 1ms ale neviem ako tam napisat to spustanie ad prevodu a priemerovanie. Predpokladam ze vysledok kazdeho prevodu sa prirata do nejakej premennej a vydeli napr. 20. Pouzivam takuto funkciu na AD prevod:
ostatnu hodnotu z AD pripocitas k premennej - pre 20vzoriek staci 16bitova.
Spusti novy prevod
po spraveni 20 prevodov vloz kumulativnu hodnotu do inej premennej (urcite typu volatile),
nastav priznak (nastav nejaku premennu/bit na dohodnutu hodnotu) pre program v hlavnej slucke ze kumulacia je spravena
kumulativnu hodnotu vynuluj a vynuluj pocitadlo do 20 (do poctu prevodov, vyhybaj sa pouzivat v programe cisla miesto konstant cez #define, inak sa v tom zamoces)
Ked znovu spravis 20 prevodov, skontroluj ci je riznak vynulovany - t.j. hlavna slucka hodontu spracovala a caka na dalsiu davku.
Zaklad je nastavit si casove parametre AD prevodu tak, aby sa do 1ms urcite skoncil. Potom nemusis o 1ms kontrolovat ci je prevod hotovy. Urcite ze je
Osvedcilo sa mi nastavovat delicku na 128, maximalne na 64. Potom netreba realizovat ziadne speci protisumove opatrenia (ako napriklad zastavovat zvysok procesora) a hodnota je celkom pekne stabilna. Samozrejme ak je plosak dobre navrhnuty.
Takze Ta tvoja cast, ked program jalovo caka na priznak ukoncenia prevodu je prave to, coho by si sa mal v programovani snazit vyhnut. Ale vsetci sa ucime.
Pristup cez 1ms casovac je to prave orechove. Zaroven pod tou 1ms mozes pripadne otestovat tlacitka, impulzy od vstupov z niekolkych vodomerov/elektromerov a procesor bude mat este tak asi 85% casu robit nieco ine.
Preboha len takto nie. Pre spravnu filtraciu musia byt vzorky ROVNOMERNE rozlozene v periode signalu, ktory chces filtrovat. Takze ak perioda 50Hz trva 20ms, musis v ramci 20ms spravit minimalne dve vzorky (Shanon-Kotelnikova teorema, ak nemas vzdelanie, wiki Ti napovie) Ak robis 20 vzoriek (filtracia do 10 harmonickej z 50Hz) v ramci 20ms, tie musis spravit ROVNOMERNE, t.j. za 1ms, presne jednu vzorku, nie 20 vzoriek v zhluku. k comu by to bolo… k nicomu
A co potrebujes testovat, ked vies ze prevod trva napriklad 400us lebo si si tak nastavil AD prevodnik? Co na tom treba dookola testovat ?
jednoducho uloz predchadzajucu vzorku, spusti novy prevod (samozrejme v rezime jednorazoveho prevodu) a pri najblizsom casovom preruseni za dalsiu 1ms hned na zaciatku uloz vzorku ktoru si spustil pred 1ms a spusti dalsi prevod.
Testovanim ukoncenia AD prevodu na zaciatku casoveho prerusenia akurat zistis, ze prevod je ukonceny. Ved loogis, ked je nastaveny na trvanie 400us, no nie?
volatile unsigned int adc, adc1;
volatile char count=0, priznak;
ISR(TIMER1_OVF_vect){
count++; //pocitanie prevodov
TCNT1 = 64535;//pretecenie kazdych 1ms pri F_CPU 1MHz
adc+=ADC; //hodnotu z AD pripocitavam k premenej
ADCSRA |= (1 << ADSC); // start conversion
if(count==20){
adc1=adc; //vlozenie kum. hodnoty do premennej
priznak = 1; //kumulacia je hotova
count = 0;
adc = 0;
}
}
int main(){
TCCR1B|=(1<<CS10); //T1 bez predelicky
TIMSK|=(1<<TOIE1); //povolenie prerusenia T1
ADMUX|=(1 << REFS0); //referencia 5V
// povolenie AD prevodnika,preddelicka 16 pri frekvencii hodin 1MHz
ADCSRA|=(1 << ADEN)|(1 <<ADPS2)| (1 <<ADPS0);
sei(); // povol globalne prerusenia
char text[32];
lcd_init(LCD_DISP_ON);
while(1){
if(priznak){
adc1 = adc1/20; //s priemerovanie kum. hodnoty
lcd_gotoxy(0,0);
sprintf(text,"ADC:%d ",adc1);
lcd_puts(text);
priznak = 0;
}
}
}
Hodnotu z AD prevodnika som si dal zobrazit na lcd. Funguje to dobre ale mam to zatial vo vyvojovej doske (po otestovani to chcem dat na plosak do aplikacie). Chcel som aby si sa pozrel na kod a napisal co je zle resp. co by sa dalo lepsie spravit.
Predelicku AD prevodu som dal na 16 cize pri F_CPU 1Mhz ide prevodnik na 62,5 kHz. V datasheete som cital ze najlepsie pracuje v rozmedzi od 50khz-200khz. Je to v poriadku?
Mozno v rychlosti nedpochytim vsetko, ale aspon takto narychlo.
Pouzivaj na formatovanie kodu tlacitko “Code” pri pisani prispevku sa nerozsype formatovanie kodu. Super, ze komentujes riadky, je to daleko zrozumitelnejsie .
toto nie je moc vhodny sposob odpocitavania presneho casu. Principialne nevies kedy PRESNE skoci program do vyhodnotenia prerusenia. Uz si teraz presne nepamatam pre aky procesor to robis, ale skus to nejako takto:
#define FALSE 0
#define TRUE 0xff
#define ZAKAZ_GLOB_PRERUSENIE cli()
#define POVOL_GLOB_PRERUSENIE sei()
#define TEST_GLOB_PRERUSENIE TST(SREG,I)
#define GLOB_PRERUSENIE_NASTAVENE (1<<I)
#define TB_SIG_OUTPUT_COMPARE TIMER2_COMPA_vect // nazov vektoru pre prerusenie od casovaca CZ - compare match
#define TB_NASTAV_CASOVAC TCCR2A = (1<<WGM21) | (1<<WGM20);\
TCCR2B = ((1<<WGM22) | (1<<CS21)) // mod 7 a preddelic 8
#define TB_POVOLENIE_PRERUSENIA (SET(TIMSK2,OCIE2A)) // povolenie interuptu pri compare match
#define TB_ZAKAZ_PRERUSENIA (RES(TIMSK2,OCIE2A)) // zakaz interuptu pri compare match
#define TB_CNT TCNT2
#define TB_PREDVOLBA OCR2A
#define TB_DEFAULT_1 229
// nastavenie celeho casovaca
#define TB_NASTAV_TB TB_NASTAV_CASOVAC;\
TB_PREDVOLBA = TB_DEFAULT_1;\
TB_POVOLENIE_PRERUSENIA;
// ....
int main(void)
{
// ....
TB_PREDVOLBA = TB_DEFAULT_1;
TB_POVOLENIE_PRERUSENIA;
POVOL_GLOB_PRERUSENIE;
// ....
}
ISR(TB_SIG_OUTPUT_COMPARE)
{
// tu nemas preco manipulovat s TCNTx, lebo ked TCNTx dosiahne hodnotu TB_PREDVOLBA, potom nastavi priznak prerusenia, automaticky sa vynuluje a pocita sam od seba nanovo na tik hodin presne. Ty iba (napriklad cez spustenie prerusovacej rutiny) spsutis akciu/akcie po dosiahnuti casoveho kvanta. Ja pouzivam 8bit, T2.
// ...
}
Nie je to samozrejme dogma, ale na casovu zakladnu s vhodne zvolenym preddelicom to staci. 16b casovac by som si nechal v rezerve na generovanie PWM v rezime 8,9,10,16b. Pouzit 16b pocitadlo na casovu zakladnu je zbytocne. S casovpou zakaldnou sa mozes dalej hrat, ked budes pri vyhodnoteni prerusenia menit hodnotu v OCRxx. To je korektne, lebo casove kvantum je zas generovane presne (za predpokladu, ze casovac nedosiahne hodnotu OCRxx skor, ako Ty s nim budes bantovat). Vhodne je aby hodnota v OCRxx v sucine s preddelicom bola vacsia ako 200 (mas cca 100-200instrukcii procesora na vykonanie vsetkej cinnosti v ramci prerusenia, ak nestihas bude casova zakladna v sklze) a samozrejme mensia ako je zelany casovy rozsah.
potom staci jedna zmena na jednom mieste a prekladac prelozi program spravne. Nedajboze by si mal viac vyznamovo roznych konstant 20, potom by si mohol lahko spravit chybu, ze by si omylom zmenil aj to co netreba (poznam ).
No a tu sme pri tom, ze urcite by som zaviedol dalsiu (napr. lokalnu ak treba tak aj staticku) premennu napr. “adc2” v hlavnej slucke pre spracovanie v tejto hlavnej slucke a pri vypocte by som este aj zakazal prerusenie.
Ak budes “dlho” a viac krat v hlavnej slucke pouzivat premennu s ktorou zaroven manipuluje funkcia pod prerusenim, tak si casom koledujes o pekny pruser.
Dokonca ani pri naplnani dalsej premennje, ak nemas garantovane (a to casom nemas, respektive kto by sa zdrzoval neustalou kontrolou) ze v case vykonavania prikazu
adc2 = adc1/POCET_PREVODOV_PRE_PRIEMEROVANIE; //s
sa zrovna nespusti prerusenie a to prave nezmeni horny/dolny bajt prenasanej hodnoty adc1, nemozes sa na vysledok 100% spolahnut.
To iste plati pre hodontu priznaku.
Ty “nechces” robit prerusenie od pretecenia casovaca ale od komparacie s obsahom OCRxx. Vysvetlenie bolo vyssie.
Ako som uz pisal inde, 16 je taka hodnota, ze vysledok budes mat velmi zasumeny. Pod hodnotu preddelicky 64 by som ani nesiel. Preco mcu nebezi na 8MHz? Ak k tomu nie je nejaky relevanty dovod (napr. spotreba), potom staci spravne nastavit poistku pri programovani. A hned mozes pouzit preddelicku 128 (= 8*16). Aj tak Ti vychadza cas prevodu okolo 224us a vysledok si stahujes 1x za 1ms.takze sa vobec nebran nastavit preddelicku na 64 (aj bez zmeny frekvencie mcu). Nastavenim preddelicky na 16 nic neziskavas, akurat si humusis vyslednu hodnotu vlastnym sumom z mcu.
Ospravedlnujem sa ze som hned na zaciatku nespomenul ze sa jedna o atmegu 8.
Frekvenciu 1 MHz som mal nastavenu kvoli tomu aby mi korektne zobrazoval lcd. Ked som nastavil na 8MHz tak som mal lcd cisty nic nezobrazoval. Ale uz je to vyriesene takze uz ficim na 8 MHz predelicku ADC som nastavil na 128. Este otazka kvoli stabilite AD je lepsie pouzit externy krystal alebo vystaci aj vnutorne zdroj Frek?
Snazim sa pochopit kod ktory si zverejnil vsetko mi je jasne, az na jednu vec nikde v datasheete nemozem najst bit WGM22 v ktorom registri sa nachadza lebo v datasheete od atmegy8 sa spomina len TCCR2 a v nom bit WGM22 sa nenachadza. Nie je mi jasne ani ten mod 7…
Ak som dobre pochopil ATOMIC_BLOCK(ATOMIC_RESTORESTATE) sluzi na vykonanie nejakych prikazov ktore su uvedene v zatvorke bez ohladu na to ci nastane prerusenie najskor dokonci prikaz v zatvorke a az potom vykona prikazy v preruseni?
Pozeram ze skoro vsetko si definoval cez #define nastavenie timeru, prerusenie, atd je to kvoli priehladnosti? lebo ja som to doteraz nastavoval v main. #define som takmer vobec nepouzival.
Pytam sa preto lebo ako zaciatocnik snazim sa pri pisani kodu chytat dobre programatorske navyky