A/D převod ATMEGA 168-pokles napětí o 3-4 b při sepnutí relé

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.

:arrow_right: administrator: přejmenováno z "Dotaz na A/D převod ATMEGA 168"
termostat1.PNG

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. :slight_smile:

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 :slight_smile:

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. :slight_smile:

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 :slight_smile:
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 :slight_smile:

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 *
;*****************************************************************

AD_PREVOD_1: ;AD převod pro napěťový rozsah

LDI	R16,0x32	;počet 50x opakování AD převodu

AD_PREVOD_2:
LDS R17,ADCSRA
SET
BLD R17,ADSC
STS ADCSRA,R17
AD_PREVOD_3:
LDS R17,ADCSRA
sbrs R17,ADIF;
JMP AD_PREVOD_3
LDS R17,ADCSRA
CLT
BLD R17,ADSC
STS ADCSRA,R17 ;stop AD převodu

LDS R17,ADCSRA	
SET
BLD R17,ADIF
STS ADCSRA,R17	;vynulovani ADIF zapisem 1 do něho

LDS R17,ADCL
MOV R0,R17
LDS R17,ADCH
MOV R1,R17

ADD	R2,R0	;V R2 dolní BYTE SOUčtu 50 měření
ADC	R3,R1	;V R3 horní BYTE SOUčtu 50 měření

DEC	R16
BRNE	AD_PREVOD_2

RET

;*****************************************************************

A podle tebe bych měl dát za ukončením převodu (bit ADIF,v reg.ADCSRA) časovou smyčku 1mS a opakovat to třeba jen 20x ?

Jinak MARTINE moc děkuji za rady

Je vidět, že opravdu začínáš :smiley: - 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.

  1. 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ž.

  1. 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.

Jednoznacne sa k tomuto nazoru pripajam.

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.

No mi hovor. to je alfa a omega. :slight_smile:

Jenom malá poznámka.
Všiml jsem si, že nastavuješ bit v prac. registru přes pomocný bit T.

LDS R17,ADCSRA SET BLD R17,ADSC STS ADCSRA,R17

Bit se dá stručněji nastavit instrukcí SBR (Set Bits in Register), která ale funguje trochu neobvykle.

Např. nastavit bit R16.3 nejde takto

SBR R16, 3

Musíme napsat ne pozici bitu, ale jeho váhu.

SBR R16, 8 nebo SBR R16, 0b00001000 nebo SBR R16, (1<<3)
Poslední způsob má výhodu v tom, že vidíme číslo (nebo jméno) nastavovaného bitu.

Tvůj kód by pak vypadal takto

LDS R17,ADCSRA SBR R17,(1<<ADSC) STS ADCSRA,R17

Jde nastavit i více bitů najednou

SBR r16,(1<<2)|(1<<3)|(1<<5)

Stejně funguje instrukce CBR (Clear Bits in Register).

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:

unsigned int Read_ADC(unsigned char channel){

// cislo kanala adc  
ADMUX &= 0xF0;  
ADMUX |= channel & 0x0F;  

// start conversion  
ADCSRA |= (1 << ADSC);  

// cakaj na priznak skoncenia konverzie  
while(!(ADCSRA & (1<<ADIF)));   

//  navratova hodnota - vysledok ad prevodu  
return ADC;  

}

za odpoved dakujem

Pod prerusenim

nastav kanal pre novy 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 :slight_smile:
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.

Ak som dobre pochopil tak tieto podmienky potrebujem dat do prerusenia?

while(!(ADCSRA & (1<<ADIF))); tento riadok by sa mal pouzit aby som vedel ze prevod skoncil nie?

Lebo ked spustim prevod musim najprv pockat kym skonci aby sa mohol spustit dalsi.

A takto pustat dalsi a dalsi prevod… napr do 20 nie?

Alebo je aj iny sposob ako otestovat ze prevod skoncil a moze sa spustat dalsi?

dobre si pochopil :slight_smile:

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 :slight_smile:

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?

Tot vsjo :slight_smile:

Martin na zaklade tvojich rad som napisal take nieco:

#include <avr/io.h>
#include <avr/interrupt.h>
#include <stdio.h>

#include “lcd.h”

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 :slight_smile:.

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.

Je vhodne cislo 20 nahradit napr.

#define POCET_PREVODOV_PRE_PRIEMEROVANIE 20

//...
	if(count==POCET_PREVODOV_PRE_PRIEMEROVANIE){
//...
       }

//...

       if(priznak){

   		adc1 = adc1/POCET_PREVODOV_PRE_PRIEMEROVANIE; //s priemerovanie kum. hodnoty			

//...
      }

//...

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 :slight_smile: ).
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.

Preto je bezpecnejsie napisat

ZAKAZ_GLOB_PRERUSENIE;
adc2 = adc1/POCET_PREVODOV_PRE_PRIEMEROVANIE; //s 
priznak = FALSE;
POVOL_GLOB_PRERUSENIE;

alebo si skor zvykni pouzit makro ATOMIC_BLOCK, lebo to osetruje aj pripadnu potrebu vyskocit z bloku na zaklade nejakej podmienky

ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
adc2 = adc1/POCET_PREVODOV_PRE_PRIEMEROVANIE; //s 
}

Do programu sa vlozia len dve instrukcie ktore trvaju zanedbatelny cas a program je “odolnejsi” voci zahadnym obcasnym vysledkom

No a samozrejme, aby si system zbytocne nezdrzoval, lepsie pouzitie je:

ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
adc2 = adc1;
priznak = FALSE;
}
adc2 = adc2/POCET_PREVODOV_PRE_PRIEMEROVANIE; //s 

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.

tak v kratkosti tolko :slight_smile:

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 :slight_smile: