久久久久久久999_99精品久久精品一区二区爱城_成人欧美一区二区三区在线播放_国产精品日本一区二区不卡视频_国产午夜视频_欧美精品在线观看免费
標題:
簡單按鍵掃描程序
[打印本頁]
作者:
qunqun
時間:
2015-7-9 00:41
標題:
簡單按鍵掃描程序
核心算法:
unsigned char Trg;
unsigned char Cont;
void KeyRead( void )
{
unsigned char ReadData = PINB^0xff; // 1
Trg = ReadData & (ReadData ^ Cont); // 2
Cont = ReadData; // 3
}
下面是程序解釋:
Trg(triger) 代表的是觸發,Cont(continue)代表的是連續按下。
1:讀PORTB的端口數據,取反,然后送到ReadData 臨時變量里面保存起來。
2:算法1,用來計算觸發變量的。一個位與操作,一個異或操作,我想學過C語言都應該懂吧?Trg為全局變量,其它程序可以直接引用。
3:算法2,用來計算連續變量。
看到這里,有種“知其然,不知其所以然”的感覺吧?代碼很簡單,但是它到底是怎么樣實現我們的目的的呢?好,下面就讓我們繞開云霧看青天吧。
我們最常用的按鍵接法如下:AVR是有內部上拉功能的,但是為了說明問題,我是特意用外部上拉電阻。那么,按鍵沒有按下的時候,讀端口數據為1,如果按鍵按下,那么端口讀到0。下面就看看具體幾種情況之下,這算法是怎么一回事。
(1) 沒有按鍵的時候
端口為0xff,ReadData讀端口并且取反,很顯然,就是 0x00 了。
Trg = ReadData & (ReadData ^ Cont); (初始狀態下,Cont也是為0的)很簡單的數學計算,因為ReadData為0,則它和任何數“相與”,結果也是為0的。
Cont = ReadData; 保存Cont 其實就是等于ReadData,為0;
結果就是:
ReadData = 0;
Trg = 0;
Cont = 0;
(2) 第一次PB0按下的情況
端口數據為0xfe,ReadData讀端口并且取反,很顯然,就是 0x01 了。
Trg = ReadData & (ReadData ^ Cont); 因為這是第一次按下,所以Cont是上次的值,應為為0。那么這個式子的值也不難算,也就是 Trg = 0x01 & (0x01^0x00) = 0x01
Cont = ReadData = 0x01;
結果就是:
ReadData = 0x01;
Trg = 0x01;Trg只會在這個時候對應位的值為1,其它時候都為0
Cont = 0x01;
(3) PB0按著不松(長按鍵)的情況
端口數據為0xfe,ReadData讀端口并且取反是 0x01 了。
Trg = ReadData & (ReadData ^ Cont); 因為這是連續按下,所以Cont是上次的值,應為為0x01。那么這個式子就變成了 Trg = 0x01 & (0x01^0x01) = 0x00
Cont = ReadData = 0x01;
結果就是:
ReadData = 0x01;
Trg = 0x00;
Cont = 0x01;
因為現在按鍵是長按著,所以MCU會每個一定時間(20ms左右)不斷的執行這個函數,那么下次執行的時候情況會是怎么樣的呢?
ReadData = 0x01;這個不會變,因為按鍵沒有松開
Trg = ReadData & (ReadData ^ Cont) = 0x01 & (0x01 ^ 0x01) = 0 ,只要按鍵沒有松開,這個Trg值永遠為 0 。!
Cont = 0x01;只要按鍵沒有松開,這個值永遠是0x01。
(4) 按鍵松開的情況
端口數據為0xff,ReadData讀端口并且取反是 0x00 了。
Trg = ReadData & (ReadData ^ Cont) = 0x00 & (0x00^0x01) = 0x00
Cont = ReadData = 0x00;
結果就是:
ReadData = 0x00;
Trg = 0x00;
Cont = 0x00;
很顯然,這個回到了初始狀態,也就是沒有按鍵按下的狀態。
總結一下,不知道想懂了沒有?其實很簡單,答案如下:
Trg 表示的就是觸發的意思,也就是跳變,只要有按鍵按下(電平從1到0的跳變),那么Trg在對應按鍵的位上面會置一,我們用了PB0則Trg的值為0x01,類似,如果我們PB7按下的話,Trg 的值就應該為 0x80 ,這個很好理解,還有,最關鍵的地方,Trg 的值每次按下只會出現一次,然后立刻被清除,完全不需要人工去干預。所以按鍵功能處理程序不會重復執行,省下了一大堆的條件判斷,這個可是精粹哦!!Cont代表的是長按鍵,如果PB0按著不放,那么Cont的值就為 0x01,相對應,PB7按著不放,那么Cont的值應該為0x80,同樣很好理解。
如果還是想不懂的話,可以自己演算一下那兩個表達式,應該不難理解的。
應用一:一次觸發的按鍵處理
假設PB0為蜂鳴器按鍵,按一下,蜂鳴器beep的響一聲。這個很簡單,但是大家以前是怎么做的呢?對比一下看誰的方便?
#define KEY_BEEP 0x01
void KeyProc(void)
{
if (Trg & KEY_BEEP) // 如果按下的是KEY_BEEP
{
Beep(); // 執行蜂鳴器處理函數
}
}
應用2:長按鍵的處理
這里具個簡單例子,為了只是說明原理,PB0是模式按鍵,短按則切換模式,PB1就是加,如果長按的話則連加(玩過電子表吧?沒錯,就是那個。
#define KEY_MODE 0x01 // 模式按鍵
#define KEY_PLUS 0x02 // 加
void KeyProc(void)
{
if (Trg & KEY_MODE) // 如果按下的是KEY_MODE,而且你常按這按鍵也沒有用,
{ //它是不會執行第二次的哦 , 必須先松開再按下
Mode++; // 模式寄存器加1,當然,這里只是演示,你可以執行你想
// 執行的任何代碼
}
if (Cont & KEY_PLUS) // 如果“加”按鍵被按著不放
{
cnt_plus++; // 計時
if (cnt_plus > 100) // 20ms*100 = 2S 如果時間到
{
Func(); // 你需要的執行的程序
}
}
}
應用3:點觸型按鍵和開關型按鍵的混合使用
volatile unsigned char Intrcnt;
void InterruptHandle() // 中斷服務程序
{
Intrcnt++; // 1ms 中斷1次,可變
}
void main(void)
{
SysInit();
while(1) // 每20ms 執行一次大循環
{
KeyRead(); // 將每個子程序都掃描一遍
KeyProc();
Func1();
Funt2();
…
…
while(1)
{
if (Intrcnt>20) // 一直在等,直到20ms時間到
{
Intrcnt="0";
break; // 返回主循環
}
}
}
}
歡迎光臨 (http://www.zg4o1577.cn/bbs/)
Powered by Discuz! X3.1
主站蜘蛛池模板:
亚洲91精品
|
精品一区欧美
|
91在线精品秘密一区二区
|
国产一二三视频在线观看
|
国产 亚洲 网红 主播
|
国产精品一区在线观看
|
亚洲欧美综合精品久久成人
|
在线免费观看黄a
|
日本午夜免费福利视频
|
国产精品18久久久久久白浆动漫
|
极品一区
|
国产乱码精品一品二品
|
国产目拍亚洲精品99久久精品
|
日干夜干
|
奇米影视首页
|
日韩精品一区二区三区在线播放
|
亚洲成人精品视频
|
五月激情婷婷在线
|
久久99精品国产
|
中文字幕免费在线
|
国产一区二区三区在线观看免费
|
久久久高清
|
日本免费一区二区三区
|
日韩在线观看一区
|
精品国产18久久久久久二百
|
免费久久久久久
|
九九亚洲精品
|
亚洲+变态+欧美+另类+精品
|
日本午夜精品
|
日本精品一区二区三区在线观看视频
|
365夜爽爽欧美性午夜免费视频
|
午夜一级黄色片
|
天天操天天舔
|
国产精品一区在线播放
|
中文字幕一二三区
|
久久综合成人精品亚洲另类欧美
|
99成人
|
午夜欧美a级理论片915影院
|
日韩日b视频
|
精品一区在线看
|
精精国产xxxx视频在线播放7
|