標(biāo)題: 請教51單片機矩陣鍵盤反轉(zhuǎn)法掃描遇到的無法解決的問題 [打印本頁]

作者: 萬家燈火51    時間: 2024-10-30 17:06
標(biāo)題: 請教51單片機矩陣鍵盤反轉(zhuǎn)法掃描遇到的無法解決的問題
mcu 是stc8a8k64s4a12單片機,矩陣鍵盤是帶上拉電阻的真實鍵盤,P1口連接,采用反轉(zhuǎn)法掃描。1.必須設(shè)置成開漏模式才能采集到數(shù)據(jù)。其它模式都不行,不知道啥原因。2.第一次置P1=0xf0,可以正確設(shè)置,且能正確采集回按鍵情況;第二次反轉(zhuǎn) 設(shè)置P1=0x0f,然后采集p1口的數(shù)據(jù)完全是錯的,比如只采集p1一次,得到的數(shù)據(jù)是第一次(反轉(zhuǎn)設(shè)置之前)的數(shù)據(jù);比如重復(fù)寫一次采集數(shù)據(jù)(連續(xù)采集兩次),得到的數(shù)據(jù)跟采集一次的又完全不同,且還發(fā)現(xiàn)低電平被拉高了(本來應(yīng)該是高電平被拉低)。
沒招數(shù)了。請大神指點下迷津。

P1為KEY_ScanPort  要設(shè)置這個 初始化 P1M1=0xff;P1M0=0xff;才能讀回數(shù)據(jù)

        
        KEY_ScanPort=0xF0;                 //列線為輸入,行線為輸出,并置行線輸出全為0
        temp=KEY_ScanPort;                 //讀P1口       能正確得到數(shù)據(jù)
        temp=temp&0xF0;
        temp=~((temp>>4)|0xF0);
        if(temp==1)
                key=0;
        else if(temp==2)
                key=1;
        else if(temp==4)
                key=2;
        else if(temp==8)
                key=3;
        KEY_ScanPort=0xFF;//for read  這一句可有可不有,但proteus里那鍵盤keypad仿真必須得有這個,否則無法采集
        KEY_ScanPort=0x0F;                 //設(shè)置反轉(zhuǎn),行線為輸入,列線為輸出,并置列線輸出全為0
        MDelay(3);        //懷疑引腳電平反轉(zhuǎn)起效果時有一個較長的時間延遲
        temp=KEY_ScanPort;                 //讀P1口 讀出來跟沒有反轉(zhuǎn)之前的采集情況一樣,就是高四位有3個1
        temp=KEY_ScanPort;                //重復(fù)采集一下發(fā)現(xiàn)低四位有4個1 高四位有1~2個1,低電平反而被拉高了。
       temp=KEY_ScanPort;                //再重復(fù)采集一下發(fā)現(xiàn)低四位有4個1,高四位是4個0,不動了,按鍵沒效果。反正反轉(zhuǎn)后無法采集到正確信息
        temp=temp&0x0F;
        temp=~(temp|0xF0);        
        if(temp==1)
                key=key+0;
        else if(temp==2)
                key=key+4;
        else if(temp==4)
                key=key+8;
        else if(temp==8)
                key=key+12;
                             


作者: xiaobendan001    時間: 2024-10-30 19:07
矩陣怎么接的?4*4的?一次拉低4個IO,怎么判斷是那個IO上的KEY?
作者: qinlu123    時間: 2024-10-31 09:44
反轉(zhuǎn)法矩陣掃描當(dāng)然要配置成開漏模式啦必須所有用到的IO都是開漏才行,這樣你讓IO輸出高電平的時候該IO可以被外界信號拉低或者拉高方便你檢測,這和IIC的SDA要配置成開漏一個原理。我沒看明白你是開漏模式下完全正常還是開漏模式下也存在問題。還有設(shè)置完IO口狀態(tài)再去讀取IO口電平時中間要間隔一段時間一般情況下1ms完全夠了,因為電路存在寄生電容,開漏模式下IO狀態(tài)從低到高需要上拉電阻給寄生電容充電需要時間不會瞬間變化的。
作者: qinlu123    時間: 2024-10-31 09:46
xiaobendan001 發(fā)表于 2024-10-30 19:07
矩陣怎么接的?4*4的?一次拉低4個IO,怎么判斷是那個IO上的KEY?

