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, 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 }