Generátor: Generovaní sinusového a trojúhelníkového průběhu

Tak promin, ale zkratka jsem to nepochopil… To neni o tom, ze bych si nechtel nechat poradit!

To je uplne v poriadku. Pytaj sa dokedy nebudes rozumiet.
V mojom programe je vela komentov preto, aby mu bolo rozumiet (aspon sa snazim :slight_smile: ), ale ako mi tu uz niekto v dobrom radil, menej je viac. Tak to skusim este raz a ak nebudes niecomu KONKRETNEMU v programe rozumiet, pytaj sa kludne bod po bode. :slight_smile:


#include <avr/io.h>
#include <stdint.h>

// Definice makier s parametrami, toto jednoducho akceptuj a aj v dalsich svojich programoch pouzivaj obdobne substitucie. 
// vedie to k prehladnejsiemu a zrozumitelnejsiemu kodu.
// to ocenis, najma ak sa budes niekoho pytat o radu. Cim neprehladnejsi zdroja, tym menej ochotnych sa nim zaoberat :-)
#define SET(BAJT,BIT) ((BAJT) |= (1<<(BIT)))
#define TST(BAJT,BIT) ((BAJT) & (1<<(BIT)))

#define TRUE 0x00
#define FALSE 0xff
#define SINUS TRUE
#define TROJUHOLNIK FALSE
#define PREDVOLBA_CZ_SINUS 7 
#define TLACITKO_BIT  5 // nech je tlacitko na piatom bite
#define TLACITKO_PORT  PIND // nech je tlacitko na porte D
#define TLACITKO_SMER_PORT DDRD // nech je tlacitko na porte D
#define MAX_VZORKY_TROJUHOLNIK 20
#define MAX_VZORKY_SINUS 32
#define PORT_PRE_DA PORTB
#define SMER_PORT_PRE_DA DDRB

uint8_t generuj_signal = SINUS;
uint8_t stav_tlacitka_new,  stav_tlacitka_old, i; 

unsigned char sinu  [MAX_VZORKY_SINUS] = {127,138,149,160,171,182,193,205,      //127-205
                     205,193,182,171,160,149,138,127,      //205-127
                     127,116,105,94,83,72,61,49,         //127-49
                     49,61,72,83,94,105,116,127};      //49-127
unsigned char troj  [MAX_VZORKY_TROJUHOLNIK] = {0,12,24,36,48,      //0-48
                     60,71,82,93,103,      //60-103
                     114,125,136,147,154,      //114-154
                     124,93,62,31,0,};   //124-0

int main(void)
{
   // ========= zaciatok inicializacie ===========
   OCR2 = PREDVOLBA_CZ_SINUS;
   SET(TCCR2,WGM21);
   SET(TCCR2,CS22); 
   RES(TLACITKO_SMER_PORT,TLACITKO_BIT);
   SMER_PORT_PRE_DA = 0xff;

   if (TST(TLACITKO_PORT,TLACITKO_BIT)) stav_tlacitka_new = TRUE;
   else stav_tlacitka_new = FALSE;
   stav_tlacitka_old = stav_tlacitka_new;
   // ========= koniec inicializacie ===========

   while(1) {
      if (TST(TIFR,OCF2)) {
         SET(TIFR,OCF2);
         // =========== zaciatok testovania tlacitka ===========
         if (TST(TLACITKO_PORT,TLACITKO_BIT)) stav_tlacitka_new = TRUE;
         else stav_tlacitka_new = FALSE;
         if (stav_tlacitka_new == FALSE) && (stav_tlacitka_old == TRUE)) {
            if (generuj_signal == SINUS) {
               generuj_signal = TROJUHOLNIK;
               // trojuholnik moze mat inu periodu ako sinus
               OCR2 = PREDVOLBA_CZ_TROJUHOLNIK;
            }
            else {
               generuj_signal = SINUS;
               // sinus moze mat inu periodu ako trojuholnik
               OCR2 = PREDVOLBA_CZ_SINUS;
            }
            i = 0;
         }
         stav_tlacitka_old = else stav_tlacitka_new;
         // =========== koniec testovania tlacitka ===========

         // ========= zaciatok generovania vzorky ===========
         // volba spravnej funkcie na zaklade stavu "tlacitka"
         if (generuj_signal == SINUS) {
            PORT_PRE_DA = sinu*;
            i++;
            if (i >= MAX_VZORKY_SINUS) i = 0;
         }
         else {
            PORT_PRE_DA = troj*;
            i++;
            if (i >= MAX_VZORKY_TROJUHOLNIK) i = 0;
         }
         // ========= koniec generovania vzorky ===========

      }
   }

   return;
}

