// Knihovna pro generovani hudebnich zvuku dane frekvence a delky nebo// dane noty temperovaneho ladeni a delky.//// Pro gnerovani pouziva casovac T0, T1 a jednotku CCP1.//// POZOR -- POZOR -- POZOR// Pri nizsi frekvenci XTALu (nez asi 5MHz) je rezie preruseni tak velka, ze spotrebuje// veskery strojovy cas a uz nedojde k ukonceni rozehraneho tonu vyssi frekvence (z oktavy 7// nebo nad cca 8KHz). Resenim je pouzit vlastni INT proceduru s minimalni rezii.//// (c)miho 2004//// Historie// 1.00 Uvodni verze// Konfiguracni parametry//#define SOUND_HI PIN_xx // Pozitivni vystup//#define SOUND_LO PIN_xx // Komplementarni vystup#ifndef SOUND_CLOCK#define SOUND_CLOCK 4000000 // Frelvence krystalu v Hz#endif// Definice hudebnich tonu (not) pro proceduru SoundNote()#define SOUND_C 0#define SOUND_Cis 1#define SOUND_D 2#define SOUND_Dis 3#define SOUND_E 4#define SOUND_F 5#define SOUND_Fis 6#define SOUND_G 7#define SOUND_Gis 8#define SOUND_A 9#define SOUND_Ais 10#define SOUND_H 11#define SOUND_Space 12 // Pomlka// Prototypy verejnych procedurvoid SoundBeep(unsigned int16 Frequency, unsigned int16 Duration);// Predava se frekvence v Hz a doba trvani v ms (0 znamena ticho)void SoundNote(unsigned int8 Note, Octave, unsigned int16 Duration);// Predava se cislo noty (0 je C), posunuti v oktavach (0 nejnizsi ton,// SOUND_Space je ticho), doba trvani v ms// Alternativni makra pro generovani konstatnich tonu// SoundBeepMacro(Frequency, Duration) - frekvence nesmi byt 0// SoundNoteMacro(Note, Octave, Duration) - nepodporuje SOUND_Space// SoundSpaceMacro(Duration) - hraje ticho// Privatni cast#int_ccp1void IntCCP1()// Preruseni od jednotky CCP1 generuje vystup{volatile int1 Data; // Posledni stav vystupuoutput_bit(SOUND_HI,Data); // Nastav vystupoutput_bit(SOUND_LO,~Data);Data=~Data; // Otoc stav vystupu}#if SOUND_CLOCK < (65535*32*4*2) // < 16.7 MHz#define SOUND_PRESCALE 1#elif SOUND_CLOCK < (65535*32*4*2*2) // < 33.6 MHz#define SOUND_PRESCALE 2#elif SOUND_CLOCK < (65535*32*4*2*4) // < 67.1 MHz#define SOUND_PRESCALE 4#elif SOUND_CLOCK < (65535*32*4*2*8) // < 134 MHz#define SOUND_PRESCALE 8#else#error SOUND_CLOCK Frequency too high#endif#bit T0IF=0x0B.2void SoundBeep(unsigned int16 Frequency, unsigned int16 Duration)// Predava se frekvence v Hz a doba trvani v ms (0 znamena ticho)// Rozumne frekvence jsou od 32Hz{unsigned int16 Time; // Pocitadlo zlomkoveho casu// Inicializace casovaceif (Frequency!=0) // Frekvence 0 znamena ticho{setup_ccp1(CCP_COMPARE_RESET_TIMER);set_timer1(0);(int16)CCP_1=SOUND_CLOCK/SOUND_PRESCALE/4/2/Frequency;#if SOUND_PRESCALE==1setup_timer_1(T1_INTERNAL|T1_DIV_BY_1);#elif SOUND_PRESCALE==2setup_timer_1(T1_INTERNAL|T1_DIV_BY_2);#elif SOUND_PRESCALE==4setup_timer_1(T1_INTERNAL|T1_DIV_BY_4);#elif SOUND_PRESCALE==8setup_timer_1(T1_INTERNAL|T1_DIV_BY_8);#endifenable_interrupts(int_ccp1);enable_interrupts(global);}// Delka tonu merena casovacem T0 (bez preruseni)Time=0;setup_timer_0(RTCC_INTERNAL|RTCC_DIV_1);while (Duration){if (T0IF) // Preteceni T0 - kazdych (1/CLK)*4*256{T0IF = 0;Time += (256*4*1000*2048+SOUND_CLOCK/2)/SOUND_CLOCK;}if (Time>>11){Time -= 2048;Duration--;}}// Konec casovacedisable_interrupts(int_ccp1);disable_interrupts(global);}// Definice casu pulperody pro nejnizsi oktavu, v kvantech casovace T1// Pulperiody tonu v dalsich oktavach se ziskavaji rotaci vpravo#define SOUND_Peri_C ((30578*(SOUND_CLOCK/1000)/1000/4/2)/SOUND_PRESCALE) // Perioda 30578us#define SOUND_Peri_Cis ((28862*(SOUND_CLOCK/1000)/1000/4/2)/SOUND_PRESCALE) // Perioda 28862us#define SOUND_Peri_D ((27242*(SOUND_CLOCK/1000)/1000/4/2)/SOUND_PRESCALE) // Perioda 27242us#define SOUND_Peri_Dis ((25713*(SOUND_CLOCK/1000)/1000/4/2)/SOUND_PRESCALE) // Perioda 25713us#define SOUND_Peri_E ((24270*(SOUND_CLOCK/1000)/1000/4/2)/SOUND_PRESCALE) // Perioda 24270us#define SOUND_Peri_F ((22908*(SOUND_CLOCK/1000)/1000/4/2)/SOUND_PRESCALE) // Perioda 22908us#define SOUND_Peri_Fis ((21622*(SOUND_CLOCK/1000)/1000/4/2)/SOUND_PRESCALE) // Perioda 21622us#define SOUND_Peri_G ((20408*(SOUND_CLOCK/1000)/1000/4/2)/SOUND_PRESCALE) // Perioda 20408us#define SOUND_Peri_Gis ((19263*(SOUND_CLOCK/1000)/1000/4/2)/SOUND_PRESCALE) // Perioda 19263us#define SOUND_Peri_A ((18182*(SOUND_CLOCK/1000)/1000/4/2)/SOUND_PRESCALE) // Perioda 18182us#define SOUND_Peri_Ais ((17161*(SOUND_CLOCK/1000)/1000/4/2)/SOUND_PRESCALE) // Perioda 17161us#define SOUND_Peri_H ((16198*(SOUND_CLOCK/1000)/1000/4/2)/SOUND_PRESCALE) // Perioda 16198us// Kontrola na delku konstanty (musi byt mensi nez delka citace)#if SOUND_Peri_C > 65535#error "SOUND_Peri_C too long (Note C requires delay > 65535 cycles)"#endif// Casove konstanty pro noty nejnizsi oktavyconst unsigned int16 Table[12] =SOUND_Peri_C, SOUND_Peri_Cis, SOUND_Peri_D, SOUND_Peri_Dis,SOUND_Peri_E, SOUND_Peri_F, SOUND_Peri_Fis, SOUND_Peri_G,SOUND_Peri_Gis, SOUND_Peri_A, SOUND_Peri_Ais, SOUND_Peri_H;void SoundNote(unsigned int8 Note, Octave, unsigned int16 Duration)// Predava se cislo noty (0 je C), posunuti v oktavach (0 nejnizsi ton)// doba trvani v ms (0 znamena ticho)// Zahraje zadanou notu v zadane oktave dane delky{unsigned int16 Time; // Pocitadlo zlomkoveho casu// Inicializace casovaceif (Note!=SOUND_Space) // Pokud se ma hrat spust hrani{setup_ccp1(CCP_COMPARE_RESET_TIMER);set_timer1(0);(int16)CCP_1=Table[Note]>>Octave;#if SOUND_PRESCALE==1setup_timer_1(T1_INTERNAL|T1_DIV_BY_1);#elif SOUND_PRESCALE==2setup_timer_1(T1_INTERNAL|T1_DIV_BY_2);#elif SOUND_PRESCALE==4setup_timer_1(T1_INTERNAL|T1_DIV_BY_4);#elif SOUND_PRESCALE==8setup_timer_1(T1_INTERNAL|T1_DIV_BY_8);#endifenable_interrupts(int_ccp1);enable_interrupts(global);}// Delka tonu merena casovacem T0 (bez preruseni)Time=0;setup_timer_0(RTCC_INTERNAL|RTCC_DIV_1);while (Duration){if (T0IF) // Preteceni T0 - kazdych (1/CLK)*4*256{T0IF = 0;Time += (256*4*1000*2048+SOUND_CLOCK/2)/SOUND_CLOCK;}if (Time>>11){Time -= 2048;Duration--;}}// Konec casovacedisable_interrupts(int_ccp1);disable_interrupts(global);}