Generátor obdélníku 60kHz

Ahoj,
potřeboval bych udělat generátor obdélníku 60kHz…

Chtěl jsem na to využít Atmegu16A…ale z nějakýho důvodu to nejde…

Program vypadá takhle:

[code]#define F_CPU 12000000UL
//includovane knihovny zde

volatile unsigned int tim0; //pomocna promenna - kolikrat pretece TIMER0

int main(void)
{
sei();//init interrupt
TIMSK|= (1 << TOIE0);// prerušeni pri pretečení TCNT0
// TCCR0|= (1 << CS02)| (1 << CS00); // preddelicka 1024
DDRB |= (1 << PB0); // vystup

while (1) 
{

}

}

//////////////////////////////////////////////////////////////////////////
// TIMER 0
ISR (TIMER0_OVF_vect){ // 8bitu
tim0++;

switch (tim0)
{
	case 1:
	PORTB = (1 << PB0); 
	break;
	
	case 150:
	PORTB ^= (1 << PB0); 
	break;
	
	case 300:
	PORTB ^= (1 << PB0);
	tim0=0;
	break;

}

}
[/code]

Dá se s tím něco dělat?? …a nebo to prostě nejde? (jaká je nejjednodušší lepší varianta)

  1. Máš zakomentované spuštění čítače.
  2. Jak jsi to počítal ? 12000000/1024/256 = 45,7763671875 Hz. Jak z toho chceš dalším dělením dostat obdélník 60 kHz ?

A 2 dotazy :

  1. opravdu máš u procesoru krystal 12 MHz ?
  2. Pokud to bude jenom generátor 60kHz, určitě potřebuješ IO s tolika nožičkama a tak velikou pamětí ?

Úloha má velice jednoduché řešení s minimálním nároky na výkon procesoru. V Cčku jsem shopný se při této konfiguraci dostat na obdélník přes 128khz (v assembleru ještě o kus výše). Samozřejmě s tím, že procesor má ještě čas i na další práci.

Ale domácí úkol tady opravdu řešit nebudu …

Mám zakomentovanou jen předděličku (1024)

Udělal jsem změny:

  1. Výměna krystalu za 14 745 600Hz
  2. tento MCU jsem měl doma i s DPS…tak není co řešít…inak to samozřejmě nepotřebuju

Když odkomentuju předděličku a přepíšu konstanty v časovači, bude to vypadat takhle:

[code]#define F_CPU 14745600UL

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#include <math.h>

volatile unsigned int tim0; //pomocna promenna - kolikrat pretece TIMER0

int main(void)
{
sei();//init interrupt
TIMSK|= (1 << TOIE0);// prerušeni pri pretečení TCNT0
TCCR0|= (1 << CS00)|(1 << CS00); // preddelicka /1024 //datasheet str.73
DDRB |= (1 << PB0); // LEDka na PB0

while (1) 
{

}

}

//////////////////////////////////////////////////////////////////////////
// TIMER 0
ISR (TIMER0_OVF_vect){ //pocita do 255 - 8bitu
TCNT0 = 111; //Prerusi se po 10ms =>(14745600/1024)/(255-111)
tim0++;

switch (tim0)
{
	case 1:
	PORTB = (1 << PB0); 
	break;
	
	case 2:
	PORTB ^= (1 << PB0);
	tim0=0;
	break;

}

}[/code]

FUSES - LOW 0xDF, HIGH 0x D9

Výsledná frekvence by pak měla být 14745600/ 1024/ (255-111)/2
=20ms

Zpoždění MCU je 2us/cyklus…

Takže byl zřejmě špatný krystal…

Teď už jen vymyslet, jak to udělat, aby MCU dával přesně! 60 kHz (nebo 40kHz)

PS: Není to úkol…

Chtěl jsem udělat 12 000 000 bez předděličky, jenom do CASEů napsat 100+100

…bez zpoždění by to vyšlo přesně, byl by prostor na doladění (99+99)
scope_5.bmp (394 KB)

Teda teď fakt nevím, co vlastně chceš 50Hz není 60kHz - to jsi o řád jinde…

