Problém s clear timer on compare match a generováním pwm

Ahoj,

jsem naprostý začátečník a snažím se podle tohoto návodu: hw.cz/novinky/art3140-rizeni-ser … -mmia.html naprogramovat pwm signál pro řízení modelářského serva.

Program by měl pracovat tak, že každou 1ms nastane přerušení ve kterém je počítadlo do 20 ms(50hz). Jenže mě přijde že frekvence je mnohem nižší.

Používám atmega162 s int. rc ascilátorem 8Mhz. Mod timeru0 CTC OCR=124 předdělička 64.

Najde se prosím někdo kdo poradí? Už jsem u toho proseděl 3 noci a fakt nevím co s tím…

#define SERVO_PORT PORTB

#include <avr/io.h>// hlavičkový soubor pro mikrokontrolér ATmega16
#include <stdio.h> // definiční soubor pro mikrokontrolér ATmega16
#include “.\avr\interrupt.h” //definicni soubor pro obsluhu preruseni
#include <util/delay.h>//definicni soubor pro zpozdeni

#define PIN_OUT0 0
#define DDR( x ) ( *(&x - 1) )// adresa směrového registru portu
#define output0low SERVO_PORT=SERVO_PORT | (1<<PIN_OUT0)
#define output0hi SERVO_PORT=SERVO_PORT & (0xFF-(1<<PIN_OUT0))

volatile char timer = 255;
volatile char poloha0;
volatile char hodn=124;

void servo_init( void )
{
DDRB = 0b11111111;//deklarace výstupního portu pro serva

// Nastaveni Citace Casovace 0
TCCR0 = (1<<WGM01)|(0<<WGM00)|(0<<CS02)|(1<<CS01)|(1<<CS00);	//nastaveni citace/casovace 0
OCR0 = hodn;

TIMSK = (1<<OCIE0);			//povoleni preruseni od citace/casovace 0 

//nastaveni vychozich poloh serv
poloha0  = 1;  

}

ISR( TIMER0_COMP_vect )
{
// casovani PWM
switch (timer)
{

	case 0:					// t=0ms
		{
		output0low;
		OCR0 = hodn;
		break;
		}

	case 1:				// t=1ms
		{
		output0low;
		OCR0 = poloha0;
		break;
		}

	case 2:
		{
		output0hi;
		OCR0 = hodn-poloha0;
		break;
		}
	default:                      // t=2ms az 20ms
		{
		OCR0 = hodn;
		break;
		}
}


++timer;
if(timer==21) timer=255;

}

int main()
{
sei();
servo_init();

while(1)
{
	poloha0=0;
}	
return 0;

}
aa.c (1.53 KB)

Zdarec,
ten program je dost chaotický, moc se mi do toho nechce.
Možná by bylo jednodušší ho napsat znova. Potřebuješ to přesně jak to má tam?
Moc jsem to nepochopil. Chce použít CTC režim na generování 1ms, při druhém průchodu timer patřičně zkrátí dle požadované šířky pulzu a další zas nechá plné. S tím není problém. Zkrácením 1 pulzu se zas tolik nestane, maximálně bude prioda místo 20ms jen 19ms. Jenže tam píše o využití dalších časových slotů. Když všechny zkrátí, tak už může perioda klesnout i na polovičku a nevím, co by na to serva říkala. Samozřejmě se to dá programově vcelku snadno kompenzovat, jen to tam nikde nevidím.
Velice podobným způsobem lze použít FastPWM (i ten má ve sprévném módu nastavitelnou hodnotu TOP) a kompenzace nebude nutná. Obsluha jednodušší a také lze řídit až 10 serv 1 timerem.

Kolik serv chceš řídit?
Co to má všechno umět? nebo zatím stačí jen po zapnutí ta pwm s periodou napevno nastavenou v programu?
S tvým procesorem bych použil 16bit timer1 a režim FastPWM.
Na pochopení to bude snadné a přesnost 1us (u něj je 4us). Perioda zůstane konstantní bez ohledu na nastavenou hodnotu. V základu bez dalších složitostí můžeš pomocí HW pwm řídit 2 serva 1 timerem (má 2 OC registry a piny).
Druhá možnost je využití 8b timeru0 obdobně jako v tom článku, jen bych upřednostnil tu FastPWM s nastavitelnou hodnotou TOP a serv půjde řídit až 10 na tom 1 timeru.

Abych nezapoměl - zdrojáky dávej do “code”, jinak aby se v tom prase vyznalo :wink:.

edit: tak jsem si stáhnul ten zdroják v příloze a ten je čitelnější :slight_smile: Ta kompenzace tam je také, tak uvidíme.

Jesli mě zrak nešálí, má logickou chybu při korekci. Při hodnotách menších než je perioda
pro 1ms to je vpořádku - chybějící čas se přidá v dalším průchodu timeru a perioda se srovná.
Celkem je tedy 21 otoček na 20ms.
Ovšem pří hodnotách vyšších by se měl chybějící čas odečíst -> ubrat obrátku. To mu tam chybí.
Každopádně změna ale bude nejvýš 2ms, což je posun z 50Hz na 45.5Hz, takže by to neměla být taková tragédie.

Jakou frekvenci odhaduješ/měříš? Máš opravdu mcu na 8MHz a né na továrních 1MHz?
Mění se pomocí fuses, nastavení v projektu nemá na fyzickou rychlost procesoru vliv. Pokud bys měl opravdu mcujen na 1MHz, nevrtej se prosím ve fuses sám jesli dobře nevíš, co děláš a můžeš zařídit.

Některé zápisy a komentáře v tom kódu jsou řekněme neobvyklé :slight_smile:

Díky moc za reakci,

