BASIC4MCU | 질문게시판 | ATMEGA128 질문입니다.
페이지 정보
작성자 나홀로 작성일2020-12-04 04:48 조회10,252회 댓글4건본문
atmega128 부저로 노래를 만들고 있는데 전체음을 일일히 올리지 않고 한번에 모든음을 반음 업하고 싶은데 그러려면 어떤 함수를 수정해야 하나요?? 아래 코드를 베이스로 햇습니다
sw2 누를때마다 업하고 싶은데 도무지 감이 안와서 질문드립니다.
// 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개 tonereqFreq=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/8OCR3AH=19999>>8; OCR3AL=19999&0xFF; // OCR3A=19999ETIFR=(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 인터럽트 enableSREG|=0x80; // 전체 인터럽트 enablewhile(1){if(timer3Flag){ timer3Flag=0; // every 100 millisecif(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;}}
댓글 4
조회수 10,252master님의 댓글
master 작성일
#define LA_FREQ 110.
#define MULTIPLICATION_FACTOR 1.059463
음의 기준값을 변경해주면 되려나요?
소스코드를 파악해서 수정해보세요
master님의 댓글
master 작성일
freq=reqFreq*2; // toggle 함에 따라서 카운터 주파수는 2배가 되어야 함 <-- 2배가 되어서는 전혀 다른 음이 될테고요
https://cafe.naver.com/circuitsmanual/6685
//A4(라)=440*2^( 0/12)=440.00 Hz (기준 주파수)
440Hz 기준으로 위 공식 중 지수부만 변경됩니다. (440*2^(n/12)Hz)
링크글의 표에보면 -45/12 부터 50/12 까지 나와 있습니다.
음의 기본 원리는 링크글이 도움이 되실겁니다.
master님의 댓글
master 작성일
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배가 되어야 함
여기까지가 주파수를 만드는 코드 같군요
그 아래는 OCR0에 넣을 값을 만드는 듯...
소스코드 위에 제 이름이 적혀있지만 제가 만든 소스는 아닙니다.
질문 소스를 수정(코드정리 또는 일부 변경)해서 만들면서 이름을 추가한 것입니다.
제가 만들면 8비트 타이머를 사용하지 않고 위 댓글의 링크처럼 주파수 폭이 넓은 16비트 타이머를 사용합니다.
나홀로님의 댓글
나홀로
감사합니다 한번 해볼께요!