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