Periodu menis roznym nastavenim hodnoty v OCR2. Bud tam vlozis
hodnotu PREDVOLBA_CZ_SINUS alebo hodnotu PREDVOLBA_CZ_TROJUHOLNIK. Na substitucie cisel textom si zvykni, je to velmi uzitocne. Nema to nijaky vplyv na vysledny kod, iba a vylucne na lepsiu citatelnost kodu.

Drzim palce, pytaj sa dalej :slight_smile:

P.S. Moj kod je kratsi ako Tvoj, tak sa skus cez neho preluskat a skus ho vyskusat. Po skuske mozno budes mat dalsie otazky, mozno na simulatore v AVR studiu zistis, ako kod pracuje.

P.S.2: Pokial som si dobre vsimol, Tvoj kod postupne vola sinu() a z neho troj() a potom sinu() a znovu troj() a znovu sinu() a znovu troj()… Az kym sa nezaplni zasobnik a program neskolabuje. Vsetko zavisi od poctu stlacenia tlacitka a od velkosti volnej pamate. Skratka tak ako som si stacil vsimnut, program je odsudeny na to ist do kytiek a preto som tie while(1) nazval nezmyselnymi. :slight_smile:

P.S.3: Vsimni si, ze kod testovania tlacitka je dlhsi ako cely kod na generovanie trojuholnika a sinusu dokopy :slight_smile:**

Martin to už mezitím připsal a vysvětlil, ale nechám to beze změn:

hypnoz: jedna z chyb (jak psal už Martin) - křížové volání funkcí sinu1 a trojl. Při volání funkce se ukládá do zásobníku návratová adresa. Když funkce voláš křížově mezi sebou, ukazatel zásobníku se neustále posouvá. Což po pár vnoření bude mít za následek přetečení zásobníku a zhroucení programu.

Jiná chyba - PIND vrací stav bitů portu D, nelze proto jednoduše testovat stisk tlačítka (PIND==0x04). Je nutné testovat stav jen jednoho bitu.

Dále - tlačítko nastavuje stav bitu po celou dobu držení. Nelze tedy testovat stisk tlačítka jednoduchou podmínkou, mělo by to za následek neustálé překlápění stavu po celou dobu držení (ve Tvém případě vnořování do funkcí s následkem zahlcení zásobníku ihned po stisku). Je nutno testovat změnu stavu bitu a navíc by bylo vhodné ošetřovat ještě zákmity tlačítka.

Borci, strasne Vam dekuji. Konecne jsem to pobral. Jen jeste nechapu PREDVOLBA_CZ_SINUS a PREDVOLBA_CZ_TROJUHOLNIK to je hodnota, ktera se zapise do OCR? Myslim ze ANO, ale nevim, jak ji spocitat… Muzete mi nekdo dat vzorecek? :wink: DIKY.

A mohu nastavit preddelicku takto?

SET(TCCR0B,CS01);
SET(TCCR0B,CS00); //:64

Nevadi, ze se nenastavi zaroven?

A posledni dotaz:

#define VZORKY_SINUS 32 //pocet vzorku
#define VZORKY_TROJUHOLNIK 20 //pocet vzorku

nemelo by tam byt 31 a 19? Protoze v te mnozine je sice 32 a 20 hodnot, ale pocita to od nulte hodnoty.

