最近在某個(gè)項(xiàng)目中需要用到按鍵檢測(cè)電子表格使用方法電子表格使用方法,常規(guī)想法是矩陣鍵盤,于是就這么做下去了。
后來在編程的時(shí)候發(fā)現(xiàn),實(shí)現(xiàn)按鍵檢測(cè)并不是一件容易的事情,特別是有多個(gè)按鍵同時(shí)按下的情況下。
在這個(gè)過程中邏輯太容易亂了,于是借助了電子表格工具(WPS或者Excel),試圖節(jié)省工作量。
后來發(fā)現(xiàn)效果確實(shí)不錯(cuò),于是在這里分享一下。
繪制PCB使用的是 10,但是家中未安裝該軟件,于是使用將原理圖重新繪制了一遍,大家將就著看。
我們的目的是實(shí)現(xiàn)2*3的矩陣鍵盤的檢測(cè),思路大概是這樣的:
1.將Row1置低,其他管腳設(shè)置為帶有上拉的輸入狀態(tài),將其狀態(tài)記錄下來。
2.將Row2置低,其他管腳設(shè)置為帶有上拉的輸入狀態(tài),記錄輸入結(jié)果并計(jì)算按鍵狀態(tài)。
或許大家覺得這個(gè)過程很容易,一看Col哪個(gè)被拉低就知道是哪個(gè)按鍵被按下了。
其實(shí)卻不是這樣,有可能存在多個(gè)按鍵共同作用導(dǎo)致某個(gè)Col被拉低的情況。
為什么不用Col來掃描?——因?yàn)閽呙鑂ow只需要掃描2回,掃描Col需要掃描3回。
為了解決這個(gè)問題,盡可能多的檢測(cè)出多個(gè)按鍵按下的不同狀況,我使用了大名鼎鼎的電子表格(俗稱Excel),來實(shí)現(xiàn)這個(gè)檢測(cè)。
作為6個(gè)按鍵,有2^6=64種不同的狀態(tài),所以我們可以通過電子表格的自動(dòng)填充功能實(shí)現(xiàn)這個(gè)工作。
我們將A列定義為64種不同狀態(tài)(0-63)
然后在B2單元格內(nèi)輸入“=(A2,6)”,將A列的數(shù)據(jù)轉(zhuǎn)換為二進(jìn)制數(shù)
C列表頭為SW1,C2單元格“=LEFT(B2,1)”,即二進(jìn)制數(shù)左端第1個(gè)數(shù)
D列表頭為SW2,D2單元格“=RIGHT(LEFT(B2,2),1)”,即二進(jìn)制數(shù)左端取2個(gè),再?gòu)倪@兩個(gè)里取右端的一個(gè),也就是左起第二個(gè)數(shù)
同理:
E列表頭SW3,E2單元格“=RIGHT(LEFT(B2,3),1)”
F列表頭SW4,F(xiàn)2單元格“=RIGHT(LEFT(B2,4),1)”
G列表頭SW5,G2單元格“=RIGHT(LEFT(B2,5),1)”
H列表頭SW6,H2單元格“=RIGHT(B2,1)”
完成上述步驟之后,我們空出一列來(I列),接下來計(jì)算按鍵按下之后產(chǎn)生的邏輯關(guān)系,這也是最讓人頭疼的問題。
為了節(jié)省列寬(屏幕大小有限,可以顯示更多內(nèi)容),我們將J1單元格輸入R2(Row_2),K1單元格輸入C1(Col_1),L1=C2,M1=C3
為什么沒有R1?——這里計(jì)算的是R1設(shè)定為低的情況下其他信號(hào)線的輸入狀態(tài),R1一定為0。
接下來就是信號(hào)怎么判斷了。
由于上拉是弱上拉,在按鍵按下的時(shí)候,如果對(duì)應(yīng)行是低電平,那么列會(huì)被拉低。
在這里我們約定,如果SW1=1,表示SW1按下,其余按鍵以此類推。
在R1=0時(shí),要讓R2也等于0,那么需要SW1和SW4同時(shí)按下,或者SW2和SW5同時(shí)按下,又或者SW3和SW6同時(shí)按下。
于是,J2單元格(Row2列)的邏輯就是“=IF(C2*F2+D2*G2+E2*H2,0,1)”(組合邏輯不要忘記了)
接下來計(jì)算Col1列,這個(gè)時(shí)候剛剛計(jì)算得到的Row2列的結(jié)果可以用到。
我們知道,如果Row1為低,且SW1按下,那么Col為低,如果Row2為低,且SW4為低,那么Col也為低。
故K2單元格:“=IF(C2+F2*(1-J2),0,1)”
L2:“=IF(D2+G2*(1-J2),0,1)”
M2:“=IF(E2+H2*(1-J2),0,1)”
繼續(xù)空一列(N列),有了之前的經(jīng)驗(yàn),很容易填寫下面的單元格:
O2:“=IF(C2*F2+D2*G2+E2*H2,0,1)”
P2:“=IF(F2+C2*(1-O2),0,1)”
Q2:“=IF(G2+D2*(1-O2),0,1)”
R2:“=IF(H2+E2*(1-O2),0,1)”
然后選中這一行的所有數(shù)據(jù),向下填充到65行(表頭占一行,數(shù)據(jù)有64行)
效果如下圖所示:
有人要問了,不就是計(jì)算個(gè)邏輯嗎,何必搞的那么復(fù)雜呢?又是公式又是填充的。
剛剛說了那么久,還沒提到電氣連接是怎么樣的。
這個(gè)項(xiàng)目原本我是用STM32實(shí)現(xiàn)的,但是,這里是板塊嘛,那么我就移植一下咯,用最常見的來做。
R1:P1.4
R2:P1.3
C1:P1.2
C2:P1.1
C3:P1.0
初始化的代碼就不寫了,定義兩個(gè)宏:
# R1OUT() do{\
P1DIR &= ~BIT3;\
P1OUT |= BIT3;\
P1REN |= BIT3;\
P1REN &= ~BIT4;\
P1OUT &= ~BIT4;\
P1DIR |= BIT4;\
}while(0)
# R2OUT() do{\
P1DIR &= ~BIT4;\
P1OUT |= BIT4;\
P1REN |= BIT4;\
P1REN &= ~BIT3;\
P1OUT &= ~BIT3;\
P1DIR |= BIT3;\
}while(0)
那么我們可以分兩輪掃描,定期執(zhí)行。
第一輪掃描R2OUT()運(yùn)行時(shí)的P1IN,讀取完畢執(zhí)行R1OUT()。
第二輪掃描R1OUT()運(yùn)行時(shí)的P1IN,讀取完畢執(zhí)行R2OUT()。
那么我們可以知道,第一輪掃描的時(shí)候,R2是輸出,我們需要讀取P1.4 P1.2 P1.1 P1.0的鍵值。
第二輪掃描的時(shí)候,R1輸出,我們需要讀取P1.3 P1.2 P1.1 P1.0的鍵值。
由于使用了連續(xù)的寄存器,所以我們能夠很方便的使用一個(gè)寄存器來儲(chǔ)存鍵碼。
于是,我們只需要在第一輪掃描的時(shí)候?qū)⒓拇嫫髑宄賹㈡I值搬運(yùn)到寄存器的高4位,在第二輪掃描的時(shí)候直接將寄存器加上P1IN的低4位即可。
void ()
{
char count=1;
char =0;
char ====0;
if(count&0x01)//奇數(shù)輪
{
char temp=0;
temp=P1IN;
=((temp&0x07)