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