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