![]() |
發(fā)布時間: 2013-7-9 23:08
正文摘要:在51hei論壇吸取各位前輩的經(jīng)驗,將之前二極管用量多的問題優(yōu)化一下,目前不用二極管能接6鍵,2只二極管能接12鍵,6只二極管能接18鍵,9只二極管能接21鍵,第22鍵要單獨占用3只二極管最不化算。 實驗用89S51作試 ... |
厲害呀,受教了 |
由于還是新人 只有跟在高手后面慢慢做了! |
這是深夜逛論壇翻到寶了。! |
樓主辛苦 回復的很仔細 |
6膜拜大佬 |
超級贊! 新手 目前寫個 點亮一個LED都帶寫錯的。。。。直接膜拜! |
高手啊,掌握了精髓,所以可以隨心所欲了。 |
這真是大神啊 |
謝謝分享 |
高手呀,收藏一下 |
好東西,攬下試試,謝謝! |
學習。。。。。。。。。。。。。 |
![]() |
支持支持!! |
看看學習學習。。 |
樓主,我沒看見按鍵? |
有套件賣嗎?我要 |
由于還是新人 只有跟在高手后面慢慢做了! |
今天太晚了,下次再弄吧 |
const unsigned char Key_tab[]= //鍵碼映射表 {// 0 1 2 3 4 5 6 7 8 9 22, 0, 2, 0, 0, 0, 0, 0, 4, 0, //0 0, 0, 0, 0, 0,18, 0, 0, 0, 0, //1X 0, 0, 0, 0, 0, 0, 3,14, 0, 0, //2X 20,10, 6, 0, 0, 0, 0, 0, 1,19, //3X 0, 5, 0, 0, 0,15, 0,11, 0, 0, //4X 0,17, 0, 0,13, 8, 0,21, 0, 9, //5X 16,12, 7, 0 //6X }; //=============== 檢測按鍵 ================= void Key_scan() { unsigned char i; Key_count --; //掃描次序 Key_count &= 3; switch (Key_count) //按次序處理 { case 2: //第一輪掃描 if (PINA & 0x02) Key_state |= 0x01; //讀入PINA.1,記錄于Key_state.0 if (PINA & 0x04) Key_state |= 0x02; //讀入PINA.2,記錄于Key_state.1 DDRA &= ~(1<<0); //A口位0先改為輸入 PORTA |= (1<<0); //A口位0上拉有效 DDRA &= ~(1<<2); //A口位2先改為輸入 PORTA |= (1<<2); //A口位2上拉有效 PORTA &= ~(1<<1); //A口位1設(shè)定為0 DDRA |= (1<<1); //A口位1改為輸出0 break; case 1: //每二輪掃描 if (PINA & 0x01) Key_state |= 0x04; //讀入PINA.0,記錄于Key_state.2 if (PINA & 0x04) Key_state |= 0x08; //讀入PINA.2,記錄于Key_state.3 PORTA |= (1<<1); DDRA &= ~(1<<1); PORTA &= ~(1<<2); DDRA |= (1<<2); DDRA &= ~(1<<0); PORTA |= (1<<0); break; case 0: //每三輪掃描 if (PINA & 0x02) Key_state |= 0x10; //讀入PINA.1,記錄于Key_state.4 if (PINA & 0x01) Key_state |= 0x20; //讀入PINA.0,記錄于Key_state.5 PORTA |= (1<<2); DDRA &= ~(1<<2); PORTA &= ~(1<<0); DDRA |= (1<<0); DDRA &= ~(1<<1); PORTA |= (1<<1); break; default: //每四輪掃描 if (!(PINA&0X01)) Key_state &= ~(1<<0); if (!(PINA&0X02)) Key_state &= ~(1<<1); if (!(PINA&0X04)) Key_state &= ~(1<<2); break; } //======更新顯示緩沖區(qū)======= i = Key_tab[Key_state]; if (i == 0) { Disp_buf[2] = 0x11; //顯示三橫 Disp_buf[1] = 0x11; Disp_buf[0] = 0x11; } else { Disp_buf[2] = 0x0c; //字符"C" Disp_buf[1] = i / 10; //鍵碼十位 Disp_buf[0] = i % 10; //鍵碼個位 } //Key_state = 0; } Key_state什么時候清零才合適?要是4IO口的話,鍵碼又如何擴展呢? |
你沒細看程序,Key_state只用了6位,defalt那次的位用壓縮方或與前面6位中的3位相與。如果真的用到9位,鍵碼表占512字節(jié)就不好了。 至于dafalt后的break,在這里可用可不用,因為defalt后已經(jīng)是switch的未端。 你可以把文件傳到這里,或發(fā)至cowboy3@163.com |
四個IO掃3次,那Key_state就不止8位了,咋辦呢? 另外,default語句是不是漏了break? 樓主,能否把QQ號給我?我直接把仿真文件給你,就能直觀地看到錯誤了 |
h333 發(fā)表于 2013-7-10 00:43 51的四個IO能掃65個鍵(或可以再多6個,但這6個可靠性不太好). AVR的,2個IO就可以掃15鍵,4個IO可能超100了,你可以搜索一下h2feo4的貼子。 |
先改變IO狀態(tài),立刻回讀IO,有時會出錯,IO外部受分布參數(shù)影響會有延時,特別是AVR上拉電阻較大,如果立該回讀可能出錯。 這里看似先讀再改變IO輸出,其實讀的時候,上一輪掃描中已經(jīng)把IO改變,到現(xiàn)在已過了5ms,IO狀態(tài)足夠穩(wěn)定了,這時讀入就可靠。 讀完了,再改變IO狀態(tài),其實是為下一次做好準備。 Key_state用組合生成,效果是一樣,只是處理繁瑣且占內(nèi)存也多。你先前的程序IO切換過程不正確才可能導致沒效果。 |
4個IO口,能掃多少鍵呢? ^_^ |
為什么 不是: case 2: //第一輪掃描 DDRA &= ~(1<<0); //A口位0先改為輸入 PORTA |= (1<<0); //A口位0上拉有效 PORTA &= ~(1<<1); //A口位1設(shè)定為0 DDRA |= (1<<1); //A口位1改為輸出0 //第一輪掃描 if (PINA & 0x02) Key_state |= 0x01; //讀入PINA.1,記錄于Key_state.0 if (PINA & 0x04) Key_state |= 0x02; //讀入PINA.2,記錄于Key_state.1 break; 先改變IO口狀態(tài),再做鍵值判斷? 我那個 Key_state = (KB5<<5 + KB4<<4 + KB3<<3 + KB2<<2 + KB1<<1 + KB0);效果也應該是一樣呀,只不過繁瑣了一些 |
樓上還是沒搞明白,舉例說明一下 case 2: //第一輪掃描 if (PINA & 0x02) Key_state |= 0x01; //讀入PINA.1,記錄于Key_state.0 if (PINA & 0x04) Key_state |= 0x02; //讀入PINA.2,記錄于Key_state.1 DDRA &= ~(1<<0); //A口位0先改為輸入 PORTA |= (1<<0); //A口位0上拉有效 PORTA &= (1<<1); //A口位1設(shè)定為0 DDRA |= (1<<1); //A口位1改為輸出0 break; //以上端口變化順序不要更改,否則可以出現(xiàn)短路 |
unsigned char KB0,KB1,KB2,KB3,KB4,KB5; //=============== 檢測按鍵 ================= void Key_scan() { unsigned char i; Key_count --; //掃描次序 Key_count &= 3; switch (Key_count) //按次序處理 { case 2: //第一輪掃描 KB0 = PINA&0X02; KB1 = PINA&0X04; PORTA |= (1<<0); DDRA |= (1<<0); PORTA &= ~(1<<1); DDRA &= ~(1<<1); break; case 1: //每二輪掃描 KB2 = PINA&0X04; KB3 = PINA&0X01; PORTA |= (1<<1); DDRA |= (1<<1); PORTA &= ~(1<<2); DDRA &= ~(1<<2); break; case 0: //每三輪掃描 KB4 = PINA&0X01; KB5 = PINA&0X02; PORTA &= ~(1<<0); DDRA &= ~(1<<0); PORTA |= (1<<2); DDRA |= (1<<2); break; default: //每四輪掃描 if (!(PINA&0X01)) KB0 = 0; if (!(PINA&0X02)) KB2 = 0; if (!(PINA&0X04)) KB4 = 0; //======更新顯示緩沖區(qū)======= Key_state = (KB0<<5 + KB1<<4 + KB2<<3 + KB3<<2 + KB4<<1 + KB5); i = Key_tab[Key_state]; if (i == 0) { Disp_buf[2] = 0x11; //顯示三橫 Disp_buf[1] = 0x11; Disp_buf[0] = 0x11; } else { Disp_buf[2] = 0x0c; //字符"C" Disp_buf[1] = i / 10; //鍵碼十位 Disp_buf[0] = i % 10; //鍵碼個位 } Key_state = 0; } } void main() { // TMOD = 0x10; //定時器1,16位模式 //TCON = 0xc0; //TR1=1;TF1=1; init_devices(); while(1) //主循環(huán) { //Bus_drive(); //顯示總線驅(qū)動 PORTB = LED_font[Disp_buf[2]]; PORTC = LED_font[Disp_buf[1]]; PORTD = LED_font[Disp_buf[0]]; Key_scan(); //檢測按鍵 delay_ms(5); //延時5MS } } 怎么按,都是顯示C22 |
h333 發(fā)表于 2013-7-10 00:21 首先,AVR的IO不是準雙向口,在作為輸入時,需要開上拉電阻,當切換到輸出0時,需要改變PORTA和DDRA,你程序里沒有更改DDRA,因而不能動作。 其次,沒看到你對KB0~KB5的變量類型聲明,51中聲明為bit,AVR中的位操作比較麻煩,建議讀入時直接更新Key_state,取消KB0~KB5。 至于顯示的問題,我打算遲些開個新帖,因為和這主題關(guān)系不大。鍵碼已從 i= Key_tab[Key_state] 獲得,需要送顯示可自行處理。 |
樓主,兩點請求: 1、能否給我單總線數(shù)碼管顯示那塊的電路圖 2、我移植到AVR下,按鍵值不變,錯在哪里呢? //=============== 檢測按鍵 ================= void Key_scan() { unsigned char i; Key_count --; //掃描次序 Key_count &= 3; switch (Key_count) //按次序處理 { case 2: //第一輪掃描 KB0 = PINA&0X02; KB1 = PINA&0X04; PORTA |= (1<<0); PORTA &= ~(1<<1); break; case 1: //每二輪掃描 KB2 = PINA&0X04; KB3 = PINA&0X01; PORTA |= (1<<1); PORTA &= ~(1<<2); break; case 0: //每三輪掃描 KB4 = PINA&0X01; KB5 = PINA&0X02; PINA &= ~(1<<0); PORTA |= (1<<0); break; default: //每四輪掃描 if (!(PINA&0X01)) KB0 = 0; if (!(PINA&0X02)) KB2 = 0; if (!(PINA&0X04)) KB4 = 0; //======更新顯示緩沖區(qū)======= Key_state = KB0<<5 + KB1<<4 + KB2<<3 + KB3<<2 + KB4<<1 + KB5; i = Key_tab[Key_state]; if (i == 0) { Disp_buf[2] = 0x11; //顯示三橫 Disp_buf[1] = 0x11; Disp_buf[0] = 0x11; } else { Disp_buf[2] = 0x0c; //字符"C" Disp_buf[1] = i / 10; //鍵碼十位 Disp_buf[0] = i % 10; //鍵碼個位 } Key_state = 0; } } 還有,你那個筆段代碼是BCD碼嗎? |
對于這種方式的按鍵識別方法,很多朋友擔心編程會很復雜,其實仔細分析后也很簡單.比如上面例子,其本的思路是依次把三個IO拉低,然后記錄另外兩個IO的狀態(tài),最后三個IO都不下拉,再記錄一次,就可得出的結(jié)果.對于按下不同的按鍵,就有不同的結(jié)果.如果只掃18鍵,那么最后一次掃描可以省掉,即掃描三次即可.實際應用時5MS的掃描間隔可以用定時中斷來實現(xiàn),這樣就只占用很少的MCU時間. |
作為試驗目的,沒有接按鍵,只焊了個鍵盤框架,用鑷子短路相應的節(jié)點來當按鍵。圖中接二極管陣列的三根線是3個IO,單獨的一根是地線。MCU發(fā)送串行數(shù)據(jù)給HC595驅(qū)動數(shù)碼管作鍵碼顯示。 |
下次焊個四面體的4IO玩玩看 ----------------------------------------------------- 二極管數(shù)量 6條楞,每楞兩個,12個 中間星型,4個 共16個 |
Powered by 單片機教程網(wǎng)