<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>

                ??碼云GVP開源項目 12k star Uniapp+ElementUI 功能強大 支持多語言、二開方便! 廣告
                【105.1 按住不松手的連續均勻觸發。】 ![](https://img.kancloud.cn/89/70/8970513a066fe0726b2997dcb0329ce0_194x190.png) 上圖105.1.1 有源蜂鳴器電路 ![](https://img.kancloud.cn/73/34/7334d9d189f0de190e15939b9fff75d9_214x279.png) 上圖105.1.2 LED電路 ![](https://img.kancloud.cn/c1/8a/c18ad9232965b2a0699e388df49ac7b9_341x221.png) 上圖105.1.3 3\*3矩陣按鍵的電路 矩陣按鍵與前面章節獨立按鍵的“按住不松手的連續均勻觸發”的處理思路是一樣的。在電腦上刪除某個文件某行文字的時候,單擊一次“退格按鍵\[Backspace\]”,就刪除一個文字,如果按住“退格按鍵\[Backspace\]”不松手,就會“連續均勻”的觸發“刪除”的功能,自動逐個把整行文字刪除清空,這就是“按住不松手的連續均勻觸發”應用案例之一。除此之外,在很多需要人機交互的項目中都有這樣的功能,為了快速加減某個數值,按住某個按鍵不松手,某個數值有節奏地快速往上加或者快速往下減。這種“按住不松手連續均勻觸發”的按鍵識別,在程序上有“3個時間”需要留意,第1個是按鍵單擊的“濾波”時間,第2個是按鍵“從單擊進入連擊”的間隔時間(此時間是“單擊”與“連擊”的分界線),第3個是按鍵“連擊”的間隔時間, 本節例程實現的功能如下:(1)8個受按鍵控制的跑馬燈在某一時刻只有1個LED亮,每觸發一次S1按鍵,“亮的LED”就“往左邊跑一步”;相反,每觸發一次S9按鍵,“亮的LED”就“往右邊跑一步”。如果按住S1或者S9不松手就連續觸發,“亮的LED”就“連續跑”,一直跑到左邊或者右邊的盡頭。(2)按鍵每“單擊”一次S1或者S9蜂鳴器就鳴叫一次,但是,當按鍵“從單擊進入連擊”后,蜂鳴器就不鳴叫。代碼如下: \#include "REG52.H" \#define KEY\_VOICE\_TIME 50 \#define KEY\_SHORT\_TIME 20 //按鍵單擊的“濾波”時間 \#define KEY\_ENTER\_CONTINUITY\_TIME 240 //按鍵“從單擊進入連擊”的間隔時間 \#define KEY\_CONTINUITY\_TIME 64 //按鍵“連擊”的間隔時間 \#define BUS\_P0 P0 //8個LED燈一一對應單片機的P0口總線 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); void DisplayTask(void); //顯示的任務函數(LED顯示狀態) 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; unsigned char Gu8LedStatus=0; //LED燈的狀態 unsigned char Gu8DisplayUpdate=1; //顯示的刷新標志 volatile unsigned char vGu8KeySec=0; //按鍵的觸發序號 volatile unsigned char vGu8ShieldVoiceFlag=0; //屏蔽聲音的標志 void main() { SystemInitial(); Delay(10000); PeripheralInitial(); while(1) { KeyTask(); DisplayTask(); //顯示的任務函數(LED顯示狀態) } } /\* 注釋一: \* Gu8DisplayUpdate這類“顯示刷新變量”在“顯示框架”里是很常見的,而且屢用屢爽。 \* 目的是,既能及時刷新顯示,又能避免主函數“不斷去執行顯示代碼”而影響程序效率。 \*/ void DisplayTask(void) //顯示的任務函數(LED顯示狀態) { if(1==Gu8DisplayUpdate) //需要刷新一次顯示 { Gu8DisplayUpdate=0; //及時清零,避免主函數“不斷去執行顯示代碼”而影響程序效率 //Gu8LedStatus是左移的位數,范圍(0至7),決定了跑馬燈的顯示狀態。 BUS\_P0=~(1<<Gu8LedStatus); //“左移<<”之后的“取反~”,因為LED電路是灌入式驅動方式。 } } /\* 注釋二: \* 本節破題的關鍵: \* 矩陣按鍵涉及的按鍵數量很多,但是實際項目上一般只需要少數個別按鍵具備這種 \* “單擊”與“連續均勻觸發”的特殊技能,因此,在代碼上,必須把這類“特殊技能按鍵”與 \* “大眾按鍵”區分開來,才能相互清晰互不干擾。本節的“特殊技能按鍵”是S1和S9。 \* 如果覺得本節的講解不夠詳細具體,請先閱讀一下前面章節“獨立按鍵按住不松手的連續均勻觸發”。 \*/ void KeyScan(void) //此函數放在定時中斷里每1ms掃描一次 { static unsigned char Su8KeyLock=0; static unsigned int Su16KeyCnt=0; static unsigned char Su8KeyStep=1; static unsigned char Su8ColumnRecord=0; 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: //等待列輸出穩定,但不是去抖動延時 Su16KeyCnt++; if(Su16KeyCnt>=2) { Su16KeyCnt=0; Su8KeyStep++; } break; case 3: if(1==ROW\_INPUT1&&1==ROW\_INPUT2&&1==ROW\_INPUT3) { Su8KeyStep=1; //返回步驟1繼續掃描 Su8KeyLock=0; Su16KeyCnt=0; Su8ColumnRecord++; if(Su8ColumnRecord>=3) { Su8ColumnRecord=0; } } else if(0==Su8KeyLock) { if(0==ROW\_INPUT1&&1==ROW\_INPUT2&&1==ROW\_INPUT3) { Su16KeyCnt++; if(Su16KeyCnt>=KEY\_SHORT\_TIME) { Su8KeyLock=1; if(0==Su8ColumnRecord) { vGu8KeySec=1; //觸發一次單擊 Su16KeyCnt=0; //計時器清零,為即將來臨的計時做準備 Su8KeyStep=4; //跳到S1按鍵的專屬區,脫離大眾按鍵 } else if(1==Su8ColumnRecord) { vGu8KeySec=2; } else if(2==Su8ColumnRecord) { vGu8KeySec=3; } } } else if(1==ROW\_INPUT1&&0==ROW\_INPUT2&&1==ROW\_INPUT3) { Su16KeyCnt++; if(Su16KeyCnt>=KEY\_SHORT\_TIME) { Su8KeyLock=1; if(0==Su8ColumnRecord) { vGu8KeySec=4; } else if(1==Su8ColumnRecord) { vGu8KeySec=5; } else if(2==Su8ColumnRecord) { vGu8KeySec=6; } } } else if(1==ROW\_INPUT1&&1==ROW\_INPUT2&&0==ROW\_INPUT3) { Su16KeyCnt++; if(Su16KeyCnt>=KEY\_SHORT\_TIME) { Su8KeyLock=1; if(0==Su8ColumnRecord) { vGu8KeySec=7; } else if(1==Su8ColumnRecord) { vGu8KeySec=8; } else if(2==Su8ColumnRecord) { vGu8KeySec=9; //觸發一次單擊 Su16KeyCnt=0; //計時器清零,為即將來臨的計時做準備 Su8KeyStep=6; //跳到S9按鍵的專屬區,脫離大眾按鍵 } } } } break; /\*---------S1按鍵的專屬區----------------\*/ case 4: if(0==ROW\_INPUT1&&1==ROW\_INPUT2&&1==ROW\_INPUT3) //僅判斷S1按鍵,避免交叉影響 { Su16KeyCnt++; if(Su16KeyCnt>=KEY\_ENTER\_CONTINUITY\_TIME)//該時間是“單擊”與“連擊”的分界線 { Su16KeyCnt=0; //計時器清零,為即將來臨的計時做準備 Su8KeyStep=5; //S1按鍵進入有節奏的連續觸發 } } else //如果期間檢查到S1按鍵已經松手 { Su8KeyStep=1; //返回步驟1繼續掃描 Su8KeyLock=0; Su16KeyCnt=0; Su8ColumnRecord++; if(Su8ColumnRecord>=3) { Su8ColumnRecord=0; } } break; case 5: //S1按鍵進入有節奏的連續觸發 if(0==ROW\_INPUT1&&1==ROW\_INPUT2&&1==ROW\_INPUT3) //僅判斷S1按鍵,避免交叉影響 { Su16KeyCnt++; if(Su16KeyCnt>=KEY\_CONTINUITY\_TIME) //該時間是“連擊”的時間 { Su16KeyCnt=0; //清零,為了繼續連擊。 vGu8KeySec=1; //觸發一次S1按鍵 vGu8ShieldVoiceFlag=1; //因為連擊,把當前按鍵觸發的聲音屏蔽掉 } } else //如果期間檢查到S1按鍵已經松手 { Su8KeyStep=1; //返回步驟1繼續掃描 Su8KeyLock=0; Su16KeyCnt=0; Su8ColumnRecord++; if(Su8ColumnRecord>=3) { Su8ColumnRecord=0; } } break; /\*---------S9按鍵的專屬區----------------\*/ case 6: if(1==ROW\_INPUT1&&1==ROW\_INPUT2&&0==ROW\_INPUT3) //僅判斷S9按鍵,避免交叉影響 { Su16KeyCnt++; if(Su16KeyCnt>=KEY\_ENTER\_CONTINUITY\_TIME)//該時間是“單擊”與“連擊”的分界線 { Su16KeyCnt=0; //計時器清零,為即將來臨的計時做準備 Su8KeyStep=7; //S9按鍵進入有節奏的連續觸發 } } else //如果期間檢查到S9按鍵已經松手 { Su8KeyStep=1; //返回步驟1繼續掃描 Su8KeyLock=0; Su16KeyCnt=0; Su8ColumnRecord++; if(Su8ColumnRecord>=3) { Su8ColumnRecord=0; } } break; case 7: //S9按鍵進入有節奏的連續觸發 if(1==ROW\_INPUT1&&1==ROW\_INPUT2&&0==ROW\_INPUT3) //僅判斷S9按鍵,避免交叉影響 { Su16KeyCnt++; if(Su16KeyCnt>=KEY\_CONTINUITY\_TIME) //該時間是“連擊”的時間 { Su16KeyCnt=0; //清零,為了繼續連擊。 vGu8KeySec=9; //觸發一次S9按鍵 vGu8ShieldVoiceFlag=1; //因為連擊,把當前按鍵觸發的聲音屏蔽掉 } } else //如果期間檢查到S9按鍵已經松手 { Su8KeyStep=1; //返回步驟1繼續掃描 Su8KeyLock=0; Su16KeyCnt=0; Su8ColumnRecord++; if(Su8ColumnRecord>=3) { Su8ColumnRecord=0; } } break; } } void KeyTask(void) { if(0==vGu8KeySec) { return; } switch(vGu8KeySec) { case 1: //S1按鍵的任務 if(Gu8LedStatus>0) { Gu8LedStatus--; //控制LED“往左邊跑” Gu8DisplayUpdate=1; //刷新顯示 } if(0==vGu8ShieldVoiceFlag) //聲音沒有被屏蔽 { vGu8BeepTimerFlag=0; vGu16BeepTimerCnt=KEY\_VOICE\_TIME; //發出“嘀”一聲 vGu8BeepTimerFlag=1; } vGu8ShieldVoiceFlag=0; //及時把屏蔽標志清零,避免平時正常的單擊聲音也被淹沒。 vGu8KeySec=0; //響應按鍵服務處理程序后,按鍵編號必須清零,避免一致觸發 break; case 9: //S9按鍵的任務 if(Gu8LedStatus<7) { Gu8LedStatus++; //控制LED“往右邊跑” Gu8DisplayUpdate=1; //刷新顯示 } if(0==vGu8ShieldVoiceFlag) //聲音沒有被屏蔽 { vGu8BeepTimerFlag=0; vGu16BeepTimerCnt=KEY\_VOICE\_TIME; //發出“嘀”一聲 vGu8BeepTimerFlag=1; } vGu8ShieldVoiceFlag=0; //及時把屏蔽標志清零,避免平時正常的單擊聲音也被淹沒。 vGu8KeySec=0; //響應按鍵服務處理程序后,按鍵編號必須清零,避免一致觸發 break; default: 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>

                              哎呀哎呀视频在线观看