BASIC4MCU | 질문게시판 | ATMEGA128 노래 속도
페이지 정보
작성자 Leos 작성일2019-12-14 17:45 조회3,676회 댓글0건본문
스위치 1번을 한 번누르면 노래 재생
두 번 누르면 2배
세 번 누르면 3배속으로 재생되는 코드를 추가하려하는데 delay함수는 사용하지 않고 추가 하는법을 알려주세요.
#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
const 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 short cs[8] = {0, 1, 8, 32, 64, 128, 256, 1024};
// 가능한 prescale 선택값
unsigned char tccr0_set[LENGTH]; // tone을 만들기 위한 TCCR0 값
unsigned char ocr0_set[LENGTH]; // tone을 만들기 위한 OCR0 값
unsigned char i;
unsigned short us;
unsigned long time10Millisec;
unsigned char fndDispHoldVal[4] = {1, 2, 3, 4};
const 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;
int i, j;
float num, freq;
int steps;
float reqClks;
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. )
{ // CTC 모드에서 toggle 출력
tccr0_set[i] = j | 0b00011000; // TCCR0 값 찾기
ocr0_set[i] = ((unsigned char)num) - 1; // OCR0 값 찾기
break;
}
}
}
}//////////////////////////////////////////////////////////////////////////
// 실제 음 tone을 만들기 위하여, TCCR0와 OCR0 에 갓을 써 넣음
///////////////////////////////////////////////////////////////////////////
void SetTone(unsigned char n)
{
TCCR0 = tccr0_set[n];
OCR0 = ocr0_set[n];
DDRB.4 = 1; // 부저에 연결된 핀을 출력으로
}//////////////////////////////////////////////////////////////////////////
// 100 millisec 마다 CTC 인터럽트가 발생하도록 함.
///////////////////////////////////////////////////////////////////////////
void InitTimer3()
{
TCCR3A = 0; // CTC mode
TCCR3B = (1 << WGM32); // CTC mode
TCCR3B |= (1 << CS31); // 1/8
OCR3AH = (19999>>8) & 0xFF; // OCR3A = 19999
OCR3AL = (19999) & 0xFF;
ETIFR = (1 << OCF3A); // ETIFR의 OCF3A(비교일치 flag) 을 클리어시킴
ETIMSK |= (1 << OCIE3A); // 비교 일치 인터럽트 enable
}
//////////////////////////////////////////////////////////////////
// 타이머 3의 ISR, 100 millisec 마다, 시간변수 increment
//////////////////////////////////////////////////////////////////
unsigned char timer3Flag;
unsigned short remainCnt;
int seq;
interrupt [TIM3_COMPA] void Timer3A_cmp_isr(void) // 100 msec interval
{
++ timer3Flag;
}//////////////////////////////////////////////////////////////////
// SW1를 누르면 플레이 시작
//////////////////////////////////////////////////////////////////interrupt [EXT_INT4] void ext4_isr()
{
a++;
if(a%3==0)
{
PORTA=0xC2;
}
if(a%3==1)
{
remainCnt = 1; // mainloop에서 시작하도록 함
seq = 0;
StartTimer();
DDRB.4 = 1;
PORTA=0x92;
}
if(a%3==2)
{
PORTA=0xA2;
}
}
//////////////////////////////////////////////////////////////////
// SW2를 누르면 중단
//////////////////////////////////////////////////////////////////
interrupt [EXT_INT5] void ext5_isr()
{
a++;
if(a%4==0)
{
PORTA=0x92;
}
if(a%4==1)
{PORTA=0x94;
}
if(a%4==2)
{
remainCnt = 0;
PORTA =0x98;
DDRB.4 = 0;
StopTimer();
}
else if(a%4==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();
}
const 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()
{
MakeTone();
InitTimer1();
InitTimer3();
EICRB = 0x0A; // falling edge에서 인터럽트 발생
EIMSK = 0x30; // SW1, SW2 인터럽트 enable
SREG |= 0x80; // 전체 인터럽트 enable
InitFnd();
DDRA = 0xFF;
while ( 1 )
{
if ( timer3Flag ) // every 100 millisec
{
timer3Flag = 0;
if ( remainCnt )
{
if ( remainCnt == 10) // 끝나기 0.1 sec 전에 음 제거
{
DDRB.4 = 0;
}
else if ( remainCnt == 1)
{
if ( musicCode1[seq].leng != 0.0 )
{
SetTone( musicCode1[seq].tone );
remainCnt = (unsigned short)(musicCode1[seq].leng * 100.);
++ seq;
}
}
}
-- remainCnt;
us = time10Millisec;
for (i = 0; i < 4; i ++)
{
fndDispHoldVal[i] = fndHexCode[ us % 10 ];
us = us / 10;
}
}
}
}
댓글 0
조회수 3,676등록된 댓글이 없습니다.