if (i >= VZORKY_SINUS)
{
i = 0;
}

Takze zde se i vynuluje az je vetsi nebo rovno 32 (ale to je 33 hodnot)

Ako som Ti uz pisal,

#define PREDVOLBA_CZ_SINUS 7 // spravnost hodnoty predvolby teraz neskumam, treba si ju vypocitat podla Tvojich potrieb
#define PREDVOLBA_CZ_TROJUHOLNIK 5 // spravnost hodnoty predvolby teraz neskumam, treba si ju vypocitat podla Tvojich potrieb

hodnoty si prepocitaj podla Tvojich potrieb (ci 32 lebo 31 alebo 19 alebo 20, to je cisto Tvoja vec)

vzhladom k tomu ze:

   OCR2 = PREDVOLBA_CZ_SINUS;
...
   OCR2 = PREDVOLBA_CZ_TROJUHOLNIK;

asi tie hodnoty budu predvolby casovej zakladne :slight_smile:

Pro sinus trvá jedna perioda 24 us (1/41670).
Jestli chceme mít 32 vzorků na periodu, musí timer vyvolat přerušení ne za 24us ale za 24/32 = 0,75us.
Jinak řečeno, frekvence přerušení musí být 32*41670 = 1 333 440 Hz.

V módu CTC
frekvence = (F_CPU/prescaler)/(OCR0A+1)
OCR0A = ((F_CPU/prescaler)/frekvence)-1

Pro frekvenci 1333440 Hz a předdělič 1 dostaneme OCR0A = 13,99

//nastavení timeru TCCR0A = (1<<WGM01); // mód CTC TCCR0B = (1<<CS00); // prescaler 1 OCR0A = 14;

Při každém přerušení zapíšeme hodnotu z tabulky sinus.

Důležité je, že tento zápis nesmí trvat déle než 0,75 us, to jest, než přijde další přerušení.
Nemůžeme tady použít kód od Martina, protože tam bude trvat zápis podstatně déle.

Dokonce ani nejjednodušší kód bez testování tlačítka:

