版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認(rèn)領(lǐng)
文檔簡介
一、學(xué)習(xí)目標(biāo)1.了解矩陣鍵盤的結(jié)構(gòu)。2.掌握行列式掃描編程原理。3.掌握線反轉(zhuǎn)法編程原理。二、學(xué)習(xí)任務(wù)任務(wù)一鍵盤接口概述及行列式掃描編程原理;任務(wù)二線反轉(zhuǎn)法編程原理;任務(wù)三簡易計算器的實現(xiàn)。三、任務(wù)分解任務(wù)一鍵盤接口概述及行列式掃描編程原理【任務(wù)描述】認(rèn)識4*4矩陣鍵盤,通過行列式掃描編程,檢測到按鍵并通過顯示器顯示出來。【任務(wù)描述】【任務(wù)分析】
當(dāng)按鍵被按下時,電平被拉成低電平,此電平作為作為單片機的輸入,單片機接收到低電平時,認(rèn)為產(chǎn)生了按鍵動作,執(zhí)行相應(yīng)的程序?!鞠嚓P(guān)知識】鍵盤有獨立式鍵盤和矩陣式鍵盤兩種,獨立式鍵盤在前面項目中已有介紹。若鍵盤閉合鍵的識別是由專用硬件實現(xiàn)的,則稱為編碼鍵盤;若用軟件實現(xiàn)閉合鍵識別的,則稱為非編碼鍵盤。鍵盤接口應(yīng)有以下功能:鍵盤掃描功能,即檢測是否有鍵閉合;鍵識別功能,確定被閉合鍵所在的行列位置;產(chǎn)生相應(yīng)的鍵的代碼(鍵值)功能;消除按鍵抖動及對應(yīng)對多鍵串按(復(fù)鍵)的功能。矩陣中無按鍵按下時,行線為高電平;當(dāng)有按鍵按下時,行線電平狀態(tài)將由與此行線相連的列線的電平?jīng)Q定。列線的電平如果為低,則行線電平為低;列線的電平如果為高,則行線的電平也為高,這是識別按鍵是否按下的關(guān)鍵所在。第1步,識別鍵盤有無鍵按下。先把所有列線均置為0(執(zhí)行P3=0xf0),然后檢查各行線電平是否都為高,如果不全為高,說明有鍵按下,否則無鍵被按下。00001111例如,當(dāng)K7鍵按下時,第2行線為低,還不能確定是K7鍵被按下,因為如果同一行的鍵4、5或6之一被按下,行線也為低電平。只能得出第2行有鍵被按下的結(jié)論。第2步,識別出哪個按鍵被按下。采用逐行掃描法,在某一時刻只讓1條行線處于低電平,其余所有行線處于高電平。(輸出指令P3=0xef指令)當(dāng)?shù)?行為低電平,其余各行為高電平時,因為是鍵7被按下,第1行的行線仍處于高電平,此時讀回P3口的值為P3=0xef,只要P3口輸出與輸入的值相等,便說明不是此行的鍵按下。當(dāng)?shù)?行為低電平(輸出指令P3=0xdf),由于K7鍵按下,第4列被拉成了0電平,此時讀回P3口的值為P3=0xd7,只要P3口輸出與輸入的值不相等,便說明是此行的鍵按下,把讀回P3口的值作為特征碼,在程序中作進一步判定。請大家分析一下如果是K9鍵按下時,單片機是如何判定的。綜上所述,掃描法的思想是,先把某一行置為低電平,其余各行置為高電平,檢查各行線電平的變化,如果某列線電平為低電平,則可確定此行此列交叉點處的按鍵被按下。【項目實施】#include<reg51.h>#defineucharunsignedchar#defineuintunsignedintucharkey;unsignedcharcodedisp_code[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};//共陰段碼表unsignedcharcodekey_code[]={0xee,0xed,0xeb,0xe7,0xde,0xdd,0xdb,0xd7,0xbe,0xbd,0xbb,0xb7,0x7e,0x7d,0x7b,0x77};//按鍵按下產(chǎn)生的特征碼unsignedcharcodetest_code[]={0xef,0xdf,0xbf,0x7f};//行掃描用的值voiddelayms(uintms){uchart;while(ms--){for(t=0;t<120;t++);}}ucharkeyscan()//鍵盤掃描程序{ucharscan1,temp,j;P3=0xf0;scan1=P3;if((scan1&0xf0)!=0xf0)//判鍵是否按下
{delayms(30);//延時10msscan1=P3; if((scan1&0xf0)!=0xf0)//二次判鍵是否按下
temp=0x0e; { for(j=0;j<4;j++)//用特征碼掃描1-4次,最少1次跳出此循環(huán){ P3=test_code[j];//輸出行掃描用的值
switch(P3)//讀入P3口的特征值
{ case0xee:P0=disp_code[0];break; case0xed:P0=disp_code[1];break; case0xeb:P0=disp_code[2];break; case0xe7:P0=disp_code[3];break; case0xde:P0=disp_code[4];break; case0xdd:P0=disp_code[5];break; case0xdb:P0=disp_code[6];break; case0xd7:P0=disp_code[7];break; case0xbe:P0=disp_code[8];break;case0xbd:P0=disp_code[9];break; case0xbb:P0=disp_code[10];break; case0xb7:P0=disp_code[11];break; case0x7e:P0=disp_code[12];break; case0x7d:P0=disp_code[13];break; case0x7b:P0=disp_code[14];break; case0x77:P0=disp_code[15];break; } }}}elseP3=0xff;return(16);}main(){P0=0x40;//數(shù)碼管顯示"-"P3=0xff; while(1){keyscan();//調(diào)用鍵盤掃描子程序
}}【進階提高】按鍵按下時候,如何產(chǎn)生按鍵音?程序該如何修改?#include<reg51.h>#defineucharunsignedchar#defineuintunsignedintucharkey;unsignedcharcodedisp_code[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};unsignedcharcodekey_code[]={0xee,0xed,0xeb,0xe7,0xde,0xdd,0xdb,0xd7,0xbe,0xbd,0xbb,0xb7,0x7e,0x7d,0x7b,0x77};voiddelayms(uintms){uchart;while(ms--){for(t=0;t<120;t++);}}ucharkeyscan()//鍵盤掃描程序{ucharscan1,scan2,keycode,j;P3=0xf0;scan1=P3;if((scan1&0xf0)!=0xf0)//判鍵是否按下
{delayms(30);//延時30msscan1=P3;if((scan1&0xf0)!=0xf0)//二次判鍵是否按下
{P3=0x0f;scan2=P3;keycode=scan1|scan2;//組合成鍵編碼for(j=0;j<=15;j++){if(keycode==key_code[j])//查表得鍵值
{key=j;return(key);}}}}elseP3=0xff;return(16);}//蜂鳴器
voidBeep(){ uchari; for(i=0;i<100;i++) { delayms(1); BEEP=~BEEP; } BEEP=0;}voidkeydown()//判斷是否有鍵按下{P3=0x0f;if((P3&0x0f)!=0x0f){keyscan(); Beep();P0=disp_code[key];//在數(shù)碼管上顯示鍵值
}}main(){P0=0x40;//數(shù)碼管顯示"-"P3=0xff; BEEP=0;while(1){keydown();}}任務(wù)二線反轉(zhuǎn)法【任務(wù)描述】認(rèn)識4*4矩陣鍵盤,通過線反轉(zhuǎn)掃描編程,檢測到按鍵并通過顯示器顯示出來。【任務(wù)分析】反轉(zhuǎn)法就是通過給單片機的端口賦值兩次,最后得出所按鍵的值的一種算法。【相關(guān)知識】首先我們給P1口賦值0x0f,即00001111,假設(shè)0鍵按下了,則這時P1口的實際值為00001110;接著我們給P1口再賦值0xf0,即11110000,如果0鍵按下了,則這時P1口的實際值為11100000;最后我們把兩次P1口的實際值相加得11101110,即0xee。由此我們便得到了按下0鍵時所對應(yīng)的數(shù)值0xee,以此類推可得出其他15個按鍵對應(yīng)的數(shù)值,有了這種對應(yīng)關(guān)系,矩陣鍵盤編程問題也就解決了,也就是程序的算法已經(jīng)有了?!救蝿?wù)實施】#include<reg52.h> //頭文件#defineucharunsignedchar //宏定義#defineuintunsignedintucharkey,n; //定義變量ucharcodetable[]={0xee,0xed,0xeb,0xe7,0xde,0xdd,0xdb,0xd7,0xbe,0xbd,0xbb,0xb7,0x7e,0x7d,0x7b,0x77};//反轉(zhuǎn)法矩陣鍵盤的各個按鍵的計算值ucharcodeyin[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71}; //共陰極數(shù)碼管顯示0~Fvoiddelay(uinti)//延時函數(shù){while(i--);}voidkeyscan(){ucharlow,height,i; //定義局部變量,用low得出低4位的值,用height得出高4位的值
P3=0x0f; //給P3賦值00001111low=P3&0x0f;if(low!=0x0f){delay(100);if(low!=0x0f) low=P3&0x0f; //若有鍵按下,得出低四位的值
}P3=0xf0; //給P3賦值11110000height=P3&0xf0;if(height!=0xf0){delay(100);if(height!=0xf0) height=P3&0xf0; //若有鍵按下,得出高4位的值
}
key=low+height; //高4位的值與低4位的值相加
for(i=0;i<16;i++) {if(key==table[i]) //通過查表得出n的值
n=i; }}voidmain(){while(1){ keyscan(); P0=yin[n]; //在數(shù)碼管上顯示相應(yīng)的鍵值
}}【進階提高】用狀態(tài)機實現(xiàn)按鍵檢測識別。#include<reg52.h> //頭文件#defineucharunsignedchar //宏定義#defineuintunsignedintucharkey,n; //定義變量ucharcodetable[]={0xee,0xed,0xeb,0xe7,0xde,0xdd,0xdb,0xd7,0xbe,0xbd,0xbb,0xb7,0x7e,0x7d,0x7b,0x77};//矩陣鍵盤的各個按鍵的計算值ucharcodeyin[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71,0x00}; //共陰極數(shù)碼管顯示0~F#definekeyP3 //矩陣鍵盤的數(shù)據(jù)口#defineno_key0xff//無按鍵按下#definekey_state00//狀態(tài)0,此時無按鍵按下#definekey_state11 //狀態(tài)1,此時處于確定按鍵是否按下#definekey_state22 //狀態(tài)2,此時判斷按鍵是否釋放uintflag=0;voiddelay(uinti)//延時函數(shù){while(i--);}ucharKeyscan(){ ucharkey_state;//狀態(tài)指示
ucharkey_value; //鍵值返回
ucharkey_temp; ucharkey1,key2; key=0xf0; key1=key; key1=key&0xf0; //確定哪一行的按鍵按下
key=0x0f; key2=key; key2=key&0x0f; //確定哪一列的按鍵按下 key_temp=key1|key2; //確定按鍵位置
switch(key_state) //檢測當(dāng)前狀態(tài)
{ casekey_state0: //之前無按鍵被按下
if(key_temp!=no_key) //說明有按鍵按下或者抖動
{ key_state=key_state1; //轉(zhuǎn)換為狀態(tài)1,然后去判斷是否真的按下
} break;
casekey_state1: //狀態(tài)1,說明之前已經(jīng)有按鍵按下或者抖動
if(key_temp==no_key) //全為高電平,說明是抖動{ key_state=key_state0; //返回到狀態(tài)1,
} else //確實有按鍵被按下
{ switch(key_temp)//當(dāng)確定按鍵按下后,列舉所有的按鍵情況
{ case0xee:key_value=1;break; case0xed:key_value=2;break; case0xeb:key_value=3;break; case0xe7:key_value=4;break; case0xde:key_value=5;break; case0xdd:key_value=6;break; case0xdb:key_value=7;break; case0xd7:key_value=8;break;case0xbe:key_value=9;break; case0xbd:key_value=10;break; case0xbb:key_value=11;breakkey_value=15;break; case0x77:key_value=16;break; default:key_value=17; } key_state=key_state2; //跳到狀態(tài)2,進而判斷是否被釋放
};
break; casekey_state2: //狀態(tài)2,判斷是否被釋放
if(key_temp==no_key) //釋放,轉(zhuǎn)回到狀態(tài)0 { key_state=key_state0; } break; } returnkey_value;}voidTimer0()interrupt1{ TH0=0xd8; //10Ms產(chǎn)生一次中斷
TL0=0xf0; flag=1;}voidTimer0_init(){ TMOD=0x01; TH0=0xd8; //12MHz10Ms TL0=0xf0; EA=1; ET0=1; TR0=1; }voidmain(){ucharkey_state=0; ucharreadkey; readkey=0xff; Timer0_init();while(1) { if(flag) { flag=0; readkey=Keyscan(); if(0<readkey&&readkey<=17){ P0=yin[readkey-1]; } else{ P0=yin[16];//Targetnotcreated } } }}任務(wù)三簡易計算器的實現(xiàn)【任務(wù)描述】本計算器是以51單片機為核心構(gòu)成的簡易計算器系統(tǒng)。該系統(tǒng)通過單片機控制,實現(xiàn)對4*4鍵盤掃描進行實時的按鍵檢測,并把檢測數(shù)據(jù)和計算結(jié)果存儲下來,顯示在LED數(shù)碼管上,并可實現(xiàn)清零?!救蝿?wù)分析】功能模塊一:實時鍵盤掃描;功能模塊二:數(shù)據(jù)存儲和計算;功能模塊三:LED數(shù)碼管顯示;功能模塊四:清零程序的主要思想是:將按鍵抽象為字符,然后就是對字符的處理。將操作數(shù)分別轉(zhuǎn)化為字符串存儲,操作符存儲為字符形式。然后調(diào)用compute()函數(shù)進行計算并返回結(jié)果。【相關(guān)知識】一、Break語句與continue語句的區(qū)別while循環(huán)、do-while循環(huán)和for循環(huán)中,可以用break語句跳出循環(huán),用continue語句結(jié)束本次循環(huán),而對用goto語句和if語句構(gòu)成的循環(huán),不能用break語句和continue語句進行控制。二、任意整數(shù)送數(shù)碼管顯示之前的分離出千位、百位等位數(shù)的方法假如整數(shù)n=100086,試分離出n的萬位、千位、百位、十位和個位。#include<stdio.h>voidmain(){unsignedintn=10086;unsignedintwan,qian,bai,shi,ge;wan=n/10000%10;//分離出萬位上的數(shù),抓住n/10000這個規(guī)律
qian=n/1000%10;////分離出千位上的數(shù),抓住n/1000這個規(guī)律bai=n/100%10;//分離出百位上的數(shù),抓住n/1000這個規(guī)律
shi=n/10%10;//分離出十位上的數(shù),抓住n/1000這個規(guī)律
ge=n%10;////分離出千位上的數(shù),抓住n%10這個規(guī)律
printf("%d%d%d%d%d",wan,qian,bai,shi,ge);}【任務(wù)實施】這里仿真電路中使用的鍵盤是Proteus系統(tǒng)自帶的,關(guān)鍵字為“KEYPAD-SMALLCALC”。簡易計算器電路對應(yīng)的程序代碼如下:#include<reg52.h>#include<intrins.h>#defineucharunsignedchar#defineuintunsignedint#definekeymask0x0f#defineKEYPORT P1 //鍵盤接入端口#defineNOKEY255 //無鍵值標(biāo)志#defineKEYMASK0x0f //ucharaa,flag=0,op,flag1,flag2,timerflag=0;longdiyi,dier,jieguo;ucharcodeweixuan[]={0xdf,0xef,0xf7,0xfb,0xfd,0xfe};ucharcodetable[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x00};ucharbuffer[6]={10,10,10,10,10,10};ucharg_ucKeyNum=16; //鍵值voiddelay(uintz){ uintx,y; for(x=z;x>0;x--) for(y=110;y>0;y--);}ucharScanKey(void){ staticucharKeyState=0; //按鍵狀態(tài)
staticucharKeyValue; //臨時鍵值
staticucharKeyLine; //按鍵行值
ucharKeyReturn=NOKEY; //鍵值返回變量
uchari; //循環(huán)變量
switch(KeyState) //狀態(tài)判斷
{case0: //初始狀態(tài)
KeyLine=0x10;for(i=1;i<=4;i++){KEYPORT=~KeyLine; //第一列送低電平
KEYPORT=~KeyLine;KeyValue=KEYMASK&KEYPORT; //讀取P1口行值
if(KeyValue==KEYMASK){ KeyLine<<=1;//掃描下一列
}else{KeyState++;break;}}break;case1: //確認(rèn)狀態(tài)
if(KeyValue==(KEYMASK&KEYPORT)){
switch(KeyLine|KeyValue){case0x87:KeyReturn=10;break;//+號
case0x8b:KeyReturn=11;break;//-號
case0x8d:KeyReturn=12;break; //×號
case0x8e:KeyReturn=13;break;//÷號
case0x47:KeyReturn=14;break;//=號
case0x4b:KeyReturn=3;break;case0x4d:KeyReturn=6;break;case0x4e:KeyReturn=9;break;case0x27:KeyReturn=0;break;case0x2b:KeyReturn=2;break;case0x2d:KeyReturn=5;break;case0x2e:KeyReturn=8;break;case0x17:KeyReturn=15;break;//清0case0x1b:KeyReturn=1;break;case0x1d:KeyReturn=4;break;case0x1e:KeyReturn=7;break; default:KeyReturn=16;break;}KeyState++; //進入狀態(tài)2}else KeyState--; //否則進入狀態(tài)0break;case2: //完成態(tài)
KEYPORT=0x0f;KEYPORT=0x0f;if((KEYMASK&KEYPORT)==KEYMASK){ KeyState=0; }break;}returnKeyReturn;
}voiddoo(ucharkey)//鍵值處理函數(shù){uchari,n,k,a[6],b[6],c[6];longm;if((key>=0)&&(key<=9)){if(flag==1)//允許清緩存數(shù)組了
{flag=0;for(i=0;i<6;i++)//六個元素置為10,數(shù)碼管便不顯示
buffer[i]=10;}if(flag2==1)buffer[0]=10;//有按鍵,buffer[0]首先顯示
for(i=0;i<5;i++)buffer[5-i]=buffer[4-i];//一個按鍵值進來首先向左移動一個位置
buffer[0]=key;}if((key>=10)&&(key<=13))//準(zhǔn)備運算的兩個操作數(shù)
{op=key;for(i=0;i<6;i++)//取出緩存數(shù)組的值放數(shù)組a{a[i]=buffer[i];if(a[i]==10)//標(biāo)志10表示的是0a[i]=0;}diyi=a[5]*100000+a[4]*10000+a[3]*1000+a[2]*100+a[1]*10+a[0];//拼成一個數(shù)
flag=1;//放置標(biāo)志位flag=1,可以清緩存數(shù)組了
}if(key==14)//點了=號的話,準(zhǔn)備運算,為假的話準(zhǔn)備接收第2個操作數(shù)
{for(i=0;i<6;i++)//第二個操作數(shù)放數(shù)組b {b[i]=buffer[i]; if(b[i]==10) b[i]=0; } dier=b[5]*100000+b[4]*10000+b[3]*1000+b[2]*100+b[1]*10+b[0];//拼成第2個操作數(shù)
switch(op) {case10:jieguo=diyi+dier;break;//兩個數(shù)進行加減乘除運算
case11:jieguo=diyi-dier;break; case12:jieguo=diyi*dier;break; case13:m=diyi/dier;n=diyi%dier*10/dier;k=diyi%dier*10%dier*10/dier;break; default:break; }if(op==13)//除法相關(guān)操作
{flag1=1; buffer[0]=k; buffer[1]=n; for(i=2;i<6;i++) {c[i]=m%10; m=
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 旅游業(yè)務(wù)賦能增長
- 旅游業(yè)績超越預(yù)期
- 2025年智能制造園區(qū)廠房拆遷補償及產(chǎn)業(yè)布局協(xié)議4篇
- 個人投資企業(yè)資產(chǎn)轉(zhuǎn)讓協(xié)議版A版
- 2025柴油終端零售居間合作協(xié)議書4篇
- 2025年度茶葉產(chǎn)品研發(fā)與技術(shù)轉(zhuǎn)移合同4篇
- 2025年度海上風(fēng)電場建設(shè)分包工程合同4篇
- 2025年度教育培訓(xùn)課程定制合同書4篇
- 專業(yè)服裝面料供應(yīng)協(xié)議范本版B版
- 二零二四二手設(shè)備購買與維修合同2篇
- 2024-2025學(xué)年成都高新區(qū)七上數(shù)學(xué)期末考試試卷【含答案】
- 定額〔2025〕1號文-關(guān)于發(fā)布2018版電力建設(shè)工程概預(yù)算定額2024年度價格水平調(diào)整的通知
- 2025年浙江杭州市西湖區(qū)專職社區(qū)招聘85人歷年高頻重點提升(共500題)附帶答案詳解
- 《數(shù)學(xué)廣角-優(yōu)化》說課稿-2024-2025學(xué)年四年級上冊數(shù)學(xué)人教版
- “懂你”(原題+解題+范文+話題+技巧+閱讀類素材)-2025年中考語文一輪復(fù)習(xí)之寫作
- 2025年景觀照明項目可行性分析報告
- 2025年江蘇南京地鐵集團招聘筆試參考題庫含答案解析
- 2025年度愛讀書學(xué)長參與的讀書項目投資合同
- 電力系統(tǒng)分析答案(吳俊勇)(已修訂)
- 化學(xué)-河北省金太陽質(zhì)檢聯(lián)盟2024-2025學(xué)年高三上學(xué)期12月第三次聯(lián)考試題和答案
- 期末復(fù)習(xí)試題(試題)-2024-2025學(xué)年四年級上冊數(shù)學(xué) 北師大版
評論
0/150
提交評論