Rev 3235 Rev 3255
Line -... Line 1...
-   1 // Knihovna pro generovani hudebnich zvuku dane frekvence a delky nebo
-   2 // dane noty temperovaneho ladeni a delky.
-   3 //
-   4 // Pro gnerovani pouziva casovac T0, T1 a jednotku CCP1.
-   5 //
-   6 // POZOR -- POZOR -- POZOR
-   7 // Pri nizsi frekvenci XTALu (nez asi 5MHz) je rezie preruseni tak velka, ze spotrebuje
-   8 // veskery strojovy cas a uz nedojde k ukonceni rozehraneho tonu vyssi frekvence (z oktavy 7
-   9 // nebo nad cca 8KHz). Resenim je pouzit vlastni INT proceduru s minimalni rezii.
-   10 //
-   11 // (c)miho 2004, pefi 2004,
-   12 //
-   13 // Historie
-   14 // 1.00 Uvodni verze
-   15 // 1.01 Pridana podpora zapnuteho WDT
-   16  
-   17 // Konfiguracni parametry
-   18 //#define SOUND_HI PIN_xx // Pozitivni vystup
-   19 //#define SOUND_LO PIN_xx // Komplementarni vystup
-   20 //#define SOUND_WDT 1 // Pokud je pouzit WDT
-   21 #ifndef SOUND_CLOCK
-   22 #define SOUND_CLOCK 4000000 // Frelvence krystalu v Hz
-   23 #endif
-   24  
-   25  
-   26 // Definice hudebnich tonu (not) pro proceduru SoundNote()
-   27 #define SOUND_C 0
-   28 #define SOUND_Cis 1
-   29 #define SOUND_D 2
-   30 #define SOUND_Dis 3
-   31 #define SOUND_E 4
-   32 #define SOUND_F 5
-   33 #define SOUND_Fis 6
-   34 #define SOUND_G 7
-   35 #define SOUND_Gis 8
-   36 #define SOUND_A 9
-   37 #define SOUND_Ais 10
-   38 #define SOUND_H 11
-   39 #define SOUND_Space 12 // Pomlka
-   40  
-   41  
-   42 // Prototypy verejnych procedur
-   43  
-   44 void SoundBeep(unsigned int16 Frequency, unsigned int16 Duration);
-   45 // Predava se frekvence v Hz a doba trvani v ms (0 znamena ticho)
-   46  
-   47 void SoundNote(unsigned int8 Note, Octave, unsigned int16 Duration);
-   48 // Predava se cislo noty (0 je C), posunuti v oktavach (0 nejnizsi ton,
-   49 // SOUND_Space je ticho), doba trvani v ms
-   50  
-   51 // Alternativni makra pro generovani konstatnich tonu
-   52 // SoundBeepMacro(Frequency, Duration) - frekvence nesmi byt 0
-   53 // SoundNoteMacro(Note, Octave, Duration) - nepodporuje SOUND_Space
-   54 // SoundSpaceMacro(Duration) - hraje ticho
-   55  
-   56 // Privatni cast
-   57  
-   58  
-   59 #int_ccp1
-   60 void IntCCP1()
-   61 // Preruseni od jednotky CCP1 generuje vystup
-   62 {
-   63 volatile int1 Data; // Posledni stav vystupu
-   64 output_bit(SOUND_HI,Data); // Nastav vystup
-   65 output_bit(SOUND_LO,~Data);
-   66 Data=~Data; // Otoc stav vystupu
-   67 }
-   68  
-   69  
-   70 #if SOUND_CLOCK < (65535*32*4*2) // < 16.7 MHz
-   71 #define SOUND_PRESCALE 1
-   72 #elif SOUND_CLOCK < (65535*32*4*2*2) // < 33.6 MHz
-   73 #define SOUND_PRESCALE 2
-   74 #elif SOUND_CLOCK < (65535*32*4*2*4) // < 67.1 MHz
-   75 #define SOUND_PRESCALE 4
-   76 #elif SOUND_CLOCK < (65535*32*4*2*8) // < 134 MHz
-   77 #define SOUND_PRESCALE 8
-   78 #else
-   79 #error SOUND_CLOCK Frequency too high
-   80 #endif
-   81 #bit T0IF=0x0B.2
-   82 void SoundBeep(unsigned int16 Frequency, unsigned int16 Duration)
-   83 // Predava se frekvence v Hz a doba trvani v ms (0 znamena ticho)
-   84 // Rozumne frekvence jsou od 32Hz
-   85 {
-   86 unsigned int16 Time; // Pocitadlo zlomkoveho casu
-   87  
-   88 // Inicializace casovace
-   89 if (Frequency!=0) // Frekvence 0 znamena ticho
-   90 {
-   91 setup_ccp1(CCP_COMPARE_RESET_TIMER);
-   92 set_timer1(0);
-   93 (int16)CCP_1=SOUND_CLOCK/SOUND_PRESCALE/4/2/Frequency;
-   94 #if SOUND_PRESCALE==1
-   95 setup_timer_1(T1_INTERNAL|T1_DIV_BY_1);
-   96 #elif SOUND_PRESCALE==2
-   97 setup_timer_1(T1_INTERNAL|T1_DIV_BY_2);
-   98 #elif SOUND_PRESCALE==4
-   99 setup_timer_1(T1_INTERNAL|T1_DIV_BY_4);
-   100 #elif SOUND_PRESCALE==8
-   101 setup_timer_1(T1_INTERNAL|T1_DIV_BY_8);
-   102 #endif
-   103 enable_interrupts(int_ccp1);
-   104 enable_interrupts(global);
-   105 }
-   106  
-   107 // Delka tonu merena casovacem T0 (bez preruseni)
-   108 Time=0;
-   109 setup_timer_0(RTCC_INTERNAL|RTCC_DIV_1);
-   110 while (Duration)
-   111 {
-   112 #ifdef SOUND_WDT
-   113 restart_wdt(); // Nuluj watchdog abychom se nezresetovali
-   114 #endif
-   115 if (T0IF) // Preteceni T0 - kazdych (1/CLK)*4*256
-   116 {
-   117 T0IF = 0;
-   118 Time += (256*4*1000*2048+SOUND_CLOCK/2)/SOUND_CLOCK;
-   119 }
-   120 if (Time>>11)
-   121 {
-   122 Time -= 2048;
-   123 Duration--;
-   124 }
-   125 }
-   126  
-   127 // Konec casovace
-   128 disable_interrupts(int_ccp1);
-   129 disable_interrupts(global);
-   130 }
-   131  
-   132  
-   133 // Definice casu pulperody pro nejnizsi oktavu, v kvantech casovace T1
-   134 // Pulperiody tonu v dalsich oktavach se ziskavaji rotaci vpravo
-   135 #define SOUND_Peri_C ((30578*(SOUND_CLOCK/1000)/1000/4/2)/SOUND_PRESCALE) // Perioda 30578us
-   136 #define SOUND_Peri_Cis ((28862*(SOUND_CLOCK/1000)/1000/4/2)/SOUND_PRESCALE) // Perioda 28862us
-   137 #define SOUND_Peri_D ((27242*(SOUND_CLOCK/1000)/1000/4/2)/SOUND_PRESCALE) // Perioda 27242us
-   138 #define SOUND_Peri_Dis ((25713*(SOUND_CLOCK/1000)/1000/4/2)/SOUND_PRESCALE) // Perioda 25713us
-   139 #define SOUND_Peri_E ((24270*(SOUND_CLOCK/1000)/1000/4/2)/SOUND_PRESCALE) // Perioda 24270us
-   140 #define SOUND_Peri_F ((22908*(SOUND_CLOCK/1000)/1000/4/2)/SOUND_PRESCALE) // Perioda 22908us
-   141 #define SOUND_Peri_Fis ((21622*(SOUND_CLOCK/1000)/1000/4/2)/SOUND_PRESCALE) // Perioda 21622us
-   142 #define SOUND_Peri_G ((20408*(SOUND_CLOCK/1000)/1000/4/2)/SOUND_PRESCALE) // Perioda 20408us
-   143 #define SOUND_Peri_Gis ((19263*(SOUND_CLOCK/1000)/1000/4/2)/SOUND_PRESCALE) // Perioda 19263us
-   144 #define SOUND_Peri_A ((18182*(SOUND_CLOCK/1000)/1000/4/2)/SOUND_PRESCALE) // Perioda 18182us
-   145 #define SOUND_Peri_Ais ((17161*(SOUND_CLOCK/1000)/1000/4/2)/SOUND_PRESCALE) // Perioda 17161us
-   146 #define SOUND_Peri_H ((16198*(SOUND_CLOCK/1000)/1000/4/2)/SOUND_PRESCALE) // Perioda 16198us
-   147  
-   148 // Kontrola na delku konstanty (musi byt mensi nez delka citace)
-   149 #if SOUND_Peri_C > 65535
-   150 #error "SOUND_Peri_C too long (Note C requires delay > 65535 cycles)"
-   151 #endif
-   152  
-   153 // Casove konstanty pro noty nejnizsi oktavy
-   154 const unsigned int16 Table[12] =
-   155 SOUND_Peri_C, SOUND_Peri_Cis, SOUND_Peri_D, SOUND_Peri_Dis,
-   156 SOUND_Peri_E, SOUND_Peri_F, SOUND_Peri_Fis, SOUND_Peri_G,
-   157 SOUND_Peri_Gis, SOUND_Peri_A, SOUND_Peri_Ais, SOUND_Peri_H;
-   158  
-   159  
-   160 void SoundNote(unsigned int8 Note, Octave, unsigned int16 Duration)
-   161 // Predava se cislo noty (0 je C), posunuti v oktavach (0 nejnizsi ton)
-   162 // doba trvani v ms (0 znamena ticho)
-   163 // Zahraje zadanou notu v zadane oktave dane delky
-   164 {
-   165 unsigned int16 Time; // Pocitadlo zlomkoveho casu
-   166  
-   167 // Inicializace casovace
-   168 if (Note!=SOUND_Space) // Pokud se ma hrat spust hrani
-   169 {
-   170 setup_ccp1(CCP_COMPARE_RESET_TIMER);
-   171 set_timer1(0);
-   172 (int16)CCP_1=Table[Note]>>Octave;
-   173 #if SOUND_PRESCALE==1
-   174 setup_timer_1(T1_INTERNAL|T1_DIV_BY_1);
-   175 #elif SOUND_PRESCALE==2
-   176 setup_timer_1(T1_INTERNAL|T1_DIV_BY_2);
-   177 #elif SOUND_PRESCALE==4
-   178 setup_timer_1(T1_INTERNAL|T1_DIV_BY_4);
-   179 #elif SOUND_PRESCALE==8
-   180 setup_timer_1(T1_INTERNAL|T1_DIV_BY_8);
-   181 #endif
-   182 enable_interrupts(int_ccp1);
-   183 enable_interrupts(global);
-   184 }
-   185  
-   186 // Delka tonu merena casovacem T0 (bez preruseni)
-   187 Time=0;
-   188 setup_timer_0(RTCC_INTERNAL|RTCC_DIV_1);
-   189 while (Duration)
-   190 {
-   191 if (T0IF) // Preteceni T0 - kazdych (1/CLK)*4*256
-   192 {
-   193 T0IF = 0;
-   194 Time += (256*4*1000*2048+SOUND_CLOCK/2)/SOUND_CLOCK;
-   195 }
-   196 if (Time>>11)
-   197 {
-   198 Time -= 2048;
-   199 Duration--;
-   200 }
-   201 #ifdef SOUND_WDT
-   202 restart_wdt(); // Nuluj watchdog abychom se nezresetovali
-   203 #endif
-   204 }
-   205  
-   206 // Konec casovace
-   207 disable_interrupts(int_ccp1);
-   208 disable_interrupts(global);
-   209 }