<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ThinkChat2.0新版上線,更智能更精彩,支持會話、畫圖、視頻、閱讀、搜索等,送10W Token,即刻開啟你的AI之旅 廣告
                **【99.1** **“行列掃描式”矩陣按鍵。】** ![](https://img.kancloud.cn/89/70/8970513a066fe0726b2997dcb0329ce0_194x190.png) 上圖99.1.1 有源蜂鳴器電路 ![](https://img.kancloud.cn/c1/8a/c18ad9232965b2a0699e388df49ac7b9_341x221.png) 上圖99.1.2 3\*3矩陣按鍵的電路 上圖是3\*3的矩陣按鍵電路,其它4\*4或者8\*8的矩陣電路原理是一樣的,編程思路也是一樣的。相對獨立按鍵,矩陣按鍵因為采用動態行列掃描的方式,能更加節省IO口,比如3\*3的3行3列,1行占用1根IO口,1列占用1根IO口,因此3\*3矩陣按鍵占用6個IO口(3+3=6),但是能識別9個按鍵(3\*3=9)。同理,8\*8矩陣按鍵占用16個IO口(8+8=16),但是能識別64個按鍵(8\*8=64)。 矩陣按鍵的編程原理。如上圖3\*3矩陣按鍵的電路,行IO口(P2.2,P2.1,P2.0)定為輸入,列IO口(P2.5,P2.4,P2.3)定為輸出。同一時刻,列輸出的3個IO口只能有1根是輸出L(低電平),其它2根必須全是H(高電平),然后依次輪番切換輸出狀態,列輸出每切換一次,就分別讀取一次行輸入的3個IO口,這樣一次就能識別到3個按鍵的狀態,如果列連續切換3次就可以讀取全部9個按鍵的狀態。列的3種輸出狀態分別是:(P2.5為L,P2.4為H,P2.3為H),(P2.5為H,P2.4為L,P2.3為H),(P2.5為H,P2.4為H,P2.3為L)。為什么列輸出每切換一次就能識別到3個按鍵的狀態?因為,首先要明白一個前提,在沒有任何按鍵“被按下”的時候,行輸入的3個IO口因為內部上拉電阻的作用,默認狀態都是H電平。并且,H與H相互短接輸出為H,H與L相互短接輸出L,也就是,L(低電平)的優先級最大,任何H(高電平)碰到L(低電平)輸出的結果都是L(低電平)。L(低電平)就像數學乘法運算里的數字0,任何數跟0相乘必然等于0。多說一句,這個“L最高優先級”法則是有前提的,就是H(高電平)的產生必須是純粹靠上拉電阻拉高的H(高電平)才行,比如剛好本教程所用的51單片機內部IO口輸出的H(高電平)是依靠內部的上拉電阻產生,如果是其它“非上拉電阻產生的高電平”與“低電平”短接就有“短路燒壞芯片”的風險,這時就需要額外增加“三極管開漏式輸出”電路或者外掛“開漏式輸出集成芯片”電路。繼續回到正題,為什么列輸出每切換一次就能識別到3個按鍵的狀態?舉個例子,比如當列輸出狀態處于(P2.5為L,P2.4為H,P2.3為H)下,我們讀取行輸入的P2.2口,行輸入的P2.2與列輸出P2.5,P2.4,P2.3的“交叉處”有3個按鍵S1,S2,S3,此時,如果P2.2口是L(低電平),那么必然是S1“被按下”,因為想讓P2.2口是L,只有S1有這個能力,而如果S1沒有“被按下”,另外兩個S2,S3即使“被按下”,P2.2口也是H而絕對不會為L,因為S2,S3的列輸出P2.4為H,P2.3為H,H與H相互短接輸出的結果必然為H。 本節例程實現的功能:9個矩陣按鍵,每按下1個按鍵都觸發一次蜂鳴器鳴叫。 \#include "REG52.H" \#define KEY\_VOICE\_TIME 50 \#define KEY\_SHORT\_TIME 20 //按鍵去抖動的“濾波”時間 void T0\_time(); void SystemInitial(void) ; void Delay(unsigned long u32DelayTime) ; void PeripheralInitial(void) ; void BeepOpen(void); void BeepClose(void); void VoiceScan(void); void KeyScan(void); void KeyTask(void); sbit P3\_4=P3^4; //蜂鳴器 sbit ROW\_INPUT1=P2^2; //第1行輸入口。 sbit ROW\_INPUT2=P2^1; //第2行輸入口。 sbit ROW\_INPUT3=P2^0; //第3行輸入口。 sbit COLUMN\_OUTPUT1=P2^5; //第1列輸出口。 sbit COLUMN\_OUTPUT2=P2^4; //第2列輸出口。 sbit COLUMN\_OUTPUT3=P2^3; //第3列輸出口。 volatile unsigned char vGu8BeepTimerFlag=0; volatile unsigned int vGu16BeepTimerCnt=0; volatile unsigned char vGu8KeySec=0; //按鍵的觸發序號 void main() { SystemInitial(); Delay(10000); PeripheralInitial(); while(1) { KeyTask(); //按鍵的任務函數 } } /\* 注釋一: \* 矩陣按鍵掃描的詳細過程: \* 先輸出某1列低電平,其它2列輸出高電平,延時等待2ms后(等此3列輸出同步穩定), \* 再分別判斷3行的輸入IO口, 如果發現哪一行是低電平,就說明對應的某個按鍵被觸發。 \* 依次循環切換輸出的3種狀態,并且分別判斷輸入的3行,就可以檢測完9個按鍵。矩陣按鍵的 \* 去抖動處理方法跟我前面講的獨立按鍵去抖動方法是一樣的,不再重復多講。 \*/ void KeyScan(void) //此函數放在定時中斷里每1ms掃描一次 { static unsigned char Su8KeyLock=0; static unsigned int Su16KeyCnt=0; static unsigned char Su8KeyStep=1; switch(Su8KeyStep) { case 1: //按鍵掃描輸出第一列低電平 COLUMN\_OUTPUT1=0; COLUMN\_OUTPUT2=1; COLUMN\_OUTPUT3=1; Su16KeyCnt=0; //延時計數器清零 Su8KeyStep++; //切換到下一個運行步驟 break; case 2: //延時等待2ms后(等此3列輸出同步穩定)。不是按鍵的去抖動延時。 Su16KeyCnt++; if(Su16KeyCnt>=2) { Su16KeyCnt=0; Su8KeyStep++; //切換到下一個運行步驟 } break; case 3: if(1==ROW\_INPUT1&&1==ROW\_INPUT2&&1==ROW\_INPUT3) { Su8KeyStep++; //如果沒有按鍵按下,切換到下一個運行步驟 Su8KeyLock=0; //按鍵自鎖標志清零 Su16KeyCnt=0; //按鍵去抖動延時計數器清零,此行非常巧妙 } else if(0==Su8KeyLock) //有按鍵按下,且是第一次觸發 { if(0==ROW\_INPUT1&&1==ROW\_INPUT2&&1==ROW\_INPUT3) { Su16KeyCnt++; //去抖動延時計數器 if(Su16KeyCnt>=KEY\_SHORT\_TIME) { Su16KeyCnt=0; Su8KeyLock=1;//自鎖置1,避免一直觸發,只有松開按鍵,此標志位才會被清零 vGu8KeySec=1; //觸發1號鍵 對應S1鍵 } } else if(1==ROW\_INPUT1&&0==ROW\_INPUT2&&1==ROW\_INPUT3) { Su16KeyCnt++; //去抖動延時計數器 if(Su16KeyCnt>=KEY\_SHORT\_TIME) { Su16KeyCnt=0; Su8KeyLock=1;//自鎖置1,避免一直觸發,只有松開按鍵,此標志位才會被清零 vGu8KeySec=2; //觸發2號鍵 對應S2鍵 } } else if(1==ROW\_INPUT1&&1==ROW\_INPUT2&&0==ROW\_INPUT3) { Su16KeyCnt++; //去抖動延時計數器 if(Su16KeyCnt>=KEY\_SHORT\_TIME) { Su16KeyCnt=0; Su8KeyLock=1;//自鎖置1,避免一直觸發,只有松開按鍵,此標志位才會被清零 vGu8KeySec=3; //觸發3號鍵 對應S3鍵 } } } break; case 4: //按鍵掃描輸出第二列低電平 COLUMN\_OUTPUT1=1; COLUMN\_OUTPUT2=0; COLUMN\_OUTPUT3=1; Su16KeyCnt=0; //延時計數器清零 Su8KeyStep++; //切換到下一個運行步驟 break; case 5: //延時等待2ms后(等此3列輸出同步穩定)。不是按鍵的去抖動延時。 Su16KeyCnt++; if(Su16KeyCnt>=2) { Su16KeyCnt=0; Su8KeyStep++; //切換到下一個運行步驟 } break; case 6: if(1==ROW\_INPUT1&&1==ROW\_INPUT2&&1==ROW\_INPUT3) { Su8KeyStep++; //如果沒有按鍵按下,切換到下一個運行步驟 Su8KeyLock=0; //按鍵自鎖標志清零 Su16KeyCnt=0; //按鍵去抖動延時計數器清零,此行非常巧妙 } else if(0==Su8KeyLock) //有按鍵按下,且是第一次觸發 { if(0==ROW\_INPUT1&&1==ROW\_INPUT2&&1==ROW\_INPUT3) { Su16KeyCnt++; //去抖動延時計數器 if(Su16KeyCnt>=KEY\_SHORT\_TIME) { Su16KeyCnt=0; Su8KeyLock=1;//自鎖置1,避免一直觸發,只有松開按鍵,此標志位才會被清零 vGu8KeySec=4; //觸發4號鍵 對應S4鍵 } } else if(1==ROW\_INPUT1&&0==ROW\_INPUT2&&1==ROW\_INPUT3) { Su16KeyCnt++; //去抖動延時計數器 if(Su16KeyCnt>=KEY\_SHORT\_TIME) { Su16KeyCnt=0; Su8KeyLock=1;//自鎖置1,避免一直觸發,只有松開按鍵,此標志位才會被清零 vGu8KeySec=5; //觸發5號鍵 對應S5鍵 } } else if(1==ROW\_INPUT1&&1==ROW\_INPUT2&&0==ROW\_INPUT3) { Su16KeyCnt++; //去抖動延時計數器 if(Su16KeyCnt>=KEY\_SHORT\_TIME) { Su16KeyCnt=0; Su8KeyLock=1;//自鎖置1,避免一直觸發,只有松開按鍵,此標志位才會被清零 vGu8KeySec=6; //觸發6號鍵 對應S6鍵 } } } break; case 7: //按鍵掃描輸出第三列低電平 COLUMN\_OUTPUT1=1; COLUMN\_OUTPUT2=1; COLUMN\_OUTPUT3=0; Su16KeyCnt=0; //延時計數器清零 Su8KeyStep++; //切換到下一個運行步驟 break; case 8: //延時等待2ms后(等此3列輸出同步穩定)。不是按鍵的去抖動延時。 Su16KeyCnt++; if(Su16KeyCnt>=2) { Su16KeyCnt=0; Su8KeyStep++; //切換到下一個運行步驟 } break; case 9: if(1==ROW\_INPUT1&&1==ROW\_INPUT2&&1==ROW\_INPUT3) { Su8KeyStep=1; //如果沒有按鍵按下,返回到第一步,重新開始掃描!!!!!! Su8KeyLock=0; //按鍵自鎖標志清零 Su16KeyCnt=0; //按鍵去抖動延時計數器清零,此行非常巧妙 } else if(0==Su8KeyLock) //有按鍵按下,且是第一次觸發 { if(0==ROW\_INPUT1&&1==ROW\_INPUT2&&1==ROW\_INPUT3) { Su16KeyCnt++; //去抖動延時計數器 if(Su16KeyCnt>=KEY\_SHORT\_TIME) { Su16KeyCnt=0; Su8KeyLock=1;//自鎖置1,避免一直觸發,只有松開按鍵,此標志位才會被清零 vGu8KeySec=7; //觸發7號鍵 對應S7鍵 } } else if(1==ROW\_INPUT1&&0==ROW\_INPUT2&&1==ROW\_INPUT3) { Su16KeyCnt++; //去抖動延時計數器 if(Su16KeyCnt>=KEY\_SHORT\_TIME) { Su16KeyCnt=0; Su8KeyLock=1;//自鎖置1,避免一直觸發,只有松開按鍵,此標志位才會被清零 vGu8KeySec=8; //觸發8號鍵 對應S8鍵 } } else if(1==ROW\_INPUT1&&1==ROW\_INPUT2&&0==ROW\_INPUT3) { Su16KeyCnt++; //去抖動延時計數器 if(Su16KeyCnt>=KEY\_SHORT\_TIME) { Su16KeyCnt=0; Su8KeyLock=1;//自鎖置1,避免一直觸發,只有松開按鍵,此標志位才會被清零 vGu8KeySec=9; //觸發9號鍵 對應S9鍵 } } } break; } } void KeyTask(void) //按鍵任務函數,放在主函數內 { if(0==vGu8KeySec) { return; //按鍵的觸發序號是0意味著無按鍵觸發,直接退出當前函數,不執行此函數下面的代碼 } switch(vGu8KeySec) //根據不同的按鍵觸發序號執行對應的代碼 { case 1: //S1觸發的任務 vGu8BeepTimerFlag=0; vGu16BeepTimerCnt=KEY\_VOICE\_TIME; //發出“嘀”一聲 vGu8BeepTimerFlag=1; vGu8KeySec=0; //響應按鍵服務處理程序后,按鍵編號必須清零,避免一直觸發 break; case 2: //S2觸發的任務 vGu8BeepTimerFlag=0; vGu16BeepTimerCnt=KEY\_VOICE\_TIME; //發出“嘀”一聲 vGu8BeepTimerFlag=1; vGu8KeySec=0; //響應按鍵服務處理程序后,按鍵編號必須清零,避免一直觸發 break; case 3: //S3觸發的任務 vGu8BeepTimerFlag=0; vGu16BeepTimerCnt=KEY\_VOICE\_TIME; //發出“嘀”一聲 vGu8BeepTimerFlag=1; vGu8KeySec=0; //響應按鍵服務處理程序后,按鍵編號必須清零,避免一直觸發 break; case 4: //S4觸發的任務 vGu8BeepTimerFlag=0; vGu16BeepTimerCnt=KEY\_VOICE\_TIME; //發出“嘀”一聲 vGu8BeepTimerFlag=1; vGu8KeySec=0; //響應按鍵服務處理程序后,按鍵編號必須清零,避免一直觸發 break; case 5: //S5觸發的任務 vGu8BeepTimerFlag=0; vGu16BeepTimerCnt=KEY\_VOICE\_TIME; //發出“嘀”一聲 vGu8BeepTimerFlag=1; vGu8KeySec=0; //響應按鍵服務處理程序后,按鍵編號必須清零,避免一直觸發 break; case 6: //S6觸發的任務 vGu8BeepTimerFlag=0; vGu16BeepTimerCnt=KEY\_VOICE\_TIME; //發出“嘀”一聲 vGu8BeepTimerFlag=1; vGu8KeySec=0; //響應按鍵服務處理程序后,按鍵編號必須清零,避免一直觸發 break; case 7: //S7觸發的任務 vGu8BeepTimerFlag=0; vGu16BeepTimerCnt=KEY\_VOICE\_TIME; //發出“嘀”一聲 vGu8BeepTimerFlag=1; vGu8KeySec=0; //響應按鍵服務處理程序后,按鍵編號必須清零,避免一直觸發 break; case 8: //S8觸發的任務 vGu8BeepTimerFlag=0; vGu16BeepTimerCnt=KEY\_VOICE\_TIME; //發出“嘀”一聲 vGu8BeepTimerFlag=1; vGu8KeySec=0; //響應按鍵服務處理程序后,按鍵編號必須清零,避免一直觸發 break; case 9: //S9觸發的任務 vGu8BeepTimerFlag=0; vGu16BeepTimerCnt=KEY\_VOICE\_TIME; //發出“嘀”一聲 vGu8BeepTimerFlag=1; vGu8KeySec=0; //響應按鍵服務處理程序后,按鍵編號必須清零,避免一直觸發 break; } } void T0\_time() interrupt 1 { VoiceScan(); KeyScan(); //按鍵識別的驅動函數 TH0=0xfc; TL0=0x66; } void SystemInitial(void) { TMOD=0x01; TH0=0xfc; TL0=0x66; EA=1; ET0=1; TR0=1; } void Delay(unsigned long u32DelayTime) { for(;u32DelayTime>0;u32DelayTime--); } void PeripheralInitial(void) { } void BeepOpen(void) { P3\_4=0; } void BeepClose(void) { P3\_4=1; } void VoiceScan(void) { static unsigned char Su8Lock=0; if(1==vGu8BeepTimerFlag&&vGu16BeepTimerCnt>0) { if(0==Su8Lock) { Su8Lock=1; BeepOpen(); } else { vGu16BeepTimerCnt--; if(0==vGu16BeepTimerCnt) { Su8Lock=0; BeepClose(); } } } }
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看