while (1) { if(TIFR & (1<<OCF0A)) { PORTB = sin_tab*; // "i" se vynuluje po hodnotě 31 i++; TIFR = (1<<OCF0A); // clear flag } }
se nedá použít, trvá 0,8us. (Avrstudio 4.17.666 - Winavr 20100110)

Proto bych zvolil menší počet vzorků na periodu, třeba 16 a zkontroloval jestli časování bude sedět.*

Inak v mojom kode sa bude vyberat z pola s indexami 0 az 31 a 0 az 19. Pri dosiahnuti 32 respektive hodnoty 20 sa premenna i vynuluje. Takze ak Ti slo o velkost deklarovaneho pola v mojom kode, malo by byt vsetko OK :slight_smile:

if (generuj_signal == SINUS) { PORT_PRE_DA = sinu *; i++; if (i >= MAX_VZORKY_SINUS) i = 0; } else { PORT_PRE_DA = troj *; i++; if (i >=MAX_VZORKY_TROJUHOLNIK) i = 0; **

V poslední poště jsem ukázal, že přerušení musí být vyvoláno každých 0,75us. Ty máš nastaveno
F_CPU=20MHz
prescaler=64
OCR2=7
takže přerušení nastane za 22,4us.
Všech 32 vzorků odešleš za 22,4*32=716,8us.
To znamená, že kmitočet na výstupu bude 1000/716,8 = 1,395 kHz.
Požadováno bylo 41,67 kHz.

Ale ani předdělič 1 nepomůže, jak je vidět v mé ukázce.
Jedině zmenšit počet vzorků na periodu, aby mezi zápisem vzorků bylo více času.

Zdravim. Presne takto jsem si predstavoval Vase rady… Strucne, jasne a vystizne. Takze vsem moc dekuji. Hned jak bude chvilka, tak se na to vrhnu a poslu Vam sem vysledek.

A naposled vložím metodu poslední záchrany za kterou mě zde nejspíš ukamenují :slight_smile:

while(1)
{
PORTB=hodnota_1;
PORTB=hodnota_2;
PORTB=hodnota_3;
PORTB=hodnota_4;
PORTB=hodnota_5;
.
.
.
.
PORTB=hodnota_n;
}

Plus ještě test tlačítka a přechod do další takové stupidní smyčky…atd.

Prostě co smyčka to jedna výstupní fukce.

Akorát je potřeba dát pozor na optimalizaci kompilátoru a nebo to nejlíp rovnou napsat v ASM

Tato metoda nic nezachrání.
Vzorky se musí posílat s přesně vypočítanými časovými odstupy,
ne je hrnout jeden za druhým co procesor dá.

To o čem se tu bavíme je vlastně pulsní kódová modulace.
Na googlu se o tom dá něco najít.

Ak sa ma testovat tlacitko a signal ma byt spojity, potom sa tlacitko musiniekedy testovat a toto testovanie nesmie narusit spojitost signalu. Naviac nestaci iba testovat tlacitko, ale vyhodnotit nabeznu (dobeznu hranu), lebo ako som pochopil tlacitko ma fungovat ako prepinac. Musi mat samozrejme osetrene zakmity, lebo ak prepnem tvar signalu iba detekovanim stlacenia tlacitka, program bude medzi stavmi pri stlaceni velmi rychlo prepinat a nemam istotu na generovani ktoreho signalu sa zastavi.
Ak taketo vyhodnotenie tlacitka nema narusit kontinuitu signalu, malo by sa dat stihnut medzi lubovolnymi vzorkami. Este by sa dala pouzit metoda “rozprestrenia” vyhodnotenia tlacitka medzi jednotlive vzorky.
Kedze ide o cas, samozrejme by sa dala pouzit Radiusova metoda. Kedze su znama vystupna frekvencia, program sa moze napisat a nastavit taktovaci generator (Xtal, RC, …) procesora tak, aby vystupna frekvencia zodpovedala poziadavku. Do “pomalsieho” signalu by sa medzi jednotlive vzorky vhodne vlozili NOPy.

Toto vsak cele povazujem za nejaky ulet nejakeho profesora. Ak sa jedna o skolske zadanie, podmienky mal vyucujuci zatat take, aby sa student mohol niecomu priucit a nie hned na zaciatku vymyslat krkolomne riesenia aby sa stihlo generovat 50kHz. A ani s krkolomnymi zverstavmi nebude sinus na osciloskope vyzerat ako sinus ale bude zatazeny velkym skreslenim. K comu je toto dobre, nerozumiem.

Ak je to realny problem, v takom pripade by som skor odporucil MCU + svab s frekvencnou syntezou. Na to tie obvody su. Alebo pouzit externu RAM a ani nemusi byt hned dvojportova. Najprv MCU do nej naseka vzorky a potom su tieto vzorky vycitavane a posielane do DA, pricom v druhej faze adesu RAM zabezpecuje 74HC393.
74HC393 dostava hodiny z vystupu jedneho z casovaco procesora. Ak bude pamat napriklad 1024B, zmesti sa do nej 4x256 vzoriek, co by mohlo zodpovedat styrom signalom. Ktory z nich sa ma aktualne vysielat moze urcit procesor pomocou svojich dvoch noziciek.
Toto by som povazoval za slusne riesenie aj pre vyssie frekvencie. A procesor nie je presnym casovanim a rychlym vysielanim signalu prakticky vobec zatazovany. Ak sa nepouzije 2port RAM, treba este medzi dolnych 8b adresej zbernice RAM a vystupmi 74HC393 vlozit nejaky 3stavovyu oddelovat, napriklad 74HC245. Signal RD, WR a CS tej RAMky je plne v rezii MCU.

Takze na to cele by malo stacit pouzit MCU, DA, RAM, 74HC393 a 74HC245

Prajem pekny den :slight_smile:

Nevím co myslíš tou pulzní modulací, když se jedná o generátor funkce-cí, ale pokud potřebuješ co nejlépe zachovat tvar funkce což znamená co nejvíce vzorků na periodu, tak rychleji ty vzorky z cpu nedostaneš.
Testování tlačítka a přechod mezi funkcemi taky nevidím jako problém.
Vzdálenost vzorků je důležitá , nicméně technicky vzato klidně nemusí být mezi všemi vzorky stejná, podstatné je aby odpovídala výstupní hodnota v daný čas.

Trochu to už připomíná dobu, kdy se na 8bitech počítaly takty kvůli správnému časování load/save. Ale jo, proč ne. Už by to ale mělo být v assembleru a počítat přesně taktování - např. prokládat instrukce pro výstup instrukcemi obsluhy tlačítek (což už v C nelze). Pak lze dosáhnout podstatně vyšší frekvence a také přesnosti (např. při snížení frekvence vzorky z tabulky interpolovat).

To jen v případě, že by tabulka sin měla mnohem vyšší jemnost, ale tady má daný počet vzorků a je potřeba zajistit správnou výstupní frekvenci, takže je potřeba zajistit i správné časování vzorků.

Souhlas. Pro takové úlohy už není tento cpu podle mě dost silný. Potíž není s průběhem sin x kde se dá dodatečnš použít analogový interpolační filrt ale s takovými průbehy jako troj x a podobně kde se vyskytují vyšší harmonické.

:arrow_right: administrator: příspěvek byl upraven
Předchozí příspěvky se necitují.

Poslední Martinův příspěvek to shrnuje asi nejlíp - pokud toto zadání mělo posloužit jako test pro studenty, tak měla být výstupní frekvence volena v této konfiguraci nejvýše v jednotkách KHz a úloha mohla být zkomplikována jinými požadavky.

No tak som sa vybuzeroval a tu je vysledok. Ak sa bude zdat byt niekomu zdrojak prilis dlhy, je to v najlepsom slova zmysle jeho problem :slight_smile:
Prekladane pre ATmega8 20MHz, -O3, GCC

Testoval som nasledovne varianty. Teda bolo ich omnoho viac, ale za zdielanie stoja tieto ako hlavne predstavitelky socialneho experimentu.

  1. dalsia vzorka najrychlejsie ako sa da - oba priebehy (SINUS a TROJUHOLNIK) maju rovnaky pocet vzoriek a teda aj rovnaku pevnu rychlost. Ide o demonstrovanie maximalnej rychlosti a zaroven demonstrovanie roznej rychlosti pri roznom algoritmyckom konstrukte.

Frekvencia sa da nastavit vhodnym poctom vzoriek, pripadne dosolichat roznym poctom ASM inistrukcii “nop”. V priklade su vlozene nop-y vyREMovane

  1. dalsia vzorka najrychlejsie ako sa da - rozna frekvencia pre SINUS a TROJUHOLNIK sa da dosiahnut roznym poctom vzoriek, podla zadania bude mat SINUS 1.2x viac vzoriek ako TROJUHOLNIK. Dalej sa da frekvencia znizit vlozenim potrebneho poctu “nop”-ov

  2. dalsia vzorka sa zapise na zaklade zmeny hodnoty predvolby casovaca, oba signaly maju rovnaky pocet vzoriek

  3. dalsia vzorka sa zapise na zaklade zmeny hodnoty predvolby casovaca, oba signaly maju rozny pocet vzoriek

Spolocne rysy:
Aby sme usetrili cas, vyuzijeme nasledovne javy.

  1. Tlacitko sa vyhodnoti cez interupt (dobezna hrana), netreba teda neustale testovat jeho stav.

  2. Nebude sa pri kazdej vzorke testovat aky tvar signalu sa ma generovat, ale vyuzije sa ukazovatel na zaciatok pola premennych pre ten ktory signal. Pri stlaceni tlacitka sa zmeni pociatocna hodnota ukazatela na zaciatok prislusneho pola a zaroven sa (podla demonstrovaneho pripadu) pripadne zmeni prednastavena hodnota poctu prvkov toho pola.

Spolocny kod na zaciatku - v roznych variantoch ho uz nebudem opakovat, ved naco :slight_smile:

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

#define SET(BAJT,BIT) ((BAJT) |= (1<<(BIT)))
#define TST(BAJT,BIT) ((BAJT) & (1<<(BIT)))

#define TRUE 0x00
#define FALSE 0xff
#define PREDVOLBA_CZ 10 // je naschval nizka, aby sw nestihal a tak sa ukazali jeho maximalne moznosti
#define MAX_VZORKY_TROJUHOLNIK 20
#define MAX_VZORKY_SINUS 32
#define PORT_PRE_DA PORTB
#define SMER_PORT_PRE_DA DDRB

uint8_t generuj_signal = SINUS;
uint8_t stav_tlacitka_new,  stav_tlacitka_old, i;

uint8_t sinu  [MAX_VZORKY_SINUS] = {127,138,149,160,171,182,193,205,      //127-205
                     205,193,182,171,160,149,138,127,      //205-127
                     127,116,105,94,83,72,61,49,         //127-49
                     49,61,72,83,94,105,116,127};      //49-127
uint8_t troj  [MAX_VZORKY_TROJUHOLNIK] = {0,12,24,36,48,      //0-48
                     60,71,82,93,103,      //60-103
                     114,125,136,147,154,      //114-154
                     124,93,62,31,0,};   //124-0

// trojuholnik s rovnakym poctom prvkov ako SINUS. 
uint8_t troj2  [MAX_VZORKY_SINUS] = {0,10,20,30,40,50,60,70,
                     80,90,100,110,120,130,140,150,  
                     160,150,140,130,120,110,100,90,    
                     80,70,60,50,40,30,20,10};   

Pripad 1a) maximalna rychlost, oba priebehy maju rovnaky pocet vzoriek.
Cas sa da upravit odREMovanim “nop”-ov pripadne zvysenim/znizenim poctu vzoriek. Cas behu slucky je 0.3us. Tento cas povazujem za velmi slusny. :slight_smile:

volatile uint8_t *p_bajt_pom;

int main(void)
{
register uint8_t i, predvolba;
register uint8_t *p_bajt;

 	sei(); //povolenie globálneho prerušenia  
	SET(GICR,INT0); // povolenie prerušenia od INT0 
	SET(MCUCR, ISC01); // prerusenie na dobeznu hranu
	p_bajt_pom = sinu;
	p_bajt = (uint8_t *)p_bajt_pom;
	
	predvolba = MAX_VZORKY_SINUS;
	i = predvolba;
	SMER_PORT_PRE_DA = 0xff;
	while(1) {

// kod s ktorym slucka s tou istou funkcionalitou trva 0.3us
		if (i == 0) {
			i = predvolba;
			p_bajt = (uint8_t *)p_bajt_pom;
/*
asm volatile("nop\n\t"
             "nop\n\t"
             ::);
*/
	   }
		else {

/*
asm volatile("nop\n\t"
             "nop\n\t"
             "nop\n\t"
             "nop\n\t"
             "nop\n\t"
             "nop\n\t"
             ::);
*/
		}
// ----------------------------------------------------------
		
		PORT_PRE_DA = *p_bajt;
		i--;
		p_bajt++;

	}

}


// nech je tlacitko pripojene na pin s INT0 a dobre osetrene proti zakmitom
ISR (INT0_vect) { 
	if (p_bajt_pom == sinu) {
		 p_bajt_pom = troj2;
	}	 
	else {
		p_bajt_pom = sinu;
	}
	return;   
}  

Pripad 1b) to co predtym, len s horsie napisanym algoritmom. Testovanie na konstantu moze trvat dlhsie ako testovanie na nulu. Vsimnite si tiez poprehadzovanie riadkov s dekrementom i a inkrementom ukazatela. Ich umiestnenim na povodne miesto v zdrojaku bude mat vplyv na rychlejsi beh programu.

Cas trvania slucky 0.45us.


volatile uint8_t *p_bajt_pom;

int main(void)
{
register uint8_t i, predvolba;
register uint8_t *p_bajt;

 	sei(); //povolenie globálneho prerušenia  
	SET(GICR,INT0); // povolenie prerušenia od INT0 
	SET(MCUCR, ISC01); // prerusenie na dobeznu hranu
	p_bajt_pom = sinu;
	p_bajt = (uint8_t *)p_bajt_pom;
	
	predvolba = MAX_VZORKY_SINUS;
	i = predvolba;
	SMER_PORT_PRE_DA = 0xff;
	while(1) {

		PORT_PRE_DA = *p_bajt;

		if (i == predvolba) {
			i = 0;
			p_bajt = p_bajt_pom;
	   }
		else {
		}
		i++; 
		p_bajt++;
	}
}

// nech je tlacitko pripojene na pin s INT0 a dobre osetrene proti zakmitom
ISR (INT0_vect) { 
	if (p_bajt_pom == sinu) {
		 p_bajt_pom = troj2;
	}	 
	else {
		p_bajt_pom = sinu;
	}
	return;   
}  
  1. premenna predvolba uz musi byt typu volatile kvoli spracovaniu cez interupt (obmedzenie je len z hladiska pouzitia prekladaca C, pre ASM by to neplatilo). Vysledny kod trva 0.45us
volatile uint8_t *p_bajt_pom, predvolba;

int main(void)
{
register uint8_t i;
register uint8_t *p_bajt;

 	sei(); //povolenie globálneho prerušenia  
	SET(GICR,INT0); // povolenie prerušenia od INT0 
	SET(MCUCR, ISC01); // prerusenie na dobeznu hranu
	p_bajt_pom = sinu;
	p_bajt = (uint8_t *)p_bajt_pom;
	
	predvolba = MAX_VZORKY_SINUS;
	i = predvolba;
	SMER_PORT_PRE_DA = 0xff;
	while(1) {

// kod s ktorym slucka trva 11.35us
		if (i == 0) {
			i = predvolba;
			p_bajt = p_bajt_pom;
	   }
		else {
		}
// ----------------------------------------------------------

		PORT_PRE_DA = *p_bajt;
		i--; 
		p_bajt++;
	}
}


// nech je tlacitko pripojene na pin s INT0 a dobre osetrene proti zakmitom
ISR (INT0_vect) { 
	if (p_bajt_pom == sinu) {
		 p_bajt_pom = troj;
		 predvolba = MAX_VZORKY_TROJUHOLNIK;
	}	 
	else {
		p_bajt_pom = sinu;
		predvolba = MAX_VZORKY_SINUS;
	}
	return;   
}  
  1. Vzorkovanie je riadenie presne casovacom. Kratky cas slucky je 0.7us

PREDVOLBA_CZ_1 20  // pre casovanie pod 1us,  pre trojuholnik 20 vzoriek
PREDVOLBA_CZ_2 24  // pre casovanie pod 1.2us, pre sinus tiez 20 vzoriek


volatile uint8_t *p_bajt_pom;

int main(void)
{
	register uint8_t i, predvolba, j;
	register uint8_t *p_bajt, p_bajt_pom;

	p_bajt_pom = sinu;
	p_bajt = p_bajt_pom;
		
	predvolba = MAX_VZORKY_SINUS;
	i = predvolba;
	DDRB = 0xff;

   OCR2 = PREDVOLBA_CZ;
   SET(TCCR2,WGM21);
   SET(TCCR2,CS20); // delicka 1


	while(1) {

		j = TIFR;
		if (TST(j, OCF2)) {
		   TIFR = j;

   		if (i == 0) {
	   		i = predvolba;
				p_bajt = p_bajt_pom;
	      }
		   else {
			   i++;
				p_bajt++;
		   }

		   PORTB = *p_bajt;
		}
	}
}

// nech je tlacitko pripojene na pin s INT0 a dobre osetrene proti zakmitom
ISR (INT0_vect) { 
	if (p_bajt_pom == sinu) {
		 p_bajt_pom = troj2;
//   OCR2 = PREDVOLBA_CZ_1;

	}	 
	else {
		p_bajt_pom = sinu;
//   OCR2 = PREDVOLBA_CZ_2;
	}
	return;   
}  
  1. cas slusky je 0.85us. V tomto stave si mozeme dovolit konfort rozneho poctu vzoriek a roznej periody presne definovanej casovacom a nie dlzkou programu pri roznych rozhodovacich vetveniach. Netreba ich teda vyhodnocovat a zaprasovat kod "nop"mi
volatile uint8_t *p_bajt_pom, predvolba;

int main(void)
{
	register uint8_t i, j;
	register uint8_t *p_bajt, p_bajt_pom;

	p_bajt_pom = sinu;
	p_bajt = p_bajt_pom;
		
	predvolba = MAX_VZORKY_SINUS;
	i = predvolba;
	DDRB = 0xff;

   OCR2 = PREDVOLBA_CZ;
   SET(TCCR2,WGM21);
   SET(TCCR2,CS20); // delicka 1


	while(1) {

		j = TIFR;
		if (TST(j, OCF2)) {
		   TIFR = j;

   		if (i == 0) {
	   		i = predvolba;
				p_bajt = p_bajt_pom;
	      }
		   else {
			   i--;
				p_bajt++;
		   }

		   PORTB = *p_bajt;
		}
	}
}

// nech je tlacitko pripojene na pin s INT0 a dobre osetrene proti zakmitom
ISR (INT0_vect) { 
	if (p_bajt_pom == sinu) {
		 p_bajt_pom = troj;
		 predvolba = MAX_VZORKY_TROJUHOLNIK;
	}	 
	else {
		p_bajt_pom = sinu;
		predvolba = MAX_VZORKY_SINUS;
	}
	return;   
}  

Vysledky su medzi casmi 0.3us na vzorku az 0.85us na vzorku. Pravdu povediac, sam som milo poteseny vybornymi vysledkami prekladaca GCC. ASm som ciastocne analyzoval a kujon jeden, zdrojak prelozil v celku efektivne. Vzhladom k tomu, ze zapis v C vedie k daleko lepsie udrziavatelnejsiemu kodu, ktory je zaroven lepsie zdielatelny s komunitou, pracovat v cistom ASM neprinasa nejaku znatelnu efektivitu.

Zaver:
Pre rovnaku frekvenciu a maximalne casovanie oboch signalov je mozne pouzit 66.67 vzorky signalu na frekvenciu 50kHz. Vzorkovanie treba na presnu frekvenciu dosolichat nopmi z in-line asembleru.

Pre rozne frekvencie a maximalne casovanie je mozne pouzit 44 vzorky na periodu pre 50kHz a 53 vzorky pre 41.67kHz. Vzorkovanie treba na presnu frekvenciu dosolichat nopmi z in-line asembleru.

Pre roznu frekvenciu nastavenu casovacom je mozne pouzit na 50kHz 23 vzorky a dosolichat casovac a na 41.67kHz 49 vzoriek.

Osobne by som siel na casovu zakladnu 1us. Na generovanie trojuholnika by som pouzil 20 vzoriek a na generovanie sinusu 24 vzoriek. Tym sa dosiahnu frekvencie presne podla zadania.
Medzi nami , nie je to z hladiska skreslenia boh vie co, ale signal sa bude ako tak podobat a vyucujuci by mal byt spokojny.

Usetreny cas by som venoval napriklad moznej komunikacii s PC a cez neho nastavovaniu vystupnej frekvenie alebo typu priebehu.

BRAVO!!!

To Martin:
Tak toto sem fakt necekal :smiley: Nejlepsi clanek, ktery jsem kdy cetl! Jde videt, ze se v tomto prostredi umis pohybovat :wink: :smiley: Diky