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