反轉(zhuǎn)法,先把四個列線拉低檢測4個行線電平,然后把4個行線拉低去檢測4個列線電平。把兩次檢測結(jié)果或在一起就能知道是哪個按鍵被按下了
作者: cy009    時間: 2024-10-31 10:25
矩陣鍵盤反轉(zhuǎn)法掃描實例,以 P1口為例。
1.拉低P1低4位;
2.若P1高4位出現(xiàn)低電平,則讀P1的值;
3.反轉(zhuǎn),釋放P1低4位,拉低P1高4位;
4.讀P1的值;
5.將步驟2和4的值或運算;
6.對步驟5的值進行判斷或查表,執(zhí)行給定任務(wù)。
作者: xiaobendan001    時間: 2024-10-31 12:51
cy009 發(fā)表于 2024-10-31 10:25
矩陣鍵盤反轉(zhuǎn)法掃描實例,以 P1口為例。
1.拉低P1低4位;
2.若P1高4位出現(xiàn)低電平,則讀P1的值;

這樣就是需要都設(shè)置標(biāo)準(zhǔn)IO才行吧,設(shè)置開漏就是沒有上拉電阻,那么高電平由誰提供?
我還真沒試過這種,都是一個IO一個IO的拉低,然后檢測另外四個的電平變化。
作者: qinlu123    時間: 2024-10-31 14:05
xiaobendan001 發(fā)表于 2024-10-31 12:51
這樣就是需要都設(shè)置標(biāo)準(zhǔn)IO才行吧,設(shè)置開漏就是沒有上拉電阻,那么高電平由誰提供?
我還真沒試過這種, ...

外部上拉電阻提供高電平啊,所有的按鍵電路無論矩陣也好獨立按鍵也好不都得配上拉電阻嗎?
作者: lkc8210    時間: 2024-10-31 14:57
上拉電阻阻值多大?
作者: 萬家燈火51    時間: 2024-10-31 15:44
xiaobendan001 發(fā)表于 2024-10-30 19:07
矩陣怎么接的?4*4的?一次拉低4個IO,怎么判斷是那個IO上的KEY?

4*4的,p1低四位接行,高四位接列。每條線都有上拉電阻,上拉電阻電路是放矩陣鍵盤里面的。反轉(zhuǎn)法是f0   再0f的,按鍵按下,只會有一個高電平會被拉低的。原理上來說。仿真都沒有問題的。就是實際這個鍵盤,反轉(zhuǎn)后采集不回來數(shù)據(jù)。
作者: 萬家燈火51    時間: 2024-10-31 15:45
qinlu123 發(fā)表于 2024-10-31 09:46
反轉(zhuǎn)法,先把四個列線拉低檢測4個行線電平,然后把4個行線拉低去檢測4個列線電平。把兩次檢測結(jié)果或在一 ...

就是行線拉低,采集不回數(shù)據(jù)。
作者: WL0123    時間: 2024-10-31 15:45
給你一個4*4矩陣按鍵示例,端口設(shè)置為準(zhǔn)雙向模式。有無外置上拉電阻無所謂。程序放在主函數(shù)里查詢。key初值為0,鍵值輸出1~16,使用后可以清0.
void keyscan()                                        //按鍵掃描程序
{
        static bit sign=0;                        //按鍵狀態(tài)標(biāo)志
        static int count=0;                        //消抖計數(shù)變量                       
        unsigned char temp=0;                //臨時變量
        P1=0xf0;                                        //賦值P1 1111 0000
        if(P1!=0xf0)                                //檢測有按鍵按下
        {
                count++;                                //消抖計數(shù)
                if(count>=100 && sign==0)//根據(jù)主程序查詢周期調(diào)整count大小,約10~20ms防抖即可
                {                       
                        sign=1;                                //按鍵狀態(tài)標(biāo)志置1
                        temp=P1;                        //保存P1值xxxx 0000,x為0或1
                        temp|=0x0f;                        //保存temp按位或0x0f值xxxx 1111
                        P1=temp;                        //賦值P1 xxxx 1111
                        switch(P1)
                        {
                                case 0xee: key= 1; break;
                                case 0xde: key= 2; break;
                                case 0xbe: key= 3; break;
                                case 0x7e: key= 4; break;
                                case 0xed: key= 5; break;
                                case 0xdd: key= 6; break;
                                case 0xbd: key= 7; break;
                                case 0x7d: key= 8; break;
                                case 0xeb: key= 9; break;
                                case 0xdb: key=10; break;
                                case 0xbb: key=11; break;
                                case 0x7b: key=12; break;
                                case 0xe7: key=13; break;
                                case 0xd7: key=14; break;
                                case 0xb7: key=15; break;
                                case 0x77: key=16; break;
                        }
                }
        }
        else                                                //鍵抬起
        {
                sign=0;                                        //按鍵狀態(tài)標(biāo)志清0
                count=0;                                //消抖計數(shù)清0
        }
}
作者: 萬家燈火51    時間: 2024-10-31 15:46
qinlu123 發(fā)表于 2024-10-31 09:44
反轉(zhuǎn)法矩陣掃描當(dāng)然要配置成開漏模式啦必須所有用到的IO都是開漏才行,這樣你讓IO輸出高電平的時候該IO可以 ...

