<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之旅 廣告
                【101.1 矩陣按鍵鼠標式的單擊與雙擊。】 ![](https://img.kancloud.cn/89/70/8970513a066fe0726b2997dcb0329ce0_194x190.png) 上圖101.1.1 有源蜂鳴器電路 ![](https://img.kancloud.cn/68/91/6891d9a9e89ee7345b1505221de5c26b_252x282.png) 上圖101.1.2 LED電路 ![](https://img.kancloud.cn/c1/8a/c18ad9232965b2a0699e388df49ac7b9_341x221.png) 上圖101.1.3 3\*3矩陣按鍵的電路 矩陣按鍵與前面章節獨立按鍵的單擊與雙擊的處理思路是一樣的,本節講矩陣按鍵的單擊與雙擊,也算是重溫之前章節講的內容。 鼠標的左鍵,可以觸發單擊,也可以觸發雙擊。雙擊的規則是這樣的,兩次單擊,如果第1次單擊與第2次單擊的時間比較“短”的時候,則這兩次單擊就構成雙擊。編寫這個程序的最大亮點是如何控制好第1次單擊與第2次單擊的時間間隔。程序例程要實現的功能是:以S1按鍵為例,(1)單擊改變LED燈的顯示狀態。單擊一次LED從原來“滅”的狀態變成“亮”的狀態,或者從原來“亮”的狀態變成“滅”的狀態,依次循環切換。(2)雙擊則蜂鳴器發出“嘀”的一聲。代碼如下: \#include "REG52.H" \#define KEY\_VOICE\_TIME 50 \#define KEY\_SHORT\_TIME 20 //按鍵去抖動的“濾波”時間 \#define KEY\_INTERVAL\_TIME 80 //連續兩次單擊之間的最大有效時間。因為是矩陣,80不一定是80ms void T0\_time(); void SystemInitial(void) ; void Delay(unsigned long u32DelayTime) ; void PeripheralInitial(void) ; void BeepOpen(void); void BeepClose(void); void LedOpen(void); void LedClose(void); void VoiceScan(void); void KeyScan(void); void SingleKeyTask(void); //單擊按鍵任務函數,放在主函數內 void DoubleKeyTask(void); //雙擊按鍵任務函數,放在主函數內 sbit P3\_4=P3^4; //蜂鳴器 sbit P1\_4=P1^4; //LED 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; unsigned char Gu8LedStatus=0; //記錄LED燈的狀態,0代表滅,1代表亮 volatile unsigned char vGu8SingleKeySec=0; //單擊按鍵的觸發序號 volatile unsigned char vGu8DoubleKeySec=0; //雙擊按鍵的觸發序號 void main() { SystemInitial(); Delay(10000); PeripheralInitial(); while(1) { SingleKeyTask(); //單擊按鍵任務函數 DoubleKeyTask(); //雙擊按鍵任務函數 } } /\* 注釋一: \* 矩陣按鍵掃描的詳細過程: \* 先輸出某1列低電平,其它2列輸出高電平,延時等待2ms后(等此3列輸出同步穩定), \* 再分別判斷3行的輸入IO口, 如果發現哪一行是低電平,就說明對應的某個按鍵被觸發。 \* 依次循環切換輸出的3種狀態,并且分別判斷輸入的3行,就可以檢測完9個按鍵。矩陣按鍵的 \* 去抖動處理方法跟我前面講的獨立按鍵去抖動方法是一樣的。 \*/ /\* 注釋二: \* 雙擊按鍵掃描的詳細過程: \* 第一步:平時沒有按鍵被觸發時,按鍵的自鎖標志,去抖動延時計數器一直被清零。 \* 如果之前已經有按鍵觸發過1次單擊,那么啟動時間間隔計數器Su16KeyIntervalCnt1, \* 在KEY\_INTERVAL\_TIME這個允許的時間差范圍內,如果一直沒有第2次單擊觸發, \* 則把累加按鍵觸發的次數Su8KeyTouchCnt1也清零,上一次累計的單擊數被清零, \* 就意味著下一次新的雙擊必須重新開始累加兩次單擊數。 \* 第二步:一旦有按鍵被按下,去抖動延時計數器開始在定時中斷函數里累加,在還沒累加到 \* 閥值KEY\_SHORT\_TIME時,如果在這期間由于受外界干擾或者按鍵抖動,而使 \* IO口突然瞬間觸發成高電平,這個時候馬上把延時計數器Su16KeyCnt \* 清零了,這個過程非常巧妙,非常有效地去除瞬間的雜波干擾,以后凡是用到開關感應器的時候, \* 都可以用類似這樣的方法去干擾。 \* 第三步:如果按鍵按下的時間超過了閥值KEY\_SHORT\_TIME,馬上把自鎖標志Su8KeyLock置1, \* 防止按住按鍵不松手后一直觸發。與此同時,累加1次按鍵次數,如果按鍵次數累加有2次, \* 則認為觸發雙擊按鍵,并把編號vGu8DoubleKeySec賦值。 \* 第四步:等按鍵松開后,自鎖標志Su8KeyLock及時清零解鎖,為下一次自鎖做準備。并且累加間隔時間, \* 防止兩次按鍵的間隔時間太長。如果連續2次單擊的間隔時間太長達到了KEY\_INTERVAL\_TIME \* 的長度,立即清零當前按鍵次數的計數器,這樣意味著上一次的累加單擊數無效,下一次雙擊 \* 必須重新累加新的單擊數。 \*/ void KeyScan(void) //此函數放在定時中斷里每1ms掃描一次 { static unsigned char Su8KeyLock=0; static unsigned int Su16KeyCnt=0; static unsigned char Su8KeyStep=1; static unsigned char Su8ColumnRecord=0; //用來切換當前列的輸出 static unsigned char Su8KeyTouchCnt1; //S1按鍵的次數記錄 static unsigned int Su16KeyIntervalCnt1; //S1按鍵的間隔時間計數器 switch(Su8KeyStep) { case 1: if(0==Su8ColumnRecord) //按鍵掃描輸出第一列低電平 { COLUMN\_OUTPUT1=0; COLUMN\_OUTPUT2=1; COLUMN\_OUTPUT3=1; } else if(1==Su8ColumnRecord) //按鍵掃描輸出第二列低電平 { COLUMN\_OUTPUT1=1; COLUMN\_OUTPUT2=0; COLUMN\_OUTPUT3=1; } else //按鍵掃描輸出第三列低電平 { COLUMN\_OUTPUT1=1; COLUMN\_OUTPUT2=1; COLUMN\_OUTPUT3=0; } 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=1; //如果沒有按鍵按下,返回到第一個運行步驟重新開始掃描!!!!!! Su8KeyLock=0; //按鍵自鎖標志清零 Su16KeyCnt=0; //按鍵去抖動延時計數器清零,此行非常巧妙 if(Su8KeyTouchCnt1>=1) //之前已經有按鍵觸發過一次,啟動間隔時間的計數器 { Su16KeyIntervalCnt1++; //按鍵間隔的時間計數器累加 if(Su16KeyIntervalCnt1>=KEY\_INTERVAL\_TIME) //達到最大允許的間隔時間,溢出無效 { Su16KeyIntervalCnt1=0; //時間計數器清零 Su8KeyTouchCnt1=0; //清零按鍵的按下的次數,因為間隔時間溢出無效 } } Su8ColumnRecord++; //輸出下一列 if(Su8ColumnRecord>=3) { Su8ColumnRecord=0; //依次輸出完第3列之后,繼續從第1列開始輸出低電平 } } else if(0==Su8KeyLock) //有按鍵按下,且是第一次觸發 { if(0==ROW\_INPUT1&&1==ROW\_INPUT2&&1==ROW\_INPUT3) { Su16KeyCnt++; //去抖動延時計數器 if(Su16KeyCnt>=KEY\_SHORT\_TIME) { Su8KeyLock=1;//自鎖置1,避免一直觸發,只有松開按鍵,此標志位才會被清零 if(0==Su8ColumnRecord) //第1列輸出低電平 { Su16KeyIntervalCnt1=0; //按鍵有效間隔的時間計數器清零 Su8KeyTouchCnt1++; //記錄當前單擊的次數 if(1==Su8KeyTouchCnt1) //只按了1次 { vGu8SingleKeySec=1; //單擊任務,觸發1號鍵 對應S1鍵 } else if(Su8KeyTouchCnt1>=2) //連續按了兩次以上 { Su8KeyTouchCnt1=0; //統計按鍵次數清零 vGu8SingleKeySec=1; //單擊任務,觸發1號鍵 對應S1鍵 vGu8DoubleKeySec=1; //雙擊任務,觸發1號鍵 對應S1鍵 } } else if(1==Su8ColumnRecord) //第2列輸出低電平 { vGu8SingleKeySec=2; //觸發2號鍵 對應S2鍵 } else if(2==Su8ColumnRecord) //第3列輸出低電平 { vGu8SingleKeySec=3; //觸發3號鍵 對應S3鍵 } } } else if(1==ROW\_INPUT1&&0==ROW\_INPUT2&&1==ROW\_INPUT3) { Su16KeyCnt++; //去抖動延時計數器 if(Su16KeyCnt>=KEY\_SHORT\_TIME) { Su8KeyLock=1;//自鎖置1,避免一直觸發,只有松開按鍵,此標志位才會被清零 if(0==Su8ColumnRecord) //第1列輸出低電平 { vGu8SingleKeySec=4; //觸發4號鍵 對應S4鍵 } else if(1==Su8ColumnRecord) //第2列輸出低電平 { vGu8SingleKeySec=5; //觸發5號鍵 對應S5鍵 } else if(2==Su8ColumnRecord) //第3列輸出低電平 { vGu8SingleKeySec=6; //觸發6號鍵 對應S6鍵 } } } else if(1==ROW\_INPUT1&&1==ROW\_INPUT2&&0==ROW\_INPUT3) { Su16KeyCnt++; //去抖動延時計數器 if(Su16KeyCnt>=KEY\_SHORT\_TIME) { Su8KeyLock=1;//自鎖置1,避免一直觸發,只有松開按鍵,此標志位才會被清零 if(0==Su8ColumnRecord) //第1列輸出低電平 { vGu8SingleKeySec=7; //觸發7號鍵 對應S7鍵 } else if(1==Su8ColumnRecord) //第2列輸出低電平 { vGu8SingleKeySec=8; //觸發8號鍵 對應S8鍵 } else if(2==Su8ColumnRecord) //第3列輸出低電平 { vGu8SingleKeySec=9; //觸發9號鍵 對應S9鍵 } } } } break; } } void SingleKeyTask(void) //按鍵單擊的任務函數,放在主函數內 { if(0==vGu8SingleKeySec) { return; //按鍵的觸發序號是0意味著無按鍵觸發,直接退出當前函數,不執行此函數下面的代碼 } switch(vGu8SingleKeySec) //根據不同的按鍵觸發序號執行對應的代碼 { case 1: //S1按鍵的單擊任務 //通過Gu8LedStatus的狀態切換,來反復切換LED的“滅”與“亮”的狀態 if(0==Gu8LedStatus) { Gu8LedStatus=1; //標識并且更改當前LED燈的狀態。0就變成1。 LedOpen(); //點亮LED } else { Gu8LedStatus=0; //標識并且更改當前LED燈的狀態。1就變成0。 LedClose(); //關閉LED } vGu8SingleKeySec=0; //響應按鍵服務處理程序后,按鍵編號必須清零,避免一直觸發 break; default: //其它按鍵觸發的單擊 vGu8SingleKeySec=0; //響應按鍵服務處理程序后,按鍵編號必須清零,避免一直觸發 break; } } void DoubleKeyTask(void) //雙擊按鍵任務函數,放在主函數內 { if(0==vGu8DoubleKeySec) { return; //按鍵的觸發序號是0意味著無按鍵觸發,直接退出當前函數,不執行此函數下面的代碼 } switch(vGu8DoubleKeySec) //根據不同的按鍵觸發序號執行對應的代碼 { case 1: //S1按鍵的雙擊任務 vGu8BeepTimerFlag=0; vGu16BeepTimerCnt=KEY\_VOICE\_TIME; //觸發雙擊后,發出“嘀”一聲 vGu8BeepTimerFlag=1; vGu8DoubleKeySec=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) { /\* 注釋三: \* 把LED的初始化放在PeripheralInitial而不是放在SystemInitial,是因為LED顯示內容對上電 \* 瞬間的要求不高。但是,如果是控制繼電器,則應該把繼電器的輸出初始化放在SystemInitial。 \*/ //根據Gu8LedStatus的值來初始化LED當前的顯示狀態,0代表滅,1代表亮 if(0==Gu8LedStatus) { LedClose(); //關閉LED } else { LedOpen(); //點亮LED } } void BeepOpen(void) { P3\_4=0; } void BeepClose(void) { P3\_4=1; } void LedOpen(void) { P1\_4=0; } void LedClose(void) { P1\_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>

                              哎呀哎呀视频在线观看