回覆列表
  • 1 # 小紅的甜心

    //絕對除錯透過,AVR-GCC,mega16,帶數碼顯示,單鍵開關多功能控制

    #include <avr/io.h>

    #include <avr/interrupt.h>

    #include <tone.h>

    #include <avr/pgmspace.h>

    #define uchar unsigned char

    #define uint unsigned int

    #define key_input PINA

    #define pgm16(A) ((typeof(A))pgm_read_word(&(A)))

    const unsigned char seg_code[] ={0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,0x80,0x90,0x88,0x83,0xC6,0xA1,0x86,0x8E,0x7f,0x3f};

    const uint music[] PROGMEM={M3,F2,M5,B1,M3,F4,M2,F4,M1,B2,L6,F2,M1,F2,MM,M1,F2,L6,F2,L5,B2, L6,F2,M1,B1,MM,M1,F2,L6,F2,M6,F2,L5,F2,M3,F2,M2,F2,MM,M2,F4,M1,F4,L6,F2,M3,F2,M2,B2, M3,F2,MM,M3,F2,MM,M3,F2,M2,F2,M1,B2,L6,F2,M1,F2,L7,F2,L5,F2,L6,B2, L5,F2,L6,F2,MM,L6,F2,L5,F2,M6,F2,M5,F2,MM,M5,F2,M3,F2,M2,F2,MM,M2,F4,M3,F4,M3,F2,M2,F2,M1,B2, M6,F2,H1,B1,M6,F2,H2,F2,H1,F2,MM,H1,F2,M6,F2,MM,M6,F2,M5,F2,MM,M5,F2,M3,F2,M5,B2, M6,F2,H1,B1,M6,F2,H2,F2,H1,F2,MM,H1,F2,M6,F2,M5,F2,MM,M5,F2,MM,M5,F2,M3,F2,M2,B2, M3,B1,MM,M3,F2,M5,F2,M6,F2,M5,F2,MM,M5,F2,M3,F2,MM,M3,F2,M2,F2,MM,M2,F2,M1,F2,L6,B2, L5,F2,M5,F4,MM,M5,F4,MM,M5,F2,M6,F2,M5,F2,M3,F2,M2,F2,M3,F2,MM,M3,F2,M2,B1,L6,F2,M1,B2, M6,F2,H1,B1,M6,F2,H2,F2,H1,B1,M6,F2,MM,M6,F2,M5,F2,MM,M5,F2,M3,F2,M5,B2, M6,F2,H1,B1,M6,F2,H2,F2,H1,B1,M6,F2, M5,F2,MM,M5,F2,MM,M5,F2,M3,F2,M2,B2,MM, M2,F2,MM,M2,F4,M1,F4,M2,F2,M3,F2,M5,F2,MM,M5,F2,MM,M5,F2,M3,F2,M2,F2,MM,M2,F4,M3,F4,M2,F2,M1,F2,L6,B2, L5,F2,M5,F4,MM,M4,F4,MM,M5,F2,M6,F2,M5,F2,M3,F2,M2,F2,M2,F4,M3,F4,MM,M3,F2,M2,B1,L6,F2,M1,B3,0XFF,0XFF};

    //因為兩個相同的音符之間無停頓,人為插入了MM(極短暫的

    volatile uint i=1;

    volatile uchar timeOK=0;

    uchar key_scan(void);

    ISR(TIMER0_COMP_vect) //CTC模式,控制音調高低

    {

    OCR0=pgm16(music[i-1]);

    }

    ISR(TIMER1_OVF_vect) //時間溢位模式,控制節拍長短

    {

    i+=2;

    TCNT1H=(65536-pgm16(music[i]))/256; //相當於(65536-beat[i])/256

    TCNT1L=(65536-pgm16(music[i]))%256; //相當於(65536-beat[i])%256

    if(pgm16(music[i])==0xff)i=1; //在音調陣列的最後加一個0xff,作為終止訊號

    if(pgm16(music[i])==0x00)TIMSK&=(~(1<<OCIE0));

    else TIMSK|=(1<<OCIE0);

    }

    ISR(TIMER2_OVF_vect) //時間溢位模式,用於檢測按鍵,週期10ms

    {

    TCNT2=100;

    timeOK=1;

    }

    void timer0_init(void)

    {

    TCCR0=0x00;

    TCNT0=0x00;

    OCR0=pgm16(music[i-1]);

    TCCR0=0x1a;

    //TIMSK|=(1<<OCIE0);

    }

    void timer1_init(void)

    {

    TCCR1B=0x00;

    TCNT1H=(65536-pgm16(music[i]))/256;

    TCNT1L=(65536-pgm16(music[i]))%256;

    TCCR1A=0x00;

    TCCR1B=0x05;

    //TIMSK|=(1<<TOIE1);

    }

    void timer2_init(void)

    {

    TCCR2=0x00;

    TCNT2=100;

    TCCR2=0x03;

    TIMSK|=(1<<TOIE2);

    }

    void MCU_init(void)

    {

    DDRA=0X00;

    DDRB=0X00;

    DDRC=0XFF;

    DDRD=0XFF;

    PORTB=0X00;

    PORTC=0xfe;

    PORTD=0xff;

    }

    {

    static uchar key_state=0,key_time1=0,key_time0=0; //靜態變數,呼叫以後,值被保留;

    uchar key_press,key_return=0;

    key_press=(~key_input)&0x01; //有鍵1,無鍵0

    switch(key_state) //狀態機

    {

    if(key_press)key_state=1;

    break;

    {

    //TIMSK^=(1<<TOIE0);

    key_state=2;

    key_time1=0; //按下時間初始

    }

    key_state=0;

    break;

    {

    key_state=3;

    key_time0=0; //釋放時間初始

    }

    {

    key_state=8;

    key_time1=0;

    key_return=2;

    }

    break;

    case 8:

    if(!key_press)

    {

    key_state=0;

    key_time1=0;

    }

    else if (++key_time1>=50)

    {

    key_return=2;

    key_time1=0;

    }

    break;

    {

    key_state=5;

    key_time0=0;

    }

    break;

    case 4: //狀態4:第二按的消抖處理

    if(key_press)key_state=2; //快速連按(被認為人手指達不到要求的速率)將被返回到2,當作第一按處理

    else key_state=3; //如果第二按只出現一次,不到10ms,消抖

    break;

    case 5: //狀態5:第二按前等待時間到達,進入正常的第二按等待輸入狀態,第二按只允許在此時間內輸入方為有效

    if(key_press)key_state=6; //此時間內有被按下,轉6,判決抖動;

    else if(++key_time0>14) //無輸入,則等待輸入有效時間過去,時間滿後,判定為單按,返回值1,狀態位回到0

    {

    key_state=0;

    key_time0=0; //雙擊間隔時間一般為100ms,能夠穩定做到第二擊完成時間總共約180~200ms(因人而異)

    key_return=1; //為增加取樣成功率,可適當縮短第二按前的間隙時間,增加第二按等待輸入時間,但總時間不可短於150ms

    break;

    case 6: //狀態6:第二按的抖動判斷

    {

    key_state=7;

    key_return=3;

    }

    else key_state=5; //抖動消除,退回5繼續等待輸入或等待輸入有效時間過去

    if(!key_press)key_state=0;

    key_time1=0;

    key_time0=0;

    break;

    }

    return key_return;

    }

    int main(void)

    {

    MCU_init();

    timer0_init();

    timer1_init();

    timer2_init();

    sei();

    while(1)

    {

    if(timeOK)

    {

    cli();

    uchar key;

    key=key_scan();

    if(key>0)PORTD=seg_code[key];

    switch(key)

    {

    case 1:

    TIMSK^=((1<<OCIE0)|(1<<TOIE1)); DDRB^=(1<<DDB3); PORTC=0xfd;

    break;

    case 2:

    //TIMSK|=((1<<OCIE0)&(1<<TOIE1));

    if(i>1)i+=10;

    if (i>=(sizeof(music)-20))

    {

    i=1;

    TIMSK&=(~((1<<OCIE0)|(1<<TOIE1)));

    DDRB&=~(1<<DDB3);

    }

    PORTC=0xf0;

    break;

    case 3:

    TIMSK&=(~((1<<OCIE0)|(1<<TOIE1)));

    i=1;

    TIMSK|=((1<<OCIE0)|(1<<TOIE1));

    PORTC=0xfe;

    break;

    default:

    break;

    }

    timeOK=0;

    sei();

    }

    }

    }

  • 中秋節和大豐收的關聯?
  • 喜歡動漫的朋友,請介紹幾首你認為最好聽的動漫歌曲吧?