我明天試試,延遲1ms后再采集試試。
作者: 萬家燈火51    時間: 2024-10-31 15:50
cy009 發(fā)表于 2024-10-31 10:25
矩陣鍵盤反轉(zhuǎn)法掃描實例,以 P1口為例。
1.拉低P1低4位;
2.若P1高4位出現(xiàn)低電平,則讀P1的值;

您這步驟完全正確。就是第三步,代碼直接用  P1=0x0f,起不了作用。您所謂 釋放p1低四位,拉低p1高四位,是不是不使用的P1=0x0f語句?如不使,應(yīng)該怎么用?
作者: 萬家燈火51    時間: 2024-10-31 15:51
xiaobendan001 發(fā)表于 2024-10-31 12:51
這樣就是需要都設(shè)置標(biāo)準(zhǔn)IO才行吧,設(shè)置開漏就是沒有上拉電阻,那么高電平由誰提供?
我還真沒試過這種, ...

鍵盤上提供了上拉結(jié)構(gòu)的,高電平有鍵盤提供。開漏是可以的。
作者: xiaobendan001    時間: 2024-10-31 16:39
qinlu123 發(fā)表于 2024-10-31 14:05
外部上拉電阻提供高電平啊,所有的按鍵電路無論矩陣也好獨立按鍵也好不都得配上拉電阻嗎?

既然要用外部上拉,為何還要關(guān)閉內(nèi)部上拉?還是說這種接法和讀取方法需要非常精確的上拉,內(nèi)部因為制造工藝問題誤差太大不能用?那么多少才最好用?
作者: 萬家燈火51    時間: 2024-10-31 23:25
WL0123 發(fā)表于 2024-10-31 15:45
給你一個4*4矩陣按鍵示例,端口設(shè)置為準(zhǔn)雙向模式。有無外置上拉電阻無所謂。程序放在主函數(shù)里查詢。key初值 ...

這代碼也許不錯,第二次只有一個低電平線。明天試試效果。
作者: 萬家燈火51    時間: 2024-10-31 23:30
xiaobendan001 發(fā)表于 2024-10-31 16:39
既然要用外部上拉,為何還要關(guān)閉內(nèi)部上拉?還是說這種接法和讀取方法需要非常精確的上拉,內(nèi)部因為制造工 ...

是這樣的,設(shè)置為其它模式,一次數(shù)據(jù)都讀不回來。設(shè)置為開漏,立刻就讀回來了。原因我不會分析。另外查到stm32,如果是開漏模式,還有幾個寄存器要聯(lián)合配置,比如有個配置低電平究竟是哪個范圍,范圍不對采集的數(shù)據(jù)可能會錯。不知道是不是因為沒配置的原因?我不知道stc8有沒有這些寄存器。沒看它的說明書。
作者: 405616736    時間: 2024-11-1 00:48
        KEY_ScanPort=0xF0;
******
        KEY_ScanPort=0xFF;//for read  這一句可有可不有,但proteus里那鍵盤keypad仿真必須得有這個,否則無法采集

這里加一個延時試試,我解釋不了,但我這樣做就正常了
        KEY_ScanPort=0x0F;                 //設(shè)置反轉(zhuǎn),行線為輸入,列線為輸出,并置列線輸出全為0
作者: qinlu123    時間: 2024-11-1 08:12
xiaobendan001 發(fā)表于 2024-10-31 16:39
既然要用外部上拉,為何還要關(guān)閉內(nèi)部上拉?還是說這種接法和讀取方法需要非常精確的上拉,內(nèi)部因為制造工 ...

習(xí)慣問題吧,我很少用單片機的內(nèi)部上拉,51多年不用了不了解,stm32的內(nèi)部上拉電阻太大很多場合都不合適?戳讼51IO設(shè)置結(jié)合我之前做51時候的經(jīng)歷把IO配置成準(zhǔn)雙向IO也行即M1=0;M0=0
作者: qinlu123    時間: 2024-11-1 08:15
萬家燈火51 發(fā)表于 2024-10-31 15:45
就是行線拉低,采集不回數(shù)據(jù)。

