Mám k Tobě dvě věci :
-
Nepoužívej termíny, které nevíš, co znamenají. Najdi si, co je PWM. Ty prostě potřebuješ obdélníkový signál se střídou 1:1 a kmitočtem 300kHz.
-
y=~y;
z=~z;
DDRD=(y<<3);
DDRB=(z<<3);
Víš, co to dělá a co vlastně do DDR registrů zapisuješ ?
A teďka ke Tvému problému :
-
Výše zmíněnými střípky kódu zapisuješ do DDRD a DDRB blbosti. Ale to by ještě nemusel být až tak velký problém, protože směr na pinech střídáš, jen těch pinů měníš víc, než si myslíš.
-
Jak jsi správně spočítal, tak OCR2A=25; i OCR2B=25; je správně, ale při prescaleru 1 máš na provedení přerušení jenom 26 cyklů a to včetně zavolání přerušení a návratu z něj.
[code]int x;
int y;
int z;
ISR(TIMER2_COMPA_vect )
{
x++;
if(x==10)
{
y=~y;
z=~z;
DDRD=(y<<3);
DDRB=(z<<3);
x=0;
}
}[/code]
Jenže obsluha tohoto přerušení (tak, jak je napsaná) potřebuje mnohem více času, než máš k dispozici. Pokud není splněna podmínka if(x==10), trvá obsluha 52 cyklů (dvojnásobek času), pokud je splněna podmínka, pak obsluha trvá 80 cyklů (více, než trojnásobek času).
První průšvih je, že int je 16-bitová hodnota a AVRko je 8-bitový mcu. Pokud nepotřebuješ 16 bitů, pak je mnohem lepší nadefinovat proměnné jako char nebo unsigned char.
Dalším problémem by mohlo být načítání od nuly do nějaké hodnoty. V asm je dosažením nuly nastaven příznak Z ve stavovém slově mcu. Pokud je překladač dostatečně inteligetní, dokáže toho využít. Z hlediska procesoru je tedy lepší počítat od nějaké hodnoty do nuly.
[code]unsigned char x;
unsigned char y;
unsigned char z;
ISR(TIMER2_COMPA_vect)
{
if(–x==0)
{
y=~y;
z=~z;
DDRD=(y<<3);
DDRB=(z<<3);
x=10;
}
}[/code]
Tady bohužel ani tohle nepomohlo - dostal jsem se na 38 a 58 cyklů. Vzhledem k tomu, že mcu stejně nic jinýho nedělá, byl tedy další krok vyřadit úschovu a obnovu registrů a vynechání reti instrukce (ta se musí ručně doplnit, jinak by to nechodilo).
[code]unsigned char x;
unsigned char y;
unsigned char z;
ISR(TIMER2_COMPA_vect, ISR_NAKED)
{
if(–x==0)
{
y=~y;
z=~z;
DDRD=(y<<3);
DDRB=(z<<3);
x=10;
}
reti();
}[/code]
Tady už jsme se dostali při nesplněné podmínce na 15 cyklů, ale při splněné jsme pořád vysoko - na 35 cyklech.
Tady už jsem opustil Tvoje řešení a zkusil jsem svoje :
[code]unsigned char x;
ISR(TIMER2_COMPA_vect, ISR_NAKED )
{
if(–x==0) x=40;
if (x<21)
{
PIND=(1<<3);
PINB=(1<<3);
}
reti();
}[/code]
Tady jsem se dostal na 20-22 cyklů podle splněných podmínek, takže je to s odřenýma ušima, ale stíhá to. Zkusil jsem ještě nadeklarovat x jako proměnnou trvale usazenou v registru :
[code]register unsigned char x asm(“r18”);
ISR(TIMER2_COMPA_vect, ISR_NAKED )
{
if(–x==0) x=40;
if (x<21)
{
PIND=(1<<3);
PINB=(1<<3);
}
reti();
}[/code]
A tady už jsem na 15-17 cyklech, takže se slušnou rezervou. Lepší (efektivnější, rychlejší) by to šlo už napsat jenom v assembleru.
Tady máš výchozí nastavení pinů procesoru před spuštěním čítače:
[code]void setup()
{
DDRD=(1<<3);
DDRB=(1<<3);
DDRA=0;
PORTD=255;
PORTA=255;
PORTB=~(1<<3);
x=1;
plus nastavení čítače do CTC režimu.
}[/code]
Čítač nastav na CTC režim s OCR2A=25; s přerušením od OC2A.
Nevím, co z toho zvládne compiler pro uino. Tohle je odzkoušený kód v AVR Studiu 4.19+WinAVR.