답변 : ATMEGA128 노래 속도
페이지 정보
작성자 master 작성일19-12-14 20:54 조회4,056회 댓글0건본문
// MCU BASIC: https://www.basic4mcu.com
// DateTime : 2019-12-14 오후 8:54:18
// by Ok-Hyun Park
//
#include <io.h>
//
typedef enum{
la_0,lasharp_0,si_0,do_1,dosharp_1,re_1,resharp_1,mi_1,fa_1,fasharp_1,sol_1,solsharp_1,la_1,lasharp_1,
si_1,do_2,dosharp_2,re_2,resharp_2,mi_2,fa_2,fasharp_2,sol_2,solsharp_2,la_2,lasharp_2,si_2,do_3,dosharp_3,
re_3,resharp_3,mi_3,fa_3,fasharp_3,sol_3,solsharp_3,la_3,lasharp_3,si_3,rest
}melody_code;
//
typedef struct{
melody_code tone;
float leng;
}MUSIC_CODE;
//
#define LENGTH 39
//
flash MUSIC_CODE musicCode1[]={
{ do_2,1},{ do_2,0.5},{ do_2,0.5},{ do_2,1},{ do_2,1},//곰세마리가
{ mi_2,1},{ sol_2,0.5},{ sol_2,0.5},{ mi_2,1},{ do_2,1},//한 집에 있어
{ sol_2,0.5},{ sol_2,0.5},{ mi_2,1},{ sol_2,0.5},{ sol_2,0.5},{ mi_2,1},{ do_2,1},{ do_2,1},{ do_2,2},// 아빠곰 엄마곰 애기곰
{ sol_2,1},{ sol_2,1},{ mi_2,1},{ do_2,1},{ sol_2,1},{ sol_2,1},{ sol_2,2},//아빠곰은 뚱뚱해
{ sol_2,1},{ sol_2,1},{ mi_2,1},{ do_2,1},{ sol_2,1},{ sol_2,1},{ sol_2,2},//엄마곰은 날씬해
{ sol_2,1},{ sol_2,1},{ mi_2,1},{ do_2,1},{ sol_2,0.5},{ sol_2,0.5},{ sol_2,0.5},{ la_2,0.5},{ sol_2,2},//애기곰은 너무귀여워
{ do_3,1},{ sol_2,1},{ do_3,1},{ sol_2,1},{ mi_2,1},{ re_2,1},{ do_2,2} //으쓱 으쓱 잘한다
{ 0,0}
};
int a=0;
int baseToneStep[8]={0,2,3,5,7,8,10,12};
//
#define LA_FREQ 110.
#define MULTIPLICATION_FACTOR 1.059463
//
unsigned int cs[8]={0,1,8,32,64,128,256,1024};
//
unsigned char tccr0_set[LENGTH]; // tone을 만들기 위한 TCCR0 값
unsigned char ocr0_set[LENGTH]; // tone을 만들기 위한 OCR0 값
unsigned char i;
unsigned int us;
unsigned long time10Millisec;
unsigned char fndDispHoldVal[4]={ 1,2,3,4};
unsigned char fndHexCode[16]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x27,0x7F,0x6F,0x77,0x7C,0x39,0x5E,0x79,0x71};
//
interrupt[TIM1_COMPA]void Timer1A_cmp_isr(void){++time10Millisec; }
//
void StartTimer(){
time10Millisec=0; TCNT1=0; TIFR=(1<<OCF1A); TIMSK|=(1<<OCIE1A); TCCR1B|=(1<<CS10); TCCR1B|=(1<<CS11);
}
//
void StopTimer(){ TIMSK&=~(1<<OCIE1A); TCCR1B&=~(1<<CS10); TCCR1B&=~(1<<CS11); }
//
void RestartTimer(){ TIMSK|=(1<<OCIE1A); TCCR1B|=(1<<CS10); TCCR1B|=(1<<CS11); }
//---------------------------------------------------------
// 음계 ‘라’로 부터 3 옥타브에 걸친 음의 tone을 만들기 위하여 필요한
// 타이머 0의 clock selection 필드 값과 OCR0 값을 미리 준비해 둠
//---------------------------------------------------------
void MakeTone(){
float reqFreq,num,freq,reqClks; int i,j,steps;
reqFreq=LA_FREQ; // ‘라’ 음의 기준 주파수로 부터 시작함.
for(i=0; i<LENGTH; i++){ // 24개 tone
reqFreq=LA_FREQ;
// 기준 주파수로 부터 몇 단계 떨어져 있는가?
steps=i;
// tone의 주파수 계산
for(j=0; j<steps; j++)
reqFreq*=MULTIPLICATION_FACTOR;
freq=reqFreq*2; // toggle 함에 따라서 카운터 주파수는 2배가 되어야 함
// 한 개의 주기에 16MHz 클럭이 몇 개가 있느가?
reqClks=(16.0E6/freq);
// 가능한 최대 크기의 OCR0 값을 만들 수 있도록 clock selection 선택
for(j=1; j<8; j++){ // 각 prescale 에 대해
num=reqClks /((float)cs[j]);
if(num<=256.){ tccr0_set[i]=j|0b00011000; ocr0_set[i]=((unsigned char)num)-1; break; } // CTC 모드에서 toggle 출력 // TCCR0 값 찾기 // OCR0 값 찾기
}
}
}
//---------------------------------------------------------
// 실제 음 tone을 만들기 위하여,TCCR0와 OCR0 에 갓을 써 넣음
//---------------------------------------------------------/
void SetTone(unsigned char n){ TCCR0=tccr0_set[n]; OCR0=ocr0_set[n]; DDRB.4=1; } // 부저에 연결된 핀을 출력으로
//---------------------------------------------------------
// 100 millisec 마다 CTC 인터럽트가 발생하도록 함.
//---------------------------------------------------------/
void InitTimer3(){
TCCR3B=(1<<WGM32)|(1<<CS31); // CTC mode // 1/8
OCR3AH=19999>>8; OCR3AL=19999&0xFF; // OCR3A=19999
ETIFR=(1<<OCF3A); // ETIFR의 OCF3A(비교일치 flag)을 클리어시킴
ETIMSK|=(1<<OCIE3A); // 비교 일치 인터럽트 enable
}
//
void ReSetTimer3(int a){
switch(a){
case 0: OCR3AH=19999>>8; OCR3AL=19999&0xFF; break;
case 1: OCR3AH= 9999>>8; OCR3AL= 9999&0xFF; break;
case 2: OCR3AH= 6666>>8; OCR3AL= 6666&0xFF; break;
}
}
//---------------------------------------------------------
// 타이머 3의 ISR,100 millisec 마다,시간변수 increment
//---------------------------------------------------------
unsigned char timer3Flag;
unsigned int remainCnt;
int seq;
//
interrupt[TIM3_COMPA]void Timer3A_cmp_isr(void){ timer3Flag++; } // 100 msec interval
//---------------------------------------------------------
// SW1 누르면 플레이 시작
//---------------------------------------------------------
interrupt[EXT_INT4]void ext4_isr(){
if(++a>2)a=0;
if(a==0){ PORTA=0xC2; }
if(a==1){ PORTA=0x92; remainCnt=1; seq=0; StartTimer(); DDRB.4=1; }
if(a==2){ PORTA=0xA2; }
ReSetTimer3(a);
}
//---------------------------------------------------------
// SW2 누르면 중단
//---------------------------------------------------------
interrupt[EXT_INT5]void ext5_isr(){
if(++a>3)a=0;
if(a==0){ PORTA=0x92; }
if(a==1){ PORTA=0x94; }
if(a==2){ remainCnt=0; PORTA=0x98; DDRB.4=0; StopTimer(); }
if(a==3){ remainCnt=1; PORTA=0x91; DDRB.4=1; RestartTimer(); }
}
//
void InitTimer1(){ TCCR1A=0; TCCR1B=(1<<WGM12); OCR1A=24999; }
//
#define T2_OCR 16000000.*0.005/1024.
//
void Timer2Init(){ TCCR2=(1<<WGM21)|(1<<CS22)|(1<<CS20); OCR2=(unsigned char)(T2_OCR)-1; TIMSK|=0x80; }
//
void InitFnd(){ DDRC=0xFF; DDRG|=0x0F; Timer2Init(); }
//
unsigned char fndOnVal[4]={0x01,0x02,0x04,0x08};
//
interrupt[TIM2_COMP]void Timer2_cmp_isr(void){
static unsigned char currFndPos=0;
PORTG=0x00;
PORTC=fndDispHoldVal[currFndPos];
if(currFndPos==1)PORTC|=0x80;
PORTG=fndOnVal[currFndPos];
currFndPos=(++currFndPos)%4;
}
//
void main(){
DDRA=0xFF;
InitFnd();
MakeTone();
InitTimer1();
InitTimer3();
EICRB=0x0A; // falling edge에서 인터럽트 발생
EIMSK=0x30; // SW1,SW2 인터럽트 enable
SREG|=0x80; // 전체 인터럽트 enable
while(1){
if(timer3Flag){ timer3Flag=0; // every 100 millisec
if(remainCnt){
if (remainCnt==10){ DDRB.4=0; } // 끝나기 0.1 sec 전에 음 제거
else if(remainCnt== 1){
if(musicCode1[seq].leng!=0.0){
SetTone(musicCode1[seq].tone);
remainCnt=(unsigned int)(musicCode1[seq].leng*100.);
++seq;
}
}
}
--remainCnt;
us=time10Millisec;
for(i=0; i<4; i++){ fndDispHoldVal[i]=fndHexCode[us%10]; us=us/10; }
}
}
}
//
void ReSetTimer3(int a){
switch(a){
case 0: OCR3AH=19999>>8; OCR3AL=19999&0xFF; break;
case 1: OCR3AH= 9999>>8; OCR3AL= 9999&0xFF; break;
case 2: OCR3AH= 6666>>8; OCR3AL= 6666&0xFF; break;
}
}
댓글 : 0
조회수 : 4,056
등록된 댓글이 없습니다.