你先檢查IO輸入檢測有沒有問題,把8和IO都輸出0讀一下IO狀態(tài)然后都輸出1再讀一下狀態(tài)。用萬用表量一量是不是對
作者: Graves    時間: 2024-11-1 14:21
temp=KEY_ScanPort;                 //讀P1口 讀出來跟沒有反轉(zhuǎn)之前的采集情況一樣,就是高四位有3個1
不知道你是用什么方法來讀temp值的?這時候萬用表量一下高低電平是不是和讀的符合,感覺大概率硬件問題
作者: 萬家燈火51    時間: 2024-11-1 18:47
問題解決。∈紫确浅8兄x各位大佬積極出主意和提供經(jīng)驗。看到您們的回復(fù),一下子覺得很踏實。困惑幾周的問題,綜合大家的想法突然有了思路。問題出在兩個地方:一個是沒有等待按鍵釋放就退出掃描,代碼又重復(fù)進入掃描覆蓋了前一次的數(shù)據(jù)。這個是看到上面大佬代碼里搞那么多狀態(tài)標(biāo)記驚醒了我。第二個問題是,開漏輸出,電平上拉全靠外電路,電阻值大小和是否有旁路電容等,這個拉高過程有點長。電路理論里的三要素法,大致可以判斷,時間常數(shù)在毫秒級。線反轉(zhuǎn)法第一次設(shè)置后,要延時1毫秒,反轉(zhuǎn)后要延時2毫秒再采集數(shù)據(jù),就完全正確了。非常感謝大家之外,有幾點感觸。1是謝謝大家技術(shù)上的開放心態(tài)。。特別鄙視xxxx,看兩句話就要收錢要么就是各種坑各種牛皮。,知識都被鎖。2.是遇到問題不要輕易懷疑芯片不可靠,是自己不可靠。3是這個論壇能查到真東西,能解決真問題。到搜這個論壇很難搜到,全是冒充51黑的網(wǎng)站。網(wǎng)絡(luò)生態(tài)太惡心。。廣告了
作者: xiaobendan001    時間: 2024-11-2 07:19
萬家燈火51 發(fā)表于 2024-11-1 18:47
問題解決!首先非常感謝各位大佬積極出主意和提供經(jīng)驗?吹侥鷤兊幕貜(fù),一下子覺得很踏實。困惑幾周的問 ...

不用開漏用標(biāo)準(zhǔn)IO不行嗎?要等2MS,這太浪費時間了吧。2US還行
作者: 萬家燈火51    時間: 2024-11-2 12:14
xiaobendan001 發(fā)表于 2024-11-2 07:19
不用開漏用標(biāo)準(zhǔn)IO不行嗎?要等2MS,這太浪費時間了吧。2US還行

標(biāo)準(zhǔn)口,沒有用延時等待不行。改天測一下用了延時,行不行。一般用鍵盤,按鍵都要延時5-10毫秒消抖的,正好掃描占用3毫秒,延時消抖3毫秒,效果很好。能滿足常規(guī)要求。
作者: 萬家燈火51    時間: 2024-11-2 12:18
Graves 發(fā)表于 2024-11-1 14:21
temp=KEY_ScanPort;                 //讀P1口 讀出來跟沒有反轉(zhuǎn)之前的采集情況一樣,就是高四位有3個1
不 ...

查出來原因了。應(yīng)該是反復(fù)進入掃描循環(huán),等待時間不夠,引腳反復(fù)處于高低電平變換造成的。
作者: 萬家燈火51    時間: 2024-11-2 12:21
405616736 發(fā)表于 2024-11-1 00:48
KEY_ScanPort=0xF0;
******
        KEY_ScanPort=0xFF;//for read  這一句可有可不有,但prote ...

你提醒了我。應(yīng)該就是延時等待電平穩(wěn)定。這一句與讀準(zhǔn)備沒關(guān)系。就是起了延時作用。
作者: hxy52zero    時間: 2024-11-2 13:33
萬家燈火51 發(fā)表于 2024-11-1 18:47
問題解決!首先非常感謝各位大佬積極出主意和提供經(jīng)驗?吹侥鷤兊幕貜(fù),一下子覺得很踏實。困惑幾周的問 ...

當(dāng)時是搜A2開發(fā)板仿真電路才搜到的這個論壇
作者: 萬家燈火51    時間: 2024-11-2 23:05
hxy52zero 發(fā)表于 2024-11-2 13:33
當(dāng)時是搜A2開發(fā)板仿真電路才搜到的這個論壇

用百度白天搜 51黑電子論壇  就能搜到,晚上用這個關(guān)鍵詞搜,會出來一堆顏色相關(guān)的,且翻幾頁都找不到這個論壇。我并且截圖留證了。百度惡心得很,想搜時又搜不到。
作者: qinlu123    時間: 2024-11-4 08:04
xiaobendan001 發(fā)表于 2024-11-2 07:19
不用開漏用標(biāo)準(zhǔn)IO不行嗎?要等2MS,這太浪費時間了吧。2US還行

用我的驅(qū)動就不用擔(dān)心浪費時間,建議樓主如果做項目的話還是用我的驅(qū)動吧,平常玩玩就無所謂了。還有樓主借鑒的程序也不咋地找個好點的用。




歡迎光臨 (http://www.torrancerestoration.com/bbs/) Powered by Discuz! X3.1