Výpočet máš pro 50 Hz, osciloskop ukazuje 44,279 kHz - opět o řád jinde.
To mi nějak nesedí.

Řešení je velice jednoduché, ale chci, abys mě přesvědčil, že je to Tvoje práce a není to domácí úkol. S domácím úkolem pomohu (pomůžeme), ale když to za Tebe tady vyřešíme, tak se nic nenaučíš. Jakmile tady vidíme snahu o řešení nebo alespoň se něco naučit pomůžeme (případně i řešení dodáme).

Řešní mám jednoduché (jednodušší a přesnější, než to Tvoje), i když se mi pořád moc nechce věřit, že to není domácí úkol.

Jinak z kmitočtu 14745600 neuděláš 60000 Hz (alespoň ne přesně). Musí to být dělitelný.

12000000/60000=200 => tohle lze.
14745600/60000=245,76 => tohle nepůjde => 14745600/246=59 941,46341 Hz

12000000/40000=300 => tohle lze.
14745600/40000=368,64 => tohle nepůjde => 14745600/367=40 178,746594 Hz

Tady je to řešení - samozřejmě pro krystal 12 MHz:

[code]#define F_CPU 12000000UL

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

ISR(TIMER0_COMP_vect)
{
PORTB ^= (1<<PB0);
}

int main(void)
{

DDRB = (1<<PB0);

OCR0 = 99;// 60 kHz
//OCR0 = 149;//40 kHz
TCCR0 = (1<<WGM01)|(1<<CS00);
TIMSK = (1<<OCIE0);
sei();

for(;;)
{
}

}[/code]

Je smutný, že se člověk nemůže jen tak bavit a něco vymýšlet…
Úkol do školy to není…je mi 25 :wink:
Každopádně sem asi nechci psát, čeho součástí bude ten generátor…

Tvoje řešení je hodně hezký,
Z datasheetu jsem moc nepochopil,
jakej je rozdíl mezi (1<<OCIE0) a 1 << TOIE0)

A současně nevím, co dělá 1<<WGM01)

…ale to je v tuto chvíli skoro jedno, vyzkouším to a bude to :wink:

Díky moc za vřešení problému!!

(…A doufám, že dnes nemá každej malej kluk doma osciloskop jako já …to bych se nas*al :smiley:

Když ono to zadání bylo tak jednoduchý, že to domácí úlohou opravdu dost zavánělo.

Rozdíl mezi OCIE a TOIE je v tom, kdy přerušení nastává. OCIE nastává v okamžiku, kdy TCNT dosahne OCR. TOIE je přerušení při přetečení TCNT z 0xFF (0xFFFF pro 16-bitový čítač) do 0.

Jinak WGM01 je v tomto případě součástí WGM01:WGM00 a jeho nastavení určuje chování čítače. V tomto případě je čítač nastaven na CTC (Clear Timer on Compare match) neboli čítač čítá 0-OCR a ne 0-0xFF(0xFFFF). V tomto případě TOV nemůže nikdy nastat, protože čítač hodnoty 0xFF (0xFFFF) nidky nedosahne.

Ale tohle je dost dobře v datasheetech popsané.

Na druhou stranu, je dobře, že jsou i takoví jako Ty, kteří ještě něco doma staví a hlavně učí se. Drtivá většina jen koupí arduino, stáhnou uino a pak chodí na fóra s dotazy typu “Už týden hledám knihovnu na rozsvícení LEDky a nemůžu nic najít …”. Jasně, že pokud je tu vidět snaha (i když máš nějaký supertajný projekt o kterým se nesmíš zmínit :slight_smile: ), tak tady poradíme a pomůžeme.

Díky moc!
V týdnu skočím pro krystal a dám sem měření z osciloskopu :wink:

Nakonec jsem vydoloval jenom starej krystal s popisem 16 000kHz
…funguje to, výsledek je takovej:
scope_6.bmp (394 KB)

Pokud bys netrval na PB0, tak si myslím, že by se dal udělat generátor 60kHz úplně bez účasti programu (vyjma prvotního nastavení čítače, samozřejmě) na pinu PB3, případně PD7, PD5 nebo PD4.