serv chci řídit čím víc tím líp(v uvedeném kodu je řízení pouze jednoho), umět to má pouze po zapnutí pwm s periodou napevno nastavenou v programu.

MCU by měla být na 8 Mhz , atmega162 jinou možnost int. Rc oscilátoru nemá. Frekvenci dosaženou tímto kódem odhaduju zhruba na 3hz.

Myslím si, že v návodu používá nesprávný vzorec pro výpočet frekvence: f ocn= f clk / N * OCR0 v dokumentaci jsem našel: f ocn= f clk / 2* N * (OCR0 + 1) což by pro přerušení každou 1ms bylo asi OCR0 = 62. Frekvence se tak zvýší na rychlé blikání, ale určitě to není okolo 50hz.

Co se týče té logické chyby tak šířka pulsu je od 1 do 2 ms což by mělo být v pořádku → 1. přurušení nastavena 1ms , další přerušení šířka pulzu nad 1 ms , 3. přerušení doplní do 2 ms a pak další přerušení doplní zbylých 18 ms.

Mohl by si mi prosím trochu nastínit jak řídit 10 serv přes to fastPWM?

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

Co jsem zběžně koukal na ty jeho nastavení, tak se mi zdála vpořádku.
Tím pwm by to bylo asi následovně: děličkou a nastavením TOP hodnoty (mode 14/15) zařídíš přetečení každou 1ms. Při jednom přetečení timeru nastavíš výstup na požadovanou hodnotu, timer přeteče, nastavíš ocr registr a v ocr přerušení zase pin shodíš, timer ovšem jede dále až do přetečení (není třeba ta kompenzace, protože doba do přetečení zde není závislá na hodnotě ocr). Tyto 2 přetečení potřebuješ na obsluhu 1 serva. Jelikož je těch přetečení v periodě 20, zbývá ti dalších 9 dvojic = dalších 9 serv.
Teď koukám, že 8bit timery tady neumějí fastpwm režim s volitelnou hodnotou TOP. Musely by se použít 16bit timery 1/3.

Zastihl jsi mě ovšem na odchodu a nejspíš budu k dispozici až v neděli, takže dřív to nebude pokud to nespácháš sám nebo nenajdeš chybu :slight_smile:

Do ramce 20ms se vejde jen 8 serv, ne 9. Impuls je dlouhy od 1ms do 2ms + tam musi byt jeste synchro impuls delsi nez 2ms. Pri 9 servech by zbyvalo na synchro jen ty 2ms.
Ale k tematu. Delal jsem tohle bez pwm. Puzil jsem k tomu 2 timery. Jeden stale bezici na ramec 20ms spoustel druhy timer, ktery nahodil impuls a casoval jeho delku a ukoncil impuls a zablokoval se. Za dalsich 20ms ho ten prvni timer zas spustil a tak porad dokola. Pokud bys mel zajem, mohl bych ti poslat zdrojak dekoderu z prijimace. Je tam dekodovani signalu z vysilace a generovani impulsu pro 8 serv najednou.

Zájem určitě mám : odstraněno

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

:arrow_right: administrator: příspěvek byl upraven
Vymazal jsem emailovou adresu. Není zakázáno zveřejňovat kontaktní údaje, je zakázáno žádat o soukromou pomoc, kterou nemohou využít ostatní čtenáři fóra.

Prosím, zdroják uveřejni přímo v příspěvku. Děkuji.

Je to do dekoderu prijimace, takze je tam dekodovani kanalu z vysilace (preruseni INT0 a mereni delky TIMER0) a generovani impulsu pro 8 kanalu (TIMER1 a 2). ADF4001.c je pro obsluhu syntezy kmitoctu, tak si ho nemusis vsimat.
PPMdekoder.zip (3.8 KB)

Přepočítal jsem ocr0 a vypadá to, že ten muj mcu je nastavený vážně na frekvenci 1 Mhz , přitom v dokumentaci takovou hodnotu neuvádí. Mohli byste mi prosím poradit jak nastavovat fuses nejlépe na externí kristal 8 mhz. Našel jsem něco pro pony prog, ale já používám programátor jtag ice.

Potom bych měl ještě prosbičku zda nevíte o nějakém dobrém článku nebo knize s problematikou timerů.

Ale uvadzaju :slight_smile:

Na strane 36 v podkapitole Default Clock Source

Skratka pri kupe procesora je nastaveny fuse na delenie hodinoveho signalu 8x. No a Ty si tuto skutocnost experimentalne overil.
Fuses zmenis v programatore.

POZOR!!! V ponyprogu ma zaskrtnute policko vyznam log.0. Ak si zle nastavis CLK, mozes sa hned zhanat po paralelnom HV programatore, alebo minimalne po extenom zdroji hodin. To uz zavisi od toho, ako si fuses okolo zdroja hodin a /RES ponastavujes.

Tak Ti drzim palce a daj vediet co ako. :slight_smile:

Mrkni do kapitol:
System Clock and Clock Options -> Clock Sources
Memory Programming -> Fuse Bits

Pro začátek bych se s krystalem nepatlal pokud ho nezbytně nepotřebuješ (blbne komunikace na uartu, přesný časování…) a jel jen na interním 8MHz RC oscilátoru. Ve tvém případě to znamená jen přepnout pojistku CKDIV8.
Mimochodem - špatným nastavením CKDIV8 si procesor nevymrtvíš, což lze při modifikaci CKSEL3:0 zařídit velice snadno :wink:.

Naprogramuj si blikátko na 1Hz a poznáš hned, na čem ti mcu běží.
U mě je to téměř vždy 1. program, který procesor uvidí. Teprve potom mu nastavuju hodiny a podobně. Snadno tak poznám, jesli je nastaven správně.