最佳答案

//絕對除錯透過,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]))%6; //相當於(65536-beat[i])%6

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

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

else TIMSK|=(1OCIE0);

}

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|=(1OCIE0);

}

void timer1_init(void)

{

TCCR1B=0x00;

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

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

TCCR1A=0x00;

TCCR1B=0x05;

//TIMSK|=(1TOIE1);

}

void timer2_init(void)

{

TCCR2=0x00;

TCNT2=100;

TCCR2=0x03;

TIMSK|=(1TOIE2);

}

void MCU_init(void)

{

DDRA=0X00;

DDRB=0X00;

DDRC=0XFF;

DDRD=0XFF;

PORTB=0X00;

PORTC=0xfe;

PORTD=0xff;

}

uchar key_scan(void) //按鈕掃描函式

{

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) //狀態機

{

case 0: //狀態0:無按鈕按下狀態

if(key_press)key_state=1;

break;

case 1: //狀態1:檢測到有按鈕被按下

if(key_press) //按鈕仍按下,轉2

{

//TIMSK^=(1TOIE0);

key_state=2;

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

}

else //按鈕已經釋放,消抖

key_state=0;

break;

case 2: //狀態2:等待釋放或等待按下時間達到長按要求

if(!key_press) //按鈕已經釋放,轉3,繼續判斷是雙按還是單按

{

key_state=3;

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

}

else if ( key_time1=100) //按下時間達到1000ms,返回值2,作長按判斷,轉7等待按鈕釋放

{

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;

case 3: //狀態3:雙按的第二次按鈕輸入前的等待間隙,設定100ms(經過測試,100ms為比較合適的時間間隙,即為人體普通可以雙擊的速度

if(key_press)key_state=4; //在此時間,如果有按鈕被按下,將當作釋放抖動,轉4進一步作出判斷

else if ( key_time04) //如果沒有按鈕被按下,則等待此100ms過去,然後轉5

{

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_time014) //無輸入,則等待輸入有效時間過去,時間滿後,判定為單按,返回值1,狀態位回到0

{

key_state=0;

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

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

} //小於150ms,手指將很難達到雙擊的速度要求,如果時間太長則單按判斷時間過長,按鈕不靈敏,此處180ms經測試較為合適

break;

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

if(key_press) //按鈕仍有效,按下有效,返回3,雙按成立,轉7等待按鈕釋放

{

key_state=7;

key_return=3;

}

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

case 7: //按鈕釋放等待狀態,所有已按下並被識別操作目的的按鈕狀態都將轉到7等待按鈕釋放,並將所有計時初始

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(key0)PORTD=seg_code[key];

switch(key)

{

case 1:

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

break;

case 2:

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

if(i1)i =10;

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

{

i=1;

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

DDRB&=~(1DDB3);

}

PORTC=0xf0;

break;

case 3:

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

i=1;

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

PORTC=0xfe;

break;

default:

break;

}

timeOK=0;

sei();

}

}

}

繼續學習常見問答

三代吉利帝豪油箱多少升

三代吉利帝豪油箱容量為54升。油箱的容積是衡量汽車儲油能力的標準。油箱的容積越大,加的油就越多。車輛續航時間越長越強,跑得越遠,可以減少加油次數。外觀方面,帝豪GL的前臉非常時尚,非常適合年輕人,整個前臉有很強的層次感。鍍鉻條裝飾的家族式進...


吉利遠景ge7油箱幾升的

吉利遠景ge7的油箱容量為48升。1.根據官方資料和專業評測,吉利遠景ge7的工信部油耗資料為5.8L/100km,綜合工況續航里程為828km。根據這個數字和油耗公式,我們可以大約計算出ge7的油箱容量為48升。2.ge7車型是一款以節油...


2014款吉利gx7油箱是多少升的

吉利gx7的燃油箱容積為60L。外觀:時尚動感的車身線條貫徹整個車身,並採用了規格為225/65-R17的五輻條樣式輪轂。新車的軸距則達到了2661mm,整車的長寬高為4541×1833×1700mm。內飾:車廂內飾依舊採用了家用車當前時下...


充電器的瓦數高與低有什麼區別

通用的手機充電器一般都是5V電壓輸出,輸出電壓是一樣的,但不同的充電器輸出功率有所不同,因為平板的電池容量更大,需要的充電功率更大,所以平板用的充電器功率會更大。充電器的功率可以用電流為標示。充電器的功率也不是越大越好的,充電器只是提供充電...


oppo充電器頭從哪看多少W

oppo充電器頭從背面看多少W可以按照如下方式進行計算:1、充電器輸出電壓乘以輸出電流,如普通手機充電器輸出為5V-2A既5X2=10W,充電器上會有標註但標註的為充電器端最大輸出值而並不一定是手機充電的功率,實際充電輸出會因手機可承受的功...


充電器瓦數大小有什麼區別

充電器瓦數越大充電越快,瓦數越小充電越慢。通用的手機充電器一般都是5V電壓輸出,輸出電壓是一樣的,但不同的充電器輸出功率有所不同,因為平板的電池容量更大,需要的充電功率更大,所以平板用的充電器功率會更大。充電器的功率可以用電流為標示。充電器...


win10怎麼調視訊記憶體

按Delete鍵進入BIOS;1、找到集顯調節位置,一般是在Chipset-NorthBridge子項中;2、找到IGDMemory,該選項是整合顯示卡視訊記憶體大小設定選項;3、按下回車鍵,選擇一個較大的視訊記憶體,按下回車鍵儲存,之後按...


手機號碼的郵箱格式是什麼

手機號碼[email protected]或者手機號碼[email protected]。現在很多網站都支援手機號碼註冊的郵箱!如果是移動手機,郵箱的格式是“通行證/手機號/別名@139.com”。電子郵箱(E-MAILBOX)是透過網路電子郵局為網路客戶提供的網路交流的電...


高鐵充電寶能帶幾個

1-2個左右。乘坐高鐵對移動電源沒有限制,也就是說帶多少毫安的充電寶都可以上高鐵的。充電寶不屬於《鐵路旅客運輸規程》中所規定的旅客禁止或限量攜帶物品,乘坐高鐵對於移動電源是沒有明確的規定的,所以高鐵是可以帶充電寶的。在乘坐高鐵時不會管乘客攜...


高鐵座椅上有沒有充電

都有。高鐵座椅上肯定有充電口。高鐵、動車是最近十年發展起來的新型列車,為方便廣大旅客充電使用,按照標準都配備有充電口,旅客可以給手機、電腦等小功率電器充電使用,充電口通常就在座位下方。就連普客列車臥鋪車廂都有充電口,你乘坐一次就知道了。一些...