Баловались пару-тройку лет назад.
Заведите мегу128 с кварцем на 14...16 МГц, подключите лопух через транзистор на OC1A (вывод 15) и сыграйте эту программу.
(пример для Codevision 1.25.8)
http://www.youtube.com/watch?v=dtV1chilwxU - вот звучёк с пилообразным сэмплом:)
Программа навеяна даташитом на DDS-ки )))
В аттаче HEX готовый к прошивке.
#include <mega128.h>
#include <delay.h>
#include <math.h>
char sin_samples[255];
enum{ SINE=0,
TRIANGLE,
SAW,
RECTANGLE
};
void generate_sample(char t)
{
char a;
switch(t)
{
case SINE: for(a=0;a<255;a++) sin_samples[a]=127.0*(1+sin((2*PI/255.0)*a));
break;
case TRIANGLE: for (a=0; a<127; a++) sin_samples[a]=a*2;
for (;a<255;a++) sin_samples[a]=255-(a-127)*2;
break;
case SAW: for (a=0; a<255; a++) sin_samples[a]=a;
break;
case RECTANGLE: for (a=0; a<127; a++) sin_samples[a]=0;
for (; a<255; a++) sin_samples[a]=0xff;
break;
}
}
/********************************************************/
#define SAMPLE_RATE (57600.0)
#define SAMPLE_PERIOD (255)
#define TICKS_ROW (2600)
#define ROWS (64)
int row=0;
int ticks_row=0;
#define C (261.6) //note freq
#define D (293.7) //
#define E (329.6)
#define F (349.2)
#define G (392.0)
#define GD (415.0)
#define A (440.0)
#define B (494.0)
flash float notes[64*4]={
E*12, A*3, 0, 100,//0
E*12, A*3, 0, 0,
E*12, C*6, E*6, 0,
E*12, 0, 0, 0,
E*12, E*3, 0, 100,//4
E*12, E*3, 0, 0,
C*12, C*6, E*6, 0,
C*12, C*6, E*6, 0,
D*12, GD*3, 0, 100,//8
0, GD*3, 0, 0,
D*12, B*3, 0, 0,
D*12, 0, E*6, 0,
C*12, E*3, 000, 100,//12
C*12, E*3, 000, 0,
B*6, B*3, E*6, 0,
B*6, B*3, E*6, 0,
A*6, A*3, E*6, 100,//16
A*6, A*3, E*6, 0,
A*6, C*6, 0, 0,
A*6, 0, E*6, 0,
A*6, E*3, 0, 100,//20
A*6, E*3, 0, 0,
C*12, C*6, E*6, 0,
C*12, C*6, E*6, 0,
E*12, A*3, E*6, 100,//24
E*12, A*3, 0, 0,
E*12, 0, E*6, 0,
E*12, C*6, 0, 0,
D*12, E*3, 0, 100,//28
D*12, E*3, 0, 0,
C*12, C*6, E*6, 0,
C*12, C*6, E*6, 0,
B*6, GD*3, 0, 100,//32
B*6, GD*3, 0, 0,
B*6, B*3, 0, 0,
B*6, 0, E*6, 0,
B*6, E*3, 0, 100,//36
B*6, E*3, 0, 0,
C*12, B*3, E*6, 0,
C*12, B*3, E*6, 0,
D*12, GD*3, 0, 100, //40
D*12, GD*3, 0, 0,
D*12, B*3, 0, 0,
D*12, 0, E*6, 0,
E*12, E*3, 0, 100,//44
E*12, E*3, 0, 0,
E*12, B*3, E*6, 0,
E*12, B*3, E*6, 0,
C*12, A*3, 0, 100,//48
C*12, A*3, 0, 0,
C*12, C*6, 0, 0,
C*12, 0, E*6, 0,
A*6, E*3, E*6, 100,//52
A*6, E*3, 0, 0,
A*6, C*6, E*6, 0,
0, C*6, E*6, 0,
A*6, A*3, 0, 100,//56
A*6, A*3, 0, 0,
A*6, 0, E*6, 0,
A*6, C*6, 0, 0,
A*6, E*3, 0, 100,//60
A*6, E*3, 0, 0,
A*6, C*6, E*6, 0,
A*6, C*6, E*6, 0
};
unsigned int phase_fix=0, phase_increment_fix=0,
phase2_fix=0, phase_increment2_fix=0,
phase3_fix=0, phase_increment3_fix=0;
char load_notes=0;
/// Timer 1 overflow interrupt service routine
interrupt [TIM1_OVF] void timer1_ovf_isr(void)
{
//note loader
if (ticks_row--);
else
{
load_notes=1; //грузим ноты
ticks_row=TICKS_ROW;
}
// месим три канала
OCR1AL = (char)((int)((int)sin_samples[(char)(phase_fix>>8)]+
(int)sin_samples[(char)(phase2_fix>>8)]+
(int)sin_samples[(char)(phase3_fix>>8)])>>2);
//DDS
if ((phase_fix+=phase_increment_fix)>(SAMPLE_PERIOD-1)<<8) phase_fix-=(SAMPLE_PERIOD-1)<<8;
if ((phase2_fix+=phase_increment2_fix)>(SAMPLE_PERIOD-1)<<8) phase2_fix-=(SAMPLE_PERIOD-1)<<8;
if ((phase3_fix+=phase_increment3_fix)>(SAMPLE_PERIOD-1)<<8) phase3_fix-=(SAMPLE_PERIOD-1)<<8;
}
/********************************************************/
void main(void)
{
char current_sample=0;
PORTB=0x00;
DDRB=0x20; //OC1A
// Timer/Counter 1 initialization
// Clock source: System Clock
// Mode: Ph. & fr. cor. PWM top=ICR1
// OC1A output: Non-Inv.
// Timer 1 Overflow Interrupt: On
TCCR1A=0x80;
TCCR1B=0x11;
TCNT1H=0x00;
TCNT1L=0x00;
ICR1H=0x01;
ICR1L=0x90;
OCR1AH=0x00;
OCR1AL=0x7F; //medium
OCR1BH=0x00;
OCR1BL=0x00;
OCR1CH=0x00;
OCR1CL=0x00;
// Timer(s)/Counter(s) Interrupt(s) initialization
TIMSK=0x04;
ETIMSK=0x00;
generate_sample(SINE);
#asm("sei");
while(1)
{
if (load_notes)
{
load_notes=0;
phase_increment3_fix=
phase_increment2_fix=
phase_increment_fix=(unsigned int)(256*((float)SAMPLE_PERIOD/(float)SAMPLE_RATE));
#define multfixSlow(a,B) ((unsigned int)((((long)(a))*((long)(B)))>>8)) //multiply two fixed #
phase_increment_fix=multfixSlow(phase_increment_fix,((long)notes[row]*128));
phase_increment2_fix=multfixSlow(phase_increment2_fix,((long)notes[row+1]*128));
phase_increment3_fix=multfixSlow(phase_increment3_fix,((long)notes[row+2]*128));
if((row+=4)>ROWS*4-1)
{
row=0;
if(++current_sample>RECTANGLE) current_sample=0;
generate_sample(current_sample);
}
}
};
}
board128.zip